( function( $ ){ /* Internal shorthand */ var api = wp.customize; /** * Helper class for live Customizer previews. * * @since 1.2.0 * @class FLCustomizerPreview */ FLCustomizerPreview = { /** * An instance of FLStyleSheet for live previews. * * @since 1.2.0 * @access private * @property {FLStyleSheet} _styleSheet */ _styleSheet: null, /** * A reference to the current value of fl-heading-style * * @since 1.7 * @access private * @property String _headingStyleValue */ _headingStyleValue: '', /** * A reference of responsive controls. * * @since 1.7.2 * @access private * @property String _responsiveControls */ _responsiveControls: {}, /** * Initializes all live Customizer previews. * * @since 1.2.0 * @method init */ init: function() { // Create the stylesheet. this._styleSheet = new FLStyleSheet(); // Bind CSS callbacks. this._css( 'fl-body-bg-image', 'body', 'background-image', 'url({val})', 'none' ); this._css( 'fl-body-bg-repeat', 'body', 'background-repeat' ); this._css( 'fl-body-bg-position', 'body', 'background-position' ); this._css( 'fl-body-bg-attachment', 'body', 'background-attachment' ); this._css( 'fl-body-bg-size', 'body', 'background-size' ); this._css( 'fl-title-text-color', 'h1, h1 a', 'color' ); this._css( 'fl-title-font-format', 'h1', 'text-transform'); this._css( 'fl-h1-font-size', 'h1', 'font-size', '{val}px', '36px', 'int', true ); this._css( 'fl-h2-font-size', 'h2', 'font-size', '{val}px', '30px', 'int', true ); this._css( 'fl-h3-font-size', 'h3', 'font-size', '{val}px', '24px', 'int', true ); this._css( 'fl-h4-font-size', 'h4', 'font-size', '{val}px', '18px', 'int', true ); this._css( 'fl-h5-font-size', 'h5', 'font-size', '{val}px', '14px', 'int', true ); this._css( 'fl-h6-font-size', 'h6', 'font-size', '{val}px', '12px', 'int', true ); this._css( 'fl-topbar-bg-repeat', '.fl-page-bar', 'background-repeat' ); this._css( 'fl-topbar-bg-position', '.fl-page-bar', 'background-position' ); this._css( 'fl-topbar-bg-attachment', '.fl-page-bar', 'background-attachment' ); this._css( 'fl-topbar-bg-size', '.fl-page-bar', 'background-size' ); this._css( 'fl-header-bg-repeat', '.fl-page-header', 'background-repeat' ); this._css( 'fl-header-bg-position', '.fl-page-header', 'background-position' ); this._css( 'fl-header-bg-attachment', '.fl-page-header', 'background-attachment' ); this._css( 'fl-header-bg-size', '.fl-page-header', 'background-size' ); this._css( 'fl-logo-font-size', '.fl-logo-text', 'font-size', '{val}px', '40px', 'int' ); this._css( 'fl-nav-bg-repeat', '.fl-page-nav-wrap', 'background-repeat' ); this._css( 'fl-nav-bg-position', '.fl-page-nav-wrap', 'background-position' ); this._css( 'fl-nav-bg-attachment', '.fl-page-nav-wrap', 'background-attachment' ); this._css( 'fl-nav-bg-size', '.fl-page-nav-wrap', 'background-size' ); this._css( 'fl-nav-font-size', '.fl-page-nav .navbar-nav', 'font-size', '{val}px', '16px', 'int' ); this._css( 'fl-nav-font-size', '.fl-page-nav .navbar-nav a', 'font-size', '{val}px', '16px', 'int' ); this._css( 'fl-nav-font-size', '.fl-page-header-vertical .fl-page-nav-search a.fa-search', 'font-size', '{val}px', '16px', 'int' ); this._css( 'fl-nav-font-size', '.fl-page-nav .navbar-toggle', 'font-size', '{val}px', '16px', 'int' ); this._css( 'fl-nav-font-format', '.fl-page-nav .navbar-nav', 'text-transform' ); this._css( 'fl-nav-font-format', '.fl-page-nav .navbar-nav a', 'text-transform' ); this._css( 'fl-nav-font-format', '.fl-page-nav .navbar-toggle', 'text-transform' ); this._css( 'fl-content-bg-repeat', '.fl-page-content', 'background-repeat' ); this._css( 'fl-content-bg-position', '.fl-page-content', 'background-position' ); this._css( 'fl-content-bg-attachment', '.fl-page-content', 'background-attachment' ); this._css( 'fl-content-bg-size', '.fl-page-content', 'background-size' ); this._css( 'fl-footer-widgets-bg-repeat', '.fl-page-footer-widgets', 'background-repeat' ); this._css( 'fl-footer-widgets-bg-position', '.fl-page-footer-widgets', 'background-position' ); this._css( 'fl-footer-widgets-bg-attachment', '.fl-page-footer-widgets', 'background-attachment' ); this._css( 'fl-footer-bg-size', '.fl-page-footer-widgets', 'background-size' ); this._css( 'fl-footer-bg-repeat', '.fl-page-footer', 'background-repeat' ); this._css( 'fl-footer-bg-position', '.fl-page-footer', 'background-position' ); this._css( 'fl-footer-bg-attachment', '.fl-page-footer', 'background-attachment' ); this._css( 'fl-footer-bg-size', '.fl-page-footer', 'background-size' ); this._css( 'fl-vertical-header-width', '.fl-page-header-vertical', 'width', '{val}px', '230px', 'int' ); this._css( 'fl-vertical-header-width', '.fl-nav-vertical-left .fl-page-bar, .fl-nav-vertical-left .fl-page-content, .fl-nav-vertical-left .fl-page-footer-wrap, .fl-nav-vertical-left footer.fl-builder-content', 'margin-left', '{val}px', '230px', 'int' ); this._css( 'fl-vertical-header-width', '.fl-nav-vertical-right .fl-page-bar, .fl-nav-vertical-right .fl-page-content, .fl-nav-vertical-right .fl-page-footer-wrap, .fl-nav-vertical-right footer.fl-builder-content', 'margin-right', '{val}px', '230px', 'int' ); this._css( 'fl-header-padding', '.fl-page-header-vertical .fl-page-header-logo, .fl-page-header-vertical .fl-page-nav-collapse ul.navbar-nav > li > a, .fl-page-header-vertical .fl-page-nav-search a.fa-search', 'padding-left', '{val}px', '30px', 'int' ); this._css( 'fl-header-padding', '.fl-page-header-vertical .fl-page-header-logo, .fl-page-header-vertical .fl-page-nav-collapse ul.navbar-nav > li > a, .fl-page-header-vertical .fl-page-nav-search a.fa-search', 'padding-right', '{val}px', '30px', 'int' ); this._css( 'fl-header-logo-top-spacing', '.fl-nav-vertical .fl-page-header-vertical .fl-page-header-container', 'padding-top', '{val}px', '50px', 'int' ); this._css( 'fl-nav-item-spacing', '.fl-page-header-vertical .fl-page-nav-collapse ul.navbar-nav > li > a', 'padding-bottom', '{val}px', '15px', 'int' ); this._css( 'fl-nav-menu-top-spacing', '.fl-page-header-vertical .fl-page-nav-collapse ul.navbar-nav', 'padding-top', '{val}px', '30px', 'int' ); this._css( 'fl-body-font-size', 'body', 'font-size', '{val}px', '14px', 'int', true ); this._css( 'fl-body-line-height', 'body', 'line-height', '{val}', '1.45', false, true ); this._css( 'fl-h1-line-height', 'h1', 'line-height', '{val}', '1.4', false, true ); this._css( 'fl-h1-letter-spacing', 'h1', 'letter-spacing', '{val}px', '0', false, true ); this._css( 'fl-h2-line-height', 'h2', 'line-height', '{val}', '1.4', false, true ); this._css( 'fl-h2-letter-spacing', 'h2', 'letter-spacing', '{val}px', '0', false, true ); this._css( 'fl-h3-line-height', 'h3', 'line-height', '{val}', '1.4', false, true ); this._css( 'fl-h3-letter-spacing', 'h3', 'letter-spacing', '{val}px', '0', false, true ); this._css( 'fl-h4-line-height', 'h4', 'line-height', '{val}', '1.4', false, true ); this._css( 'fl-h4-letter-spacing', 'h4', 'letter-spacing', '{val}px', '0', false, true ); this._css( 'fl-h5-line-height', 'h5', 'line-height', '{val}', '1.4', false, true ); this._css( 'fl-h5-letter-spacing', 'h5', 'letter-spacing', '{val}px', '0', false, true ); this._css( 'fl-h6-line-height', 'h6', 'line-height', '{val}', '1.4', false, true ); this._css( 'fl-h6-letter-spacing', 'h6', 'letter-spacing', '{val}px', '0', false, true ); this._css( 'fl-layout-spacing', 'body', 'padding', '{val}px 0', '0' ); this._css( 'fl-header-padding', '.fl-page-nav-centered-inline-logo .fl-page-header-container, .fl-page-nav-bottom .fl-page-header-container, .fl-page-nav-right .fl-page-header-container, .fl-page-nav-left .fl-page-header-container, .fl-page-nav-centered .fl-page-header-container', 'padding', '{val}px 0', '30' ); this._css( 'fl-nav-item-spacing', '.fl-page-header-vertical .navbar-nav > li > a', 'padding-botom', '{val}px', '0' ); this._css( 'fl-nav-item-spacing', '.fl-page-nav .navbar-nav > li > a', 'padding-left', '{val}px', '0' ); this._css( 'fl-nav-item-spacing', '.fl-page-nav .navbar-nav > li > a', 'padding-right', '{val}px', '0' ); // Bind HTML callbacks. this._html( 'fl-topbar-col1-text', '.fl-page-bar-text-1' ); this._html( 'fl-topbar-col2-text', '.fl-page-bar-text-2' ); this._html( 'fl-logo-text', '.fl-logo-text' ); this._html( 'fl-footer-col1-text', '.fl-page-footer-text-1' ); this._html( 'fl-footer-col2-text', '.fl-page-footer-text-2' ); // Bind custom callbacks. this._bind( 'fl-css-code', this._cssCodeChanged ); // Setup Button Styles Preview this._initButtonStyles(); // Bind responsive controls callback. this._initResponsiveStyles(); // Setup responsive controls preview. this._initResponsivePreview(); }, /** * Binds a callback function to be fired when a setting changes. * * @since 1.2.0 * @access private * @method _bind * @param {String} key The key of the setting to bind to. * @param {Function} callback The callback function to bind. */ _bind: function( key, callback ) { api( key, function( val ) { val.bind( function( newVal ) { callback.call( FLCustomizerPreview, newVal ); }); }); }, /** * Applies a CSS preview when a setting changes. * * @since 1.2.0 * @access private * @method _css * @param {String} key The key of the setting to bind to. * @param {String} selector The CSS selector to apply the change to. * @param {String} property The CSS property to apply the change to. * @param {String} format (Optional) A format in brackets for the value such as "{val}px". * @param {String} fallback (Optional) A fallback value if the value is empty. * @param {String} sanitizeCallback (Optional) The type of sanitization function to call on the value. * @param {Boolean} responsive (Optional) If a control is responsive, then add CSS property for each device. */ _css: function( key, selector, property, format, fallback, sanitizeCallback, responsive ) { api( key, function( val ) { val.bind( function( newVal ) { switch ( sanitizeCallback ) { case 'int': newVal = FLCustomizerPreview._sanitizeInt( newVal ); break; } if ( 'undefined' != typeof fallback && null != fallback && '' == newVal ) { newVal = fallback; } else if ( 'undefined' != typeof format && null != format ) { newVal = format.replace( '{val}', newVal ); } FLCustomizerPreview._styleSheet.updateRule( selector, property, newVal ); }); }); if ( 'undefined' !== typeof responsive && false !== responsive ) { FLCustomizerPreview._responsiveControls[ key ] = { selector: selector, property: property, format : format, fallback: fallback, sanitizeCallback: sanitizeCallback, }; } }, /** * Applies an HTML preview when a setting changes. * * @since 1.2.0 * @access private * @method _html * @param {String} key The key of the setting to bind to. * @param {String} selector The CSS selector to apply the change to. */ _html: function( key, selector ) { api( key, function( val ) { val.bind( function( newVal ) { $( selector ).html( newVal ); }); }); }, /** * Makes sure a value is a number. * * @since 1.2.0 * @access private * @method _sanitizeInt * @param {Number} val The value to sanitize. * @return {Number} */ _sanitizeInt: function( val ) { var number = parseInt( val ); return isNaN( number ) ? 0 : number; }, /** * Callback for when the custom CSS field is changed. * * @since 1.3.3 * @access private * @method _cssCodeChanged * @param {String} val */ _cssCodeChanged: function( val ) { $( '#fl-theme-custom-css' ).html( val ); }, _initButtonStyles: function() { var mainSelector = '.fl-page button,' + '.fl-page button:visited,' + '.fl-page input[type=button],' + '.fl-page input[type=submit],' + '.fl-page a.fl-button,' + '.fl-page a.fl-button:visited,' + '.fl-responsive-preview-content button,' + '.fl-responsive-preview-content button:visited,' + '.fl-responsive-preview-content input[type=button],' + '.fl-responsive-preview-content input[type=submit],' + '.fl-responsive-preview-content a.fl-button,' + '.fl-responsive-preview-content a.fl-button:visited'; var mainInsideSelector = '.fl-page button *,' + '.fl-page button:visited *,' + '.fl-page input[type=button] *,' + '.fl-page input[type=submit] *,' + '.fl-page a.fl-button *,' + '.fl-page a.fl-button:visited *,' + '.fl-responsive-preview-content button *,' + '.fl-responsive-preview-content button:visited *,' + '.fl-responsive-preview-content input[type=button] *,' + '.fl-responsive-preview-content input[type=submit] *,' + '.fl-responsive-preview-content a.fl-button *,' + '.fl-responsive-preview-content a.fl-button:visited *'; var hoverSelector = '.fl-page button:hover,' + '.fl-page input[type=button]:hover,' + '.fl-page input[type=submit]:hover,' + '.fl-page a.fl-button:hover,' + '.fl-responsive-preview-content button:hover,' + '.fl-responsive-preview-content input[type=button]:hover,' + '.fl-responsive-preview-content input[type=submit]:hover,' + '.fl-responsive-preview-content a.fl-button:hover'; var hoverInsideSelector = '.fl-page button:hover *,' + '.fl-page input[type=button]:hover *,' + '.fl-page input[type=submit]:hover *,' + '.fl-page a.fl-button:hover *,' + '.fl-responsive-preview-content button:hover *,' + '.fl-responsive-preview-content input[type=button]:hover *,' + '.fl-responsive-preview-content input[type=submit]:hover *,' + '.fl-responsive-preview-content a.fl-button:hover *'; // Color this._css( 'fl-button-color', mainSelector, 'color' ); this._css( 'fl-button-color', mainInsideSelector, 'color' ); // Hover Color this._css( 'fl-button-hover-color', hoverSelector, 'color' ); this._css( 'fl-button-hover-color', hoverInsideSelector, 'color' ); // Background Color this._css( 'fl-button-background-color', mainSelector, 'background-color' ); // Background Hover this._css( 'fl-button-background-hover-color', hoverSelector, 'background-color' ); // Border Color this._css( 'fl-button-border-color', mainSelector, 'border-color' ); this._css( 'fl-button-border-color', hoverSelector, 'border-color' ); // Border Width this._css( 'fl-button-border-width', mainSelector, 'border-width', '{val}px' ); this._css( 'fl-button-border-width', hoverSelector, 'border-width', '{val}px' ); // Border Style this._css( 'fl-button-border-style', mainSelector, 'border-style' ); this._css( 'fl-button-border-style', hoverSelector, 'border-style' ); // Border Radius this._css( 'fl-button-border-radius', mainSelector, 'border-radius', '{val}px' ); this._css( 'fl-button-border-radius', hoverSelector, 'border-radius', '{val}px' ); // Text Transform this._css( 'fl-button-text-transform', mainSelector, 'text-transform' ); }, /** * Callback for when the responsive controls are changed. * * @since 1.7.2 * @access private * @method _initResponsiveStyles */ _initResponsiveStyles: function() { var controls = FLCustomizerPreview._responsiveControls, breakpoints = ['medium', 'mobile']; if ( ! $.isEmptyObject( controls ) ) { for (i = 0; i < breakpoints.length; i++ ) { $.each( controls, function( key, data ) { FLCustomizerPreview._css( key + '_' + breakpoints[i], data.selector, data.property, data.format, data.fallback, data.sanitizeCallback ); }); } } }, /** * Adds preview for responsive controls. * * @since 1.7.2 * @access private * @method _initResponsivePreview */ _initResponsivePreview: function() { var controls = FLCustomizerPreview._responsiveControls, newVal = '', controlValues = []; // Listen for a previewed-device message. api.preview.bind( 'previewed-device', function( newDevicePreview ) { controlValues = api.get(); if ( ! $.isEmptyObject( controls ) ) { $.each( controls, function( key, data ) { if ( 'desktop' != newDevicePreview ) { newVal = controlValues[ key + '_' + newDevicePreview ]; } else { newVal = controlValues[ key ]; } switch ( data.sanitizeCallback ) { case 'int': newVal = FLCustomizerPreview._sanitizeInt( newVal ); break; } if ( 'undefined' != typeof data.fallback && null != data.fallback && '' == newVal ) { newVal = data.fallback; } else if ( 'undefined' != typeof data.format && null != data.format ) { newVal = data.format.replace( '{val}', newVal ); } FLCustomizerPreview._styleSheet.updateRule( data.selector, data.property, newVal ); }); } }); }, }; $( function() { FLCustomizerPreview.init(); } ); })( jQuery );