diff --git a/wp-includes/js/customize-base.js b/wp-includes/js/customize-base.js index db573b5fca..6c41b40c43 100644 --- a/wp-includes/js/customize-base.js +++ b/wp-includes/js/customize-base.js @@ -1,25 +1,22 @@ window.wp = window.wp || {}; (function( exports, $ ){ - var api, extend, ctor, inherits, + var api = {}, ctor, inherits, slice = Array.prototype.slice; - /* ===================================================================== - * Micro-inheritance - thank you, backbone.js. - * ===================================================================== */ - - extend = function( protoProps, classProps ) { - var child = inherits( this, protoProps, classProps ); - child.extend = this.extend; - return child; - }; - // Shared empty constructor function to aid in prototype-chain creation. ctor = function() {}; - // Helper function to correctly set up the prototype chain, for subclasses. - // Similar to `goog.inherits`, but uses a hash of prototype properties and - // class properties to be extended. + /** + * Helper function to correctly set up the prototype chain, for subclasses. + * Similar to `goog.inherits`, but uses a hash of prototype properties and + * class properties to be extended. + * + * @param object parent Parent class constructor to inherit from. + * @param object protoProps Properties to apply to the prototype for use as class instance properties. + * @param object staticProps Properties to apply directly to the class constructor. + * @return child The subclassed constructor. + */ inherits = function( parent, protoProps, staticProps ) { var child; @@ -65,12 +62,9 @@ window.wp = window.wp || {}; return child; }; - api = {}; - - /* ===================================================================== - * Base class. - * ===================================================================== */ - + /** + * Base class for object inheritance. + */ api.Class = function( applicator, argsArray, options ) { var magic, args = arguments; @@ -92,6 +86,19 @@ window.wp = window.wp || {}; return magic; }; + /** + * Creates a subclass of the class. + * + * @param object protoProps Properties to apply to the prototype. + * @param object staticProps Properties to apply directly to the class. + * @return child The subclass. + */ + api.Class.extend = function( protoProps, classProps ) { + var child = inherits( this, protoProps, classProps ); + child.extend = this.extend; + return child; + }; + api.Class.applicator = {}; api.Class.prototype.initialize = function() {}; @@ -116,12 +123,11 @@ window.wp = window.wp || {}; return false; }; - api.Class.extend = extend; - - /* ===================================================================== - * Events mixin. - * ===================================================================== */ - + /** + * An events manager object, offering the ability to bind to and trigger events. + * + * Used as a mixin. + */ api.Events = { trigger: function( id ) { if ( this.topics && this.topics[ id ] ) @@ -143,10 +149,11 @@ window.wp = window.wp || {}; } }; - /* ===================================================================== + /** * Observable values that support two-way binding. - * ===================================================================== */ - + * + * @constuctor + */ api.Value = api.Class.extend({ initialize: function( initial, options ) { this._value = initial; // @todo: potentially change this to a this.set() call. @@ -254,10 +261,13 @@ window.wp = window.wp || {}; } }); - /* ===================================================================== + /** * A collection of observable values. - * ===================================================================== */ - + * + * @constuctor + * @augments wp.customize.Class + * @mixes wp.customize.Events + */ api.Values = api.Class.extend({ defaultConstructor: api.Value, @@ -379,16 +389,25 @@ window.wp = window.wp || {}; $.extend( api.Values.prototype, api.Events ); - /* ===================================================================== - * An observable value that syncs with an element. - * - * Handles inputs, selects, and textareas by default. - * ===================================================================== */ + /** + * Cast a string to a jQuery collection if it isn't already. + * + * @param {string|jQuery collection} element + */ api.ensure = function( element ) { return typeof element == 'string' ? $( element ) : element; }; + /** + * An observable value that syncs with an element. + * + * Handles inputs, selects, and textareas by default. + * + * @constuctor + * @augments wp.customize.Value + * @augments wp.customize.Class + */ api.Element = api.Value.extend({ initialize: function( element, options ) { var self = this, @@ -442,7 +461,7 @@ window.wp = window.wp || {}; api.Element.synchronizer = {}; - $.each( [ 'html', 'val' ], function( i, method ) { + $.each( [ 'html', 'val' ], function( index, method ) { api.Element.synchronizer[ method ] = { update: function( to ) { this.element[ method ]( to ); @@ -473,13 +492,24 @@ window.wp = window.wp || {}; } }; - /* ===================================================================== - * Messenger for postMessage. - * ===================================================================== */ - $.support.postMessage = !! window.postMessage; + /** + * Messenger for postMessage. + * + * @constuctor + * @augments wp.customize.Class + * @mixes wp.customize.Events + */ api.Messenger = api.Class.extend({ + /** + * Create a new Value. + * + * @param {string} key Unique identifier. + * @param {mixed} initial Initial value. + * @param {mixed} options Options hash. Optional. + * @return {Value} Class instance of the Value. + */ add: function( key, initial, options ) { return this[ key ] = new api.Value( initial, options ); }, @@ -570,10 +600,7 @@ window.wp = window.wp || {}; // Add the Events mixin to api.Messenger. $.extend( api.Messenger.prototype, api.Events ); - /* ===================================================================== - * Core customize object. - * ===================================================================== */ - + // Core customize object. api = $.extend( new api.Values(), api ); api.get = function() { var result = {}; @@ -585,6 +612,6 @@ window.wp = window.wp || {}; return result; }; - // Expose the API to the world. + // Expose the API publicly on window.wp.customize exports.customize = api; })( wp, jQuery ); diff --git a/wp-includes/js/customize-base.min.js b/wp-includes/js/customize-base.min.js index 35b0d112fc..5889a60d58 100644 --- a/wp-includes/js/customize-base.min.js +++ b/wp-includes/js/customize-base.min.js @@ -1 +1 @@ -window.wp=window.wp||{},function(a,b){var c,d,e,f,g=Array.prototype.slice;d=function(a,b){var c=f(this,a,b);return c.extend=this.extend,c},e=function(){},f=function(a,c,d){var f;return f=c&&c.hasOwnProperty("constructor")?c.constructor:function(){var b=a.apply(this,arguments);return b},b.extend(f,a),e.prototype=a.prototype,f.prototype=new e,c&&b.extend(f.prototype,c),d&&b.extend(f,d),f.prototype.constructor=f,f.__super__=a.prototype,f},c={},c.Class=function(a,d,e){var f,g=arguments;return a&&d&&c.Class.applicator===a&&(g=d,b.extend(this,e||{})),f=this,this.instance&&(f=function(){return f.instance.apply(f,arguments)},b.extend(f,this)),f.initialize.apply(f,g),f},c.Class.applicator={},c.Class.prototype.initialize=function(){},c.Class.prototype.extended=function(a){for(var b=this;"undefined"!=typeof b.constructor;){if(b.constructor===a)return!0;if("undefined"==typeof b.constructor.__super__)return!1;b=b.constructor.__super__}return!1},c.Class.extend=d,c.Events={trigger:function(a){return this.topics&&this.topics[a]&&this.topics[a].fireWith(this,g.call(arguments,1)),this},bind:function(a){return this.topics=this.topics||{},this.topics[a]=this.topics[a]||b.Callbacks(),this.topics[a].add.apply(this.topics[a],g.call(arguments,1)),this},unbind:function(a){return this.topics&&this.topics[a]&&this.topics[a].remove.apply(this.topics[a],g.call(arguments,1)),this}},c.Value=c.Class.extend({initialize:function(a,c){this._value=a,this.callbacks=b.Callbacks(),b.extend(this,c||{}),this.set=b.proxy(this.set,this)},instance:function(){return arguments.length?this.set.apply(this,arguments):this.get()},get:function(){return this._value},set:function(a){var b=this._value;return a=this._setter.apply(this,arguments),a=this.validate(a),null===a||this._value===a?this:(this._value=a,this.callbacks.fireWith(this,[a,b]),this)},_setter:function(a){return a},setter:function(a){var b=this.get();return this._setter=a,this._value=null,this.set(b),this},resetSetter:function(){return this._setter=this.constructor.prototype._setter,this.set(this.get()),this},validate:function(a){return a},bind:function(){return this.callbacks.add.apply(this.callbacks,arguments),this},unbind:function(){return this.callbacks.remove.apply(this.callbacks,arguments),this},link:function(){var a=this.set;return b.each(arguments,function(){this.bind(a)}),this},unlink:function(){var a=this.set;return b.each(arguments,function(){this.unbind(a)}),this},sync:function(){var a=this;return b.each(arguments,function(){a.link(this),this.link(a)}),this},unsync:function(){var a=this;return b.each(arguments,function(){a.unlink(this),this.unlink(a)}),this}}),c.Values=c.Class.extend({defaultConstructor:c.Value,initialize:function(a){b.extend(this,a||{}),this._value={},this._deferreds={}},instance:function(a){return 1===arguments.length?this.value(a):this.when.apply(this,arguments)},value:function(a){return this._value[a]},has:function(a){return"undefined"!=typeof this._value[a]},add:function(a,b){return this.has(a)?this.value(a):(this._value[a]=b,b.parent=this,b.extended(c.Value)&&b.bind(this._change),this.trigger("add",b),this._deferreds[a]&&this._deferreds[a].resolve(),this._value[a])},create:function(a){return this.add(a,new this.defaultConstructor(c.Class.applicator,g.call(arguments,1)))},each:function(a,c){c="undefined"==typeof c?this:c,b.each(this._value,function(b,d){a.call(c,d,b)})},remove:function(a){var b;this.has(a)&&(b=this.value(a),this.trigger("remove",b),b.extended(c.Value)&&b.unbind(this._change),delete b.parent),delete this._value[a],delete this._deferreds[a]},when:function(){var a=this,c=g.call(arguments),d=b.Deferred();return b.isFunction(c[c.length-1])&&d.done(c.pop()),b.when.apply(b,b.map(c,function(c){return a.has(c)?void 0:a._deferreds[c]=a._deferreds[c]||b.Deferred()})).done(function(){var e=b.map(c,function(b){return a(b)});return e.length!==c.length?void a.when.apply(a,c).done(function(){d.resolveWith(a,e)}):void d.resolveWith(a,e)}),d.promise()},_change:function(){this.parent.trigger("change",this)}}),b.extend(c.Values.prototype,c.Events),c.ensure=function(a){return"string"==typeof a?b(a):a},c.Element=c.Value.extend({initialize:function(a,d){var e,f,g,h=this,i=c.Element.synchronizer.html;this.element=c.ensure(a),this.events="",this.element.is("input, select, textarea")&&(this.events+="change",i=c.Element.synchronizer.val,this.element.is("input")?(e=this.element.prop("type"),c.Element.synchronizer[e]&&(i=c.Element.synchronizer[e]),("text"===e||"password"===e)&&(this.events+=" keyup")):this.element.is("textarea")&&(this.events+=" keyup")),c.Value.prototype.initialize.call(this,null,b.extend(d||{},i)),this._value=this.get(),f=this.update,g=this.refresh,this.update=function(a){a!==g.call(h)&&f.apply(this,arguments)},this.refresh=function(){h.set(g.call(h))},this.bind(this.update),this.element.bind(this.events,this.refresh)},find:function(a){return b(a,this.element)},refresh:function(){},update:function(){}}),c.Element.synchronizer={},b.each(["html","val"],function(a,b){c.Element.synchronizer[b]={update:function(a){this.element[b](a)},refresh:function(){return this.element[b]()}}}),c.Element.synchronizer.checkbox={update:function(a){this.element.prop("checked",a)},refresh:function(){return this.element.prop("checked")}},c.Element.synchronizer.radio={update:function(a){this.element.filter(function(){return this.value===a}).prop("checked",!0)},refresh:function(){return this.element.filter(":checked").val()}},b.support.postMessage=!!window.postMessage,c.Messenger=c.Class.extend({add:function(a,b,d){return this[a]=new c.Value(b,d)},initialize:function(a,c){var d=window.parent==window?null:window.parent;b.extend(this,c||{}),this.add("channel",a.channel),this.add("url",a.url||""),this.add("targetWindow",a.targetWindow||d),this.add("origin",this.url()).link(this.url).setter(function(a){return a.replace(/([^:]+:\/\/[^\/]+).*/,"$1")}),this.receive=b.proxy(this.receive,this),this.receive.guid=b.guid++,b(window).on("message",this.receive)},destroy:function(){b(window).off("message",this.receive)},receive:function(a){var b;a=a.originalEvent,this.targetWindow()&&(this.origin()&&a.origin!==this.origin()||"string"==typeof a.data&&"{"===a.data[0]&&(b=JSON.parse(a.data),b&&b.id&&"undefined"!=typeof b.data&&(!b.channel&&!this.channel()||this.channel()===b.channel)&&this.trigger(b.id,b.data)))},send:function(a,b){var c;b="undefined"==typeof b?null:b,this.url()&&this.targetWindow()&&(c={id:a,data:b},this.channel()&&(c.channel=this.channel()),this.targetWindow().postMessage(JSON.stringify(c),this.origin()))}}),b.extend(c.Messenger.prototype,c.Events),c=b.extend(new c.Values,c),c.get=function(){var a={};return this.each(function(b,c){a[c]=b.get()}),a},a.customize=c}(wp,jQuery); \ No newline at end of file +window.wp=window.wp||{},function(a,b){var c,d,e={},f=Array.prototype.slice;c=function(){},d=function(a,d,e){var f;return f=d&&d.hasOwnProperty("constructor")?d.constructor:function(){var b=a.apply(this,arguments);return b},b.extend(f,a),c.prototype=a.prototype,f.prototype=new c,d&&b.extend(f.prototype,d),e&&b.extend(f,e),f.prototype.constructor=f,f.__super__=a.prototype,f},e.Class=function(a,c,d){var f,g=arguments;return a&&c&&e.Class.applicator===a&&(g=c,b.extend(this,d||{})),f=this,this.instance&&(f=function(){return f.instance.apply(f,arguments)},b.extend(f,this)),f.initialize.apply(f,g),f},e.Class.extend=function(a,b){var c=d(this,a,b);return c.extend=this.extend,c},e.Class.applicator={},e.Class.prototype.initialize=function(){},e.Class.prototype.extended=function(a){for(var b=this;"undefined"!=typeof b.constructor;){if(b.constructor===a)return!0;if("undefined"==typeof b.constructor.__super__)return!1;b=b.constructor.__super__}return!1},e.Events={trigger:function(a){return this.topics&&this.topics[a]&&this.topics[a].fireWith(this,f.call(arguments,1)),this},bind:function(a){return this.topics=this.topics||{},this.topics[a]=this.topics[a]||b.Callbacks(),this.topics[a].add.apply(this.topics[a],f.call(arguments,1)),this},unbind:function(a){return this.topics&&this.topics[a]&&this.topics[a].remove.apply(this.topics[a],f.call(arguments,1)),this}},e.Value=e.Class.extend({initialize:function(a,c){this._value=a,this.callbacks=b.Callbacks(),b.extend(this,c||{}),this.set=b.proxy(this.set,this)},instance:function(){return arguments.length?this.set.apply(this,arguments):this.get()},get:function(){return this._value},set:function(a){var b=this._value;return a=this._setter.apply(this,arguments),a=this.validate(a),null===a||this._value===a?this:(this._value=a,this.callbacks.fireWith(this,[a,b]),this)},_setter:function(a){return a},setter:function(a){var b=this.get();return this._setter=a,this._value=null,this.set(b),this},resetSetter:function(){return this._setter=this.constructor.prototype._setter,this.set(this.get()),this},validate:function(a){return a},bind:function(){return this.callbacks.add.apply(this.callbacks,arguments),this},unbind:function(){return this.callbacks.remove.apply(this.callbacks,arguments),this},link:function(){var a=this.set;return b.each(arguments,function(){this.bind(a)}),this},unlink:function(){var a=this.set;return b.each(arguments,function(){this.unbind(a)}),this},sync:function(){var a=this;return b.each(arguments,function(){a.link(this),this.link(a)}),this},unsync:function(){var a=this;return b.each(arguments,function(){a.unlink(this),this.unlink(a)}),this}}),e.Values=e.Class.extend({defaultConstructor:e.Value,initialize:function(a){b.extend(this,a||{}),this._value={},this._deferreds={}},instance:function(a){return 1===arguments.length?this.value(a):this.when.apply(this,arguments)},value:function(a){return this._value[a]},has:function(a){return"undefined"!=typeof this._value[a]},add:function(a,b){return this.has(a)?this.value(a):(this._value[a]=b,b.parent=this,b.extended(e.Value)&&b.bind(this._change),this.trigger("add",b),this._deferreds[a]&&this._deferreds[a].resolve(),this._value[a])},create:function(a){return this.add(a,new this.defaultConstructor(e.Class.applicator,f.call(arguments,1)))},each:function(a,c){c="undefined"==typeof c?this:c,b.each(this._value,function(b,d){a.call(c,d,b)})},remove:function(a){var b;this.has(a)&&(b=this.value(a),this.trigger("remove",b),b.extended(e.Value)&&b.unbind(this._change),delete b.parent),delete this._value[a],delete this._deferreds[a]},when:function(){var a=this,c=f.call(arguments),d=b.Deferred();return b.isFunction(c[c.length-1])&&d.done(c.pop()),b.when.apply(b,b.map(c,function(c){return a.has(c)?void 0:a._deferreds[c]=a._deferreds[c]||b.Deferred()})).done(function(){var e=b.map(c,function(b){return a(b)});return e.length!==c.length?void a.when.apply(a,c).done(function(){d.resolveWith(a,e)}):void d.resolveWith(a,e)}),d.promise()},_change:function(){this.parent.trigger("change",this)}}),b.extend(e.Values.prototype,e.Events),e.ensure=function(a){return"string"==typeof a?b(a):a},e.Element=e.Value.extend({initialize:function(a,c){var d,f,g,h=this,i=e.Element.synchronizer.html;this.element=e.ensure(a),this.events="",this.element.is("input, select, textarea")&&(this.events+="change",i=e.Element.synchronizer.val,this.element.is("input")?(d=this.element.prop("type"),e.Element.synchronizer[d]&&(i=e.Element.synchronizer[d]),("text"===d||"password"===d)&&(this.events+=" keyup")):this.element.is("textarea")&&(this.events+=" keyup")),e.Value.prototype.initialize.call(this,null,b.extend(c||{},i)),this._value=this.get(),f=this.update,g=this.refresh,this.update=function(a){a!==g.call(h)&&f.apply(this,arguments)},this.refresh=function(){h.set(g.call(h))},this.bind(this.update),this.element.bind(this.events,this.refresh)},find:function(a){return b(a,this.element)},refresh:function(){},update:function(){}}),e.Element.synchronizer={},b.each(["html","val"],function(a,b){e.Element.synchronizer[b]={update:function(a){this.element[b](a)},refresh:function(){return this.element[b]()}}}),e.Element.synchronizer.checkbox={update:function(a){this.element.prop("checked",a)},refresh:function(){return this.element.prop("checked")}},e.Element.synchronizer.radio={update:function(a){this.element.filter(function(){return this.value===a}).prop("checked",!0)},refresh:function(){return this.element.filter(":checked").val()}},b.support.postMessage=!!window.postMessage,e.Messenger=e.Class.extend({add:function(a,b,c){return this[a]=new e.Value(b,c)},initialize:function(a,c){var d=window.parent==window?null:window.parent;b.extend(this,c||{}),this.add("channel",a.channel),this.add("url",a.url||""),this.add("targetWindow",a.targetWindow||d),this.add("origin",this.url()).link(this.url).setter(function(a){return a.replace(/([^:]+:\/\/[^\/]+).*/,"$1")}),this.receive=b.proxy(this.receive,this),this.receive.guid=b.guid++,b(window).on("message",this.receive)},destroy:function(){b(window).off("message",this.receive)},receive:function(a){var b;a=a.originalEvent,this.targetWindow()&&(this.origin()&&a.origin!==this.origin()||"string"==typeof a.data&&"{"===a.data[0]&&(b=JSON.parse(a.data),b&&b.id&&"undefined"!=typeof b.data&&(!b.channel&&!this.channel()||this.channel()===b.channel)&&this.trigger(b.id,b.data)))},send:function(a,b){var c;b="undefined"==typeof b?null:b,this.url()&&this.targetWindow()&&(c={id:a,data:b},this.channel()&&(c.channel=this.channel()),this.targetWindow().postMessage(JSON.stringify(c),this.origin()))}}),b.extend(e.Messenger.prototype,e.Events),e=b.extend(new e.Values,e),e.get=function(){var a={};return this.each(function(b,c){a[c]=b.get()}),a},a.customize=e}(wp,jQuery); \ No newline at end of file diff --git a/wp-includes/js/customize-loader.js b/wp-includes/js/customize-loader.js index 98bb32f1eb..2ee0c0f90b 100644 --- a/wp-includes/js/customize-loader.js +++ b/wp-includes/js/customize-loader.js @@ -10,7 +10,20 @@ window.wp = window.wp || {}; hashchange: ('onhashchange' in window) && (document.documentMode === undefined || document.documentMode > 7) }); + /** + * Allows the Customizer to be overlayed on any page. + * + * By default, any element in the body with the load-customize class will open + * the Customizer overlay with the URL specified. + * + * e.g. Open customizer + * + * @augments wp.customize.Events + */ Loader = $.extend( {}, api.Events, { + /** + * Setup the Loader; triggered on document#ready. + */ initialize: function() { this.body = $( document.body ); @@ -23,9 +36,12 @@ window.wp = window.wp || {}; this.window = $( window ); this.element = $( '
' ).appendTo( this.body ); + // Bind events for opening and closing the overlay. this.bind( 'open', this.overlay.show ); this.bind( 'close', this.overlay.hide ); + // Any element in the body with the `load-customize` class opens + // the Customizer. $('#wpbody').on( 'click', '.load-customize', function( event ) { event.preventDefault(); @@ -73,6 +89,11 @@ window.wp = window.wp || {}; } }, + /** + * Open the customizer overlay for a specific URL. + * + * @param string src URL to load in the Customizer. + */ open: function( src ) { if ( this.active ) { @@ -148,10 +169,16 @@ window.wp = window.wp || {}; } }, + /** + * Callback after the customizer has been opened. + */ opened: function() { Loader.body.addClass( 'customize-active full-overlay-active' ); }, + /** + * Close the Customizer overlay and return focus to the link that opened it. + */ close: function() { if ( ! this.active ) { return; @@ -174,6 +201,9 @@ window.wp = window.wp || {}; } }, + /** + * Callback after the customizer has been closed. + */ closed: function() { Loader.iframe.remove(); Loader.messenger.destroy(); @@ -184,10 +214,16 @@ window.wp = window.wp || {}; $( window ).off( 'beforeunload', Loader.beforeunload ); }, + /** + * Callback for the `load` event on the Customizer iframe. + */ loaded: function() { Loader.body.removeClass('customize-loading'); }, + /** + * Overlay hide/show utility methods. + */ overlay: { show: function() { this.element.fadeIn( 200, Loader.opened ); @@ -199,11 +235,12 @@ window.wp = window.wp || {}; } }); + // Bootstrap the Loader on document#ready. $( function() { Loader.settings = _wpCustomizeLoaderSettings; Loader.initialize(); }); - // Expose the API to the world. + // Expose the API publicly on window.wp.customize.Loader api.Loader = Loader; })( wp, jQuery );