Willkommen bei WordPress. Dies ist dein erster Beitrag. Bearbeite oder lösche ihn und beginne mit dem Schreiben!
Hallo Welt!
von raredesign | Dez 3, 2019 | Allgemein | 0 Kommentare
Cokiee Shell
Current Path : /var/www/web28/html/wp-content/themes/Avada/includes/lib/inc/fusion-app/ |
Current File : //var/www/web28/html/wp-content/themes/Avada/includes/lib/inc/fusion-app/fusion-app.js |
/* global builderConfig, awbTypoData, FusionPageBuilder, builderId, fusionSettings, FusionPageBuilderApp, fusionAllElements, fusionAppConfig, FusionApp, fusionOptionName, fusionBuilderText, fusionIconSearch */ /* jshint -W020 */ var FusionEvents = _.extend( {}, Backbone.Events ); ( function() { jQuery( document ).ready( function() { var fusionApp = Backbone.Model.extend( { // jshint ignore: line initialize: function() { this.builderId = builderId; // User is logged in and connected to back-end. this.connected = true; // This data is set by preview_data(); this.initialData = {}; this.callback = new FusionPageBuilder.Callback(); this.dialog = new FusionPageBuilder.Dialog(); this.inlineEditor = new FusionPageBuilder.inlineEditor(); this.validate = new FusionPageBuilder.Validate(); this.hotkeys = new FusionPageBuilder.Hotkeys(); this.settings = 'undefined' !== typeof fusionSettings ? fusionSettings : false; // Store TO changed (for multilingual). this.elementDefaults = 'undefined' !== typeof fusionAllElements ? jQuery.extend( true, {}, fusionAllElements ) : {}; this.editedDefaults = {}; this.editedTo = {}; // Content changed status for save button. this.contentChanged = {}; // Current data this.data = {}; this.data.postMeta = {}; this.data.samePage = true; this.builderActive = false; this.hasEditableContent = true; // This can have data added from external to pass on for save. this.customSave = {}; // Objects to map TO changes to defaults of others. this.settingsPoTo = false; this.settingsToPo = false; this.settingsToParams = false; this.settingsToExtras = false; this.storedPoCSS = {}; this.storedToCSS = {}; // UI this.toolbarView = new FusionPageBuilder.Toolbar( { fusionApp: this } ); this.builderToolbarView = false; this.sidebarView = false; this.postLockView = false; this.renderUI(); // Preview size. this.previewWindowSize = 'large'; // Hold scripts which are being added to frame. this.scripts = {}; // Font Awesome stuff. this.listenTo( FusionEvents, 'fusion-preview-update', this.toggleFontAwesomePro ); this.listenTo( FusionEvents, 'fusion-to-status_fontawesome-changed', this.FontAwesomeSubSets ); // Preview updates. this.listenTo( FusionEvents, 'awb-update-studio-item-preview', this.previewColors ); this.setHeartbeatListeners(); this.correctLayoutTooltipPosition(); this.initStudioPreview(); // Cache busting var. this.refreshCounter = 0; // Track changes made this.hasChange = false; this.showLoader(); this.modifierActive = false; window.onkeydown = this.keyActive.bind( this ); window.onkeyup = this.keyInactive.bind( this ); document.getElementById( 'fb-preview' ).contentWindow.onkeydown = this.keyActive.bind( this ); document.getElementById( 'fb-preview' ).contentWindow.onkeyup = this.keyInactive.bind( this ); // If page switch has been triggered manually. this.manualSwitch = false; this.linkSelectors = 'td.tribe-events-thismonth a, .tribe-events-month-event-title a,.fusion-menu a, .fusion-secondary-menu a, .fusion-logo-link, .fusion-imageframe > a, .widget a, .woocommerce-tabs a, .fusion-posts-container a:not(.fusion-rollover-gallery), .fusion-rollover .fusion-rollover-link, .project-info-box a, .fusion-meta-info-wrapper a, .related-posts a, .related.products a, .woocommerce-page .products .product a, #tribe-events-content a, .fusion-breadcrumbs a, .single-navigation a, .fusion-column-inner-bg a'; }, /** * SIframe loaded event. * * @since 2.0.0 * @return {void} */ iframeLoaded: function() { this.linkListeners(); FusionEvents.trigger( 'fusion-iframe-loaded' ); }, /** * Sets active key modifier * * @since 2.0.0 * @return {void} */ keyActive: function( event ) { if ( event.ctrlKey || 17 == event.keyCode || 91 == event.keyCode || 93 == event.keyCode ) { this.modifierActive = true; } }, /** * Resets active key modifier * * @since 2.0.0 * @return {void} */ keyInactive: function( event ) { if ( event.ctrlKey || 17 == event.keyCode || 91 == event.keyCode || 93 == event.keyCode ) { this.modifierActive = false; } }, /** * Hides frame loader. * * @since 2.0.0 * @return {void} */ hideLoader: function() { jQuery( '#fb-preview-loader' ).removeClass( 'fusion-loading' ); jQuery( '#fusion-frontend-builder-toggle-global-panel, #fusion-frontend-builder-toggle-global-page-settings' ).css( 'pointer-events', 'auto' ); }, /** * Shows frame loader. * * @since 2.0.0 * @return {void} */ showLoader: function() { if ( jQuery( 'body' ).hasClass( 'expanded' ) ) { jQuery( '#fb-preview-loader' ).css( 'width', 'calc(100% - ' + jQuery( '#customize-controls' ).width() + 'px)' ); } else { jQuery( '#fb-preview-loader' ).css( 'width', '100%' ); } jQuery( '#fusion-frontend-builder-toggle-global-panel, #fusion-frontend-builder-toggle-global-page-settings' ).css( 'pointer-events', 'none' ); jQuery( '#fb-preview-loader' ).addClass( 'fusion-loading' ); }, /** * Corrects the position of builder layout tooltips when they would overflow the modals. * * @since 2.1 * @return {void} */ correctLayoutTooltipPosition: function() { jQuery( document ).on( 'mouseenter', '.fusion-layout-buttons .fusion-builder-layout-button-load-dialog', function() { var tooltip = jQuery( this ).find( '.fusion-builder-load-template-dialog-container' ), tooltipOffsetLeft = tooltip.offset().left, tooltipWidth = tooltip.outerWidth(), tooltipOffsetRight = tooltipOffsetLeft + tooltipWidth, modalContentWrapper = jQuery( this ).closest( '.ui-dialog-content' ), modalContentWrapperOffsetLeft = modalContentWrapper.offset().left, modalContentWrapperWidth = modalContentWrapper.outerWidth(), modalContentWrapperOffsetRight = modalContentWrapperOffsetLeft + modalContentWrapperWidth; if ( tooltipOffsetRight > modalContentWrapperOffsetRight ) { jQuery( this ).find( '.fusion-builder-load-template-dialog' ).css( 'left', '-' + ( tooltipOffsetRight - modalContentWrapperOffsetRight + 20 ) + 'px' ); } } ); jQuery( document ).on( 'mouseleave', '.fusion-layout-buttons .fusion-builder-layout-button-load-dialog', function() { jQuery( this ).find( '.fusion-builder-load-template-dialog' ).css( 'left', '' ); } ); }, /** * Inits studio previews. * * @since 3.5 * @return {void} */ initStudioPreview: function() { // Studio preview. jQuery( 'body' ).on( 'click', '.studio-wrapper .fusion-page-layout:not(.awb-demo-pages-layout) img', function( event ) { var $item = jQuery( event.currentTarget ).closest( '.fusion-page-layout' ), url = $item.data( 'url' ), $wrapper = $item.closest( '.studio-wrapper' ), layoutID = $item.data( 'layout-id' ); $wrapper.addClass( 'loading fusion-studio-preview-active' ); $wrapper.find( '.fusion-loader' ).show(); $wrapper.append( '<iframe class="awb-studio-preview-frame" src="' + url + '" frameBorder="0" scrolling="auto" onload="FusionApp.studioPreviewLoaded();" allowfullscreen=""></iframe>' ); $wrapper.find( '.awb-import-options' ).addClass( 'open' ); $wrapper.data( 'layout-id', layoutID ); } ); // Remove studio preview. jQuery( 'body' ).on( 'click', '.fusion-studio-preview-back', function( event ) { var $wrapper = jQuery( event.currentTarget ).closest( '.studio-wrapper' ); event.preventDefault(); $wrapper.removeClass( 'fusion-studio-preview-active' ); $wrapper.find( '.awb-studio-preview-frame' ).remove(); $wrapper.find( '.awb-import-options' ).removeClass( 'open' ); $wrapper.removeData( 'layout-id' ); } ); // Import in preview. jQuery( 'body' ).on( 'click', '.fusion-studio-preview-active .awb-import-studio-item-in-preview', function( event ) { var $wrapper = jQuery( event.currentTarget ).closest( '.studio-wrapper ' ), dataID = $wrapper.data( 'layout-id' ); event.preventDefault(); jQuery( '.fusion-studio-preview-active .fusion-studio-preview-back' ).trigger( 'click' ); jQuery( '.fusion-page-layout[data-layout-id="' + dataID + '"]' ).find( '.awb-import-studio-item' ).trigger( 'click' ); } ); }, /** * Actions to perform when studio preview is loaded. * * @since 3.5 * @return {void} */ studioPreviewLoaded: function() { if ( 'object' === typeof FusionApp ) { this.previewColors(); } else { jQuery( '.studio-wrapper' ).removeClass( 'loading' ).find( '.fusion-loader' ).hide(); } }, /** * Trigger preview colors to update on preview. * * @since 3.7 * @return {void} */ previewColors: function() { var styleObject = getComputedStyle( document.getElementById( 'fb-preview' ).contentWindow.document.documentElement ), overWriteType = jQuery( '.awb-import-options input[name="overwrite-type"]:checked' ).val(), shouldInvert = jQuery( '.awb-import-options input[name="invert"]:checked' ).val(), varData = { color_palette: {}, typo_sets: {}, shouldInvert: shouldInvert }; varData = this.getOverWritePalette( varData, styleObject, overWriteType, shouldInvert ); varData = this.getOverWriteTypography( varData, styleObject, overWriteType ); jQuery( '.awb-studio-preview-frame' )[ 0 ].contentWindow.postMessage( varData, '*' ); // Remove loading from preview. jQuery( '.studio-wrapper' ).removeClass( 'loading' ).find( '.fusion-loader' ).hide(); }, /** * Gets overwrite palette. * * @since 3.7 * @param {Object} varData The var data. * @param {Object} styleObject The style object. * @param {String} overWriteType The overwrite type. * @param {String} shouldInvert If should invert or not. * @return {object} */ getOverWritePalette: function( varData, styleObject, overWriteType, shouldInvert ) { if ( 'inherit' === overWriteType ) { switch ( shouldInvert ) { case 'dont-invert': for ( let step = 1; 9 > step; step++ ) { varData.color_palette[ '--awb-color' + step ] = styleObject.getPropertyValue( '--awb-color' + step ); varData.color_palette[ '--awb-color' + step + '-h' ] = styleObject.getPropertyValue( '--awb-color' + step + '-h' ); varData.color_palette[ '--awb-color' + step + '-s' ] = styleObject.getPropertyValue( '--awb-color' + step + '-s' ); varData.color_palette[ '--awb-color' + step + '-l' ] = styleObject.getPropertyValue( '--awb-color' + step + '-l' ); varData.color_palette[ '--awb-color' + step + '-a' ] = styleObject.getPropertyValue( '--awb-color' + step + '-a' ); } break; case 'do-invert': for ( let i = 1, revI = 8; 8 >= i; i++, revI-- ) { varData.color_palette[ '--awb-color' + i ] = styleObject.getPropertyValue( '--awb-color' + revI ); varData.color_palette[ '--awb-color' + i + '-h' ] = styleObject.getPropertyValue( '--awb-color' + revI + '-h' ); varData.color_palette[ '--awb-color' + i + '-s' ] = styleObject.getPropertyValue( '--awb-color' + revI + '-s' ); varData.color_palette[ '--awb-color' + i + '-l' ] = styleObject.getPropertyValue( '--awb-color' + revI + '-l' ); varData.color_palette[ '--awb-color' + i + '-a' ] = styleObject.getPropertyValue( '--awb-color' + revI + '-a' ); } break; } return varData; } return varData; }, /** * Gets typography overwrite. * * @since 3.7 * @param {Object} varData The var data. * @param {Object} styleObject The style object. * @param {String} overWriteType The overwrite type. * @return {object} */ getOverWriteTypography: function( varData, styleObject, overWriteType ) { const subsets = [ 'font-family', 'font-size', 'font-weight', 'font-style', 'font-variant', 'line-height', 'letter-spacing', 'text-transform' ]; if ( 'inherit' !== overWriteType ) { return varData; } // Global typography sets. for ( let step = 1; 6 > step; step++ ) { subsets.forEach( function( subset ) { subset = '--awb-typography' + step + '-' + subset; const value = styleObject.getPropertyValue( subset ); if ( '' !== value ) { varData.typo_sets[ subset ] = value; } } ); } // Headings typography. for ( let step = 1; 7 > step; step++ ) { subsets.forEach( function( subset ) { subset = '--h' + step + '_typography-' + subset; const value = styleObject.getPropertyValue( subset ); if ( '' !== value ) { varData.typo_sets[ subset ] = value; } } ); } return varData; }, /** * Listen for heartbeat changes to ensure user is logged in. * * @since 2.0.0 * @return {void} */ setHeartbeatListeners: function() { var self = this; // Refresh nonces if they have signed back in. jQuery( document ).on( 'heartbeat-tick', function( event, data ) { // We have newly lost connection, set state and fire event. if ( 'undefined' !== typeof data[ 'wp-auth-check' ] && false === data[ 'wp-auth-check' ] && FusionApp.connected ) { self.connected = false; FusionEvents.trigger( 'fusion-disconnected' ); window.adminpage = 'post-php'; } // We have regained connection - refresh nonces, set state and fire event. if ( 'undefined' !== typeof data.fusion_builder ) { fusionAppConfig.fusion_load_nonce = data.fusion_builder.fusion_load_nonce; self.connected = true; delete window.adminpage; FusionEvents.trigger( 'fusion-reconnected' ); } } ); }, renderUI: function() { // Panel. if ( 'undefined' !== typeof FusionPageBuilder.SidebarView ) { this.sidebarView = new FusionPageBuilder.SidebarView(); jQuery( '.fusion-builder-panel-main' ).append( this.sidebarView.render().el ); } // Icon picker pre-init. this.iconPicker(); }, /** * Main init setup trigger for app. Fired from preview frame. * * @since 2.0.0 * @return {void} */ setup: function() { this.previewWindow = jQuery( '#fb-preview' )[ 0 ].contentWindow; this.updateData(); jQuery( 'body' ).append( this.toolbarView.render( ).el ); // Start Builder if ( 'undefined' !== typeof FusionPageBuilder.AppView && this.getPost( 'post_type' ) && this.isEditable() ) { this.builderActive = true; // eslint-disable-next-line vars-on-top var hasOverrideContent = this.data.template_override && this.data.template_override.content, overrideContent = hasOverrideContent && this.data.template_override.content.post_content; if ( 'fusion_tb_section' !== this.data.query.post_type && hasOverrideContent && overrideContent && ! overrideContent.includes( 'fusion_tb_content' ) ) { this.hasEditableContent = false; } if ( 'undefined' === typeof FusionPageBuilderApp ) { window.FusionPageBuilderApp = new FusionPageBuilder.AppView( { // jshint ignore: line el: jQuery( '#fb-preview' ).contents().find( '.fusion-builder-live' ) } ); // Builder toolbar if ( 'undefined' !== typeof FusionPageBuilder.BuilderToolbar ) { this.builderToolbarView = new FusionPageBuilder.BuilderToolbar(); this.toolbarView.render(); } // Post Lock if ( 'undefined' !== typeof FusionPageBuilder.postLock ) { this.postLockView = new FusionPageBuilder.postLock(); this.postLockView.render(); } } else { FusionPageBuilderApp.fusionBuilderReset(); FusionPageBuilderApp.$el = jQuery( '#fb-preview' ).contents().find( '.fusion-builder-live' ); FusionPageBuilderApp.render(); } FusionPageBuilderApp.initialBuilderLayout( this.data ); this.listenTo( FusionEvents, 'fusion-builder-loaded', this.hideLoader ); } else { this.builderActive = false; jQuery( document.getElementById( 'fb-preview' ).contentWindow.document ).ready( this.hideLoader ); } FusionEvents.trigger( 'fusion-app-setup' ); this.listenForLeave(); if ( this.sidebarView || 'undefined' !== typeof FusionPageBuilderApp ) { this.createMapObjects(); } jQuery( '#fb-preview' ).removeClass( 'refreshing' ); if ( 'undefined' !== typeof this.hotkeys ) { this.hotkeys.attachListener(); } const context = this; // Add additional data to Heartbeat data. jQuery( document ).on( 'heartbeat-send', function ( event, data ) { data[ 'fusion-post-lock-id' ] = context.initialData.postDetails.post_id; } ); // Release post lock. window.onbeforeunload = function () { if ( ! fusionAppConfig.post_lock_data ) { jQuery.ajax( { type: 'POST', url: fusionAppConfig.ajaxurl, data: { post_id: context.initialData.postDetails.post_id, fusion_load_nonce: fusionAppConfig.fusion_load_nonce, action: 'fusion_release_post_lock' } } ); } }; }, isEditable: function() { return -1 !== builderConfig.allowed_post_types.indexOf( this.getPost( 'post_type' ) ) || 'post_cards' === FusionApp.data.fusion_element_type || 'mega_menus' === FusionApp.data.fusion_element_type || true === FusionApp.data.is_shop; }, linkListeners: function() { var self = this; // Events calendar events page tweaks. jQuery( '#fb-preview' )[ 0 ].contentWindow.jQuery( '#tribe-events' ).off(); if ( 'undefined' !== typeof jQuery( '#fb-preview' )[ 0 ].contentWindow.tribe_ev ) { jQuery( '#fb-preview' )[ 0 ].contentWindow.jQuery( jQuery( '#fb-preview' )[ 0 ].contentWindow.tribe_ev.events ).on( 'post-collect-bar-params.tribe', function() { var linkHref = jQuery( '#fb-preview' )[ 0 ].contentWindow.tribe_ev.state.cur_url; if ( -1 !== linkHref.indexOf( '?' ) ) { linkHref = linkHref + '&builder=true&builder_id=' + self.builderId; } else { linkHref = linkHref + '?builder=true&builder_id=' + self.builderId; } jQuery( '#fb-preview' )[ 0 ].contentWindow.tribe_ev.state.cur_url = linkHref; self.showLoader(); } ); } jQuery( '#fb-preview' ).contents().on( 'click', this.linkSelectors, function( event ) { event.preventDefault(); self.checkLink( event ); } ); }, /** * Listen for closing or history change. * * @since 2.0.0 * @return {void} */ listenForLeave: function() { document.getElementById( 'fb-preview' ).contentWindow.addEventListener( 'beforeunload', this.leavingAlert.bind( this ) ); window.addEventListener( 'beforeunload', this.leavingAlert.bind( this ) ); this.manualSwitch = false; }, /** * Check if we should show a warning message. * * @since 2.0.0 * @return {void} */ leavingAlert: function( event ) { if ( this.hasContentChanged() && ! this.manualSwitch ) { event.returnValue = fusionBuilderText.changes_will_be_lost; } }, /** * Saves the post-content. * * @since 2.0.0 * @param {Object} successAction - Action object, containing action name and params. * @return {void} */ savePostContent: function( successAction ) { var self = this, postData = this.getAjaxData( 'fusion_app_save_post_content' ), width = jQuery( '.fusion-builder-save-page' ).outerWidth() + jQuery( '.fusion-exit-builder' ).outerWidth(), button = jQuery( '.fusion-builder-save-page' ); button.toggleClass( 'sending' ).blur(); if ( 'object' === typeof successAction && 'undefined' !== typeof successAction.action && ( 'switch_page' === successAction.action || 'exit_builder' === successAction.action ) ) { jQuery( '#fusion-builder-confirmation-modal-dark-overlay' ).css( 'top', '54px' ); jQuery( '#fusion-builder-confirmation-modal-dark-overlay' ).before( '<div class="fusion-builder-confirmation-modal-save"></div>' ); jQuery( '.fusion-builder-confirmation-modal-save' ).attr( 'style', 'width:calc(100% - ' + width + 'px);' ); } jQuery.ajax( { type: 'POST', url: fusionAppConfig.ajaxurl, dataType: 'json', data: postData } ) .done( function( data ) { if ( 'object' !== typeof data ) { return; } if ( data.success && 'undefined' === typeof data.data.failure ) { // Save was successful. button.removeClass( 'sending' ).blur(); button.addClass( 'success' ); // Switch to new page after content was saved. if ( 'object' === typeof successAction && 'undefined' !== typeof successAction.action && 'switch_page' === successAction.action ) { self.switchPage( successAction.builderid, successAction.linkhref, successAction.linkhash ); } else if ( 'object' === typeof successAction && 'undefined' !== typeof successAction.action && 'exit_builder' === successAction.action ) { self.manualSwitch = true; window.location.href = successAction.link; } else { setTimeout( function() { button.removeClass( 'success' ); FusionApp.contentReset(); }, 2000 ); FusionEvents.trigger( 'fusion-app-saved' ); } } else if ( 'undefined' !== typeof data.data.failure && ( 'logged_in' === data.data.failure || 'nonce_check' === data.data.failure ) ) { // Save failed because user is not logged in, trigger heartbeat for log in form. jQuery( '#fusion-builder-confirmation-modal-dark-overlay' ).css( 'top', '' ); jQuery( '.fusion-builder-confirmation-modal-save' ).remove(); self.hideLoader(); button.removeClass( 'sending' ).blur(); button.addClass( 'failed' ); if ( 'undefined' !== typeof wp && 'undefined' !== typeof wp.heartbeat ) { FusionApp.confirmationPopup( { action: 'hide' } ); wp.heartbeat.connectNow(); } else { // No heartbeat warning. FusionApp.confirmationPopup( { title: fusionBuilderText.page_save_failed, content: fusionBuilderText.authentication_no_heartbeat, type: 'error', icon: '<i class="fusiona-exclamation-triangle" aria-hidden="true"></i>', actions: [ { label: fusionBuilderText.ok, classes: 'save yes', callback: function() { // Try again just in case. if ( 'undefined' !== typeof wp && 'undefined' !== typeof wp.heartbeat ) { wp.heartbeat.connectNow(); } FusionApp.confirmationPopup( { action: 'hide' } ); } } ] } ); } } else { // Save failed for another reason, provide details. jQuery( '#fusion-builder-confirmation-modal-dark-overlay' ).css( 'top', '' ); jQuery( '.fusion-builder-confirmation-modal-save' ).remove(); self.hideLoader(); button.removeClass( 'sending' ).blur(); button.addClass( 'failed' ); setTimeout( function() { button.removeClass( 'failed' ); }, 2000 ); FusionApp.confirmationPopup( { title: fusionBuilderText.problem_saving, content: fusionBuilderText.changes_not_saved + self.getSaveMessages( data.data ), type: 'error', icon: '<i class="fusiona-exclamation-triangle" aria-hidden="true"></i>', actions: [ { label: fusionBuilderText.ok, classes: 'save yes', callback: function() { if ( 'undefined' !== typeof wp && 'undefined' !== typeof wp.heartbeat ) { wp.heartbeat.connectNow(); } FusionApp.confirmationPopup( { action: 'hide' } ); } } ] } ); } } ); }, /** * List out the save data. * * @since 2.0.0 * @param {Object} data - The success/fail data. * @return {string} - Returns HTML. */ getSaveMessages: function( data ) { var returnMessages = ''; if ( 'object' === typeof data.failure ) { _.each( data.failure, function( messages ) { if ( 'string' === typeof messages ) { returnMessages += '<li class="failure"><i class="fusiona-exclamation-triangle" aria-hidden="true"></i>' + messages + '</li>'; } else if ( 'object' === typeof messages ) { _.each( messages, function( message ) { if ( 'string' === typeof message ) { returnMessages += '<li class="failure"><i class="fusiona-exclamation-triangle" aria-hidden="true"></i>' + message + '</li>'; } } ); } } ); } if ( 'object' === typeof data.success ) { _.each( data.success, function( messages ) { if ( 'string' === typeof messages ) { returnMessages += '<li class="success"><i class="fusiona-check" aria-hidden="true"></i>' + messages + '</li>'; } else if ( 'object' === typeof messages ) { _.each( messages, function( message ) { if ( 'string' === typeof message ) { returnMessages += '<li class="success"><i class="fusiona-check" aria-hidden="true"></i>' + message + '</li>'; } } ); } } ); } if ( '' !== returnMessages ) { return '<ul class="fusion-save-data-list">' + returnMessages + '</ul>'; } return ''; }, /** * Maps settings to params & page-options. * * @since 2.0.0 * @return {void} */ createMapObjects: function() { // Create the settings to params object. if ( ! this.settingsToParams && 'undefined' !== typeof FusionPageBuilderApp ) { this.createSettingsToParams(); } // Create the settings to extras object. if ( ! this.settingsToExtras && 'undefined' !== typeof FusionPageBuilderApp ) { this.createSettingsToExtras(); } // Create the settings to page options object. if ( ! this.settingsToPo ) { this.createSettingsToPo(); } }, /** * Maps settings to settingsToParams. * * @since 2.0.0 * @return {void} */ createSettingsToParams: function() { var settingsToParams = {}, paramObj; _.each( fusionAllElements, function( element, elementID ) { if ( ! _.isUndefined( element.settings_to_params ) ) { _.each( element.settings_to_params, function( param, setting ) { paramObj = { param: _.isObject( param ) && ! _.isUndefined( param.param ) ? param.param : param, callback: param.callback || false, element: elementID }; if ( _.isObject( settingsToParams[ setting ] ) ) { settingsToParams[ setting ].push( paramObj ); } else { settingsToParams[ setting ] = []; settingsToParams[ setting ].push( paramObj ); } } ); } } ); this.settingsToParams = settingsToParams; }, /** * Maps settings to settingsToExtras. * * @since 2.0.0 * @return {void} */ createSettingsToExtras: function() { var settingsToExtras = {}, paramObj; _.each( fusionAllElements, function( element, elementID ) { if ( ! _.isUndefined( element.settings_to_extras ) ) { _.each( element.settings_to_extras, function( param, setting ) { paramObj = { param: _.isObject( param ) && ! _.isUndefined( param.param ) ? param.param : param, callback: param.callback || false, element: elementID }; if ( _.isObject( settingsToExtras[ setting ] ) ) { settingsToExtras[ setting ].push( paramObj ); } else { settingsToExtras[ setting ] = []; settingsToExtras[ setting ].push( paramObj ); } } ); } } ); this.settingsToExtras = settingsToExtras; }, /** * Maps settings to settingsToPo. * * @since 2.0.0 * @return {void} */ createSettingsToPo: function() { var settingsToPo = {}, settingsPoTo = {}, paramObj; _.each( this.data.fusionPageOptions, function( tab, tabID ) { _.each( tab.fields, function( option, optionID ) { if ( ! _.isUndefined( option.to_default ) ) { paramObj = { to: _.isObject( option.to_default ) && ! _.isUndefined( option.to_default.id ) ? option.to_default.id : option.to_default, callback: option.to_default.callback || false, option: optionID, tab: tabID }; // Process settingsToPo if ( _.isObject( settingsToPo[ paramObj.to ] ) ) { settingsToPo[ paramObj.to ].push( paramObj ); } else { settingsToPo[ paramObj.to ] = []; settingsToPo[ paramObj.to ].push( paramObj ); } // Process settingsPoTo if ( _.isObject( settingsPoTo[ optionID ] ) ) { settingsPoTo[ optionID ] = paramObj.to; } else { settingsPoTo[ optionID ] = []; settingsPoTo[ optionID ] = paramObj.to; } } } ); } ); this.settingsToPo = settingsToPo; this.settingsPoTo = settingsPoTo; }, /** * Update the app data with preview data on load or page change. * * @since 2.0.0 * @return {void} */ updateData: function() { // Language is different. if ( 'undefined' !== typeof this.data.language && 'undefined' !== typeof this.initialData.languageTo && this.initialData.language !== this.data.language && 'undefined' !== typeof FusionApp.sidebarView ) { this.languageSwitch(); } if ( this.getPost( 'post_id' ) === this.initialData.postDetails.post_id ) { this.data.samePage = true; } else { // Set correct url in browser and history. this.updateURL( this.initialData.postDetails.post_permalink ); this.data = this.initialData; this.data.samePage = false; this.contentReset( 'page' ); this.storedPoCSS = false; this.customSave = {}; FusionEvents.trigger( 'fusion-history-clear' ); // If toolbar exists and language set, update switcher. if ( false !== this.toolbarView && this.data.language ) { this.toolbarView.updateLanguageSwitcher(); } FusionEvents.trigger( 'fusion-data-updated' ); } }, /** * Get post details by key or on its own. * * @since 2.0.0 * @param {string} key - The key we want to get from postDetails. If undefined all postDetails will be fetched. * @return {mixed} - Returns postDetails[ key ] if a key is defined, otherwise return postDetails. */ getPost: function( key ) { if ( 'object' !== typeof this.data.postDetails ) { return false; } if ( 'undefined' === typeof key ) { return jQuery.extend( true, {}, this.data.postDetails ); } if ( 'undefined' === typeof this.data.postDetails[ key ] ) { return false; } return this.data.postDetails[ key ]; }, /** * Get post details by key or on its own. * * @since 2.0.0 * @param {string} key - The key we want to get from postDetails. If undefined all postDetails will be fetched. * @return {mixed} - Returns postDetails[ key ] if a key is defined, otherwise return postDetails. */ getDynamicPost: function( key ) { if ( 'post_meta' === key ) { if ( 'object' !== typeof this.data.examplePostDetails ) { return FusionApp.data.postMeta; } return this.data.examplePostDetails.post_meta; } if ( ( 'fusion_tb_section' === FusionApp.data.postDetails.post_type || 'post_cards' === FusionApp.data.fusion_element_type || 'awb_off_canvas' === FusionApp.data.postDetails.post_type ) && 'undefined' !== typeof FusionApp.data.postMeta._fusion && 'undefined' !== typeof FusionApp.data.postMeta._fusion.dynamic_content_preview_type && 'undefined' !== typeof FusionApp.initialData.dynamicPostID ) { return FusionApp.initialData.dynamicPostID; } if ( 'object' !== typeof this.data.examplePostDetails ) { return this.getPost( key ); } if ( 'undefined' === typeof key ) { return jQuery.extend( true, {}, this.data.examplePostDetails ); } if ( 'undefined' == typeof this.data.examplePostDetails[ key ] ) { return this.getPost( key ); } return this.data.examplePostDetails[ key ]; }, /** * Set post details by key. * * @since 2.0.0 * @param {string} key - The key of the property we want to set. * @param {string} value - The value of the property we want to set. * @return {void} */ setPost: function( key, value ) { if ( 'object' !== typeof this.data.postDetails ) { this.data.postDetails = {}; } this.data.postDetails[ key ] = value; }, /** * Get preview url. * * @since 2.0.0 * @return {string} - URL. */ getPreviewUrl: function() { return FusionApp.previewWindow.location.href.replace( 'builder=true', 'builder=false&fbpreview=true' ); }, /** * Updates language specific options. * * @since 2.0.0 * @return {void} */ languageSwitch: function() { // Save defaults and edited TO. this.editedDefaults[ this.data.language ] = jQuery.extend( true, {}, fusionAllElements ); this.editedTo[ this.data.language ] = jQuery.extend( true, {}, FusionApp.settings ); // Change setting values to those of new language. if ( 'undefined' !== typeof this.editedTo[ this.initialData.language ] ) { FusionApp.settings = this.editedTo[ this.initialData.language ]; } else { FusionApp.settings = this.initialData.languageTo; } // Change option name to option for new language. window.fusionOptionName = this.initialData.optionName; // Restore element defaults, eg button color. if ( 'undefined' !== typeof this.editedDefaults[ this.initialData.language ] ) { window.fusionAllElements = jQuery.extend( true, {}, this.editedDefaults[ this.initialData.language ] ); } else if ( 'undefined' !== typeof this.initialData.languageDefaults ) { window.fusionAllElements = jQuery.extend( true, fusionAllElements, this.initialData.languageDefaults ); } else { window.fusionAllElements = jQuery.extend( true, {}, this.elementDefaults ); } // Rebuilder sidebar views for new values. FusionApp.sidebarView.refreshTo(); }, /** * Triggers a full-refresh of the preview iframe. * * @since 2.0.0 * @param {string} target - Target URL to load. * @param {Object} event - Event on click that triggered. * @param {Object} postDetails - Post details which should be used on refresh. * @return {void} */ fullRefresh: function( target, event, postDetails ) { this.showLoader(); target = 'undefined' === typeof target ? false : target; event = 'undefined' === typeof event ? {} : event; this.setGoogleFonts(); this.reInitIconPicker(); this.doTheFullRefresh( target, event, postDetails ); }, /** * Sets builder status in post meta.. * * @since 2.0.0 * @return {void} */ setBuilderStatus: function() { var builderStatus = false, savedStatus = 'undefined' !== typeof this.data.postMeta.fusion_builder_status ? this.data.postMeta.fusion_builder_status : false; if ( 'undefined' !== typeof FusionPageBuilderApp ) { builderStatus = 'active'; } if ( builderStatus !== savedStatus ) { this.data.postMeta.fusion_builder_status = builderStatus; this.contentChange( 'page', 'page-option' ); } }, /** * Get changed data for ajax requests. * * @since 2.0.0 * @param {string} action - The ajax action. * @param {Object} postDetails - Post details which should be used on refresh. * @return {Object} - Returns the postData. */ getAjaxData: function( action, postDetails ) { var postData = { post_id: this.getPost( 'post_id' ), fusion_load_nonce: fusionAppConfig.fusion_load_nonce, custom: jQuery.param( this.customSave ), builder_id: this.builderId }; if ( 'fusion_app_full_refresh' !== action && 'fusion_app_preview_only' !== action ) { postData.query = FusionApp.data.query; } if ( 'undefined' === typeof postDetails ) { postDetails = {}; } // Set the action if set. if ( 'string' === typeof action ) { postData.action = action; } // If page settings have changed then add them, but without post_content. if ( this.hasContentChanged( 'page', 'page-setting' ) ) { postData.post_details = this.getPost(); if ( 'undefined' !== typeof postData.post_details.post_content ) { delete postData.post_details.post_content; } } // If FB is active and post_content has changed. if ( 'undefined' !== typeof FusionPageBuilderApp && this.hasContentChanged( 'page', 'builder-content' ) ) { if ( 'undefined' !== typeof postDetails.post_content ) { postData.post_content = postDetails.post_content; } else { FusionPageBuilderApp.builderToShortcodes(); postData.post_content = this.getPost( 'post_content' ); // eslint-disable-line camelcase } this.setGoogleFonts(); } this.setBuilderStatus(); // If Avada panel exists and either TO or PO has changed. if ( this.sidebarView && ( this.hasContentChanged( 'global', 'theme-option' ) || this.hasContentChanged( 'page', 'page-option' ) ) ) { this.reInitIconPicker(); if ( this.hasContentChanged( 'global', 'theme-option' ) ) { postData.fusion_options = jQuery.param( this.maybeEmptyArray( FusionApp.settings ) ); // eslint-disable-line camelcase } if ( this.hasContentChanged( 'page', 'page-option' ) ) { postData.meta_values = jQuery.param( this.data.postMeta ); // eslint-disable-line camelcase } } if ( 'object' === typeof postData.post_details ) { postData.post_details = jQuery.param( postData.post_details ); // eslint-disable-line camelcase } // Option name for multilingual saving. if ( 'undefined' !== typeof fusionOptionName ) { postData.option_name = fusionOptionName; } if ( 'object' === typeof FusionApp.data.examplePostDetails && 'undefined' !== typeof FusionApp.data.examplePostDetails.post_id ) { postData.target_post = FusionApp.data.examplePostDetails.post_id; } return postData; }, /** * Triggers a full-refresh of the preview iframe. * * @since 2.0.0 * @param {string} target - Target URL to load. * @param {Object} event - Event on click that triggered. * @param {Object} postDetails - Post details which should be used on refresh. * @return {void} */ doTheFullRefresh: function( target, event, postDetails ) { var postData = this.getAjaxData( 'fusion_app_full_refresh', postDetails ); this.refreshCounter = this.refreshCounter + 1; if ( jQuery( '.ui-dialog-content' ).length ) { jQuery( '.ui-dialog-content' ).dialog( 'close' ); } jQuery( '#fb-preview' ).addClass( 'refreshing' ); FusionEvents.trigger( 'fusion-preview-refreshed' ); this.formPost( postData ); }, formPost: function( postData, newSrc, target ) { var $form = jQuery( '#refresh-form' ), src = 'undefined' === typeof newSrc || ! newSrc ? jQuery( '#fb-preview' ).attr( 'src' ) : newSrc; $form.empty(); if ( 'string' !== typeof target ) { target = jQuery( '#fb-preview' ).attr( 'name' ); this.previewWindow.name = target; } $form.attr( 'target', target ); $form.attr( 'action', src ); _.each( postData, function( value, id ) { if ( 'post_content' === id ) { value = window.encodeURIComponent( value ); } $form.append( '<input type="hidden" name="' + id + '" value="' + value + '" />' ); } ); this.manualSwitch = true; $form.submit().empty(); }, /** * Refreshes the preview frame. * * @since 2.0.0 * @return {void} */ previewRefresh: function() { var self = this, originalCount = self.refreshCounter - 1, refreshString = '&refresh=' + originalCount; this.manualSwitch = true; jQuery( '#fb-preview' ).attr( 'src', function( i, val ) { if ( -1 === val.indexOf( '&post_id=' ) ) { val += '&post_id=' + self.getPost( 'post_id' ); } // Make sure to add unique refresh parameter. if ( -1 === val.indexOf( refreshString ) ) { val += '&refresh=' + self.refreshCounter; } else { val = val.replace( refreshString, '&refresh=' + self.refreshCounter ); } return val; } ); FusionEvents.trigger( 'fusion-preview-refreshed' ); }, /** * Checks links. * * @since 2.0.0 * @param {Object} event - The jQuery event. * @param {string} href - URL. * @return {void} */ checkLink: function( event, href ) { var self = this, linkHref = 'undefined' === typeof href ? jQuery( event.currentTarget ).attr( 'href' ) : href, linkHash = '', targetPathname = '', targetHostname = '', $targetEl = this.previewWindow.jQuery( jQuery( event.currentTarget ) ), link, linkParts; event.preventDefault(); // Split hash and move to end of URL. if ( -1 !== linkHref.indexOf( '#' ) ) { linkParts = linkHref.split( '#' ); linkHref = linkParts[ 0 ]; linkHash = '#_' + linkParts[ 1 ]; } // Get path name from event (link). if ( 'object' === typeof event ) { targetPathname = event.currentTarget.pathname; targetHostname = event.currentTarget.hostname; } // If manually passing a url, get pathname from that instead. if ( 'undefined' !== typeof href ) { link = document.createElement( 'a' ); link.href = href; targetPathname = link.pathname; targetHostname = link.hostname; } // Check for scroll links on same page and return. if ( '#' === linkHref.charAt( 0 ) || ( '' !== linkHash && targetPathname === location.pathname ) ) { if ( 'function' === typeof $targetEl.fusion_scroll_to_anchor_target && ! $targetEl.parent().parent().hasClass( 'wc-tabs' ) ) { $targetEl.fusion_scroll_to_anchor_target(); } return; } // Check if flyout submenus are enabled and menu item has submenu. if ( $targetEl.parent().hasClass( 'menu-item' ) && $targetEl.parent().hasClass( 'menu-item-has-children' ) && $targetEl.closest( '.awb-menu' ).hasClass( 'awb-menu_flyout' ) ) { return; } // Check link is on same site or manually being triggered. if ( location.hostname === targetHostname || 'undefined' !== typeof href ) { this.showLoader(); // Make user confirm. if ( this.hasContentChanged( 'page' ) ) { FusionApp.confirmationPopup( { title: fusionBuilderText.unsaved_changes, content: fusionBuilderText.changes_will_be_lost, class: 'fusion-confirmation-unsaved-changes', actions: [ { label: fusionBuilderText.cancel, classes: 'cancel no', callback: function() { self.hideLoader(); FusionApp.confirmationPopup( { action: 'hide' } ); } }, { label: fusionBuilderText.just_leave, classes: 'dont-save yes', callback: function() { self.switchPage( self.builderId, linkHref, linkHash ); } }, { label: fusionBuilderText.leave, classes: 'save yes', callback: function() { var successAction = {}; successAction.action = 'switch_page'; successAction.builderid = self.builderId; successAction.linkhref = linkHref; successAction.linkhash = linkHash; self.savePostContent( successAction ); } } ] } ); } else { self.switchPage( self.builderId, linkHref, linkHash ); } } }, switchPage: function( builderId, linkHref, linkHash ) { var postData = {}; if ( jQuery( '.ui-dialog-content' ).length ) { jQuery( '.ui-dialog-content' ).dialog( 'close' ); } jQuery( '#fb-preview' ).addClass( 'refreshing' ); this.manualSwitch = true; if ( this.hasContentChanged( 'global', 'theme-option' ) ) { postData = { fusion_load_nonce: fusionAppConfig.fusion_load_nonce, builder_id: this.builderId, action: 'fusion_app_switch_page', fusion_options: jQuery.param( FusionApp.settings ), // eslint-disable-line camelcase option_name: fusionOptionName // eslint-disable-line camelcase }; jQuery( '#fb-preview' ).addClass( 'refreshing' ); if ( -1 !== linkHref.indexOf( '?' ) ) { linkHref = linkHref + '&builder=true&builder_id=' + builderId + linkHash; } else { linkHref = linkHref + '?builder=true&builder_id=' + builderId + linkHash; } this.formPost( postData, linkHref ); } else { this.goToURL( builderId, linkHref, linkHash ); } }, /** * Goes to a URL. * * @param {string} builderId - The builder-ID. * @param {string} linkHref - The URL. * @param {string} linkHash - The hash part of the URL. * @return {void} */ goToURL: function( builderId, linkHref, linkHash ) { var newPage; this.manualSwitch = true; // Close dialogs. if ( jQuery( '.ui-dialog-content' ).length ) { jQuery( '.ui-dialog-content' ).dialog( 'close' ); } if ( jQuery( '#fusion-close-element-settings' ).length ) { jQuery( '#fusion-close-element-settings' ).trigger( 'click' ); } jQuery( '#fusion-builder-confirmation-modal' ).hide(); jQuery( '#fusion-builder-confirmation-modal-dark-overlay' ).hide(); // Add necessary details to URL. if ( -1 !== linkHref.indexOf( '?' ) ) { newPage = linkHref + '&builder=true&builder_id=' + builderId + linkHash; } else { newPage = linkHref + '?builder=true&builder_id=' + builderId + linkHash; } // Change iframe URL. jQuery( '#fb-preview' ).attr( 'src', newPage ); }, /** * Updates the URL. * * @since 2.0.0 * @return {void} */ updateURL: function( newURL ) { var frameWindow = document.getElementById( 'fb-preview' ).contentWindow, frameDocument = frameWindow.document; if ( '' === newURL || '?fb-edit=1' === newURL ) { newURL = jQuery( '#fb-preview' ).attr( 'src' ).split( '?' )[ 0 ] + '?fb-edit=1'; } window.history.replaceState( { url: newURL }, frameDocument.title, newURL ); document.title = frameDocument.title; }, /** * Removes scripts from markup and stores separately. * * @since 2.0.0 * @return {void} */ removeScripts: function( content, cid ) { var $markup = jQuery( '<div>' + content + '</div>' ), $scripts = $markup.find( 'script' ), $injection = []; if ( $scripts.length ) { $scripts.each( function() { // Add script markup to injection var. if ( jQuery( this ).attr( 'src' ) ) { $injection.push( { type: 'src', value: jQuery( this ).attr( 'src' ) } ); } else { $injection.push( { type: 'inline', value: jQuery( this ).html() } ); } // Remove script from render. jQuery( this ).remove(); } ); this.scripts[ cid ] = $injection; return $markup.html(); } return $markup.html(); }, /** * Injects stored scripts. * * @since 2.0.0 * @return {void} */ injectScripts: function( cid ) { var $body = jQuery( '#fb-preview' ).contents().find( 'body' )[ 0 ], scripts = this.scripts[ cid ], frameDocument = document.getElementById( 'fb-preview' ).contentWindow.document, oldWrite = frameDocument.write, // jshint ignore:line self = this, el, elId; // Turn document write off before partial request. frameDocument.write = function() {}; // eslint-disable-line no-empty-function if ( 'undefined' !== typeof scripts && scripts.length ) { _.each( scripts, function( script, id ) { elId = 'fusion-script-' + cid + '-' + id; // If it already exists, remove it. if ( jQuery( '#fb-preview' ).contents().find( 'body' ).find( '#' + elId ).length ) { jQuery( '#fb-preview' ).contents().find( 'body' ).find( '#' + elId ).remove(); } // Create script on iframe. el = document.createElement( 'script' ); el.setAttribute( 'type', 'text/javascript' ); el.setAttribute( 'id', 'fusion-script-' + cid + '-' + id ); if ( 'src' === script.type ) { el.setAttribute( 'src', script.value ); } else { el.innerHTML = script.value; } // If this is a hubspot form, wait and then add to element. if ( 'inline' === script.type && -1 !== script.value.indexOf( 'hbspt.forms.create' ) ) { self.initHubSpotForm( script, cid, el ); return; } $body.appendChild( el ); } ); } frameDocument.write = oldWrite; // jshint ignore:line }, /** * Init hubspot embed form. * * @since 2.2 * @return {void} */ initHubSpotForm: function( script, cid, el ) { var self = this, timeoutValue = 'undefined' !== typeof FusionApp.previewWindow.hbspt ? 0 : 500, $element = jQuery( '#fb-preview' ).contents().find( 'div[data-cid="' + cid + '"]' ).find( '.fusion-builder-element-content' ).first(); // Keep a count of repetitions to avoid. this.hubspotRepeat = 'undefined' === this.hubspotRepeat ? 0 : this.hubspotRepeat + 1; if ( 5 < this.hubspotRepeat ) { return; } setTimeout( function() { if ( 'undefined' === typeof FusionApp.previewWindow.hbspt ) { self.initHubSpotForm( script, cid, el ); return; } if ( $element.length ) { self.hubspotRepeat = 0; $element.find( '.hbspt-form' ).remove(); $element[ 0 ].appendChild( el ); } }, timeoutValue ); }, /** * Deletes scripts from DOM when element is removed. * * @since 2.0.0 * @return {void} */ deleteScripts: function( cid ) { var scripts = this.scripts[ cid ]; if ( scripts ) { _.each( scripts, function( script, id ) { var elId = 'fusion-script-' + cid + '-' + id; // If it already exists, remove it. if ( jQuery( '#fb-preview' ).contents().find( 'body' ).find( '#' + elId ).length ) { jQuery( '#fb-preview' ).contents().find( 'body' ).find( '#' + elId ).remove(); } } ); delete this.scripts[ cid ]; } }, /** * Filters elements on search. * * @since 2.0.0 * @param {Object} thisEl - jQuery DOM element. * @return {void} */ elementSearchFilter: function( thisEl ) { var name, value; thisEl.find( '.fusion-elements-filter' ).on( 'change paste keyup', function() { if ( jQuery( this ).val() ) { value = jQuery( this ).val().toLowerCase(); thisEl.find( '.fusion-builder-all-modules li, .studio-imports li' ).each( function() { var shortcode = jQuery( this ).find( '.fusion_module_label' ).length ? jQuery( this ).find( '.fusion_module_label' ).text().trim().toLowerCase() : ''; name = jQuery( this ).find( '.fusion_module_title' ).text().trim().toLowerCase(); // Also show portfolio on recent works search if ( 'portfolio' === name ) { name += ' recent works'; } if ( 'fusion_imageframe' === shortcode ) { name += ' ' + fusionBuilderText.logo.trim().toLowerCase(); } if ( -1 !== name.search( value ) || jQuery( this ).hasClass( 'spacer' ) ) { jQuery( this ).show(); } else { jQuery( this ).hide(); } } ); } else { thisEl.find( '.fusion-builder-all-modules li' ).show(); thisEl.find( '.studio-imports li' ).show(); } } ); setTimeout( function() { jQuery( '.fusion-elements-filter' ).focus(); }, 50 ); }, /** * Checks page content for element font families. * * @since 2.0.0 * @param object googleFonts * @return {Object} */ setElementFonts: function( googleFonts ) { var postContent = this.getPost( 'post_content' ), regexp, fontProps, tempFonts = {}, saveFonts = []; if ( 'string' === typeof postContent && '' !== postContent && -1 !== postContent.indexOf( 'fusion_font_' ) ) { regexp = new RegExp( '(fusion_font_[^=]*=")([^"]*)"', 'g' ); fontProps = this.getPost( 'post_content' ).match( regexp ); // Iterate through all font properties in post content and build font objects. _.each( fontProps, function( prop ) { var config = prop.slice( 0, -1 ).split( '="' ), key = config[ 0 ], value = config[ 1 ], optionId = key.replace( /fusion_font_(family|variant)_/, '' ), fontProperty = ( key.includes( 'fusion_font_variant_' ) && 'variant' ) || 'family'; if ( '' === key && 'family' === fontProperty ) { return; } if ( 'object' !== typeof tempFonts[ optionId ] ) { tempFonts[ optionId ] = {}; } else if ( 'family' === fontProperty && tempFonts[ optionId ].family ) { // If we are setting family again for something already in process, then save out incomplete and start fresh saveFonts.push( tempFonts[ optionId ] ); tempFonts[ optionId ] = {}; } tempFonts[ optionId ][ fontProperty ] = value; // If all three are set, add to save fonts and delete from temporary holder so others can be collected with same ID. if ( 'undefined' !== typeof tempFonts[ optionId ].family && 'undefined' !== typeof tempFonts[ optionId ].variant ) { saveFonts.push( tempFonts[ optionId ] ); delete tempFonts[ optionId ]; } } ); // Check for incomplete ones with family and add them too. _.each( tempFonts, function( font, option ) { if ( 'undefined' !== typeof font.family && '' !== font.family ) { saveFonts.push( tempFonts[ option ] ); } } ); // Look all fonts for saving and save. _.each( saveFonts, function( font ) { if ( 'undefined' === typeof font.family || '' === font.family ) { return; } if ( 'undefined' === typeof googleFonts[ font.family ] ) { googleFonts[ font.family ] = { variants: [] }; } // Add the variant if it does not exist already. if ( 'string' === typeof font.variant && ! googleFonts[ font.family ].variants.includes( font.variant ) ) { googleFonts[ font.family ].variants.push( font.variant ); } } ); } return googleFonts; }, /** * Checks page content for font dependencies. * * @since 2.0.0 * @return {Object} */ setGoogleFonts: function() { var self = this, googleFonts = {}, fontFamily, $fontNodes = jQuery( '#fb-preview' ).contents().find( '[data-fusion-google-font]' ); googleFonts = this.setElementFonts( googleFonts ); if ( $fontNodes.length ) { $fontNodes.each( function() { if ( 'undefined' === typeof googleFonts[ jQuery( this ).attr( 'data-fusion-google-font' ) ] ) { googleFonts[ jQuery( this ).attr( 'data-fusion-google-font' ) ] = { variants: [] }; } // Add the variant. if ( jQuery( this ).attr( 'data-fusion-google-variant' ) ) { googleFonts[ jQuery( this ).attr( 'data-fusion-google-font' ) ].variants.push( jQuery( this ).attr( 'data-fusion-google-variant' ) ); } } ); } // Delete global typographies. If is studio, then parse overwrite typography to add to meta. for ( fontFamily in googleFonts ) { if ( fontFamily.includes( 'var(' ) ) { // awbOriginalPalette is a variable present only on studio plugin. if ( window.awbOriginalPalette ) { addOverwriteTypographyToMeta( fontFamily ); } } } // Check each has a variant selected _.each( googleFonts, function( font, family ) { if ( 'object' !== typeof font.variants || ! font.variants.length ) { googleFonts[ family ].variants = [ 'regular' ]; } } ); if ( 'object' === typeof this.data.postMeta._fusion_google_fonts ) { _.each( this.data.postMeta._fusion_google_fonts, function( fontData, currentFontFamily ) { _.each( fontData, function( values, key ) { self.data.postMeta._fusion_google_fonts[ currentFontFamily ][ key ] = _.values( values ); } ); } ); // We have existing values and existing value is not the same as new. if ( ! _.isEqual( this.data.postMeta._fusion_google_fonts, googleFonts ) ) { if ( _.isEmpty( googleFonts ) ) { googleFonts = ''; } this.data.postMeta._fusion_google_fonts = googleFonts; // eslint-disable-line camelcase this.contentChange( 'page', 'page-option' ); } } else if ( ! _.isEmpty( googleFonts ) ) { // We do not have existing values and we do have fonts now. this.data.postMeta._fusion_google_fonts = googleFonts; // eslint-disable-line camelcase this.contentChange( 'page', 'page-option' ); } function addOverwriteTypographyToMeta( globalVar ) { var typoMatch = globalVar.match( /--awb-typography(\d)/ ), fontName, fontVariant, uniqueFontVariant, variantMatch, i, typoId; if ( ! typoMatch[ 1 ] || ! Array.isArray( googleFonts[ globalVar ].variants ) ) { delete googleFonts[ globalVar ]; return; } // Get the font family. typoId = typoMatch[ 1 ]; fontName = awbTypoData.data[ 'typography' + typoId ][ 'font-family' ]; fontVariant = []; // Get the global font variants and merge with non-global ones. for ( i = 0; i < googleFonts[ globalVar ].variants.length; i++ ) { if ( googleFonts[ globalVar ].variants[ i ].includes( 'var(' ) ) { variantMatch = googleFonts[ globalVar ].variants[ i ].match( /--awb-typography(\d)/ ); if ( variantMatch[ 1 ] ) { if ( awbTypoData.data[ 'typography' + variantMatch[ 1 ] ].variant ) { fontVariant.push( awbTypoData.data[ 'typography' + variantMatch[ 1 ] ].variant ); } else { fontVariant.push( '400' ); } } } else { fontVariant.push( googleFonts[ globalVar ].variants[ i ] ); } } // Update the font variant. If exist then concat them. if ( googleFonts[ fontName ] ) { if ( googleFonts[ fontName ].variants ) { googleFonts[ fontName ].variants = googleFonts[ fontName ].variants.concat( fontVariant ); } else { googleFonts[ fontName ].variants = fontVariant; } } else { googleFonts[ fontName ] = {}; googleFonts[ fontName ].variants = fontVariant; } // Remove duplicate variants. uniqueFontVariant = []; googleFonts[ fontName ].variants.forEach( function( el ) { if ( ! uniqueFontVariant.includes( el ) ) { uniqueFontVariant.push( el ); } } ); googleFonts[ fontName ].variants = uniqueFontVariant; // Finally, delete global variant. delete googleFonts[ globalVar ]; } }, /** * Adds font awesome relative stylesheets. * * @since 2.0.0 * @return {Object} */ toggleFontAwesomePro: function( id ) { if ( 'status_fontawesome_pro' === id || ( 'fontawesome_v4_compatibility' === id && 0 === jQuery( '#fontawesome-shims-css' ).length ) ) { jQuery.ajax( { type: 'GET', url: fusionAppConfig.ajaxurl, dataType: 'json', data: { action: 'fusion_font_awesome', fusion_load_nonce: fusionAppConfig.fusion_load_nonce, pro_status: FusionApp.settings.status_fontawesome_pro } } ) .done( function( response ) { fusionAppConfig.fontawesomeicons = response.icons; jQuery( '#fontawesome-css' ).attr( 'href', response.css_url ); if ( 'fontawesome_v4_compatibility' === id ) { jQuery( 'body' ).append( '<link rel="stylesheet" id="fontawesome-shims-css" href="' + response.shims_url + '" type="text/css" media="all">' ); } else { jQuery( '#fontawesome-shims-css' ).attr( 'href', response.css_url ); } FusionApp.reInitIconPicker(); } ); } }, /** * Re inits icon picker on subset value change. * * @since 2.0.0 * @return {Object} */ FontAwesomeSubSets: function() { FusionApp.reInitIconPicker(); }, /** * Checks for a context of content change. * * @since 2.0 * @return {void} */ hasContentChanged: function( context, name ) { var status = false; if ( 'undefined' !== typeof context ) { if ( 'undefined' !== typeof name ) { status = 'undefined' !== typeof this.contentChanged[ context ] && 'undefined' !== typeof this.contentChanged[ context ][ name ] && true === this.contentChanged[ context ][ name ]; } else { status = 'undefined' !== typeof this.contentChanged[ context ] && ! _.isEmpty( this.contentChanged[ context ] ); } } else { _.each( this.contentChanged, function( scopedContext ) { if ( ! _.isEmpty( scopedContext ) ) { status = true; } } ); } return status; }, /** * When content has been changed. * * @since 2.0 * @return {void} */ contentChange: function( context, name ) { if ( 'object' !== typeof this.contentChanged[ context ] ) { this.contentChanged[ context ] = {}; } this.contentChanged[ context ][ name ] = true; FusionApp.set( 'hasChange', true ); }, /** * Preinit for icon pickers. * * @since 2.0 * @return {void} */ iconPicker: function() { var icons = fusionAppConfig.fontawesomeicons, output = '<div class="fusion-icons-rendered" style="display:none;position:relative; height:0px; overflow:hidden;">', outputNav = '<div class="fusion-icon-picker-nav-rendered" style="display:none;height:0px; overflow:hidden;">', iconSubsets = { fas: 'Solid', far: 'Regular', fal: 'Light', fab: 'Brands' }, outputSets = { fas: '', fab: '', far: '', fal: '' }, self = this, isSearchDefined = 'undefined' !== typeof fusionIconSearch && Array.isArray( fusionIconSearch ); if ( jQuery( '.fusion-icons-rendered' ).length || ! Array.isArray( self.settings.status_fontawesome ) ) { return; } // Iterate through all FA icons and divide them into sets (one icon can belong to multiple sets). _.each( icons, function( icon, key ) { _.each( icon[ 1 ], function( iconSubset ) { if ( -1 !== self.settings.status_fontawesome.indexOf( iconSubset ) ) { outputSets[ iconSubset ] += '<span class="icon_preview ' + key + '" title="' + key + ' - ' + iconSubsets[ iconSubset ] + '"><i class="' + icon[ 0 ] + ' ' + iconSubset + '" data-name="' + icon[ 0 ].substr( 3 ) + '" aria-hidden="true"></i></span>'; } } ); } ); // Add FA sets to output. _.each( iconSubsets, function( label, key ) { if ( -1 !== self.settings.status_fontawesome.indexOf( key ) ) { outputNav += '<a href="#fusion-' + key + '" class="fusion-icon-picker-nav-item">' + label + '</a>'; output += '<div id="fusion-' + key + '" class="fusion-icon-set">' + outputSets[ key ] + '</div>'; } } ); // WIP: Add custom icons. icons = fusionAppConfig.customIcons; _.each( icons, function( iconSet, IconSetKey ) { outputNav += '<a href="#' + IconSetKey + '" class="fusion-icon-picker-nav-item">' + iconSet.name + '</a>'; output += '<div id="' + IconSetKey + '" class="fusion-icon-set fusion-custom-icon-set">'; _.each( iconSet.icons, function( icon ) { if ( isSearchDefined ) { fusionIconSearch.push( { name: icon } ); } output += '<span class="icon_preview ' + icon + '" title="' + iconSet.css_prefix + icon + '"><i class="' + iconSet.css_prefix + icon + '" data-name="' + icon + '" aria-hidden="true"></i></span>'; } ); output += '</div>'; } ); outputNav += '</div>'; output += '</div>'; jQuery( 'body' ).append( output + outputNav ); jQuery( '.fusion-icon-picker-save' ).trigger( 'click' ); if ( 'undefined' !== typeof window[ 'fusion-fontawesome-free-shims' ] ) { _.each( window[ 'fusion-fontawesome-free-shims' ], function( shim ) { if ( null !== shim[ 0 ] && null !== shim[ 2 ] ) { jQuery( '.fusion-icons-rendered' ).find( 'i.fa-' + shim[ 2 ] ).attr( 'data-alt-name', shim[ 0 ] ); } } ); } }, /** * Reinit icon picker. * * @since 2.0 * @return {void} */ reInitIconPicker: function() { jQuery( '.fusion-icons-rendered' ).remove(); jQuery( '.fusion-icon-picker-nav-rendered' ).remove(); this.iconPicker(); }, checkLegacyAndCustomIcons: function( icon ) { var oldIconName; if ( '' !== icon ) { if ( 'fusion-prefix-' === icon.substr( 0, 14 ) ) { // Custom icon, we need to remove prefix. icon = icon.replace( 'fusion-prefix-', '' ); } else { icon = icon.split( ' ' ), oldIconName = ''; // Legacy FontAwesome 4.x icon, so we need check if it needs to be updated. if ( 'undefined' === typeof icon[ 1 ] ) { icon[ 1 ] = 'fas'; if ( 'undefined' !== typeof window[ 'fusion-fontawesome-free-shims' ] ) { oldIconName = icon[ 0 ].substr( 3 ); jQuery.each( window[ 'fusion-fontawesome-free-shims' ], function( i, shim ) { if ( shim[ 0 ] === oldIconName ) { // Update icon name. if ( null !== shim[ 2 ] ) { icon[ 0 ] = 'fa-' + shim[ 2 ]; } // Update icon subset. if ( null !== shim[ 1 ] ) { icon[ 1 ] = shim[ 1 ]; } return false; } } ); } icon = icon[ 0 ] + ' ' + icon[ 1 ]; } } } return icon; }, /** * When content has been reset to default. * * @since 2.0 * @return {void} */ contentReset: function( context, name ) { if ( 'undefined' !== typeof name ) { // Reset for specific name. if ( 'undefined' !== typeof this.contentChanged[ context ] && 'undefined' !== typeof this.contentChanged[ context ][ name ] ) { delete this.contentChanged[ context ][ name ]; } } else if ( 'undefined' !== typeof context ) { // Reset entire context. this.contentChanged[ context ] = {}; } else { // Reset all. this.contentChanged = {}; } if ( ! this.hasContentChanged() ) { FusionApp.set( 'hasChange', false ); } }, /** * Creates and handles confirmation popups. * * @param {Object} args - The popup arguments. * @param {string} args.title - The title. * @param {string} args.content - The content for this popup. * @param {string} args.type - Can be "info" or "warning". Changes the color of the icon. * @param {string} args.icon - HTML for the icon. * @param {string} args.class - Additional CSS classes for the popup.. * @param {string} args.action - If "hide", it hides the popup. * @param {Array} args.actions - An array of actions. These get added as buttons. * @param {Object} args.actions[0] - Each item in the actions array is an object. * @param {string} args.actions[0].label - The label that will be used for the button. * @param {string} args.actions[0].classes - The CSS class that will be added to the button. * @param {Function} args.actions[0].callback - A function that will be executed when the button gets clicked. */ confirmationPopup: function( args ) { if ( 'hide' === args.action ) { // Hide elements. jQuery( '#fusion-builder-confirmation-modal-dark-overlay' ).hide(); jQuery( '#fusion-builder-confirmation-modal' ).hide(); // Early exit. return; } // Early exit if no content & title, or if there's no actions defined. if ( ( ! args.content && ! args.title ) || ( ! args.actions || ! args.actions[ 0 ] ) ) { return; } // Use default icon (exclamation mark) if no custom icon is defined. if ( ! args.icon ) { args.icon = '<i class="fas fa-exclamation" aria-hidden="true">'; } // Use default type (warning) if no type is defined. if ( ! args.type ) { args.type = 'warning'; } // Show the popup. jQuery( '#fusion-builder-confirmation-modal-dark-overlay' ).show(); jQuery( '#fusion-builder-confirmation-modal' ).show(); // Add the class. if ( 'undefined' !== typeof args[ 'class' ] ) { jQuery( '#fusion-builder-confirmation-modal' ).attr( 'class', args[ 'class' ] ); } // Add the icon. jQuery( '#fusion-builder-confirmation-modal span.icon' ) .html( args.icon ) .removeClass( 'type-warning type-error-type-info' ) .addClass( 'type-' + args.type ); // Add the title. if ( args.title ) { jQuery( '#fusion-builder-confirmation-modal h3.title' ).show(); jQuery( '#fusion-builder-confirmation-modal h3.title' ).html( args.title ); } else { jQuery( '#fusion-builder-confirmation-modal h3.title' ).hide(); } // Add the content. if ( args.content ) { jQuery( '#fusion-builder-confirmation-modal span.content' ).show(); jQuery( '#fusion-builder-confirmation-modal span.content' ).html( args.content ); } else { jQuery( '#fusion-builder-confirmation-modal span.content' ).hide(); } // Reset the HTML for buttons so we can add anew based on the arguments we have. jQuery( '#fusion-builder-confirmation-modal .actions' ).html( '' ); // Add buttons. _.each( args.actions, function( action ) { var classes = '.' + action.classes; if ( 0 < action.classes.indexOf( ' ' ) ) { classes = '.' + action.classes.replace( / /g, '.' ); } jQuery( '#fusion-builder-confirmation-modal .actions' ).append( '<button class="' + action.classes + '">' + action.label + '</button>' ); jQuery( '#fusion-builder-confirmation-modal .actions ' + classes ).on( 'click', action.callback ); } ); }, /** * Reset some CSS values, when modal settings dialogs get closed. * * @since 2.0 * @param {Object} modalView - View of the closed modal. * @return {void} */ dialogCloseResets: function( modalView ) { if ( ! modalView.$el.closest( '.ui-dialog.fusion-builder-child-element' ).length ) { jQuery( 'body' ).removeClass( 'fusion-settings-dialog-default fusion-settings-dialog-large' ); } this.previewWindow.jQuery( 'body' ).removeClass( 'fusion-dialog-ui-active' ); }, /** * Shows multiple dialogs notice. * * @return {void} */ multipleDialogsNotice: function() { this.confirmationPopup( { title: fusionBuilderText.multi_dialogs, content: fusionBuilderText.multi_dialogs_notice, actions: [ { label: fusionBuilderText.ok, classes: 'yes', callback: function() { FusionApp.confirmationPopup( { action: 'hide' } ); } } ] } ); }, /** * Getter for TO value or it's default if value is not saved yet. * * @since 3.0 * @param {string} optionKey - Option key (ID). * @return {mixed} */ getSettingValue: function( settingKey ) { var flatOptions; if ( undefined === settingKey ) { return undefined; } if ( 'undefined' !== typeof this.settings[ settingKey ] ) { return this.settings[ settingKey ]; } flatOptions = this.sidebarView.getFlatToObject(); if ( 'undefined' !== typeof flatOptions[ settingKey ] && 'undefined' !== typeof flatOptions[ settingKey ][ 'default' ] ) { return flatOptions[ settingKey ][ 'default' ]; } return undefined; }, /** * Getter for previewWindowSize property. * Used to get 'custom' screen size, which is used to change correct options in EO. * * @since 3.0 * @return {string} */ getPreviewWindowSize: function() { return this.previewWindowSize; }, /** * Helper for responsive options. * * @since 2.3.0 * @return {string} */ getResponsiveOptionKey: function ( key, isFlex = true ) { var previewSize = FusionApp.getPreviewWindowSize(), optionKey = ! isFlex || 'large' == previewSize ? key : key + '_' + previewSize; return optionKey; }, /** * Setter for previewWindowSize property. * Used to set 'custom' screen size, which is used to change correct options in EO. * * @since 3.0 * @param {string} newScreenSize - New screen size string. * @return {void} */ setPreviewWindowSize: function( newScreenSize ) { if ( -1 !== newScreenSize.indexOf( 'mobile' ) ) { this.previewWindowSize = 'small'; } else if ( -1 !== newScreenSize.indexOf( 'tablet' ) ) { this.previewWindowSize = 'medium'; } else { this.previewWindowSize = 'large'; } }, /** * Check for empty array values. * Used to fix issue with jQuery.param omit empty array. * * @since 7.2 * @param {object} obj - Object Arrays. * @return {void} */ maybeEmptyArray: function( obj ) { var key; for ( key in obj ) { if ( 'object' === typeof obj[ key ] && 0 == obj[ key ].length ) { obj[ key ] = [ '' ]; } } return obj; } } ); if ( 'undefined' === typeof FusionApp ) { window.FusionApp = new fusionApp(); // jshint ignore: line } } ); }( jQuery ) );
Cokiee Shell Web 1.0, Coded By Razor
Neueste Kommentare