( function ( api, $, _ ) { /***************************************************************************** * OBSERVE UBIQUE CONTROL'S SECTIONS EXPANSION *****************************************************************************/ if ( 'function' === typeof api.Section ) { //move controls back and forth in declared ubique sections //=> implemented in the customizr theme for the social links boolean visibility controls ( socials in header, sidebar, footer ) api.control.bind( 'add', function( _ctrl ) { if ( _ctrl.params.ubq_section && _ctrl.params.ubq_section.section ) { //save original state _ctrl.params.original_priority = _ctrl.params.priority; _ctrl.params.original_section = _ctrl.params.section; api.section.when( _ctrl.params.ubq_section.section, function( _section_instance ) { _section_instance.expanded.bind( function( expanded ) { if ( expanded ) { if ( _ctrl.params.ubq_section.priority ) { _ctrl.priority( _ctrl.params.ubq_section.priority ); } _ctrl.section( _ctrl.params.ubq_section.section ); } else { _ctrl.priority( _ctrl.params.original_priority ); _ctrl.section( _ctrl.params.original_section ); } }); } ); } }); } /***************************************************************************** * OBSERVE UBIQUE CONTROL'S PANELS EXPANSION *****************************************************************************/ if ( 'function' === typeof api.Panel ) { //move section back and forth in declared ubique panels api.section.bind( 'add', function( _sec ) { if ( _sec.params.ubq_panel && _sec.params.ubq_panel.panel ) { //save original state _sec.params.original_priority = _sec.params.priority; _sec.params.original_panel = _sec.params.panel; api.panel.when( _sec.params.ubq_panel.panel, function( _panel_instance ) { _panel_instance.expanded.bind( function( expanded ) { if ( expanded ) { if ( _sec.params.ubq_panel.priority ) { _sec.priority( _sec.params.ubq_panel.priority ); } _sec.panel( _sec.params.ubq_panel.panel ); } else { _sec.priority( _sec.params.original_priority ); _sec.panel( _sec.params.original_panel ); } }); } ); } }); } /***************************************************************************** * CLOSE THE MOD OPTION PANEL ( if exists ) ON : section change, panel change, skope switch *****************************************************************************/ //@return void() var _closeModOpt = function() { if ( ! _.has( api, 'czr_ModOptVisible') ) return; api.czr_ModOptVisible(false); }; api.bind('ready', function() { api.czr_activeSectionId.bind( _closeModOpt ); api.czr_activePanelId.bind( _closeModOpt ); }); })( wp.customize , jQuery, _); ( function ( api, $, _ ) { api.bind( 'ready', function() { /***************************************************************************** * ADD PRO BEFORE SPECIFIC SECTIONS AND PANELS *****************************************************************************/ if ( window.themeServerControlParams && themeServerControlParams.isPro ) { _.each( [ //WFC 'tc_font_customizer_settings', //hueman pro 'contx_header_bg', 'content_blog_sec', 'static_front_page', 'content_single_sec', //customizr-pro 'tc_fpu', 'nav', 'post_lists_sec', 'galleries_sec', 'footer_customizer_sec', 'custom_scripts_sec', 'contact_info_sec' ], function( _secId ) { _.delay( function() { api.section.when( _secId, function( _sec_ ) { if ( 1 >= _sec_.headContainer.length ) { _sec_.headContainer.find('.accordion-section-title').prepend( 'Pro' ); } }); }, 1000 ); }); _.each( [ //hueman pro //'hu-header-panel', //'hu-content-panel', //customizr-pro //'tc-header-panel', //'tc-content-panel', //'tc-footer-panel', //'tc-advanced-panel' ], function( _secId ) { api.panel.when( _secId, function( _sec_ ) { if ( 1 >= _sec_.headContainer.length ) { _sec_.headContainer.find('.accordion-section-title').prepend( 'Pro' ); } }); }); } /***************************************************************************** * PRO SECTION OVERRIDE *****************************************************************************/ if ( ! themeServerControlParams.isPro && _.isFunction( api.Section ) ) { proSectionInstance = api.section('go_pro_sec'); if ( ! _.isObject( proSectionInstance ) ) return; // No events for this type of section. proSectionInstance.attachEvents = function () {}; // Always make the section active. proSectionInstance.isContextuallyActive = function () { return this.active(); }; proSectionInstance._toggleActive = function(){ return true; }; proSectionInstance.active( true ); } }); })( wp.customize , jQuery, _); //named czr_multiple_picker in the php setting map var CZRMultiplePickerMths = CZRMultiplePickerMths || {}; /* Multiple Picker */ /** * @constructor * @augments wp.customize.Control * @augments wp.customize.Class */ ( function ( api, $, _ ) { $.extend( CZRMultiplePickerMths , { ready: function() { var control = this, _select = this.container.find('select'); _select.czrSelect2({ closeOnSelect: false, templateSelection: czrEscapeMarkup }); function czrEscapeMarkup(obj) { //trim dashes return obj.text.replace(/\u2013|\u2014/g, ""); } //handle case when all choices become unselected _select.on('change', function(e){ if ( 0 === $(this).find("option:selected").length ) control.setting.set([]); }); } });//$.extend })( wp.customize , jQuery, _ ); //named czr_cropped_image in the php setting map var CZRCroppedImageMths = CZRCroppedImageMths || {}; (function (api, $, _) { /* IMAGE UPLOADER CONTROL IN THE CUSTOMIZER */ //CroppedImageControl is not available before wp 4.3 if ( 'function' != typeof wp.media.controller.Cropper || 'function' != typeof api.CroppedImageControl ) return; /* CZRCustomizeImage Cropper */ /** * Custom version of: * wp.media.controller.CustomizeImageCropper (wp-includes/js/media-views.js) * * In order to use image destination sizes different than the suggested ones * * A state for cropping an image. * * @class * @augments wp.media.controller.Cropper * @augments wp.media.controller.State * @augments Backbone.Model */ wp.media.controller.CZRCustomizeImageCropper = wp.media.controller.Cropper.extend({ doCrop: function( attachment ) { var cropDetails = attachment.get( 'cropDetails' ), control = this.get( 'control' ); cropDetails.dst_width = control.params.dst_width; cropDetails.dst_height = control.params.dst_height; return wp.ajax.post( 'crop-image', { wp_customize: 'on', nonce: attachment.get( 'nonces' ).edit, id: attachment.get( 'id' ), context: control.id, cropDetails: cropDetails } ); } }); /* CZRCroppedImageControl */ $.extend( CZRCroppedImageMths , { /** * Create a media modal select frame, and store it so the instance can be reused when needed. * CZR: We don't want to crop svg (cropping fails), gif (animated gifs become static ) * @Override * We need to override this in order to use our ImageCropper custom extension of wp.media.controller.Cropper * * See api.CroppedImageControl:initFrame() ( wp-admin/js/customize-controls.js ) */ initFrame: function() { var l10n = _wpMediaViewsL10n; this.frame = wp.media({ button: { text: l10n.select, close: false }, states: [ new wp.media.controller.Library({ title: this.params.button_labels.frame_title, library: wp.media.query({ type: 'image' }), multiple: false, date: false, priority: 20, suggestedWidth: this.params.width, suggestedHeight: this.params.height }), new wp.media.controller.CZRCustomizeImageCropper({ imgSelectOptions: this.calculateImageSelectOptions, control: this }) ] }); this.frame.on( 'select', this.onSelect, this ); this.frame.on( 'cropped', this.onCropped, this ); this.frame.on( 'skippedcrop', this.onSkippedCrop, this ); }, /** * After an image is selected in the media modal, switch to the cropper * state if the image isn't the right size. * * CZR: We don't want to crop svg (cropping fails), gif (animated gifs become static ) * @Override * See api.CroppedImageControl:onSelect() ( wp-admin/js/customize-controls.js ) */ onSelect: function() { var attachment = this.frame.state().get( 'selection' ).first().toJSON(); if ( ! ( attachment.mime && attachment.mime.indexOf("image") > -1 ) ){ //Todo: better error handling, show some message? this.frame.trigger( 'content:error' ); return; } if ( ( _.contains( ['image/svg+xml', 'image/gif'], attachment.mime ) ) || //do not crop gifs or svgs this.params.width === attachment.width && this.params.height === attachment.height && ! this.params.flex_width && ! this.params.flex_height ) { this.setImageFromAttachment( attachment ); this.frame.close(); } else { this.frame.setState( 'cropper' ); } }, });//extend })( wp.customize, jQuery, _); //named czr_upload in the php setting map var CZRUploadMths = CZRUploadMths || {}; ( function ( api, $, _ ) { /** * @constructor * @augments wp.customize.Control * @augments wp.customize.Class */ $.extend( CZRUploadMths, { ready: function() { var control = this; this.params.removed = this.params.removed || ''; this.success = $.proxy( this.success, this ); this.uploader = $.extend({ container: this.container, browser: this.container.find('.czr-upload'), //dropzone: this.container.find('.upload-dropzone'), success: this.success, plupload: {}, params: {} }, this.uploader || {} ); if ( control.params.extensions ) { control.uploader.plupload.filters = [{ title: api.l10n.allowedFiles, extensions: control.params.extensions }]; } if ( control.params.context ) control.uploader.params['post_data[context]'] = this.params.context; if ( api.settings.theme.stylesheet ) control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet; this.uploader = new wp.Uploader( this.uploader ); this.remover = this.container.find('.remove'); this.remover.on( 'click keydown', function( event ) { if ( event.type === 'keydown' && 13 !== event.which ) // enter return; control.setting.set( control.params.removed ); event.preventDefault(); }); this.removerVisibility = $.proxy( this.removerVisibility, this ); this.setting.bind( this.removerVisibility ); this.removerVisibility( this.setting() ); }, success: function( attachment ) { this.setting.set( attachment.get('id') ); }, removerVisibility: function( to ) { this.remover.toggle( to != this.params.removed ); } });//extend })( wp.customize , jQuery, _ ); //named czr_layouts in the php setting map var CZRLayoutSelectMths = CZRLayoutSelectMths || {}; ( function ( api, $, _ ) { $.extend( CZRLayoutSelectMths , { ready: function() { this.setupSelect(); }, setupSelect : function( obj ) { var control = this; $_select = this.container.find('select'); function addImg( state ) { if (! state.id) { return state.text; } if ( ! _.has( control.params.layouts, state.element.value ) ) return; var _layout_data = control.params.layouts[state.element.value], _src = _layout_data.src, _title = _layout_data.label, $state = $( '' + _title + '' ); return $state; } //destroy selected if set //$_select.selecter("destroy"); //fire czrSelect2 $_select.czrSelect2( { templateResult: addImg, templateSelection: addImg, minimumResultsForSearch: Infinity }); }, });//$.extend })( wp.customize , jQuery, _ ); ( function ( api, $, _ ) { //THEME CONTROLS //api.CZRBackgroundControl = api.CZRItemControl.extend( CZRBackgroundMths ); //api.CZRWidgetAreasControl = api.CZRDynModule.extend( CZRWidgetAreasMths ); api.CZRUploadControl = api.Control.extend( CZRUploadMths ); api.CZRLayoutControl = api.Control.extend( CZRLayoutSelectMths ); api.CZRMultiplePickerControl = api.Control.extend( CZRMultiplePickerMths ); api.CZRColorAlpha = api.Control.extend({ready: api.ColorControl.prototype.ready});//api.CZRColorAlpha $.extend( api.controlConstructor, { czr_upload : api.CZRUploadControl, //czr_sidebars : api.CZRWidgetAreasControl, //czr_socials : api.CZRSocialControl, czr_multiple_picker : api.CZRMultiplePickerControl, czr_layouts : api.CZRLayoutControl, wp_color_alpha : api.CZRColorAlpha, //czr_background : api.CZRBackgroundControl }); if ( 'function' == typeof api.CroppedImageControl ) { api.CZRCroppedImageControl = api.CroppedImageControl.extend( CZRCroppedImageMths ); $.extend( api.controlConstructor, { czr_cropped_image : api.CZRCroppedImageControl }); } if ( 'function' == typeof api.CodeEditorControl ) { $.extend( api.controlConstructor, { czr_code_editor : api.CodeEditorControl }); } })( wp.customize, jQuery, _ ); ( function (api, $, _) { var $_nav_section_container, i18n = serverControlParams.i18n || {}; api.czr_CrtlDependenciesReady = $.Deferred(); api.bind( 'ready' , function() { if ( _.has( api, 'czr_ctrlDependencies') ) return; api.czr_ctrlDependencies = new api.CZR_ctrlDependencies(); api.czr_CrtlDependenciesReady.resolve(); } ); api.CZR_ctrlDependencies = api.Class.extend( { dominiDeps : [], initialize: function() { var self = this; this.defaultDominusParams = { dominus : '', servi : [], visibility : null, actions : null, onSectionExpand : true }; //store the default control dependencies this.dominiDeps = _.extend( this.dominiDeps, this._getControlDeps() ); if ( ! _.isArray( self.dominiDeps ) ) { throw new Error('Visibilities : the dominos dependency array is not an array.'); } api.czr_activeSectionId.bind( function( section_id ) { if ( ! _.isEmpty( section_id ) && api.section.has( section_id ) ) { try { self.setServiDependencies( section_id ); } catch( er ) { api.errorLog( 'In api.CZR_ctrlDependencies : ' + er ); } } }); //@param target_source is an object : // { // target : section_id to awake // source : section_id from which the request for awaking has been done // } api.bind( 'awaken-section', function( target_source ) { try { self.setServiDependencies( target_source.target, target_source.source ); } catch( er ) { api.errorLog( 'On awaken-section, ctrl deps : ' + er ); } }); //FAVICON SPECIFICS //@todo => move to the theme ? //favicon note on load and on change(since wp 4.3) this._handleFaviconNote(); }, //Process the visibility callbacks for the controls of a target targetSectionId //@param targetSectionId : string //@param sourceSectionId : string, the section from which the request has been done setServiDependencies : function( targetSectionId, sourceSectionId, refresh ) { var self = this, params, dfd = $.Deferred(); refresh = refresh || false; if ( _.isUndefined( targetSectionId ) || ! api.section.has( targetSectionId ) ) { throw new Error( 'Control Dependencies : the targetSectionId is missing or not registered : ' + targetSectionId ); } //Assign a visibility state deferred to the target section api.section( targetSectionId ).czr_ctrlDependenciesReady = api.section( targetSectionId ).czr_ctrlDependenciesReady || $.Deferred(); //Bail here if this section has already been setup for ctrl dependencies if ( ! refresh && 'resolved' == api.section( targetSectionId ).czr_ctrlDependenciesReady.state() ) return dfd.resolve().promise(); //FIND DOMINI IN THE TARGET SECTION //=> setup their callbacks _.each( self.dominiDeps , function( params ) { if ( ! _.has( params, 'dominus' ) || ! _.isString( params.dominus ) || _.isEmpty( params.dominus ) ) { throw new Error( 'Control Dependencies : a dominus control id must be a not empty string.'); } var wpDominusId = api.CZR_Helpers.build_setId( params.dominus ); if ( ! api.control.has( wpDominusId ) ) return; if ( api.control( wpDominusId ).section() != targetSectionId ) return; //Attempt to normalize the params params = self._prepareDominusParams( params ); if ( _.isEmpty(params) ) return; self._processDominusCallbacks( params.dominus, params, refresh ) .fail( function() { api.consoleLog( 'self._processDominusCallbacks fail for section ' + targetSectionId ); dfd.reject(); }) .done( function() { dfd.resolve(); }); }); //EXTERNAL DOMINI : AWAKE THE SECTIONS //check if any control of the current section is the servus of a dominus located in another section var _secCtrls = api.CZR_Helpers.getSectionControlIds( targetSectionId ), _getServusDomini = function( shortServudId ) { var _dominiIds = []; _.each( self.dominiDeps , function( params ) { if ( ! _.has( params, 'servi' ) || ! _.isArray( params.servi ) || ! _.has( params, 'dominus' ) || _.isEmpty( params.dominus ) ) { api.errorLog( 'Control Dependencies : wrong params in _getServusDomini.'); return; } if ( _.contains( params.servi , shortServudId ) && ! _.contains( _dominiIds , params.dominus ) ) { //Attempt to normalize the params params = self._prepareDominusParams( params ); if ( _.isEmpty(params) ) return; else _dominiIds.push( params.dominus ); } }); return ! _.isArray( _dominiIds ) ? [] : _dominiIds; }, _servusDominiIds = []; //Build the domini array _.each( _secCtrls, function( servusCandidateId ) { if ( _.isEmpty( _getServusDomini( servusCandidateId ) ) ) return; _servusDominiIds = _.union( _servusDominiIds, _getServusDomini( servusCandidateId ) ); }); //let's loop on the domini ids and check if we need to "awake" an external section _.each( _servusDominiIds, function( shortDominusId ){ var wpDominusId = api.CZR_Helpers.build_setId( shortDominusId ); //This dominus must be located in another section if ( api.control( wpDominusId ).section() == targetSectionId ) return; //The dominus section can't be the current source if set. => otherwise potential infinite loop scenario. if ( sourceSectionId == api.control( wpDominusId ).section() ) return; //inform the api that a section has to be awaken //=> first silently update the section controls if skope on //=> then fire the visibilities api.trigger( 'awaken-section', { target : api.control( wpDominusId ).section(), source : targetSectionId } ); } ); //This section has been setup for ctrl dependencies dfd.always( function() { api.section( targetSectionId ).czr_ctrlDependenciesReady.resolve(); }); return dfd.promise(); }, //This method fires a callback when a control is registered in the api. //If the control is registered, then it fires the callback when it is embedded //If the control is embedeed, it fires the callback //=> typical use case : a control can be both removed from the API and the DOM, and then added back on skope switch // //@param wpCtrlId : string name of the control as registered in the WP API //@param callback : fn callback to fire //@param args : [] or callback arguments _deferCallbackForControl : function( wpCrtlId, callback, args ) { var dfd = $.Deferred(); if ( _.isEmpty(wpCrtlId) || ! _.isString(wpCrtlId) ) { throw new Error( '_deferCallbackForControl : the control id is missing.' ); } if ( ! _.isFunction( callback ) ) { throw new Error( '_deferCallbackForControl : callback must be a funtion.' ); } args = ( _.isUndefined(args) || ! _.isArray( args ) ) ? [] : args; if ( api.control.has( wpCrtlId ) ) { if ( 'resolved' == api.control(wpCrtlId ).deferred.embedded.state() ) { $.when( callback.apply( null, args ) ) .fail( function() { dfd.reject(); }) .done( function() { dfd.resolve(); }); } else { api.control( wpCrtlId ).deferred.embedded.then( function() { $.when( callback.apply( null, args ) ) .fail( function() { dfd.reject(); }) .done( function() { dfd.resolve(); }); }); } } else { api.control.when( wpCrtlId, function() { api.control( wpCrtlId ).deferred.embedded.then( function() { $.when( callback.apply( null, args ) ) .fail( function() { dfd.reject(); }) .done( function() { dfd.resolve(); }); }); }); } return dfd.promise(); }, /* * @return void * show or hide setting according to the dependency + callback pair * @params setId = the short setting id, whitout the theme option prefix OR the WP built-in setting * @params o = { controls [], callback fn, onSectionExpand bool } */ _processDominusCallbacks : function( shortDominusId, dominusParams, refresh ) { var self = this, wpDominusId = api.CZR_Helpers.build_setId( shortDominusId ), dominusSetInst = api( wpDominusId ), dfd = $.Deferred(), hasProcessed = false; //loop on the dominus servi and apply + bind the visibility cb _.each( dominusParams.servi , function( servusShortSetId ) { if ( ! api.control.has( api.CZR_Helpers.build_setId( servusShortSetId ) ) ) { return; } //set visibility when control is embedded //or when control is added to the api //=> solves the problem of visibility callbacks lost when control are re-rendered var _fireDominusCallbacks = function( dominusSetVal, servusShortSetId, dominusParams, refresh ) { var _toFire = [], _args = arguments; _.each( dominusParams, function( _item, _key ) { switch( _key ) { case 'visibility' : self._setVisibility.apply( null, _args ); break; case 'actions' : if ( _.isFunction( _item ) ) _item.apply( null, _args ); break; } }); }, _deferCallbacks = function( dominusSetVal ) { dominusSetVal = dominusSetVal || dominusSetInst(); var wpServusSetId = api.CZR_Helpers.build_setId( servusShortSetId ); self._deferCallbackForControl( wpServusSetId, _fireDominusCallbacks, [ dominusSetVal, servusShortSetId, dominusParams ] ) .always( function() { hasProcessed = true; }) .fail( function() { dfd.reject(); }) .done( function() { dfd.resolve(); }); }; //APPLY THE DEPENDENCIES _deferCallbacks(); //BIND THE DOMINUS SETTING INSTANCE //store the visibility bound state if ( ! _.has( dominusSetInst, 'czr_visibilityServi' ) ) dominusSetInst.czr_visibilityServi = new api.Value( [] ); //Maybe bind to react on setting _dirty change var _currentDependantBound = dominusSetInst.czr_visibilityServi(); //Make sure a dependant visibility action is bound only once for a setting id to another setting control id if ( ! _.contains( _currentDependantBound, servusShortSetId ) ) { dominusSetInst.bind( function( dominusSetVal ) { _deferCallbacks( dominusSetVal ); }); dominusSetInst.czr_visibilityServi( _.union( _currentDependantBound, [ servusShortSetId ] ) ); } } );//_.each if ( ! hasProcessed ) return dfd.resolve().promise(); return dfd.promise(); }, //@return void() _setVisibility : function ( dominusSetVal, servusShortSetId, dominusParams, refresh ) { var wpServusSetId = api.CZR_Helpers.build_setId( servusShortSetId ), visibility = dominusParams.visibility( dominusSetVal, servusShortSetId, dominusParams.dominus ); refresh = refresh || false; //Allows us to filter between visibility callbacks and other actions //a non visibility callback shall return null if ( ! _.isBoolean( visibility ) || ( 'unchanged' == visibility && ! refresh ) ) return; //when skope is enabled, we might be doing a silent update //=> this method should be bailed if so var _doVisibilitiesWhenPossible = function() { if ( api.state.has( 'silent-update-processing' ) && api.state( 'silent-update-processing' )() ) return; api.control( wpServusSetId, function( _controlInst ) { var _args = { duration : 'fast', completeCallback : function() {}, unchanged : false }; if ( _.has( _controlInst, 'active' ) ) visibility = visibility && _controlInst.active(); if ( _.has( _controlInst, 'defaultActiveArguments' ) ) _args = control.defaultActiveArguments; _controlInst.onChangeActive( visibility , _controlInst.defaultActiveArguments ); }); if ( api.state.has( 'silent-update-processing' ) ) { api.state( 'silent-update-processing' ).unbind( _doVisibilitiesWhenPossible ); } }; if ( api.state.has( 'silent-update-processing' ) && api.state( 'silent-update-processing' )() ) { api.state( 'silent-update-processing' ).bind( _doVisibilitiesWhenPossible ); } else { _doVisibilitiesWhenPossible(); } }, /***************************************************************************** * HELPERS *****************************************************************************/ /* * Abstract * Will be provided by the theme * @return main control dependencies object */ _getControlDeps : function() { return {}; }, //@return a visibility ready object of param describing the dependencies between a dominus and its servi. //this.defaultDominusParams = { // dominus : '', // servi : [], // visibility : fn() {}, // actions : fn() {}, // onSectionExpand : true // }; _prepareDominusParams : function( params_candidate ) { var self = this, _ready_params = {}; //Check mandatory conditions if ( ! _.isObject( params_candidate ) ) { api.errorLog( 'Visibilities : a dominus param definition must be an object.'); return _ready_params; } if ( ! _.has( params_candidate, 'visibility' ) && ! _.has( params_candidate, 'actions' ) ) { api.errorLog( 'Visibilities : a dominus definition must include a visibility or an actions callback.'); return _ready_params; } if ( ! _.has( params_candidate, 'dominus' ) || ! _.isString( params_candidate.dominus ) || _.isEmpty( params_candidate.dominus ) ) { api.errorLog( 'Visibilities : a dominus control id must be a not empty string.'); return _ready_params; } var wpDominusId = api.CZR_Helpers.build_setId( params_candidate.dominus ); if ( ! api.control.has( wpDominusId ) ) { api.errorLog( 'Visibilities : a dominus control id is not registered : ' + wpDominusId ); return _ready_params; } if ( ! _.has( params_candidate, 'servi' ) || _.isUndefined( params_candidate.servi ) || ! _.isArray( params_candidate.servi ) || _.isEmpty( params_candidate.servi ) ) { api.errorLog( 'Visibilities : servi must be set as an array not empty.'); return _ready_params; } _.each( self.defaultDominusParams , function( _value, _key ) { var _candidate_val = params_candidate[ _key ]; switch( _key ) { case 'visibility' : if ( ! _.isUndefined( _candidate_val ) && ! _.isEmpty( _candidate_val ) && ! _.isFunction( _candidate_val ) ) { throw new Error( 'Visibilities : a dominus visibility callback must be a function : ' + params_candidate.dominus ); } break; case 'actions' : if ( ! _.isUndefined( _candidate_val ) && ! _.isEmpty( _candidate_val ) && ! _.isFunction( _candidate_val ) ) { throw new Error( 'Visibilities : a dominus actions callback must be a function : ' + params_candidate.dominus ); } break; case 'onSectionExpand' : if ( ! _.isUndefined( _candidate_val ) && ! _.isEmpty( _candidate_val ) && ! _.isBoolean( _candidate_val ) ) { throw new Error( 'Visibilities : a dominus onSectionExpand param must be a boolean : ' + params_candidate.dominus ); } break; } _ready_params[_key] = _candidate_val; }); return _ready_params; }, /***************************************************************************** * FAVICON SPECIFICS *****************************************************************************/ /** * Fired on api ready * May change the site_icon description on load * May add a callback to site_icon * @return void() */ _handleFaviconNote : function() { var self = this, _fav_setId = api.CZR_Helpers.build_setId( serverControlParams.faviconOptionName ); //do nothing if (||) //1) WP version < 4.3 where site icon has been introduced //2) User had not defined a favicon //3) User has already set WP site icon if ( ! api.has('site_icon') || ! api.control('site_icon') || ( api.has( _fav_setId ) && 0 === + api( _fav_setId )() ) || + api('site_icon')() > 0 ) return; var _oldDes = api.control('site_icon').params.description; _newDes = ['' , i18n.faviconNote || '' , '

' ].join('') + _oldDes; //on api ready self._printFaviconNote(_newDes ); //on site icon change api('site_icon').callbacks.add( function(to) { if ( +to > 0 ) { //reset the description to default api.control('site_icon').container.find('.description').text(_oldDes); //reset the previous favicon setting if ( api.has( _fav_setId ) ) api( _fav_setId ).set(""); } else { self._printFaviconNote(_newDes ); } }); }, //Add a note to the WP control description if user has already defined a favicon _printFaviconNote : function( _newDes ) { api.control('site_icon').container.find('.description').html(_newDes); } } );//api.Class.extend() //api.CZR_ctrlDependencies })( wp.customize, jQuery, _); //DOM READY : //1) FIRE SPECIFIC INPUT PLUGINS //2) ADD SOME COOL STUFFS //3) SPECIFIC CONTROLS ACTIONS ( function ( wp, $ ) { $( function($) { var api = wp.customize || api; //WHAT IS HAPPENING IN THE MESSENGER // $(window.parent).on( 'message', function(e, o) { // api.consoleLog('SENT STUFFS', JSON.parse( e.originalEvent.data), e ); // }); // $( window ).on( 'message', function(e, o) { // api.consoleLog('INCOMING MESSAGE', JSON.parse( e.originalEvent.data), e ); // }); // $(window.document).bind("ajaxSend", function(e, o){ // api.consoleLog('AJAX SEND', e, arguments ); // }).bind("ajaxComplete", function(e, o){ // api.consoleLog('AJAX COMPLETE', e, o); // }); /* RECENTER CURRENT SECTIONS */ $('.accordion-section').not('.control-panel').click( function () { _recenter_current_section($(this)); }); function _recenter_current_section( section ) { var $siblings = section.siblings( '.open' ); //check if clicked element is above or below sibling with offset.top if ( 0 !== $siblings.length && $siblings.offset().top < 0 ) { $('.wp-full-overlay-sidebar-content').animate({ scrollTop: - $('#customize-theme-controls').offset().top - $siblings.height() + section.offset().top + $('.wp-full-overlay-sidebar-content').offset().top }, 700); } }//end of fn /* CHECKBOXES */ api.czrSetupCheckbox = function( controlId, refresh ) { var _ctrl = api.control( controlId ); $('input[type=checkbox]:not(.nimblecheck-input)', _ctrl.container ).each( function() { //Exclude font customizer if ( 'tc_font_customizer_settings' == _ctrl.params.section ) return; //first fix the checked / unchecked status if ( 0 === $(this).val() || '0' == $(this).val() || 'off' == $(this).val() || _.isEmpty($(this).val() ) ) { $(this).prop('checked', false); } else { $(this).prop('checked', true); } //then render icheck if not done already if ( 0 !== $(this).closest('div[class^="icheckbox"]').length ) return; $(this).iCheck({ checkboxClass: 'icheckbox_flat-grey', //checkedClass: 'checked', radioClass: 'iradio_flat-grey', }) .on( 'ifChanged', function(e){ $(this).val( false === $(this).is(':checked') ? 0 : 1 ); $(e.currentTarget).trigger('change'); }); }); };//api.czrSetupCheckbox() /* SELECT INPUT */ api.czrSetupSelect = function(controlId, refresh) { //Exclude no-selecter-js $('select[data-customize-setting-link]', api.control(controlId).container ) .not('.no-selecter-js') .each( function() { $(this).selecter({ //triggers a change event on the view, passing the newly selected value + index as parameters. // callback : function(value, index) { // self.triggerSettingChange( window.event || {} , value, index); // first param is a null event. // } }); }); };//api.czrSetupSelect() /* NUMBER INPUT */ api.czrSetupStepper = function( controlId, refresh ) { var _ctrl = api.control( controlId ); $('input[type="number"]', _ctrl.container ).each( function() { $(this).stepper(); }); };//api.czrSetupStepper() // LOOP ON EACH CONTROL REGISTERED AND INSTANTIATE THE PLUGINS // @todo => react on control added api.control.each( function( control ){ if ( ! _.has( control, 'id' ) ) return; //exclude widget controls and menu controls for checkboxes if ( 'widget_' != control.id.substring(0, 'widget_'.length ) && 'nav_menu' != control.id.substring( 0, 'nav_menu'.length ) ) { api.czrSetupCheckbox(control.id); } if ( 'nav_menu_locations' != control.id.substring( 0, 'nav_menu_locations'.length ) ) { api.czrSetupSelect(control.id); } // Stepper : exclude controls from specific sections var _exclude = [ 'publish_settings', //<= the outer section introduced in v4.9 to publish / saved draft / schedule 'tc_font_customizer_settings' //the font customizer plugin has its own way to instantiate the stepper, with custom attributes previously set to the input like step, min, etc... ]; if ( 0 < control.container.find( 'input[type="number"]' ).length && control.params && control.params.section && ! _.contains( _exclude, control.params.section ) ) { api.czrSetupStepper(control.id); } }); });//end of $( function($) ) dom ready })( wp, jQuery );