//@global serverControlParams var CZRSkopeBaseMths = CZRSkopeBaseMths || {}; (function ( api, $, _ ) { $.extend( CZRSkopeBaseMths, { initialize: function() { var self = this; ///////////////////// DEFINITIONS ///////////////////// //Store the state of the first skope collection state api.czr_initialSkopeCollectionPopulated = $.Deferred(); //the czr_skopeCollection stores all skopes instantiated by the user //this collection is not updated directly //=> it's updated on skope() instance change api.czr_skopeCollection = new api.Value([]);//all available skope, including the current skopes //the current skopes collection get updated each time the 'czr-new-skopes-synced' event is triggered on the api by the preview api.czr_currentSkopesCollection = new api.Value([]); //the currently active skopes api.czr_activeSkopes = new api.Value( { local : '', group : ''} ); ///////////////////// SKOPE COLLECTIONS SYNCHRONISATION AND LISTENERS ///////////////////// //LISTEN TO SKOPE SYNC => UPDATE SKOPE COLLECTION ON START AND ON EACH REFRESH //the sent data look like : //{ // czr_new_skopes : _wpCustomizeSettings.czr_new_skopes || [], // isChangesetDirty : boolean // } api.bind( 'ready' , function() { api.previewer.bind( 'czr-new-skopes-synced', function( skope_server_data ) { if ( serverControlParams.isDevMode ) { api.infoLog( 'API SKOPE SYNCED', skope_server_data ); } // set the currently active stylesheet if ( ! _.has( skope_server_data, 'czr_stylesheet') ) { api.errorLog( "On 'czr-new-skopes-synced' : missing stylesheet in the server data" ); return; } api.czr_skopeBase.stylesheet = api.czr_skopeBase.stylesheet || new api.Value( api.settings.theme.stylesheet ); api.czr_skopeBase.stylesheet( skope_server_data.czr_stylesheet ); //api.consoleLog('czr-skopes-ready DATA', skope_server_data ); var preview = this, previousSkopeCollection = api.czr_currentSkopesCollection(); //initialize skopes with the server sent skope_server_data //if skope has not been initialized yet and the server sent wrong skope_server_data, then reject the skope ready promise() if ( ! _.has( skope_server_data, 'czr_new_skopes') ) { api.errorLog( "On 'czr-new-skopes-synced' : missing skopes in the server data" ); return; } // If no "group" skope has been sent, check if we should have one // array( 'home', 'search', '404', 'date' ) <= have no group if ( _.isEmpty( _.findWhere( skope_server_data.czr_new_skopes, { skope : 'group' } ) ) ){ var _local_ = _.findWhere( skope_server_data.czr_new_skopes, { skope : 'local' } ); if ( ! _.isEmpty( _local_ ) && ! _.contains( FlatSkopeLocalizedData.noGroupSkopeList, _local_.level ) ) { api.errorLog( 'No group level skope sent while there should be one' ); } } //1) Updated the collection with normalized skopes => prepareSkopeForAPI + api.czr_currentSkopesCollection( collection ) //2) When the api.czr_currentSkopesCollection() Value is set => instantiates the missing skope //3) Set the skope layout view when the skope embedded promise is resolved if ( serverControlParams.isDevMode ) { api.czr_skopeBase.updateSkopeCollection( skope_server_data.czr_new_skopes , preview.channel() ); } else { try { api.czr_skopeBase.updateSkopeCollection( skope_server_data.czr_new_skopes , preview.channel() ); } catch ( er ) { console.log('UPDATE SKOPE COLLECTION ERROR', er); return; } } //@return void() // => refresh skope notice below the skope switcher title // => refresh bottom skope infos in the preview // var _refreshSkopeInfosNotices = function() { // console.log('REFRESH SKOPE TITLE IF NEEDED ?'); // //WRITE THE CURRENT SKOPE TITLE // //self._writeCurrentSkopeTitle(); // }; //Always wait for the initial collection to be populated api.czr_initialSkopeCollectionPopulated.then( function() { //console.log('INITIAL SKOPE COLLECTION POPULATED'); if ( ! _.has( skope_server_data, 'czr_new_skopes' ) || _.isEmpty( skope_server_data.czr_new_skopes ) ) { api.errorLog( 'Missing skope data after refresh', skope_server_data ); } // set the local and group skope id api.czr_activeSkopes( { 'local' : self.getSkopeProperty( 'skope_id', 'local' ), 'group' : self.getSkopeProperty( 'skope_id', 'group' ) }); // if ( ! _.isEmpty( previousSkopeCollection ) ) { //Rewrite the title when the local skope has changed // var _prevLoc = _.findWhere( previousSkopeCollection , { skope : 'local' } ).opt_name, // _newLoc =_.findWhere( skope_server_data.czr_new_skopes, { skope : 'local' } ).opt_name; // if ( _newLoc !== _prevLoc ) { // //REFRESH SKOPE INFOS IN TITLE AND PREVIEW FRAME // _refreshSkopeInfosNotices(); // } // } }); });//api.previewer.bind });//api.bind( 'ready' //CURRENT SKOPE COLLECTION LISTENER //The skope collection is set on 'czr-new-skopes-synced' triggered by the preview //setup the callbacks of the skope collection update //on init and on preview change : the collection of skopes is populated with new skopes //=> instanciate the relevant skope object + render them api.czr_currentSkopesCollection.bind( function( to, from ) { return self.currentSkopesCollectionReact( to, from ); }, { deferred : true }); ///////////////////// VARIOUS ///////////////////// //DECLARE THE LIST OF CONTROL TYPES FOR WHICH THE VIEW IS REFRESHED ON CHANGE //self.refreshedControls = [ 'czr_cropped_image'];// [ 'czr_cropped_image', 'czr_multi_module', 'czr_module' ]; api.trigger( 'czr_skopeBase_initialized' ); }//initialize });//$.extend() })( wp.customize , jQuery, _);//@global serverControlParams var CZRSkopeBaseMths = CZRSkopeBaseMths || {}; ( function ( api, $, _ ) { $.extend( CZRSkopeBaseMths, { ////////////////////////////////////////////////////////// /// // @return string getSkopeProperty : function( what, skope_level ) { what = what || 'skope_id'; skope_level = skope_level || 'local'; var _skope_data = _.findWhere( api.czr_currentSkopesCollection(), { skope : skope_level }); if ( _.isEmpty( _skope_data ) ){ // display an error message if local skope not found. Should always be defined. if ( 'local' == skope_level ) { api.errorLog( "getSkopeProperty => local skope missing, returning not_set" ); } return "_skope_not_set_";//for example when trying to get a group skope_id in a context where there can't be a group skope like home or search. } else if ( !_.has( _skope_data, what ) ) { api.errorLog( "getSkopeProperty => " + what + " property does not exist" ); return "_skope_not_set_"; } else { return _skope_data[ what ]; } }, //@return string firstToUpperCase : function( str ) { return ! _.isString( str ) ? '' : str.substr(0, 1).toUpperCase() + str.substr(1); } // //@return string // buildSkopeLink : function( skope_id ) { // if ( ! api.czr_skope.has( skope_id ) ) { // api.errorLog( 'buildSkopeLink : the requested skope id is not registered : ' + skope_id ); // return ''; // } // var _link_title = [ serverControlParams.i18n.skope['Switch to scope'], api.czr_skope( skope_id )().title ].join(' : '); // return [ // '', // api.czr_skope( skope_id )().title, // '' // ].join( '' ); // }, });//$.extend })( wp.customize , jQuery, _ );//@global serverControlParams var CZRSkopeBaseMths = CZRSkopeBaseMths || {}; (function ( api, $, _ ) { $.extend( CZRSkopeBaseMths, { //Fired on 'czr-new-skopes-synced' triggered by the preview, each time the preview is refreshed. //On a Save Action, api.czr_savedDirties has been populated => // 1) check if the server sends the same saved values // 2) update the skope db properties with the latests saved ones // //A skope candidate is structured this way : //{ // id:"" // long_title:"Site wide options" // obj_id:"" // skope:"global" // title:"Site wide options" //} //@see api_overrides updateSkopeCollection : function( sent_collection ) { var self = this, _api_ready_collection = []; //normalize each sent skopes _.each( sent_collection, function( _skope ) { var skope_candidate = $.extend( true, {}, _skope );//deep clone to avoid any shared references _api_ready_collection.push( self.prepareSkopeForAPI( skope_candidate ) ); }); //set the new collection of current skopes //=> this will instantiate the not instantiated skopes api.czr_currentSkopesCollection( _api_ready_collection ); // set the group skope id //console.log( "SKOPE COLLECTION UPDATED", api.czr_currentSkopesCollection() ); }, //@param skope_candidate ////A skope candidate is structured this way : //{ // id:"" // long_title:"Site wide options" // obj_id:"" // skope:"global" // title:"Site wide options" //} prepareSkopeForAPI : function( skope_candidate ) { if ( ! _.isObject( skope_candidate ) ) { throw new Error('prepareSkopeForAPI : a skope must be an object to be API ready'); } var api_ready_skope = skope_candidate; _.each( FlatSkopeLocalizedData.defaultSkopeModel , function( _value, _key ) { var _candidate_val = skope_candidate[_key]; switch( _key ) { case 'title' : if ( ! _.isString( _candidate_val ) ) { throw new Error('prepareSkopeForAPI : a skope title property must a string'); } api_ready_skope[_key] = _candidate_val; break; case 'long_title' : if ( ! _.isString( _candidate_val ) ) { throw new Error('prepareSkopeForAPI : a skope title property must a string'); } api_ready_skope[_key] = _candidate_val; break; case 'ctx_title' : if ( ! _.isString( _candidate_val ) ) { throw new Error('prepareSkopeForAPI : a skope context title property must a string'); } api_ready_skope[_key] = _candidate_val; break; case 'skope' : if ( ! _.isString( _candidate_val ) || _.isEmpty( _candidate_val ) ) { throw new Error('prepareSkopeForAPI : a skope "skope" property must a string not empty'); } api_ready_skope[_key] = _candidate_val; break; case 'obj_id' : if ( ! _.isString( _candidate_val ) ) { throw new Error('prepareSkopeForAPI : invalid "obj_id" for skope ' + _candidate_val.skope ); } api_ready_skope[_key] = _candidate_val; break; case 'skope_id' : if ( ! _.isString( _candidate_val ) ) { throw new Error('prepareSkopeForAPI : invalid "skope_key" for skope ' + _candidate_val.skope ); } api_ready_skope[_key] = _candidate_val; break; case 'values' : // if ( ! _.isString( _candidate_val ) ) { // throw new Error('prepareSkopeForAPI : invalid "values" for skope ' + _candidate_val.skope ); // } api_ready_skope[_key] = _candidate_val; break; default : api_ready_skope[_key] = _candidate_val; break; }//switch }); //Finally, generate the id and the title api_ready_skope.id = api_ready_skope.skope + '_' + api_ready_skope.skope_id; if ( ! _.isString( api_ready_skope.id ) || _.isEmpty( api_ready_skope.id ) ) { throw new Error('prepareSkopeForAPI : a skope id must a string not empty'); } if ( ! _.isString( api_ready_skope.title ) || _.isEmpty( api_ready_skope.title ) ) { api_ready_skope.title = api_ready_skope.id; api_ready_skope.long_title = api_ready_skope.id; } return api_ready_skope; }, //cb of api.czr_currentSkopesCollection.callbacks //fired in initialize currentSkopesCollectionReact : function( to, from ) { var dfd = $.Deferred(); //ON INITIAL COLLECTION POPULATE, RESOLVE THE DEFERRED STATE //=> this way we can defer earlier actions. //For example when autofocus is requested, the section might be expanded before the initial skope collection is sent from the preview. if ( _.isEmpty( from ) && ! _.isEmpty( to ) ) { api.czr_initialSkopeCollectionPopulated.resolve(); } return dfd.resolve( 'changed' ).promise(); }//listenToSkopeCollection() });//$.extend() })( wp.customize , jQuery, _);//@global serverControlParams var CZRSkopeBaseMths = CZRSkopeBaseMths || {}; (function ( api, $ ) { // Skope $.extend( CZRSkopeBaseMths, api.Events ); var CZR_SkopeBase = api.Class.extend( CZRSkopeBaseMths ); // Schedule skope instantiation on api ready // api.bind( 'ready' , function() { // api.czr_skopeBase = new api.CZR_SkopeBase(); // }); api.czr_skopeBase = new CZR_SkopeBase(); })( wp.customize, jQuery );