diff --git a/src/js/_enqueues/wp/customize/base.js b/src/js/_enqueues/wp/customize/base.js index 4afaa945571f0..b4a380efdd9ab 100644 --- a/src/js/_enqueues/wp/customize/base.js +++ b/src/js/_enqueues/wp/customize/base.js @@ -5,9 +5,12 @@ /** @namespace wp */ window.wp = window.wp || {}; -(function( exports, $ ){ - var api = {}, ctor, inherits, - slice = Array.prototype.slice; +/** + * @param {Object} wp The WordPress global object. + * @param {JQueryStatic} $ The jQuery object. + */ +(function( wp, $ ){ + var api = {}, ctor, inherits; // Shared empty constructor function to aid in prototype-chain creation. ctor = function() {}; @@ -17,10 +20,10 @@ window.wp = window.wp || {}; * 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. + * @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 {Function} The subclassed constructor. */ inherits = function( parent, protoProps, staticProps ) { var child; @@ -33,14 +36,14 @@ window.wp = window.wp || {}; if ( protoProps && protoProps.hasOwnProperty( 'constructor' ) ) { child = protoProps.constructor; } else { - child = function() { + child = function( ...args ) { /* * Storing the result `super()` before returning the value * prevents a bug in Opera where, if the constructor returns * a function, Opera will reject the return value in favor of * the original object. This causes all sorts of trouble. */ - var result = parent.apply( this, arguments ); + var result = parent.apply( this, args ); return result; }; } @@ -75,13 +78,28 @@ window.wp = window.wp || {}; /** * Base class for object inheritance. + * + * The arguments are normally passed straight through to the class's + * initialize method. As a special case, when the first argument is + * api.Class.applicator, the second argument is used as the array of + * arguments for initialize and the third is used to extend the instance. + * This allows a class to be constructed from an argument list that is only + * known at runtime. See {@link wp.customize.Values#create}. + * + * @param {...*} args Arguments for the class's initialize method. Or + * api.Class.applicator, followed by the array of + * arguments for the initialize method, followed by an + * optional object of properties to extend the instance + * with. + * @return {Object|Function} The instance of the class, which is a function when the class + * defines an instance method, so that the instance is callable. */ - api.Class = function( applicator, argsArray, options ) { - var magic, args = arguments; + api.Class = function( ...args ) { + var magic; - if ( applicator && argsArray && api.Class.applicator === applicator ) { - args = argsArray; - $.extend( this, options || {} ); + if ( args[0] && args[1] && api.Class.applicator === args[0] ) { + $.extend( this, args[2] || {} ); + args = args[1]; } magic = this; @@ -94,8 +112,8 @@ window.wp = window.wp || {}; * It is also an object that has properties and methods inside it. */ if ( this.instance ) { - magic = function() { - return magic.instance.apply( magic, arguments ); + magic = function( ...instanceArgs ) { + return magic.instance.apply( magic, instanceArgs ); }; $.extend( magic, this ); @@ -108,9 +126,9 @@ window.wp = window.wp || {}; /** * 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. + * @param {Object} [protoProps] Properties to apply to the prototype. + * @param {Object} [staticProps] Properties to apply directly to the class. + * @return {Function} The subclass. */ api.Class.extend = function( protoProps, staticProps ) { var child = inherits( this, protoProps, staticProps ); @@ -155,23 +173,44 @@ window.wp = window.wp || {}; * Used as a mixin. */ api.Events = { - trigger: function( id ) { + /** + * Trigger an event, invoking all of the callbacks bound to it. + * + * @param {string} id ID of the event to trigger. + * @param {...*} [args] Zero or more arguments to pass to the bound callbacks. + * @return {Object} The instance the mixin is applied to. + */ + trigger: function( id, ...args ) { if ( this.topics && this.topics[ id ] ) { - this.topics[ id ].fireWith( this, slice.call( arguments, 1 ) ); + this.topics[ id ].fireWith( this, args ); } return this; }, - bind: function( id ) { + /** + * Bind one or more callbacks to an event. + * + * @param {string} id ID of the event to bind to. + * @param {...Function} callbacks A function, or multiple functions, to add to the callback stack. + * @return {Object} The instance the mixin is applied to. + */ + bind: function( id, ...callbacks ) { this.topics = this.topics || {}; this.topics[ id ] = this.topics[ id ] || $.Callbacks(); - this.topics[ id ].add.apply( this.topics[ id ], slice.call( arguments, 1 ) ); + this.topics[ id ].add.apply( this.topics[ id ], callbacks ); return this; }, - unbind: function( id ) { + /** + * Unbind one or more previously bound callbacks from an event. + * + * @param {string} id ID of the event to unbind from. + * @param {...Function} callbacks A function, or multiple functions, to remove from the callback stack. + * @return {Object} The instance the mixin is applied to. + */ + unbind: function( id, ...callbacks ) { if ( this.topics && this.topics[ id ] ) { - this.topics[ id ].remove.apply( this.topics[ id ], slice.call( arguments, 1 ) ); + this.topics[ id ].remove.apply( this.topics[ id ], callbacks ); } return this; } @@ -183,11 +222,11 @@ window.wp = window.wp || {}; * @memberOf wp.customize * @alias wp.customize.Value * - * @constructor + * @class */ api.Value = api.Class.extend(/** @lends wp.customize.Value.prototype */{ /** - * @param {mixed} initial The initial value. + * @param {*} initial The initial value. * @param {Object} options */ initialize: function( initial, options ) { @@ -204,14 +243,14 @@ window.wp = window.wp || {}; * Magic. Returns a function that will become the instance. * Set to null to prevent the instance from extending a function. */ - instance: function() { - return arguments.length ? this.set.apply( this, arguments ) : this.get(); + instance: function( ...args ) { + return args.length ? this.set.apply( this, args ) : this.get(); }, /** * Get the value. * - * @return {mixed} + * @return {*} The value. */ get: function() { return this._value; @@ -220,12 +259,14 @@ window.wp = window.wp || {}; /** * Set the value and trigger all bound callbacks. * - * @param {Object} to New value. + * @param {*} to New value. + * @param {...*} [args] Zero or more additional arguments to pass to the setter. + * @return {wp.customize.Value} The instance of the Value. */ - set: function( to ) { + set: function( to, ...args ) { var from = this._value; - to = this._setter.apply( this, arguments ); + to = this._setter( to, ...args ); to = this.validate( to ); // Bail if the sanitized value is null or unchanged. @@ -267,51 +308,81 @@ window.wp = window.wp || {}; /** * Bind a function to be invoked whenever the value changes. * - * @param {...Function} A function, or multiple functions, to add to the callback stack. + * @param {...Function} callbacks A function, or multiple functions, to add to the callback stack. + * @return {wp.customize.Value} The instance of the Value. */ - bind: function() { - this.callbacks.add.apply( this.callbacks, arguments ); + bind: function( ...callbacks ) { + this.callbacks.add.apply( this.callbacks, callbacks ); return this; }, /** * Unbind a previously bound function. * - * @param {...Function} A function, or multiple functions, to remove from the callback stack. + * @param {...Function} callbacks A function, or multiple functions, to remove from the callback stack. + * @return {wp.customize.Value} The instance of the Value. */ - unbind: function() { - this.callbacks.remove.apply( this.callbacks, arguments ); + unbind: function( ...callbacks ) { + this.callbacks.remove.apply( this.callbacks, callbacks ); return this; }, - link: function() { // values* + /** + * Update this value whenever one or more other values change. + * + * Note that this is one-directional: this value follows the supplied + * values, not the other way around. Use sync() to link in both + * directions. + * + * @param {...wp.customize.Value} values A value, or multiple values, for this value to follow. + * @return {wp.customize.Value} The instance of the Value. + */ + link: function( ...values ) { var set = this.set; - $.each( arguments, function() { + $.each( values, function() { this.bind( set ); }); return this; }, - unlink: function() { // values* + /** + * Stop updating this value when one or more other values change. + * + * @param {...wp.customize.Value} values A value, or multiple values, for this value to stop following. + * @return {wp.customize.Value} The instance of the Value. + */ + unlink: function( ...values ) { var set = this.set; - $.each( arguments, function() { + $.each( values, function() { this.unbind( set ); }); return this; }, - sync: function() { // values* + /** + * Link this value with one or more other values in both directions. + * + * @param {...wp.customize.Value} values A value, or multiple values, to keep in sync with this value. + * @return {wp.customize.Value} The instance of the Value. + */ + sync: function( ...values ) { var that = this; - $.each( arguments, function() { + $.each( values, function() { that.link( this ); this.link( that ); }); return this; }, - unsync: function() { // values* + /** + * Stop keeping this value in sync with one or more other values. + * + * @param {...wp.customize.Value} values A value, or multiple values, to stop keeping in sync with this value. + * @return {wp.customize.Value} The instance of the Value. + */ + unsync: function( ...values ) { var that = this; - $.each( arguments, function() { + $.each( values, function() { that.unlink( this ); this.unlink( that ); }); @@ -325,7 +396,7 @@ window.wp = window.wp || {}; * @memberOf wp.customize * @alias wp.customize.Values * - * @constructor + * @class * @augments wp.customize.Class * @mixes wp.customize.Events */ @@ -334,7 +405,7 @@ window.wp = window.wp || {}; /** * The default constructor for items of the collection. * - * @type {object} + * @type {Function} */ defaultConstructor: api.Value, @@ -352,27 +423,27 @@ window.wp = window.wp || {}; * the last to be a function callback that will be invoked when the requested * items are available. * - * @see {api.Values.when} + * @see {@link wp.customize.Values#when} * - * @param {string} id ID of the item. - * @param {...} Zero or more IDs of items to wait for and a callback - * function to invoke when they're available. Optional. - * @return {mixed} The item instance if only one ID was supplied. - * A Deferred Promise object if a callback function is supplied. + * @param {string} id ID of the item. + * @param {...(string|Function)} [args] Zero or more IDs of items to wait for and a callback + * function to invoke when they're available. Optional. + * @return {*} The item instance if only one ID was supplied. + * A Deferred Promise object if a callback function is supplied. */ - instance: function( id ) { - if ( arguments.length === 1 ) { + instance: function( id, ...args ) { + if ( 0 === args.length ) { return this.value( id ); } - return this.when.apply( this, arguments ); + return this.when( id, ...args ); }, /** * Get the instance of an item. * * @param {string} id The ID of the item. - * @return {[type]} [description] + * @return {*} The item instance. */ value: function( id ) { return this._value[ id ]; @@ -382,7 +453,7 @@ window.wp = window.wp || {}; * Whether the collection has an item with the given ID. * * @param {string} id The ID of the item to look for. - * @return {boolean} + * @return {boolean} True if the collection has an item with the given ID, false otherwise. */ has: function( id ) { return typeof this._value[ id ] !== 'undefined'; @@ -391,9 +462,9 @@ window.wp = window.wp || {}; /** * Add an item to the collection. * - * @param {string|wp.customize.Class} item - The item instance to add, or the ID for the instance to add. - * When an ID string is supplied, then itemObject must be provided. - * @param {wp.customize.Class} [itemObject] - The item instance when the first argument is an ID string. + * @param {string|wp.customize.Class} item The item instance to add, or the ID for the instance to add. + * When an ID string is supplied, then itemObject must be provided. + * @param {wp.customize.Class} [itemObject] The item instance when the first argument is an ID string. * @return {wp.customize.Class} The new item's instance, or an existing instance if already added. */ add: function( item, itemObject ) { @@ -436,19 +507,19 @@ window.wp = window.wp || {}; * Create a new item of the collection using the collection's default constructor * and store it in the collection. * - * @param {string} id The ID of the item. - * @param {mixed} value Any extra arguments are passed into the item's initialize method. - * @return {mixed} The new item's instance. + * @param {string} id The ID of the item. + * @param {...*} [args] Zero or more extra arguments to pass into the item's initialize method. + * @return {wp.customize.Class} The new item's instance. */ - create: function( id ) { - return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) ); + create: function( id, ...args ) { + return this.add( id, new this.defaultConstructor( api.Class.applicator, args ) ); }, /** * Iterate over all items in the collection invoking the provided callback. * - * @param {Function} callback Function to invoke. - * @param {Object} context Object context to invoke the function with. Optional. + * @param {Function} callback Function to invoke. + * @param {Object} [context] Object context to invoke the function with. */ each: function( callback, context ) { context = typeof context === 'undefined' ? this : context; @@ -494,11 +565,12 @@ window.wp = window.wp || {}; * For example: * when( id1, id2, id3, function( value1, value2, value3 ) {} ); * - * @return $.Deferred.promise(); + * @param {...(string|Function)} ids Zero or more IDs of items to wait for, optionally followed by + * a callback function to invoke once they are all available. + * @return {JQuery.Promise<*>} A promise that is resolved when all of the requested values exist. */ - when: function() { + when: function( ...ids ) { var self = this, - ids = slice.call( arguments ), dfd = $.Deferred(); // If the last argument is a callback, bind it to .done(). @@ -555,9 +627,10 @@ window.wp = window.wp || {}; /** - * Cast a string to a jQuery collection if it isn't already. + * Cast a string to a jQuery object if it isn't already. * - * @param {string|jQuery collection} element + * @param {string|jQuery} element A selector or an existing jQuery collection. + * @return {jQuery} The jQuery collection. */ api.ensure = function( element ) { return typeof element === 'string' ? $( element ) : element; @@ -571,7 +644,7 @@ window.wp = window.wp || {}; * @memberOf wp.customize * @alias wp.customize.Element * - * @constructor + * @class * @augments wp.customize.Value * @augments wp.customize.Class */ @@ -600,9 +673,9 @@ window.wp = window.wp || {}; update = this.update; refresh = this.refresh; - this.update = function( to ) { + this.update = function( to, ...args ) { if ( to !== refresh.call( self ) ) { - update.apply( this, arguments ); + update.call( this, to, ...args ); } }; this.refresh = function() { @@ -663,7 +736,7 @@ window.wp = window.wp || {}; * @memberOf wp.customize * @alias wp.customize.Messenger * - * @constructor + * @class * @augments wp.customize.Class * @mixes wp.customize.Events */ @@ -671,10 +744,10 @@ window.wp = window.wp || {}; /** * 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. + * @param {string} key Unique identifier. + * @param {*} initial Initial value. + * @param {*} [options] Options hash. + * @return {wp.customize.Value} Class instance of the Value. */ add: function( key, initial, options ) { return this[ key ] = new api.Value( initial, options ); @@ -683,11 +756,11 @@ window.wp = window.wp || {}; /** * Initialize Messenger. * - * @param {Object} params - Parameters to configure the messenger. - * {string} params.url - The URL to communicate with. - * {window} params.targetWindow - The window instance to communicate with. Default window.parent. - * {string} params.channel - If provided, will send the channel with each message and only accept messages a matching channel. - * @param {Object} options - Extend any instance parameter or method with this object. + * @param {Object} params Parameters to configure the messenger. + * @param {string} params.url The URL to communicate with. + * @param {Window} params.targetWindow The window instance to communicate with. Default window.parent. + * @param {string} [params.channel] If provided, will send the channel with each message and only accept messages a matching channel. + * @param {Object} options Extend any instance parameter or method with this object. */ initialize: function( params, options ) { // Target the parent frame by default, but only if a parent frame exists. @@ -707,10 +780,10 @@ window.wp = window.wp || {}; // First add with no value. this.add( 'targetWindow', null ); // This avoids SecurityErrors when setting a window object in x-origin iframe'd scenarios. - this.targetWindow.set = function( to ) { + this.targetWindow.set = function( to, ...args ) { var from = this._value; - to = this._setter.apply( this, arguments ); + to = this._setter( to, ...args ); to = this.validate( to ); if ( null === to || from === to ) { @@ -748,7 +821,7 @@ window.wp = window.wp || {}; /** * Receive data from the other window. * - * @param {jQuery.Event} event Event with embedded data. + * @param {JQuery.Event} event Event with embedded data. */ receive: function( event ) { var message; @@ -787,8 +860,8 @@ window.wp = window.wp || {}; /** * Send data to the other window. * - * @param {string} id The event name. - * @param {Object} data Data. + * @param {string} id The event name. + * @param {*} [data] Data. */ send: function( id, data ) { var message; @@ -821,13 +894,13 @@ window.wp = window.wp || {}; * @memberOf wp.customize * @alias wp.customize.Notification * - * @param {string} code - The error code. - * @param {object} params - Params. - * @param {string} params.message=null - The error message. - * @param {string} [params.type=error] - The notification type. - * @param {boolean} [params.fromServer=false] - Whether the notification was server-sent. - * @param {string} [params.setting=null] - The setting ID that the notification is related to. - * @param {*} [params.data=null] - Any additional data. + * @param {string} code The error code. + * @param {Object} params Params. + * @param {string} [params.message=null] The error message. + * @param {string} [params.type=error] The notification type. + * @param {boolean} [params.fromServer=false] Whether the notification was server-sent. + * @param {string} [params.setting=null] The setting ID that the notification is related to. + * @param {*} [params.data=null] Any additional data. */ api.Notification = api.Class.extend(/** @lends wp.customize.Notification.prototype */{ @@ -837,7 +910,7 @@ window.wp = window.wp || {}; * This will be populated with template option or else it will be populated with template from the ID. * * @since 4.9.0 - * @var {Function} + * @member {Function} */ template: null, @@ -845,7 +918,7 @@ window.wp = window.wp || {}; * ID for the template to render the notification. * * @since 4.9.0 - * @var {string} + * @member {string} */ templateId: 'customize-notification', @@ -853,7 +926,7 @@ window.wp = window.wp || {}; * Additional class names to add to the notification container. * * @since 4.9.0 - * @var {string} + * @member {string} */ containerClasses: '', @@ -862,15 +935,15 @@ window.wp = window.wp || {}; * * @since 4.9.0 * - * @param {string} code - Notification code. - * @param {Object} params - Notification parameters. - * @param {string} params.message - Message. - * @param {string} [params.type=error] - Type. - * @param {string} [params.setting] - Related setting ID. - * @param {Function} [params.template] - Function for rendering template. If not provided, this will come from templateId. - * @param {string} [params.templateId] - ID for template to render the notification. - * @param {string} [params.containerClasses] - Additional class names to add to the notification container. - * @param {boolean} [params.dismissible] - Whether the notification can be dismissed. + * @param {string} code Notification code. + * @param {Object} params Notification parameters. + * @param {string} params.message Message. + * @param {string} [params.type=error] Type. + * @param {string} [params.setting] Related setting ID. + * @param {Function} [params.template] Function for rendering template. If not provided, this will come from templateId. + * @param {string} [params.templateId] ID for template to render the notification. + * @param {string} [params.containerClasses] Additional class names to add to the notification container. + * @param {boolean} [params.dismissible] Whether the notification can be dismissed. */ initialize: function( code, params ) { var _params; @@ -935,7 +1008,7 @@ window.wp = window.wp || {}; * * @alias wp.customize.get * - * @return {Object} + * @return {Object} All customize settings. */ api.get = function() { var result = {}; @@ -990,5 +1063,5 @@ window.wp = window.wp || {}; * * @namespace wp.customize */ - exports.customize = api; + wp.customize = api; })( wp, jQuery ); diff --git a/src/js/_enqueues/wp/customize/controls.js b/src/js/_enqueues/wp/customize/controls.js index 00123f9141c30..7b8741a32cac8 100644 --- a/src/js/_enqueues/wp/customize/controls.js +++ b/src/js/_enqueues/wp/customize/controls.js @@ -3,7 +3,12 @@ */ /* global _wpCustomizeHeader, _wpCustomizeBackground, _wpMediaViewsL10n, MediaElementPlayer, console, confirm */ -(function( exports, $ ){ + +/** + * @param {Object} wp The WordPress global object. + * @param {JQueryStatic} $ The jQuery object. + */ +(function( wp, $ ){ var Container, focus, normalizedTransitionendEventName, api = wp.customize; var reducedMotionMediaQuery = window.matchMedia( '(prefers-reduced-motion: reduce)' ); @@ -18,7 +23,7 @@ * Whether the notification should show a loading spinner. * * @since 4.9.0 - * @var {boolean} + * @member {boolean} */ loading: false, @@ -30,8 +35,8 @@ * * @since 4.9.0 * - * @param {string} code - Code. - * @param {Object} params - Params. + * @param {string} code Notification code. + * @param {Object} params Notification params. */ initialize: function( code, params ) { var notification = this; @@ -60,7 +65,7 @@ * * @since 4.9.0 * - * @param {jQuery.Event} event - Event. + * @param {JQuery.Event} event Event. * @return {void} */ handleEscape: function( event ) { @@ -88,7 +93,7 @@ * The default constructor for items of the collection. * * @since 4.9.0 - * @type {object} + * @type {Function} */ defaultConstructor: api.Notification, @@ -100,9 +105,9 @@ * @constructs wp.customize.Notifications * @augments wp.customize.Values * - * @param {Object} options - Options. - * @param {jQuery} [options.container] - Container element for notifications. This can be injected later. - * @param {boolean} [options.alt] - Whether alternative style should be used when rendering notifications. + * @param {Object} options Options. + * @param {jQuery} [options.container] Container element for notifications. This can be injected later. + * @param {boolean} [options.alt] Whether alternative style should be used when rendering notifications. * * @return {void} */ @@ -141,8 +146,8 @@ * * @since 4.9.0 * - * @param {string|wp.customize.Notification} notification - Notification object to add. Alternatively code may be supplied, and in that case the second notificationObject argument must be supplied. - * @param {wp.customize.Notification} [notificationObject] - Notification to add when first argument is the code string. + * @param {string|wp.customize.Notification} notification Notification object to add. Alternatively code may be supplied, and in that case the second notificationObject argument must be supplied. + * @param {wp.customize.Notification} [notificationObject] Notification to add when first argument is the code string. * @return {wp.customize.Notification} Added notification (or existing instance if it was already added). */ add: function( notification, notificationObject ) { @@ -165,8 +170,8 @@ * Add notification to the collection. * * @since 4.9.0 - * @param {string} code - Notification code to remove. - * @return {api.Notification} Added instance (or existing instance if it was already added). + * @param {string} code Notification code to remove. + * @return {wp.customize.Notification} Added instance (or existing instance if it was already added). */ remove: function( code ) { var collection = this; @@ -180,9 +185,9 @@ * Notifications may be sorted by type followed by added time. * * @since 4.9.0 - * @param {Object} args - Args. - * @param {boolean} [args.sort=false] - Whether to return the notifications sorted. - * @return {Array.} Notifications. + * @param {Object} args Args. + * @param {boolean} [args.sort=false] Whether to return the notifications sorted. + * @return {wp.customize.Notification[]} Notifications. */ get: function( args ) { var collection = this, notifications, errorTypePriorities, params; @@ -309,7 +314,7 @@ * * @since 4.9.0 * - * @param {jQuery.Event} event - Event. + * @param {JQuery.Event} event Event. * @return {void} */ constrainFocus: function constrainFocus( event ) { @@ -346,7 +351,7 @@ * Default params. * * @since 4.9.0 - * @var {object} + * @member {Object} */ defaults: { transport: 'refresh', @@ -366,12 +371,12 @@ * * @since 3.4.0 * - * @param {string} id - The setting ID. - * @param {*} value - The initial value of the setting. - * @param {Object} [options={}] - Options. - * @param {string} [options.transport=refresh] - The transport to use for previewing. Supports 'refresh' and 'postMessage'. - * @param {boolean} [options.dirty=false] - Whether the setting should be considered initially dirty. - * @param {Object} [options.previewer] - The Previewer instance to sync with. Defaults to wp.customize.previewer. + * @param {string} id The setting ID. + * @param {*} value The initial value of the setting. + * @param {Object} [options={}] Options. + * @param {string} [options.transport=refresh] The transport to use for previewing. Supports 'refresh' and 'postMessage'. + * @param {boolean} [options.dirty=false] Whether the setting should be considered initially dirty. + * @param {Object} [options.previewer] The Previewer instance to sync with. Defaults to wp.customize.previewer. */ initialize: function( id, value, options ) { var setting = this, params; @@ -468,7 +473,7 @@ * @alias wp.customize._latestSettingRevisions * * @since 4.7.0 - * @type {object} + * @type {Object} * @protected */ api._latestSettingRevisions = {}; @@ -534,14 +539,14 @@ * @since 4.7.0 * @access public * - * @param {Object} [changes] - Mapping of setting IDs to setting params each normally including a value property, or mapping to null. - * If not provided, then the changes will still be obtained from unsaved dirty settings. - * @param {Object} [args] - Additional options for the save request. - * @param {boolean} [args.autosave=false] - Whether changes will be stored in autosave revision if the changeset has been promoted from an auto-draft. - * @param {boolean} [args.force=false] - Send request to update even when there are no changes to submit. This can be used to request the latest status of the changeset on the server. - * @param {string} [args.title] - Title to update in the changeset. Optional. - * @param {string} [args.date] - Date to update in the changeset. Optional. - * @return {jQuery.Promise} Promise resolving with the response data. + * @param {Object} [changes] Mapping of setting IDs to setting params each normally including a value property, or mapping to null. + * If not provided, then the changes will still be obtained from unsaved dirty settings. + * @param {Object} [args] Additional options for the save request. + * @param {boolean} [args.autosave=false] Whether changes will be stored in autosave revision if the changeset has been promoted from an auto-draft. + * @param {boolean} [args.force=false] Send request to update even when there are no changes to submit. This can be used to request the latest status of the changeset on the server. + * @param {string} [args.title] Title to update in the changeset. Optional. + * @param {string} [args.date] Date to update in the changeset. Optional. + * @return {JQuery.Promise<*>} Promise resolving with the response data. */ api.requestChangesetUpdate = function requestChangesetUpdate( changes, args ) { var deferred, request, submittedChanges = {}, data, submittedArgs; @@ -672,7 +677,7 @@ * @since 4.1.0 * * @param {wp.customize.Class} instance - * @param {Array} properties The names of the Value instances to watch. + * @param {string[]} properties The names of the Value instances to watch. */ api.utils.bubbleChildValueChanges = function ( instance, properties ) { $.each( properties, function ( i, key ) { @@ -754,7 +759,7 @@ * * @param {(wp.customize.Panel|wp.customize.Section|wp.customize.Control)} a * @param {(wp.customize.Panel|wp.customize.Section|wp.customize.Control)} b - * @return {number} + * @return {number} A negative number if a has lower priority than b, a positive number if a has higher priority than b, or zero if they have the same priority. */ api.utils.prioritySort = function ( a, b ) { if ( a.priority() === b.priority() && typeof a.params.instanceNumber === 'number' && typeof b.params.instanceNumber === 'number' ) { @@ -771,8 +776,8 @@ * * @since 4.1.0 * - * @param {jQuery.Event} event - * @return {boolean} + * @param {JQuery.Event} event Event object. + * @return {boolean} True if the event is a keydown event but not the Enter key, false otherwise. */ api.utils.isKeydownButNotEnterEvent = function ( event ) { return ( 'keydown' === event.type && 13 !== event.which ); @@ -785,9 +790,9 @@ * * @since 4.1.0 * - * @param {Array|jQuery} listA - * @param {Array|jQuery} listB - * @return {boolean} + * @param {jQuery[]|jQuery} listA First list of elements. + * @param {jQuery[]|jQuery} listB Second list of elements. + * @return {boolean} True if the two lists are equal, false otherwise. */ api.utils.areElementListsEqual = function ( listA, listB ) { var equal = ( @@ -813,14 +818,14 @@ * * @since 4.9.0 * - * @param {jQuery} button - The element to highlight. - * @param {Object} [options] - Options. - * @param {number} [options.delay=0] - Delay in milliseconds. - * @param {jQuery} [options.focusTarget] - A target for user focus that defaults to the highlighted element. - * If the user focuses the target before the delay passes, the reminder - * is canceled. This option exists to accommodate compound buttons - * containing auxiliary UI, such as the Publish button augmented with a - * Settings button. + * @param {jQuery} button The element to highlight. + * @param {Object} [options] Options. + * @param {number} [options.delay=0] Delay in milliseconds. + * @param {jQuery} [options.focusTarget] A target for user focus that defaults to the highlighted element. + * If the user focuses the target before the delay passes, the reminder + * is canceled. This option exists to accommodate compound buttons + * containing auxiliary UI, such as the Publish button augmented with a + * Settings button. * @return {Function} An idempotent function that cancels the reminder. */ api.utils.highlightButton = function highlightButton( button, options ) { @@ -887,8 +892,8 @@ * * @since 4.9.0 * - * @param {string|number|Date} datetime - Date time or timestamp of the future date. - * @return {number} remainingTime - Remaining time in milliseconds. + * @param {string|number|Date} datetime Date time or timestamp of the future date. + * @return {number} Remaining time in milliseconds. */ api.utils.getRemainingTime = function getRemainingTime( datetime ) { var millisecondsDivider = 1000, remainingTime, timestamp; @@ -957,16 +962,16 @@ * * @borrows wp.customize~focus as focus * - * @param {string} id - The ID for the container. - * @param {Object} options - Object containing one property: params. - * @param {string} options.title - Title shown when panel is collapsed and expanded. - * @param {string} [options.description] - Description shown at the top of the panel. - * @param {number} [options.priority=100] - The sort priority for the panel. - * @param {string} [options.templateId] - Template selector for container. - * @param {string} [options.type=default] - The type of the panel. See wp.customize.panelConstructor. - * @param {string} [options.content] - The markup to be used for the panel container. If empty, a JS template is used. - * @param {boolean} [options.active=true] - Whether the panel is active or not. - * @param {Object} [options.params] - Deprecated wrapper for the above properties. + * @param {string} id The ID for the container. + * @param {Object} options Object containing one property: params. + * @param {string} options.title Title shown when panel is collapsed and expanded. + * @param {string} [options.description] Description shown at the top of the panel. + * @param {number} [options.priority=100] The sort priority for the panel. + * @param {string} [options.templateId] Template selector for container. + * @param {string} [options.type=default] The type of the panel. See wp.customize.panelConstructor. + * @param {string} [options.content] The markup to be used for the panel container. If empty, a JS template is used. + * @param {boolean} [options.active=true] Whether the panel is active or not. + * @param {Object} [options.params] Deprecated wrapper for the above properties. */ initialize: function ( id, options ) { var container = this; @@ -1075,7 +1080,7 @@ * * @param {string} parentType * @param {string} childType - * @return {Array} + * @return {wp.customize.Class[]} Array of child models sorted by priority. */ _children: function ( parentType, childType ) { var parent = this, @@ -1109,11 +1114,11 @@ * * @since 4.1.0 * - * @param {boolean} active - The active state to transiution to. - * @param {Object} [args] - Args. - * @param {Object} [args.duration] - The duration for the slideUp/slideDown animation. - * @param {boolean} [args.unchanged] - Whether the state is already known to not be changed, and so short-circuit with calling completeCallback early. - * @param {Function} [args.completeCallback] - Function to call when the slideUp/slideDown has completed. + * @param {boolean} active The active state to transiution to. + * @param {Object} [args] Args. + * @param {Object} [args.duration] The duration for the slideUp/slideDown animation. + * @param {boolean} [args.unchanged] Whether the state is already known to not be changed, and so short-circuit with calling completeCallback early. + * @param {Function} [args.completeCallback] Function to call when the slideUp/slideDown has completed. */ onChangeActive: function( active, args ) { var construct = this, @@ -1172,8 +1177,8 @@ /** * @since 4.1.0 * - * @param {boolean} active - * @param {Object} [params] + * @param {boolean} active The active state to transition to. + * @param {Object} [params] Params. * @return {boolean} False if state already applied. */ _toggleActive: function ( active, params ) { @@ -1192,7 +1197,9 @@ }, /** - * @param {Object} [params] + * Activate the control. + * + * @param {Object} [params] Params. * @return {boolean} False if already active. */ activate: function ( params ) { @@ -1200,7 +1207,9 @@ }, /** - * @param {Object} [params] + * Deactivate the control. + * + * @param {Object} [params] Params. * @return {boolean} False if already inactive. */ deactivate: function ( params ) { @@ -1218,9 +1227,9 @@ /** * Handle the toggle logic for expand/collapse. * - * @param {boolean} expanded - The new state to apply. - * @param {Object} [params] - Object containing options for expand/collapse. - * @param {Function} [params.completeCallback] - Function to call when expansion/collapse is complete. + * @param {boolean} expanded The new state to apply. + * @param {Object} [params] Object containing options for expand/collapse. + * @param {Function} [params.completeCallback] Function to call when expansion/collapse is complete. * @return {boolean} False if state already applied or active state is false. */ _toggleExpanded: function( expanded, params ) { @@ -1234,9 +1243,9 @@ } api.state( 'paneVisible' ).set( true ); - params.completeCallback = function() { + params.completeCallback = function( ...args ) { if ( previousCompleteCallback ) { - previousCompleteCallback.apply( instance, arguments ); + previousCompleteCallback.apply( instance, args ); } if ( expanded ) { instance.container.trigger( 'expanded' ); @@ -1257,7 +1266,9 @@ }, /** - * @param {Object} [params] + * Expand the container. + * + * @param {Object} [params] Object containing options for expansion. * @return {boolean} False if already expanded or if inactive. */ expand: function ( params ) { @@ -1265,7 +1276,9 @@ }, /** - * @param {Object} [params] + * Collapse the container. + * + * @param {Object} [params] Object containing options for collapse. * @return {boolean} False if already collapsed. */ collapse: function ( params ) { @@ -1278,7 +1291,7 @@ * @since 4.7.0 * @private * - * @param {function} completeCallback Function to be called after transition is completed. + * @param {Function} completeCallback Function to be called after transition is completed. * @return {void} */ _animateChangeExpanded: function( completeCallback ) { @@ -1352,6 +1365,7 @@ * Return the container html, generated from its JS template, if it exists. * * @since 4.3.0 + * @return {string} Container html. */ getContainer: function () { var template, @@ -1429,17 +1443,17 @@ * * @since 4.1.0 * - * @param {string} id - The ID for the section. - * @param {Object} options - Options. - * @param {string} options.title - Title shown when section is collapsed and expanded. - * @param {string} [options.description] - Description shown at the top of the section. - * @param {number} [options.priority=100] - The sort priority for the section. - * @param {string} [options.type=default] - The type of the section. See wp.customize.sectionConstructor. - * @param {string} [options.content] - The markup to be used for the section container. If empty, a JS template is used. - * @param {boolean} [options.active=true] - Whether the section is active or not. - * @param {string} options.panel - The ID for the panel this section is associated with. - * @param {string} [options.customizeAction] - Additional context information shown before the section title when expanded. - * @param {Object} [options.params] - Deprecated wrapper for the above properties. + * @param {string} id The ID for the section. + * @param {Object} options Options. + * @param {string} options.title Title shown when section is collapsed and expanded. + * @param {string} [options.description] Description shown at the top of the section. + * @param {number} [options.priority=100] The sort priority for the section. + * @param {string} [options.type=default] The type of the section. See wp.customize.sectionConstructor. + * @param {string} [options.content] The markup to be used for the section container. If empty, a JS template is used. + * @param {boolean} [options.active=true] Whether the section is active or not. + * @param {string} options.panel The ID for the panel this section is associated with. + * @param {string} [options.customizeAction] Additional context information shown before the section title when expanded. + * @param {Object} [options.params] Deprecated wrapper for the above properties. */ initialize: function ( id, options ) { var section = this, params; @@ -1566,7 +1580,7 @@ * * @since 4.1.0 * - * @return {boolean} + * @return {boolean} True if the section has any active controls, false otherwise. */ isContextuallyActive: function () { var section = this, @@ -1585,7 +1599,7 @@ * * @since 4.1.0 * - * @return {Array} + * @return {wp.customize.Control[]} Array of control models sorted by priority. */ controls: function () { return this._children( 'section', 'control' ); @@ -1596,8 +1610,8 @@ * * @since 4.1.0 * - * @param {boolean} expanded - * @param {Object} args + * @param {boolean} expanded The expanded state to transition to. + * @param {Object} args Object containing options for expand/collapse. */ onChangeExpanded: function ( expanded, args ) { var section = this, @@ -1714,8 +1728,8 @@ * * @since 4.9.0 * - * @param {string} id - ID. - * @param {Object} options - Options. + * @param {string} id ID. + * @param {Object} options Options. * @return {void} */ initialize: function( id, options ) { @@ -1831,7 +1845,7 @@ * * @since 4.2.0 * - * @return {boolean} + * @return {boolean} True if the section is active, false otherwise. */ isContextuallyActive: function () { return this.active(); @@ -1983,10 +1997,10 @@ * * @since 4.2.0 * - * @param {boolean} expanded - * @param {Object} args - * @param {boolean} args.unchanged - * @param {Function} args.completeCallback + * @param {boolean} expanded The expanded state to transition to. + * @param {Object} args Object containing options for expand/collapse. + * @param {boolean} args.unchanged Whether the expanded state is unchanged. + * @param {Function} args.completeCallback Callback to be executed once the expand/collapse action is complete. * @return {void} */ onChangeExpanded: function ( expanded, args ) { @@ -2077,7 +2091,7 @@ * * @since 4.9.0 * - * @return {jQuery} + * @return {jQuery} The section's content element. */ getContent: function() { return this.container.find( '.control-section-content' ); @@ -2198,8 +2212,8 @@ * Loads controls into the section from data received from loadThemes(). * * @since 4.9.0 - * @param {Array} themes - Array of theme data to create controls with. - * @param {number} page - Page of results being loaded. + * @param {Object[]} themes Array of theme data to create controls with. + * @param {number} page Page of results being loaded. * @return {void} */ loadControls: function( themes, page ) { @@ -2252,7 +2266,7 @@ * * @since 4.9.0 * - * @param {string} term - The raw search input value. + * @param {string} term The raw search input value. * @return {void} */ filterSearch: function( term ) { @@ -2296,7 +2310,7 @@ * * @since 4.9.0 * - * @param {wp.customize.ThemesSection} section - The current theme section, passed through the debouncer. + * @param {wp.customize.ThemesSection} section The current theme section, passed through the debouncer. * @return {void} */ checkTerm: function( section ) { @@ -2355,8 +2369,8 @@ * * @since 4.9.0 * - * @param {string} newTerm - New term. - * @param {Array} newTags - New tags. + * @param {string} newTerm New term. + * @param {string[]} newTags New tags. * @return {void} */ initializeNewQuery: function( newTerm, newTags ) { @@ -2455,6 +2469,7 @@ * * @since 4.9.0 * + * @param {number} [count] The number of themes. Defaults to the number of visible theme controls. * @return {void} */ updateCount: function( count ) { @@ -2580,7 +2595,7 @@ * * @deprecated * @param {string} themeId Theme ID. - * @return {jQuery.promise} Promise. + * @return {JQuery.Promise<*>} Promise. */ loadThemePreview: function( themeId ) { return api.ThemesPanel.prototype.loadThemePreview.call( this, themeId ); @@ -2591,8 +2606,8 @@ * * @since 4.2.0 * - * @param {Object} theme - Theme. - * @param {Function} [callback] - Callback once the details have been shown. + * @param {Object} theme Theme. + * @param {Function} [callback] Callback once the details have been shown. * @return {void} */ showDetails: function ( theme, callback ) { @@ -2645,7 +2660,7 @@ * * @since 4.2.0 * - * @param {jQuery} el - Element to contain focus. + * @param {jQuery} el Element to contain focus. * @return {void} */ containFocus: function( el ) { @@ -2687,13 +2702,15 @@ * * @since 4.9.0 * + * @param {string} id The ID for the section. + * @param {Object} options Options, as accepted by wp.customize.Section. * @return {void} */ - initialize: function() { + initialize: function( id, options ) { var section = this; section.containerParent = '#customize-outer-theme-controls'; section.containerPaneParent = '.customize-outer-pane-parent'; - api.Section.prototype.initialize.apply( section, arguments ); + api.Section.prototype.initialize.call( section, id, options ); }, /** @@ -2702,11 +2719,11 @@ * * @since 4.9.0 * - * @param {boolean} expanded - The expanded state to transition to. - * @param {Object} [args] - Args. - * @param {boolean} [args.unchanged] - Whether the state is already known to not be changed, and so short-circuit with calling completeCallback early. - * @param {Function} [args.completeCallback] - Function to call when the slideUp/slideDown has completed. - * @param {Object} [args.duration] - The duration for the animation. + * @param {boolean} expanded The expanded state to transition to. + * @param {Object} [args] Args. + * @param {boolean} [args.unchanged] Whether the state is already known to not be changed, and so short-circuit with calling completeCallback early. + * @param {Function} [args.completeCallback] Function to call when the slideUp/slideDown has completed. + * @param {Object} [args.duration] The duration for the animation. */ onChangeExpanded: function( expanded, args ) { var section = this, @@ -2792,15 +2809,15 @@ * * @since 4.1.0 * - * @param {string} id - The ID for the panel. - * @param {Object} options - Object containing one property: params. - * @param {string} options.title - Title shown when panel is collapsed and expanded. - * @param {string} [options.description] - Description shown at the top of the panel. - * @param {number} [options.priority=100] - The sort priority for the panel. - * @param {string} [options.type=default] - The type of the panel. See wp.customize.panelConstructor. - * @param {string} [options.content] - The markup to be used for the panel container. If empty, a JS template is used. - * @param {boolean} [options.active=true] - Whether the panel is active or not. - * @param {Object} [options.params] - Deprecated wrapper for the above properties. + * @param {string} id The ID for the panel. + * @param {Object} options Object containing one property: params. + * @param {string} options.title Title shown when panel is collapsed and expanded. + * @param {string} [options.description] Description shown at the top of the panel. + * @param {number} [options.priority=100] The sort priority for the panel. + * @param {string} [options.type=default] The type of the panel. See wp.customize.panelConstructor. + * @param {string} [options.content] The markup to be used for the panel container. If empty, a JS template is used. + * @param {boolean} [options.active=true] Whether the panel is active or not. + * @param {Object} [options.params] Deprecated wrapper for the above properties. */ initialize: function ( id, options ) { var panel = this, params; @@ -2906,7 +2923,7 @@ * * @since 4.1.0 * - * @return {Array} + * @return {wp.customize.Section[]} Array of sections. */ sections: function () { return this._children( 'panel', 'section' ); @@ -3050,7 +3067,7 @@ } }); - api.ThemesPanel = api.Panel.extend(/** @lends wp.customize.ThemsPanel.prototype */{ + api.ThemesPanel = api.Panel.extend(/** @lends wp.customize.ThemesPanel.prototype */{ /** * Class wp.customize.ThemesPanel. @@ -3062,8 +3079,8 @@ * * @since 4.9.0 * - * @param {string} id - The ID for the panel. - * @param {Object} options - Options. + * @param {string} id The ID for the panel. + * @param {Object} options Options. * @return {void} */ initialize: function( id, options ) { @@ -3077,7 +3094,7 @@ * * @since 4.9.0 * - * @param {string} [slug] - Theme slug. + * @param {string} [slug] Theme slug. When omitted, whether switching is possible at all. * @return {boolean} Whether the theme can be switched to. */ canSwitchTheme: function canSwitchTheme( slug ) { @@ -3160,10 +3177,10 @@ * * @since 4.9.0 * - * @param {boolean} expanded - Expanded state. - * @param {Object} args - Args. - * @param {boolean} args.unchanged - Whether or not the state changed. - * @param {Function} args.completeCallback - Callback to execute when the animation completes. + * @param {boolean} expanded Expanded state. + * @param {Object} args Args. + * @param {boolean} args.unchanged Whether or not the state changed. + * @param {Function} args.completeCallback Callback to execute when the animation completes. * @return {void} */ onChangeExpanded: function( expanded, args ) { @@ -3215,8 +3232,8 @@ * * @since 4.9.0 * - * @param {jQuery.Event} event - Event. - * @return {jQuery.promise} Promise. + * @param {JQuery.Event} event Event. + * @return {JQuery.Promise<*>} Promise. */ installTheme: function( event ) { var panel = this, preview, onInstallSuccess, slug = $( event.target ).data( 'slug' ), deferred = $.Deferred(), request; @@ -3321,7 +3338,7 @@ * @since 4.9.0 * * @param {string} themeId Theme ID. - * @return {jQuery.promise} Promise. + * @return {JQuery.Promise<*>} Promise. */ loadThemePreview: function( themeId ) { var panel = this, deferred = $.Deferred(), onceProcessingComplete, urlParser, queryParams; @@ -3396,7 +3413,7 @@ * * @since 4.9.0 * - * @param {jQuery.Event} event - Event. + * @param {JQuery.Event} event Event. * @return {void} */ updateTheme: function( event ) { @@ -3426,7 +3443,7 @@ * * @since 4.9.0 * - * @param {jQuery.Event} event - Event. + * @param {JQuery.Event} event Event. * @return {void} */ deleteTheme: function( event ) { @@ -3484,7 +3501,7 @@ * Default params. * * @since 4.9.0 - * @var {object} + * @member {Object} */ defaults: { label: '', @@ -3508,22 +3525,22 @@ * @borrows wp.customize~Container#deactivate as this#deactivate * @borrows wp.customize~Container#_toggleActive as this#_toggleActive * - * @param {string} id - Unique identifier for the control instance. - * @param {Object} options - Options hash for the control instance. - * @param {Object} options.type - Type of control (e.g. text, radio, dropdown-pages, etc.) - * @param {string} [options.content] - The HTML content for the control or at least its container. This should normally be left blank and instead supplying a templateId. - * @param {string} [options.templateId] - Template ID for control's content. - * @param {string} [options.priority=10] - Order of priority to show the control within the section. - * @param {string} [options.active=true] - Whether the control is active. - * @param {string} options.section - The ID of the section the control belongs to. - * @param {mixed} [options.setting] - The ID of the main setting or an instance of this setting. - * @param {mixed} options.settings - An object with keys (e.g. default) that maps to setting IDs or Setting/Value objects, or an array of setting IDs or Setting/Value objects. - * @param {mixed} options.settings.default - The ID of the setting the control relates to. - * @param {string} options.settings.data - @todo Is this used? - * @param {string} options.label - Label. - * @param {string} options.description - Description. - * @param {number} [options.instanceNumber] - Order in which this instance was created in relation to other instances. - * @param {Object} [options.params] - Deprecated wrapper for the above properties. + * @param {string} id Unique identifier for the control instance. + * @param {Object} options Options hash for the control instance. + * @param {Object} options.type Type of control (e.g. text, radio, dropdown-pages, etc.) + * @param {string} [options.content] The HTML content for the control or at least its container. This should normally be left blank and instead supplying a templateId. + * @param {string} [options.templateId] Template ID for control's content. + * @param {string} [options.priority=10] Order of priority to show the control within the section. + * @param {string} [options.active=true] Whether the control is active. + * @param {string} options.section The ID of the section the control belongs to. + * @param {*} [options.setting] The ID of the main setting or an instance of this setting. + * @param {*} options.settings An object with keys (e.g. default) that maps to setting IDs or Setting/Value objects, or an array of setting IDs or Setting/Value objects. + * @param {*} options.settings.default The ID of the setting the control relates to. + * @param {string} options.settings.data @todo Is this used? + * @param {string} options.label Label. + * @param {string} options.description Description. + * @param {number} [options.instanceNumber] Order in which this instance was created in relation to other instances. + * @param {Object} [options.params] Deprecated wrapper for the above properties. * @return {void} */ initialize: function( id, options ) { @@ -3909,7 +3926,7 @@ /** * Normal controls do not expand, so just expand its parent * - * @param {Object} [params] + * @param {Object} [params] Parameters to pass to the section's expand method. */ expand: function ( params ) { api.section( this.section() ).expand( params ); @@ -3954,7 +3971,11 @@ }, /** + * Toggle the control's active state. + * + * @param {boolean} active The active state to toggle. * @deprecated 4.1.0 Use this.onChangeActive() instead. + * @return {void} */ toggle: function ( active ) { return this.onChangeActive( active, this.defaultActiveArguments ); @@ -4263,7 +4284,7 @@ * and it is the responsibility of the UploadControl to set the control's * attachmentData before calling the renderContent method. * - * @param {number|string} value Attachment + * @param {number|string} value Attachment. */ function setAttachmentDataAndRenderContent( value ) { var hasAttachmentData = $.Deferred(); @@ -4313,6 +4334,8 @@ /** * Open the media modal. + * + * @param {Object} event jQuery Event object */ openFrame: function( event ) { if ( api.utils.isKeydownButNotEnterEvent( event ) ) { @@ -4376,6 +4399,8 @@ /** * Reset the setting to the default value. + * + * @param {Object} event jQuery Event object. */ restoreDefault: function( event ) { if ( api.utils.isKeydownButNotEnterEvent( event ) ) { @@ -4390,7 +4415,7 @@ /** * Called when the "Remove" link is clicked. Empties the setting. * - * @param {Object} event jQuery Event object + * @param {Object} event jQuery Event object. */ removeFile: function( event ) { if ( api.utils.isKeydownButNotEnterEvent( event ) ) { @@ -4470,7 +4495,7 @@ * set up internal event bindings. */ ready: function() { - api.UploadControl.prototype.ready.apply( this, arguments ); + api.UploadControl.prototype.ready.call( this ); }, /** @@ -4478,7 +4503,7 @@ * Does an additional Ajax request for setting the background context. */ select: function() { - api.UploadControl.prototype.select.apply( this, arguments ); + api.UploadControl.prototype.select.call( this ); wp.ajax.post( 'custom-background-add', { nonce: _wpCustomizeBackground.nonces.add, @@ -4539,6 +4564,8 @@ /** * Open the media modal to the library state. + * + * @param {Object} event jQuery Event object. */ openFrame: function( event ) { if ( api.utils.isKeydownButNotEnterEvent( event ) ) { @@ -4611,8 +4638,8 @@ * control-specific data, to be fed to the imgAreaSelect plugin in * wp.media.view.Cropper. * - * @param {wp.media.model.Attachment} attachment - * @param {wp.media.controller.Cropper} controller + * @param {wp.media.model.Attachment} attachment The attachment to be cropped. + * @param {wp.media.controller.Cropper} controller The cropper controller. * @return {Object} Options */ calculateImageSelectOptions: function( attachment, controller ) { @@ -4874,7 +4901,7 @@ /** * Called when the "Remove" link is clicked. Empties the setting. * - * @param {Object} event jQuery Event object + * @param {Object} event jQuery Event object. */ removeFile: function( event ) { if ( api.utils.isKeydownButNotEnterEvent( event ) ) { @@ -4967,8 +4994,8 @@ * theme-specific data, to be fed to the imgAreaSelect plugin in * wp.media.view.Cropper. * - * @param {wp.media.model.Attachment} attachment - * @param {wp.media.controller.Cropper} controller + * @param {wp.media.model.Attachment} attachment The attachment to be cropped. + * @param {wp.media.controller.Cropper} controller The cropper controller. * @return {Object} Options */ calculateImageSelectOptions: function(attachment, controller) { @@ -5038,7 +5065,7 @@ * current theme, a cropping step after selection may be required or * skippable. * - * @param {event} event + * @param {JQuery.Event} event Event. */ openMedia: function(event) { var l10n = _wpMediaViewsL10n; @@ -5237,7 +5264,7 @@ * Show or hide the theme based on the presence of the term in the title, description, tags, and author. * * @since 4.2.0 - * @param {Array} terms - An array of terms to search for. + * @param {string[]} terms An array of terms to search for. * @return {boolean} Whether a theme control was activated or not. */ filter: function( terms ) { @@ -5288,6 +5315,7 @@ /** * Rerender the theme from its JS template with the installed type. * + * @param {boolean} installed Whether the theme is installed. * @since 4.9.0 * * @return {void} @@ -5319,8 +5347,8 @@ * Initialize. * * @since 4.9.0 - * @param {string} id - Unique identifier for the control instance. - * @param {Object} options - Options hash for the control instance. + * @param {string} id Unique identifier for the control instance. + * @param {Object} options Options hash for the control instance. * @return {void} */ initialize: function( id, options ) { @@ -5437,8 +5465,8 @@ * Make sure editor gets focused when control is focused. * * @since 4.9.0 - * @param {Object} [params] - Focus params. - * @param {Function} [params.completeCallback] - Function to call when expansion is complete. + * @param {Object} [params] Focus params. + * @param {Function} [params.completeCallback] Function to call when expansion is complete. * @return {void} */ focus: function( params ) { @@ -5459,7 +5487,7 @@ * Initialize syntax-highlighting editor. * * @since 4.9.0 - * @param {Object} codeEditorSettings - Code editor settings. + * @param {Object} codeEditorSettings Code editor settings. * @return {void} */ initSyntaxHighlightingEditor: function( codeEditorSettings ) { @@ -5555,7 +5583,7 @@ * Update error notice. * * @since 4.9.0 - * @param {Array} errorAnnotations - Error annotations. + * @param {Object[]} errorAnnotations Error annotations. * @return {void} */ onUpdateErrorNotice: function onUpdateErrorNotice( errorAnnotations ) { @@ -5700,7 +5728,7 @@ * * @since 4.9.0 * - * @param {string} datetime - Date/Time string. Accepts Y-m-d[ H:i[:s]] format. + * @param {string} datetime Date/Time string. Accepts Y-m-d[ H:i[:s]] format. * @return {Object|null} Returns object containing date components or null if parse error. */ parseDateTime: function parseDateTime( datetime ) { @@ -5888,8 +5916,8 @@ * Convert hour in twelve hour format to twenty four hour format. * * @since 4.9.0 - * @param {string} hourInTwelveHourFormat - Hour in twelve hour format. - * @param {string} meridian - Either 'am' or 'pm'. + * @param {string} hourInTwelveHourFormat Hour in twelve hour format. + * @param {string} meridian Either 'am' or 'pm'. * @return {string} Hour in twenty four hour format. */ convertHourToTwentyFourHourFormat: function convertHour( hourInTwelveHourFormat, meridian ) { @@ -5959,7 +5987,7 @@ * * @since 4.9.0 * @param {boolean} notify Add or remove the notification. - * @return {wp.customize.DateTimeControl} + * @return {wp.customize.DateTimeControl} The date control instance. */ toggleFutureDateNotification: function toggleFutureDateNotification( notify ) { var control = this, notificationCode, notification; @@ -6123,9 +6151,9 @@ * @since 3.4.0 * * @type {Function} - * @param {...string} ids - One or more ids for controls to obtain. - * @param {deferredControlsCallback} [callback] - Function called when all supplied controls exist. - * @return {wp.customize.Control|undefined|jQuery.promise} Control instance or undefined (if function called with one id param), + * @param {...string} ids One or more ids for controls to obtain. + * @param {wp.customize.deferredControlsCallback} [callback] Function called when all supplied controls exist. + * @return {wp.customize.Control|undefined|JQuery.Promise<*>} Control instance or undefined (if function called with one id param), * or promise resolving to requested controls. * * @example Loop over all registered controls. @@ -6185,9 +6213,9 @@ * @since 3.4.0 * * @type {Function} - * @param {...string} ids - One or more ids for sections to obtain. - * @param {deferredSectionsCallback} [callback] - Function called when all supplied sections exist. - * @return {wp.customize.Section|undefined|jQuery.promise} Section instance or undefined (if function called with one id param), + * @param {...string} ids One or more ids for sections to obtain. + * @param {wp.customize.deferredSectionsCallback} [callback] Function called when all supplied sections exist. + * @return {wp.customize.Section|undefined|JQuery.Promise<*>} Section instance or undefined (if function called with one id param), * or promise resolving to requested sections. * * @example Loop over all registered sections. @@ -6220,9 +6248,9 @@ * @since 4.0.0 * * @type {Function} - * @param {...string} ids - One or more ids for panels to obtain. - * @param {deferredPanelsCallback} [callback] - Function called when all supplied panels exist. - * @return {wp.customize.Panel|undefined|jQuery.promise} Panel instance or undefined (if function called with one id param), + * @param {...string} ids One or more ids for panels to obtain. + * @param {wp.customize.deferredPanelsCallback} [callback] Function called when all supplied panels exist. + * @return {wp.customize.Panel|undefined|JQuery.Promise<*>} Panel instance or undefined (if function called with one id param), * or promise resolving to requested panels. * * @example Loop over all registered panels. @@ -6255,9 +6283,9 @@ * @since 4.9.0 * * @type {Function} - * @param {...string} codes - One or more codes for notifications to obtain. - * @param {deferredNotificationsCallback} [callback] - Function called when all supplied notifications exist. - * @return {wp.customize.Notification|undefined|jQuery.promise} Notification instance or undefined (if function called with one code param), + * @param {...string} codes One or more codes for notifications to obtain. + * @param {wp.customize.deferredNotificationsCallback} [callback] Function called when all supplied notifications exist. + * @return {wp.customize.Notification|undefined|JQuery.Promise<*>} Notification instance or undefined (if function called with one code param), * or promise resolving to requested notifications. * * @example Check if existing notification @@ -6293,10 +6321,11 @@ * @constructs wp.customize.PreviewFrame * @augments wp.customize.Messenger * - * @param {Object} params.container - * @param {Object} params.previewUrl - * @param {Object} params.query - * @param {Object} options + * @param {Object} params The parameters object. + * @param {Object} params.container The container element for the preview frame. + * @param {string} params.previewUrl The URL of the preview. + * @param {Object} params.query The query parameters for the preview URL. + * @param {Object} options The options object. */ initialize: function( params, options ) { var deferred = $.Deferred(); @@ -6500,7 +6529,7 @@ * misnomer as it is not an actual UUID, and it is not universally unique. * This is not to be confused with `api.settings.changeset.uuid`. * - * @return {string} + * @return {string} A unique ID for a preview messenger channel. */ api.PreviewFrame.uuid = function() { return 'preview-' + String( id++ ); @@ -6531,12 +6560,13 @@ * @constructs wp.customize.Previewer * @augments wp.customize.Messenger * - * @param {Array} params.allowedUrls - * @param {string} params.container A selector or jQuery element for the preview - * frame to be placed. - * @param {string} params.form - * @param {string} params.previewUrl The URL to preview. - * @param {Object} options + * @param {Object} params The parameters object. + * @param {string[]} params.allowedUrls An array of allowed URLs for the preview. + * @param {string} params.container A selector or jQuery element for the preview + * frame to be placed. + * @param {string} params.form A selector or jQuery element for the form to be used for POSTing data to the preview frame. + * @param {string} params.previewUrl The URL to preview. + * @param {Object} options The options object. */ initialize: function( params, options ) { var previewer = this, @@ -6684,9 +6714,9 @@ * @since 4.7.0 * @access public * - * @param {Object} data - Data from preview. - * @param {string} data.currentUrl - Current URL. - * @param {Object} data.activePanels - Active panels. + * @param {Object} data Data from preview. + * @param {string} data.currentUrl Current URL. + * @param {Object} data.activePanels Active panels. * @param {Object} data.activeSections Active sections. * @param {Object} data.activeControls Active controls. * @return {void} @@ -7068,7 +7098,7 @@ * * @since 4.6.0 * @param {string[]} settingIds Setting IDs. - * @return {Object} Mapping setting ids to arrays of controls. + * @return {Object.} Mapping setting ids to arrays of controls. */ api.findControlsForSettings = function findControlsForSettings( settingIds ) { var controls = {}, settingControls; @@ -7476,7 +7506,7 @@ * @since 4.7.0 Added options param. * @access public * - * @param {Object} [options] Options. + * @param {Object} [options] Options. * @param {boolean} [options.excludeCustomizedSaved=false] Exclude saved settings in customized response (values pending writing to changeset). * @return {Object} Query vars. */ @@ -7514,11 +7544,11 @@ * @since 3.4.0 * @since 4.7.0 Added args param and return value. * - * @param {Object} [args] Args. + * @param {Object} [args] Args. * @param {string} [args.status=publish] Status. - * @param {string} [args.date] Date, in local time in MySQL format. - * @param {string} [args.title] Title - * @return {jQuery.promise} Promise. + * @param {string} [args.date] Date, in local time in MySQL format. + * @param {string} [args.title] Title. + * @return {JQuery.Promise<*>} Promise. */ save: function( args ) { var previewer = this, @@ -7790,8 +7820,6 @@ * Revert the Customizer to its previously-published state. * * @since 4.9.0 - * - * @return {jQuery.promise} Promise. */ trash: function trash() { var request, success, fail; @@ -8183,7 +8211,7 @@ /** * Lock user. * - * @type {object} + * @type {Object} */ lockUser: null, @@ -8195,8 +8223,8 @@ * * @since 4.9.0 * - * @param {string} [code] - Code. - * @param {Object} [params] - Params. + * @param {string} [code] Code. + * @param {Object} [params] Params. */ initialize: function( code, params ) { var notification = this, _code, _params; @@ -8285,9 +8313,9 @@ * * @since 4.9.0 * - * @param {Object} [args] - Args. - * @param {Object} [args.lockUser] - Lock user data. - * @param {boolean} [args.allowOverride=false] - Whether override is allowed. + * @param {Object} [args] Args. + * @param {Object} [args.lockUser] Lock user data. + * @param {boolean} [args.allowOverride=false] Whether override is allowed. * @return {void} */ function startLock( args ) { @@ -8367,7 +8395,7 @@ /** * Remove parameter from the URL. * - * @param {Array} params - Parameter names to remove. + * @param {string[]} params Parameter names to remove. * @return {void} */ function stripParamsFromLocation( params ) { @@ -8393,7 +8421,7 @@ * * @since 4.9.0 * - * @param {string} [notification] - A notification to display. + * @param {string} [notification] A notification to display. * @return {void} */ function addSiteEditorNotification( notification ) { @@ -8750,9 +8778,9 @@ * @since 4.7.0 * @access private * - * @param {Object} header - Header. - * @param {number} scrollTop - Scroll top. - * @param {number} scrollDirection - Scroll direction, negative number being up and positive being down. + * @param {Object} header Header. + * @param {number} scrollTop Scroll top. + * @param {number} scrollDirection Scroll direction, negative number being up and positive being down. * @return {void} */ positionStickyHeader = function( header, scrollTop, scrollDirection ) { diff --git a/src/js/_enqueues/wp/customize/loader.js b/src/js/_enqueues/wp/customize/loader.js index 2326f1f7dfccc..b4aaa12b9ed12 100644 --- a/src/js/_enqueues/wp/customize/loader.js +++ b/src/js/_enqueues/wp/customize/loader.js @@ -12,7 +12,11 @@ */ window.wp = window.wp || {}; -(function( exports, $ ){ +/** + * @param {Object} wp The WordPress global object. + * @param {JQueryStatic} $ The jQuery object. + */ +(function( wp, $ ){ var api = wp.customize, Loader; @@ -76,6 +80,12 @@ window.wp = window.wp || {}; } }, + /** + * Handle popstate event. + * + * @param {JQuery.Event} e The popstate event. + * @return {void} + */ popstate: function( e ) { var state = e.originalEvent.state; if ( state && state.customize ) { @@ -85,6 +95,9 @@ window.wp = window.wp || {}; } }, + /** + * Handle hashchange event. + */ hashchange: function() { var hash = window.location.toString().split('#')[1]; @@ -97,6 +110,11 @@ window.wp = window.wp || {}; } }, + /** + * Handle beforeunload event. + * + * @return {string|void} Confirmation message if there are unsaved changes. + */ beforeunload: function () { if ( ! Loader.saved() ) { return Loader.settings.l10n.saveAlert; @@ -106,7 +124,8 @@ window.wp = window.wp || {}; /** * Open the Customizer overlay for a specific URL. * - * @param string src URL to load in the Customizer. + * @param {string} src URL to load in the Customizer. + * @return {string|void} The URL, when navigating to it directly on mobile. */ open: function( src ) { @@ -189,6 +208,11 @@ window.wp = window.wp || {}; this.trigger( 'open' ); }, + /** + * Push the state of the Customizer onto the history stack. + * + * @param {string} src URL to push. + */ pushState: function ( src ) { var hash = src.split( '?' )[1]; @@ -270,10 +294,16 @@ window.wp = window.wp || {}; * Overlay hide/show utility methods. */ overlay: { + /** + * Show the overlay. + */ show: function() { this.element.fadeIn( 200, Loader.opened ); }, + /** + * Hide the overlay. + */ hide: function() { this.element.fadeOut( 200, Loader.closed ); } diff --git a/src/js/_enqueues/wp/customize/models.js b/src/js/_enqueues/wp/customize/models.js index e72266327a333..731d29fbb9d90 100644 --- a/src/js/_enqueues/wp/customize/models.js +++ b/src/js/_enqueues/wp/customize/models.js @@ -3,6 +3,11 @@ */ /* global _wpCustomizeHeader */ + +/** + * @param {JQueryStatic} $ The jQuery object. + * @param {Object} wp The WordPress global object. + */ (function( $, wp ) { var api = wp.customize; /** @namespace wp.customize.HeaderTool */ @@ -21,10 +26,15 @@ * @memberOf wp.customize.HeaderTool * @alias wp.customize.HeaderTool.ImageModel * - * @constructor + * @class * @augments Backbone.Model */ api.HeaderTool.ImageModel = Backbone.Model.extend(/** @lends wp.customize.HeaderTool.ImageModel.prototype */{ + /** + * Default attributes. + * + * @return {Object} Default attributes. + */ defaults: function() { return { header: { @@ -39,16 +49,25 @@ }; }, + /** + * Initialize. + */ initialize: function() { this.on('hide', this.hide, this); }, + /** + * Hide. + */ hide: function() { this.set('choice', ''); api('header_image').set('remove-header'); api('header_image_data').set('remove-header'); }, + /** + * Destroy. + */ destroy: function() { var data = this.get('header'), curr = api.HeaderTool.currentHeader.get('header').attachment_id; @@ -69,6 +88,9 @@ this.trigger('destroy', this, this.collection); }, + /** + * Save. + */ save: function() { if (this.get('random')) { api('header_image').set(this.get('header').random); @@ -86,6 +108,9 @@ api.HeaderTool.combinedList.trigger('control:setImage', this); }, + /** + * Import image. + */ importImage: function() { var data = this.get('header'); if (data.attachment_id === undefined) { @@ -100,6 +125,11 @@ } ); }, + /** + * Should be cropped. + * + * @return {boolean} Whether the image should be cropped. + */ shouldBeCropped: function() { if (this.get('themeFlexWidth') === true && this.get('themeFlexHeight') === true) { @@ -136,17 +166,25 @@ * @memberOf wp.customize.HeaderTool * @alias wp.customize.HeaderTool.ChoiceList * - * @constructor + * @class * @augments Backbone.Collection */ api.HeaderTool.ChoiceList = Backbone.Collection.extend({ model: api.HeaderTool.ImageModel, - // Ordered from most recently used to least. + /** + * Comparator which orders the collection from most recently used to least. + * + * @param {Backbone.Model} model The model to sort. + * @return {number} The sort order. + */ comparator: function(model) { return -model.get('header').timestamp; }, + /** + * Initialize. + */ initialize: function() { var current = api.HeaderTool.currentHeader.get('choice').replace(/^https?:\/\//, ''), isRandom = this.isRandomChoice(api.get().header_image); @@ -192,6 +230,11 @@ } }, + /** + * Maybe remove old crop. + * + * @param {Backbone.Model} model Model. + */ maybeRemoveOldCrop: function( model ) { var newID = model.get( 'header' ).attachment_id || false, oldCrop; @@ -211,12 +254,20 @@ } }, + /** + * Maybe add random choice. + */ maybeAddRandomChoice: function() { if (this.size() === 1) { this.addRandomChoice(); } }, + /** + * Add random choice. + * + * @param {string} initialChoice Initial choice. + */ addRandomChoice: function(initialChoice) { var isRandomSameType = RegExp(this.type).test(initialChoice), randomChoice = 'random-' + this.type + '-image'; @@ -234,14 +285,30 @@ }); }, + /** + * Is random choice? + * + * @param {string} choice Choice. + * @return {boolean} Whether the choice is random. + */ isRandomChoice: function(choice) { return (/^random-(uploaded|default)-image$/).test(choice); }, + /** + * Should hide title? + * + * @return {boolean} Whether the title should be hidden. + */ shouldHideTitle: function() { return this.size() < 2; }, + /** + * Set image. + * + * @param {Backbone.Model} model Model. + */ setImage: function(model) { this.each(function(m) { m.set('selected', false); @@ -252,6 +319,9 @@ } }, + /** + * Remove image. + */ removeImage: function() { this.each(function(m) { m.set('selected', false); @@ -266,11 +336,14 @@ * @memberOf wp.customize.HeaderTool * @alias wp.customize.HeaderTool.DefaultsList * - * @constructor + * @class * @augments wp.customize.HeaderTool.ChoiceList * @augments Backbone.Collection */ api.HeaderTool.DefaultsList = api.HeaderTool.ChoiceList.extend({ + /** + * Initialize. + */ initialize: function() { this.type = 'default'; this.data = _wpCustomizeHeader.defaults; diff --git a/src/js/_enqueues/wp/customize/nav-menus.js b/src/js/_enqueues/wp/customize/nav-menus.js index 607740014e5e4..5bebe8ea9f07f 100644 --- a/src/js/_enqueues/wp/customize/nav-menus.js +++ b/src/js/_enqueues/wp/customize/nav-menus.js @@ -3,6 +3,12 @@ */ /* global menus, _wpCustomizeNavMenusSettings, wpNavMenu, console */ + +/** + * @param {Object} api The Customizer API. + * @param {Object} wp The WordPress global object. + * @param {JQueryStatic} $ The jQuery object. + */ ( function( api, wp, $ ) { 'use strict'; @@ -44,7 +50,7 @@ * * @alias wp.customize.Menus.generatePlaceholderAutoIncrementId * - * @return {number} + * @return {number} A negative integer ID. */ api.Menus.generatePlaceholderAutoIncrementId = function() { return -Math.ceil( api.Menus.data.phpIntMax * Math.random() ); @@ -95,10 +101,10 @@ * @since 4.7.0 * @alias wp.customize.Menus.insertAutoDraftPost * - * @param {Object} params - Parameters for the draft post to create. - * @param {string} params.post_type - Post type to add. - * @param {string} params.post_title - Post title to use. - * @return {jQuery.promise} Promise resolved with the added post. + * @param {Object} params Parameters for the draft post to create. + * @param {string} params.post_type Post type to add. + * @param {string} params.post_title Post title to use. + * @return {JQuery.Promise<*>} Promise resolved with the added post. */ api.Menus.insertAutoDraftPost = function insertAutoDraftPost( params ) { var request, deferred = $.Deferred(); @@ -390,7 +396,7 @@ * @since 4.7.0 Changed function signature to take list of item types instead of single type/object. * @access private * - * @param {Array.} itemTypes List of objects containing type and key. + * @param {Object[]} itemTypes List of objects containing type and key. * @param {string} deprecated Formerly the object parameter. * @return {void} */ @@ -630,7 +636,7 @@ * @since 4.7.0 * @private * - * @param {jQuery.Event} event Event. + * @param {JQuery.Event} event Event. * @return {void} */ _submitNew: function( event ) { @@ -919,7 +925,7 @@ * @since 4.3.0 * @private * - * @return {Array} Fields (columns) that are hidden. + * @return {string} Comma separated list of the fields (columns) that are hidden. */ hidden: function() { return $( '.hide-column-tog' ).not( ':checked' ).map( function() { @@ -1141,7 +1147,7 @@ }, /** - * @param {Array} themeLocationSlugs Theme location slugs. + * @param {string[]} themeLocationSlugs Theme location slugs. */ updateAssignedLocationsInSectionTitle: function( themeLocationSlugs ) { var section = this, @@ -1334,7 +1340,7 @@ * Handle setting addition. * * @since 4.9.0 - * @param {wp.customize.Setting} setting - Added setting. + * @param {wp.customize.Setting} setting Added setting. * @return {void} */ function addChangeEventListener( setting ) { @@ -1348,7 +1354,7 @@ * Handle setting removal. * * @since 4.9.0 - * @param {wp.customize.Setting} setting - Removed setting. + * @param {wp.customize.Setting} setting Removed setting. * @return {void} */ function removeChangeEventListener( setting ) { @@ -1363,7 +1369,7 @@ api.bind( 'removed', removeChangeEventListener ); updateNoticeVisibility(); - api.Section.prototype.attachEvents.apply( section, arguments ); + api.Section.prototype.attachEvents.call( section ); }, /** @@ -1483,7 +1489,7 @@ * * @since 4.9.0 * - * @param {string|null} locationId - The ID of the location to select. `null` clears all selections. + * @param {string|null} locationId The ID of the location to select. `null` clears all selections. * @return {void} */ selectDefaultLocation: function( locationId ) { @@ -1643,7 +1649,7 @@ * Shows or hides buttons based on the location of the menu item. * * @param {Object} itemToRefresh The menu item that might need its advanced accessibility buttons refreshed - * + * * @since 6.6.0 */ refreshAdvancedAccessibilityOfItem: function( itemToRefresh ) { @@ -1723,7 +1729,7 @@ } control.renderContent(); control.deferred.embedded.resolve(); // This triggers control.ready(). - + // Mark all menu items as unprocessed. $( 'button.item-edit' ).data( 'needs_accessibility_refresh', true ); }, @@ -1802,7 +1808,7 @@ control.moveRight(); control.params.depth += 1; } - + moveBtn.focus(); // Re-focus after the container was moved. // Mark all menu items as unprocessed. @@ -2036,8 +2042,9 @@ }, /** + * Gets the depth of the menu item. * - * @return {number} + * @return {number} The depth of the menu item. */ getDepth: function() { var control = this, setting = control.setting(), depth = 0; @@ -2103,7 +2110,9 @@ **********************************************************************/ /** - * @return {wp.customize.controlConstructor.nav_menu|null} + * Gets the menu control that this menu item belongs to. + * + * @return {wp.customize.Menus.MenuControl|null} The menu control, or null if not found. */ getMenuControl: function() { var control = this, settingValue = control.setting(); @@ -2127,9 +2136,9 @@ /** * @since 4.6.0 * - * @param {Boolean} expanded + * @param {boolean} expanded * @param {Object} [params] - * @return {Boolean} False if state already applied. + * @return {boolean} False if state already applied. */ _toggleExpanded: api.Section.prototype._toggleExpanded, @@ -2137,7 +2146,7 @@ * @since 4.6.0 * * @param {Object} [params] - * @return {Boolean} False if already expanded. + * @return {boolean} False if already expanded. */ expand: api.Section.prototype.expand, @@ -2146,8 +2155,8 @@ * * @since 4.5.0 Added params.completeCallback. * - * @param {Object} [params] - Optional params. - * @param {Function} [params.completeCallback] - Function to call when the form toggle has finished animating. + * @param {Object} [params] Optional params. + * @param {Function} [params.completeCallback] Function to call when the form toggle has finished animating. */ expandForm: function( params ) { this.expand( params ); @@ -2157,7 +2166,7 @@ * @since 4.6.0 * * @param {Object} [params] - * @return {Boolean} False if already collapsed. + * @return {boolean} False if already collapsed. */ collapse: api.Section.prototype.collapse, @@ -2166,8 +2175,8 @@ * * @since 4.5.0 Added params.completeCallback. * - * @param {Object} [params] - Optional params. - * @param {Function} [params.completeCallback] - Function to call when the form toggle has finished animating. + * @param {Object} [params] Optional params. + * @param {Function} [params.completeCallback] Function to call when the form toggle has finished animating. */ collapseForm: function( params ) { this.collapse( params ); @@ -2179,9 +2188,9 @@ * @deprecated this is poor naming, and it is better to directly set control.expanded( showOrHide ) * @since 4.5.0 Added params.completeCallback. * - * @param {boolean} [showOrHide] - If not supplied, will be inverse of current visibility - * @param {Object} [params] - Optional params. - * @param {Function} [params.completeCallback] - Function to call when the form toggle has finished animating. + * @param {boolean} [showOrHide] If not supplied, will be inverse of current visibility + * @param {Object} [params] Optional params. + * @param {Function} [params.completeCallback] Function to call when the form toggle has finished animating. */ toggleForm: function( showOrHide, params ) { if ( typeof showOrHide === 'undefined' ) { @@ -2198,9 +2207,9 @@ * Expand or collapse the menu item control. * * @since 4.6.0 - * @param {boolean} [showOrHide] - If not supplied, will be inverse of current visibility - * @param {Object} [params] - Optional params. - * @param {Function} [params.completeCallback] - Function to call when the form toggle has finished animating. + * @param {boolean} [showOrHide] If not supplied, will be inverse of current visibility + * @param {Object} [params] Optional params. + * @param {Function} [params.completeCallback] Function to call when the form toggle has finished animating. */ onChangeExpanded: function( showOrHide, params ) { var self = this, $menuitem, $inside, complete; @@ -2267,8 +2276,8 @@ * * @since 4.5.0 Added params.completeCallback. * - * @param {Object} [params] - Params object. - * @param {Function} [params.completeCallback] - Optional callback function when focus has completed. + * @param {Object} [params] Params object. + * @param {Function} [params.completeCallback] Optional callback function when focus has completed. */ focus: function( params ) { params = params || {}; @@ -2594,7 +2603,7 @@ * * @since 4.9.0 * - * @param {Object.} selections - A map of location selections. + * @param {Object.} selections A map of location selections. * @return {void} */ setSelections: function( selections ) { @@ -2781,7 +2790,7 @@ * Notice that the UI aspects here are handled by wpNavMenu.initSortables() * which is called in MenuSection.onChangeExpanded() * - * @param {Object} menuList - The element that has sortable(). + * @param {Object} menuList The element that has sortable(). */ _setupSortable: function( menuList ) { var control = this; @@ -3019,7 +3028,9 @@ }, /** - * @return {wp.customize.controlConstructor.nav_menu_item[]} + * Get all of the nav_menu_item controls for this menu. + * + * @return {wp.customize.Menus.MenuItemControl[]} The nav_menu_item controls for this menu. */ getMenuItemControls: function() { var menuControl = this, @@ -3116,15 +3127,15 @@ * has child items, this function will only be called once all of the * settings have been updated. */ - debouncedReflowMenuItems: _.debounce( function() { - this.reflowMenuItems.apply( this, arguments ); + debouncedReflowMenuItems: _.debounce( function( ...args ) { + this.reflowMenuItems.apply( this, args ); }, 0 ), /** * Add a new item to this menu. * - * @param {Object} item - Value for the nav_menu_item setting to be created. - * @return {wp.customize.Menus.controlConstructor.nav_menu_item} The newly-created nav_menu_item control instance. + * @param {Object} item Value for the nav_menu_item setting to be created. + * @return {wp.customize.Menus.MenuItemControl} The newly-created nav_menu_item control instance. */ addItemToMenu: function( item ) { var menuControl = this, customizeId, settingArgs, setting, menuItemControl, placeholderId, position = 0, priority = 10, @@ -3189,7 +3200,9 @@ * * @since 4.9.0 * - * @param {wp.customize.controlConstructor.nav_menu_item[]} optionalMenuItemControls + * @param {wp.customize.Menus.MenuItemControl[]} [optionalMenuItemControls] The menu item controls to + * consider. Defaults to all of + * this menu's item controls. */ updateInvitationVisibility: function ( optionalMenuItemControls ) { var menuItemControls = optionalMenuItemControls || this.getMenuItemControls(); @@ -3263,9 +3276,9 @@ * * @alias wp.customize.Menus.applySavedData * - * @param {Object} data - * @param {Array} data.nav_menu_updates - * @param {Array} data.nav_menu_item_updates + * @param {Object} data + * @param {Object[]} data.nav_menu_updates + * @param {Object[]} data.nav_menu_item_updates */ api.Menus.applySavedData = function( data ) { @@ -3509,8 +3522,8 @@ * * @alias wp.customize.Menus.getMenuControl * - * @param menuId - * @return {wp.customize.controlConstructor.menus[]} + * @param {string|number} menuId The ID of the menu. + * @return {wp.customize.Menus.MenuControl|undefined} The menu control, or undefined if not found. */ api.Menus.getMenuControl = function( menuId ) { return api.control( 'nav_menu[' + menuId + ']' ); @@ -3521,8 +3534,8 @@ * * @alias wp.customize.Menus.getMenuItemControl * - * @param {string} menuItemId - * @return {Object|null} + * @param {string} menuItemId The ID of the menu item. + * @return {wp.customize.Menus.MenuItemControl|undefined} The menu item control, or undefined if not found. */ api.Menus.getMenuItemControl = function( menuItemId ) { return api.control( menuItemIdToSettingId( menuItemId ) ); @@ -3531,7 +3544,8 @@ /** * @alias wp.customize.Menus~menuItemIdToSettingId * - * @param {string} menuItemId + * @param {string} menuItemId The ID of the menu item. + * @return {string} The setting ID for the menu item. */ function menuItemIdToSettingId( menuItemId ) { return 'nav_menu_item[' + menuItemId + ']'; @@ -3543,8 +3557,8 @@ * * @alias wp.customize.Menus~displayNavMenuName * - * @param {string} name - * @return {string} + * @param {string} [name] The menu name. + * @return {string} The sanitized display name, or a fallback "unnamed" string if empty. */ function displayNavMenuName( name ) { name = name || ''; diff --git a/src/js/_enqueues/wp/customize/preview-nav-menus.js b/src/js/_enqueues/wp/customize/preview-nav-menus.js index b5bec37b52aaf..b54d4e8a4f39d 100644 --- a/src/js/_enqueues/wp/customize/preview-nav-menus.js +++ b/src/js/_enqueues/wp/customize/preview-nav-menus.js @@ -5,6 +5,13 @@ /* global _wpCustomizePreviewNavMenusExports */ /** @namespace wp.customize.navMenusPreview */ + +/** + * @param {JQueryStatic} $ The jQuery object. + * @param {_.UnderscoreStatic} _ The Underscore.js object. + * @param {Object} wp The WordPress global object. + * @param {Object} api The Customizer API. + */ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( $, _, wp, api ) { 'use strict'; @@ -91,10 +98,10 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * Constructor. * * @since 4.5.0 - * @param {string} id - Partial ID. - * @param {Object} options - * @param {Object} options.params - * @param {Object} options.params.navMenuArgs + * @param {string} id Partial ID. + * @param {Object} [options] + * @param {Object} [options.params] + * @param {Object} [options.params.navMenuArgs] * @param {string} options.params.navMenuArgs.args_hmac * @param {string} [options.params.navMenuArgs.theme_location] * @param {number} [options.params.navMenuArgs.menu] @@ -131,10 +138,10 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * Return whether the setting is related to this partial. * * @since 4.5.0 - * @param {wp.customize.Value|string} setting - Object or ID. - * @param {number|Object|false|null} newValue - New value, or null if the setting was just removed. - * @param {number|Object|false|null} oldValue - Old value, or null if the setting was just added. - * @return {boolean} + * @param {wp.customize.Value|string} setting Object or ID. + * @param {number|Object|false|null} newValue New value, or null if the setting was just removed. + * @param {number|Object|false|null} oldValue Old value, or null if the setting was just added. + * @return {boolean} True if the setting is related to this partial, false otherwise. */ isRelatedSetting: function( setting, newValue, oldValue ) { var partial = this, navMenuLocationSetting, navMenuId, isNavMenuItemSetting, _newValue, _oldValue, urlParser; @@ -210,7 +217,7 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * * @since 4.5.0 * - * @return {Promise} + * @return {Promise} A promise that is resolved when the refresh is complete, or rejected if the partial is no longer associated with a menu. */ refresh: function() { var partial = this, menuId, deferred = $.Deferred(); @@ -263,7 +270,10 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( /** * Request full refresh if there are nav menu instances that lack partials which also match the supplied args. * - * @param {Object} navMenuInstanceArgs + * @since 4.5.0 + * + * @param {Object} navMenuInstanceArgs Arguments for a nav menu instance, which may include menu and/or theme_location. + * @return {boolean} Whether a full refresh was requested. */ self.handleUnplacedNavMenuInstances = function( navMenuInstanceArgs ) { var unplacedNavMenuInstances; @@ -284,8 +294,8 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * * @param {wp.customize.Value} setting * @param {Object} [options] - * @param {boolean} options.fire Whether to invoke the callback after binding. - * This is used when a dynamic setting is added. + * @param {boolean} [options.fire] Whether to invoke the callback after binding. + * This is used when a dynamic setting is added. * @return {boolean} Whether the setting was bound. */ self.bindSettingListener = function( setting, options ) { @@ -331,6 +341,7 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * @since 4.5.0 * * @param {wp.customize.Value} setting + * @return {void} */ self.unbindSettingListener = function( setting ) { setting.unbind( this.onChangeNavMenuSetting ); @@ -344,6 +355,7 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * @since 4.5.0 * * @this {wp.customize.Value} + * @return {void} */ self.onChangeNavMenuSetting = function() { var setting = this; @@ -373,6 +385,7 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * @param {Object} newItem New value for nav_menu_item[] setting. * @param {Object} oldItem Old value for nav_menu_item[] setting. * @this {wp.customize.Value} + * @return {void} */ self.onChangeNavMenuItemSetting = function( newItem, oldItem ) { var item = newItem || oldItem, navMenuSetting; @@ -388,6 +401,7 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * @since 4.5.0 * * @this {wp.customize.Value} + * @return {void} */ self.onChangeNavMenuLocationsSetting = function() { var setting = this, hasNavMenuInstance; @@ -412,6 +426,8 @@ wp.customize.navMenusPreview = wp.customize.MenusCustomizerPreview = ( function( * Also this applies even if a nav menu is not partial-refreshable. * * @since 4.5.0 + * + * @return {void} */ self.highlightControls = function() { var selector = '.menu-item'; diff --git a/src/js/_enqueues/wp/customize/preview-widgets.js b/src/js/_enqueues/wp/customize/preview-widgets.js index e1191a65ad07f..487e294a93a29 100644 --- a/src/js/_enqueues/wp/customize/preview-widgets.js +++ b/src/js/_enqueues/wp/customize/preview-widgets.js @@ -11,10 +11,10 @@ * * @namespace wp.customize.widgetsPreview * - * @param {jQuery} $ The jQuery object. - * @param {Object} _ The utilities library. - * @param {Object} wp Current WordPress environment instance. - * @param {Object} api Information from the API. + * @param {JQueryStatic} $ The jQuery object. + * @param {_.UnderscoreStatic} _ The Underscore.js object. + * @param {Object} wp The WordPress global object. + * @param {Object} api The Customizer API. * * @return {Object} Widget-related variables. */ @@ -93,10 +93,9 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( * @alias wp.customize.widgetsPreview.WidgetPartial * @memberOf wp.customize.widgetsPreview * - * @param {string} id The partial's ID. - * @param {Object} options Options used to initialize the partial's - * instance. - * @param {Object} options.params The options parameters. + * @param {string} id The partial's ID. + * @param {Object} [options] Options used to initialize the partial's instance. + * @param {Object} [options.params] The options parameters. */ initialize: function( id, options ) { var partial = this, matches; @@ -170,9 +169,9 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( * @memberOf wp.customize.widgetsPreview * @alias wp.customize.widgetsPreview.SidebarPartial * - * @param {string} id The partial's ID. - * @param {Object} options Options used to initialize the partial's instance. - * @param {Object} options.params The options parameters. + * @param {string} id The partial's ID. + * @param {Object} [options] Options used to initialize the partial's instance. + * @param {Object} [options.params] The options parameters. */ initialize: function( id, options ) { var partial = this, matches; @@ -293,8 +292,8 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( * * @since 4.5.0 * - * @return {Array} An array containing placement objects for each of the - * dynamic sidebar boundary nodes. + * @return {wp.customize.selectiveRefresh.Placement[]} A placement for each of the dynamic + * sidebar boundary nodes. */ placements: function() { var partial = this; @@ -320,7 +319,7 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( * @throws {Error} If the setting doesn't exist in the API. * @throws {Error} If the API doesn't pass an array of widget IDs. * - * @return {Array} A shallow copy of the array containing widget IDs. + * @return {string[]} A shallow copy of the array containing widget IDs. */ getWidgetIds: function() { var sidebarPartial = this, settingId, widgetIds; @@ -344,7 +343,7 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( * * @since 4.5.0 * - * @return {Array.} List of placements + * @return {wp.customize.selectiveRefresh.Placement[]} List of placements * that were reflowed. */ reflowWidgets: function() { @@ -477,8 +476,8 @@ wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( * * @since 4.5.0 * - * @param {Array} newWidgetIds New widget IDs. - * @param {Array} oldWidgetIds Old widget IDs. + * @param {string[]} newWidgetIds New widget IDs. + * @param {string[]} oldWidgetIds Old widget IDs. * * @return {void} */ diff --git a/src/js/_enqueues/wp/customize/preview.js b/src/js/_enqueues/wp/customize/preview.js index 375cd2104ba0f..2830913f971a5 100644 --- a/src/js/_enqueues/wp/customize/preview.js +++ b/src/js/_enqueues/wp/customize/preview.js @@ -1,9 +1,14 @@ -/* +/** + * @output wp-includes/js/customize-preview.js + */ + +/** * Script run inside a Customizer preview frame. * - * @output wp-includes/js/customize-preview.js + * @param {Object} wp The WordPress global object. + * @param {JQueryStatic} $ The jQuery object. */ -(function( exports, $ ){ +(function( wp, $ ){ var api = wp.customize, debounce, currentHistoryState = {}; @@ -74,13 +79,16 @@ /** * Returns a debounced version of the function. * + * @param {Function} fn Function to debounce. + * @param {number} delay Delay in milliseconds. + * @param {Object} [context] Context to invoke the function in. Defaults to the calling context. * @todo Require Underscore.js for this file and retire this. + * + * @return {Function} Debounced function. */ debounce = function( fn, delay, context ) { var timeout; - return function() { - var args = arguments; - + return function( ...args ) { context = context || this; clearTimeout( timeout ); @@ -95,15 +103,15 @@ * @memberOf wp.customize * @alias wp.customize.Preview * - * @constructor + * @class * @augments wp.customize.Messenger * @augments wp.customize.Class * @mixes wp.customize.Events */ api.Preview = api.Messenger.extend(/** @lends wp.customize.Preview.prototype */{ /** - * @param {Object} params - Parameters to configure the messenger. - * @param {Object} options - Extend any instance parameter or method with this object. + * @param {Object} params Parameters to configure the messenger. + * @param {Object} options Extend any instance parameter or method with this object. */ initialize: function( params, options ) { var preview = this, urlParser = document.createElement( 'a' ); @@ -142,7 +150,8 @@ * @since 4.7.0 * @access public * - * @param {jQuery.Event} event Event. + * @param {JQuery.Event} event Event. + * @return {void} */ handleLinkClick: function( event ) { var preview = this, link, isInternalJumpLink; @@ -188,7 +197,8 @@ * @since 4.7.0 * @access public * - * @param {jQuery.Event} event Event. + * @param {JQuery.Event} event Event. + * @return {void} */ handleFormSubmit: function( event ) { var preview = this, urlParser, form; @@ -232,7 +242,6 @@ * * @since 4.7.0 * @access protected - * @access private * * @return {void} */ @@ -714,9 +723,9 @@ /** * Create/update a setting value. * - * @param {string} id - Setting ID. - * @param {*} value - Setting value. - * @param {boolean} [createDirty] - Whether to create a setting as dirty. Defaults to false. + * @param {string} id Setting ID. + * @param {*} value Setting value. + * @param {boolean} [createDirty] Whether to create a setting as dirty. Defaults to false. */ setValue = function( id, value, createDirty ) { var setting = api( id ); @@ -791,7 +800,7 @@ /** * Handle update to changeset UUID. * - * @param {string} uuid - UUID. + * @param {string} uuid UUID. * @return {void} */ handleUpdatedChangesetUuid = function( uuid ) { @@ -888,8 +897,8 @@ return 'background_' + prop; } ); - api.when.apply( api, bg ).done( function() { - $.each( arguments, function() { + api.when.apply( api, bg ).done( function( ...settings ) { + $.each( settings, function() { this.bind( api.settingPreviewHandlers.background ); }); }); diff --git a/src/js/_enqueues/wp/customize/selective-refresh.js b/src/js/_enqueues/wp/customize/selective-refresh.js index 6744361066ce1..cacecfe53331a 100644 --- a/src/js/_enqueues/wp/customize/selective-refresh.js +++ b/src/js/_enqueues/wp/customize/selective-refresh.js @@ -5,6 +5,11 @@ /* global jQuery, JSON, _customizePartialRefreshExports, console */ /** @namespace wp.customize.selectiveRefresh */ + +/** + * @param {JQueryStatic} $ The jQuery object. + * @param {Object} api The Customizer API. + */ wp.customize.selectiveRefresh = ( function( $, api ) { 'use strict'; var self, Partial, Placement; @@ -37,7 +42,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * @augments wp.customize.Class * @since 4.5.0 */ - Partial = self.Partial = api.Class.extend(/** @lends wp.customize.SelectiveRefresh.Partial.prototype */{ + Partial = self.Partial = api.Class.extend(/** @lends wp.customize.selectiveRefresh.Partial.prototype */{ id: null, @@ -45,7 +50,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * Default params. * * @since 4.9.0 - * @var {object} + * @member {Object} */ defaults: { selector: null, @@ -59,14 +64,14 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * * @since 4.5.0 * - * @param {string} id - Unique identifier for the partial instance. - * @param {Object} options - Options hash for the partial instance. - * @param {string} options.type - Type of partial (e.g. nav_menu, widget, etc) - * @param {string} options.selector - jQuery selector to find the container element in the page. - * @param {Array} options.settings - The IDs for the settings the partial relates to. - * @param {string} options.primarySetting - The ID for the primary setting the partial renders. - * @param {boolean} options.fallbackRefresh - Whether to refresh the entire preview in case of a partial refresh failure. - * @param {Object} [options.params] - Deprecated wrapper for the above properties. + * @param {string} id Unique identifier for the partial instance. + * @param {Object} [options] Options hash for the partial instance. + * @param {string} [options.type] Type of partial (e.g. nav_menu, widget, etc) + * @param {string} [options.selector] jQuery selector to find the container element in the page. + * @param {string[]} [options.settings] The IDs for the settings the partial relates to. + * @param {string} [options.primarySetting] The ID for the primary setting the partial renders. + * @param {boolean} [options.fallbackRefresh] Whether to refresh the entire preview in case of a partial refresh failure. + * @param {Object} [options.params] Deprecated wrapper for the above properties. */ initialize: function( id, options ) { var partial = this; @@ -119,7 +124,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * @since 4.7.0 * @access public * - * @param {Placement} placement The placement container element. + * @param {wp.customize.selectiveRefresh.Placement} placement The placement container element. * @return {void} */ createEditShortcutForPlacement: function( placement ) { @@ -148,8 +153,8 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * @since 4.7.0 * @access public * - * @param {Placement} placement The placement for the partial. - * @param {jQuery} $editShortcut The shortcut element as a jQuery object. + * @param {wp.customize.selectiveRefresh.Placement} placement The placement for the partial. + * @param {jQuery} $editShortcut The shortcut element as a jQuery object. * @return {void} */ addEditShortcutToPlacement: function( placement, $editShortcut ) { @@ -253,7 +258,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * * @since 4.5.0 * - * @return {Array.} + * @return {wp.customize.selectiveRefresh.Placement[]} The placements for this partial in the document. */ placements: function() { var partial = this, selector; @@ -285,7 +290,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * * @since 4.5.0 * - * @return {string[]} + * @return {string[]} The setting IDs related to this partial. */ settings: function() { var partial = this; @@ -344,7 +349,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * * @since 4.5.0 * - * @param {Placement} placement + * @param {wp.customize.selectiveRefresh.Placement} placement The placement to prepare. */ preparePlacement: function( placement ) { $( placement.container ).addClass( 'customize-partial-refreshing' ); @@ -364,7 +369,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * @since 4.5.0 * * @this {wp.customize.selectiveRefresh.Partial} - * @return {jQuery.Promise} + * @return {JQuery.Promise<*>} Promise for the request to render the partial. */ refresh: function() { var partial = this, refreshPromise; @@ -404,10 +409,10 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * * @since 4.5.0 * - * @param {Placement} placement - * @param {Element|jQuery} [placement.container] - This param will be empty if there was no element matching the selector. - * @param {string|Object|boolean} placement.addedContent - Rendered HTML content, a data object for JS templates to render, or false if no render. - * @param {Object} [placement.context] - Optional context information about the container. + * @param {wp.customize.selectiveRefresh.Placement} placement The placement to render into. + * @param {Element|jQuery} [placement.container] This param will be empty if there was no element matching the selector. + * @param {string|Object|boolean} placement.addedContent Rendered HTML content, a data object for JS templates to render, or false if no render. + * @param {Object} [placement.context] Optional context information about the container. * @return {boolean} Whether the rendering was successful and the fallback was not invoked. */ renderContent: function( placement ) { @@ -531,12 +536,12 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * @augments wp.customize.Class * @since 4.5.0 */ - self.Placement = Placement = api.Class.extend(/** @lends wp.customize.selectiveRefresh.prototype */{ + self.Placement = Placement = api.Class.extend(/** @lends wp.customize.selectiveRefresh.Placement.prototype */{ /** * The partial with which the container is associated. * - * @param {wp.customize.selectiveRefresh.Partial} + * @member {wp.customize.selectiveRefresh.Partial} */ partial: null, @@ -547,6 +552,8 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * DOM element, such as in the case of a sidebar partial. * This container element itself will be replaced for partials that * have containerInclusive param defined as true. + * + * @member {jQuery} */ container: null, @@ -556,6 +563,8 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * This will normally be the same as endNode since most placements appear as elements. * This is primarily useful for widget sidebars which do not have intrinsic containers, but * for which an HTML comment is output before to mark the starting position. + * + * @member {Node} */ startNode: null, @@ -565,6 +574,8 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * This will normally be the same as startNode since most placements appear as elements. * This is primarily useful for widget sidebars which do not have intrinsic containers, but * for which an HTML comment is output before to mark the ending position. + * + * @member {Node} */ endNode: null, @@ -574,14 +585,14 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * This provides information about the placement which is included in the request * in order to render the partial properly. * - * @param {object} + * @member {Object} */ context: null, /** * The content for the partial when refreshed. * - * @param {string} + * @member {string|Object|boolean} */ addedContent: null, @@ -589,11 +600,11 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * DOM node(s) removed when the partial is refreshed. * * If the partial is containerInclusive, then the removedNodes will be - * the single Element that was the partial's former placement. If the + * the jQuery object for the partial's former placement. If the * partial is not containerInclusive, then the removedNodes will be a - * documentFragment containing the nodes removed. + * DocumentFragment containing the nodes removed. * - * @param {Element|DocumentFragment} + * @member {jQuery|DocumentFragment} */ removedNodes: null, @@ -602,14 +613,14 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * * @since 4.5.0 * - * @param {Object} args - * @param {Partial} args.partial - * @param {jQuery|Element} [args.container] - * @param {Node} [args.startNode] - * @param {Node} [args.endNode] - * @param {Object} [args.context] - * @param {string} [args.addedContent] - * @param {jQuery|DocumentFragment} [args.removedNodes] + * @param {Object} args The placement properties. + * @param {wp.customize.selectiveRefresh.Partial} args.partial The partial with which the container is associated. + * @param {jQuery|Element} [args.container] DOM element which contains the placement's contents. + * @param {Node} [args.startNode] DOM node for the initial boundary of the placement. + * @param {Node} [args.endNode] DOM node for the terminal boundary of the placement. + * @param {Object} [args.context] Context data included in the request in order to render the partial. + * @param {string|Object|boolean} [args.addedContent] The content for the partial when refreshed. + * @param {jQuery|DocumentFragment} [args.removedNodes] DOM node(s) removed when the partial is refreshed. */ initialize: function( args ) { var placement = this; @@ -645,7 +656,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * @since 4.5.0 * @see wp.customize.previewer.query() * - * @return {Object} + * @return {Object} POST vars for a Customizer preview request. */ self.getCustomizeQuery = function() { var dirtyCustomized = {}; @@ -668,7 +679,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * Currently-requested partials and their associated deferreds. * * @since 4.5.0 - * @type {Object} + * @type {Object., partial: wp.customize.selectiveRefresh.Partial }>} */ self._pendingPartialRequests = {}; @@ -685,7 +696,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * Current jqXHR for the request to the partials. * * @since 4.5.0 - * @type {jQuery.jqXHR|null} + * @type {JQuery.jqXHR|null} * @private */ self._currentRequest = null; @@ -708,7 +719,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * @since 4.5.0 * * @param {wp.customize.selectiveRefresh.Partial} partial - * @return {jQuery.Promise} + * @return {JQuery.Promise<*>} Promise for the request to render the partial. */ self.requestPartial = function( partial ) { var partialRequest; @@ -856,9 +867,9 @@ wp.customize.selectiveRefresh = ( function( $, api ) { * * @since 4.5.0 * - * @param {jQuery|HTMLElement} [rootElement] - * @param {object} [options] - * @param {boolean=true} [options.triggerRendered] + * @param {jQuery|HTMLElement} [rootElement] Element to scan for partials. Defaults to the document element. + * @param {Object} [options] Options. + * @param {boolean} [options.triggerRendered=true] Whether to trigger the rendered event for the placements found. */ self.addPartials = function( rootElement, options ) { var containerElements; @@ -1016,7 +1027,7 @@ wp.customize.selectiveRefresh = ( function( $, api ) { /** * Handle rendering of partials. * - * @param {api.selectiveRefresh.Placement} placement + * @param {wp.customize.selectiveRefresh.Placement} placement */ api.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) { if ( placement.container ) { @@ -1027,8 +1038,8 @@ wp.customize.selectiveRefresh = ( function( $, api ) { /** * Handle setting validities in partial refresh response. * - * @param {object} data Response data. - * @param {object} data.setting_validities Setting validities. + * @param {Object} data Response data. + * @param {Object} data.setting_validities Setting validities. */ api.selectiveRefresh.bind( 'render-partials-response', function handleSettingValiditiesResponse( data ) { if ( data.setting_validities ) { diff --git a/src/js/_enqueues/wp/customize/views.js b/src/js/_enqueues/wp/customize/views.js index 02c984de70c43..e945b54348d8b 100644 --- a/src/js/_enqueues/wp/customize/views.js +++ b/src/js/_enqueues/wp/customize/views.js @@ -2,6 +2,11 @@ * @output wp-includes/js/customize-views.js */ +/** + * @param {JQueryStatic} $ The jQuery object. + * @param {Object} wp The WordPress global object. + * @param {_.UnderscoreStatic} _ The Underscore.js object. + */ (function( $, wp, _ ) { if ( ! wp || ! wp.customize ) { return; } @@ -18,23 +23,34 @@ * @memberOf wp.customize.HeaderTool * @alias wp.customize.HeaderTool.CurrentView * - * @constructor + * @class * @augments wp.Backbone.View */ api.HeaderTool.CurrentView = wp.Backbone.View.extend(/** @lends wp.customize.HeaderTool.CurrentView.prototype */{ template: wp.template('header-current'), + /** + * Initialize. + */ initialize: function() { this.listenTo(this.model, 'change', this.render); this.render(); }, + /** + * Render. + * + * @return {wp.customize.HeaderTool.CurrentView} Current view. + */ render: function() { this.$el.html(this.template(this.model.toJSON())); this.setButtons(); return this; }, + /** + * Set buttons. + */ setButtons: function() { var elements = $('#customize-control-header_image .actions .remove'); var addButton = $('#customize-control-header_image .actions .new'); @@ -64,7 +80,7 @@ * @memberOf wp.customize.HeaderTool * @alias wp.customize.HeaderTool.ChoiceView * - * @constructor + * @class * @augments wp.Backbone.View */ api.HeaderTool.ChoiceView = wp.Backbone.View.extend(/** @lends wp.customize.HeaderTool.ChoiceView.prototype */{ @@ -77,6 +93,9 @@ 'click .close': 'removeImage' }, + /** + * Initialize. + */ initialize: function() { var properties = [ this.model.get('header').url, @@ -90,6 +109,11 @@ } }, + /** + * Render. + * + * @return {wp.customize.HeaderTool.ChoiceView} Choice view. + */ render: function() { this.$el.html(this.template(this.extendedModel())); @@ -97,10 +121,18 @@ return this; }, + /** + * Toggle selected. + */ toggleSelected: function() { this.$el.toggleClass('selected', this.model.get('selected')); }, + /** + * Extended model. + * + * @return {Object} Extended model. + */ extendedModel: function() { var c = this.model.get('collection'); return _.extend(this.model.toJSON(), { @@ -108,12 +140,18 @@ }); }, + /** + * Select. + */ select: function() { this.preventJump(); this.model.save(); api.HeaderTool.currentHeader.set(this.extendedModel()); }, + /** + * Prevent jump. + */ preventJump: function() { var container = $('.wp-full-overlay-sidebar-content'), scroll = container.scrollTop(); @@ -123,6 +161,11 @@ }); }, + /** + * Remove image. + * + * @param {Event} e Event. + */ removeImage: function(e) { e.stopPropagation(); this.model.destroy(); @@ -142,10 +185,13 @@ * @memberOf wp.customize.HeaderTool * @alias wp.customize.HeaderTool.ChoiceListView * - * @constructor + * @class * @augments wp.Backbone.View */ api.HeaderTool.ChoiceListView = wp.Backbone.View.extend(/** @lends wp.customize.HeaderTool.ChoiceListView.prototype */{ + /** + * Initialize. + */ initialize: function() { this.listenTo(this.collection, 'add', this.addOne); this.listenTo(this.collection, 'remove', this.render); @@ -154,12 +200,23 @@ this.render(); }, + /** + * Render. + * + * @return {wp.customize.HeaderTool.ChoiceListView} Choice list view. + */ render: function() { this.$el.empty(); this.collection.each(this.addOne, this); this.toggleList(); + return this; }, + /** + * Add one. + * + * @param {Backbone.Model} choice Choice. + */ addOne: function(choice) { var view; choice.set({ collection: this.collection }); @@ -167,6 +224,9 @@ this.$el.append(view.render().el); }, + /** + * Toggle list. + */ toggleList: function() { var title = this.$el.parents().prev('.customize-control-title'), randomButton = this.$el.find('.random').parent(); @@ -188,14 +248,26 @@ * @memberOf wp.customize.HeaderTool * @alias wp.customize.HeaderTool.CombinedList * - * @constructor + * @class * @augments wp.Backbone.View */ api.HeaderTool.CombinedList = wp.Backbone.View.extend(/** @lends wp.customize.HeaderTool.CombinedList.prototype */{ + /** + * Initialize. + * + * @param {Backbone.Collection[]} collections Collections. + */ initialize: function(collections) { this.collections = collections; this.on('all', this.propagate, this); }, + + /** + * Propagate event. + * + * @param {string} event Event. + * @param {*} arg Argument. + */ propagate: function(event, arg) { _.each(this.collections, function(collection) { collection.trigger(event, arg); diff --git a/src/js/_enqueues/wp/customize/widgets.js b/src/js/_enqueues/wp/customize/widgets.js index 56459ad7452e1..999883f5fb3b6 100644 --- a/src/js/_enqueues/wp/customize/widgets.js +++ b/src/js/_enqueues/wp/customize/widgets.js @@ -3,6 +3,11 @@ */ /* global _wpCustomizeWidgetsSettings */ + +/** + * @param {Object} wp The WordPress global object. + * @param {JQueryStatic} $ The jQuery object. + */ (function( wp, $ ){ if ( ! wp || ! wp.customize ) { return; } @@ -251,7 +256,7 @@ /** * Updates the count of the available widgets that have the `search_matched` attribute. - */ + */ updateSearchMatchesCount: function() { this.searchMatchesCount = this.collection.where({ search_matched: true }).length; }, @@ -271,7 +276,7 @@ /** * Changes visibility of available widgets. - */ + */ updateList: function() { this.collection.each( function( widget ) { var widgetTpl = $( '#widget-tpl-' + widget.id ); @@ -284,7 +289,9 @@ /** * Highlights a widget. - */ + * + * @param {jQuery} widgetTpl The widget template to highlight. + */ select: function( widgetTpl ) { this.selected = $( widgetTpl ); this.selected.siblings( '.widget-tpl' ).removeClass( 'selected' ); @@ -293,6 +300,8 @@ /** * Highlights a widget on focus. + * + * @param {JQuery.Event} event The focus event. */ focus: function( event ) { this.select( $( event.currentTarget ) ); @@ -300,6 +309,8 @@ /** * Handles submit for keypress and click on widget. + * + * @param {JQuery.Event} event The keypress or click event. */ _submit: function( event ) { // Only proceed with keypress if it is Enter or Spacebar. @@ -312,7 +323,9 @@ /** * Adds a selected widget to the sidebar. - */ + * + * @param {jQuery} widgetTpl The widget template to add. + */ submit: function( widgetTpl ) { var widgetId, widget, widgetFormControl; @@ -342,6 +355,8 @@ /** * Opens the panel. + * + * @param {wp.customize.Widgets.SidebarControl} sidebarControl The sidebar control that opened the panel. */ open: function( sidebarControl ) { this.currentSidebarControl = sidebarControl; @@ -371,6 +386,8 @@ /** * Closes the panel. + * + * @param {Object} [options] Options for closing the panel. */ close: function( options ) { options = options || {}; @@ -389,6 +406,8 @@ /** * Adds keyboard accessibility to the panel. + * + * @param {JQuery.Event} event The keydown event. */ keyboardAccessible: function( event ) { var isEnter = ( event.which === 13 ), @@ -457,7 +476,7 @@ api.Widgets.formSyncHandlers = { /** - * @param {jQuery.Event} e + * @param {JQuery.Event} e * @param {jQuery} widget * @param {string} newForm */ @@ -491,6 +510,9 @@ * * @constructs wp.customize.Widgets.WidgetControl * @augments wp.customize.Control + * + * @param {string} id Control ID. + * @param {Object} options Control options. */ initialize: function( id, options ) { var control = this; @@ -953,9 +975,9 @@ formSyncHandler = api.Widgets.formSyncHandlers[ this.params.widget_id_base ]; if ( formSyncHandler ) { - $( document ).on( 'widget-synced', function( e, widget ) { + $( document ).on( 'widget-synced', function( e, widget, ...args ) { if ( $widgetRoot.is( widget ) ) { - formSyncHandler.apply( document, arguments ); + formSyncHandler.call( document, e, widget, ...args ); } } ); } @@ -968,9 +990,9 @@ * * @since 4.1.0 * - * @param {boolean} active - * @param {Object} args - * @param {function} args.completeCallback + * @param {boolean} active Whether the widget is rendered. + * @param {Object} args Args. + * @param {Function} args.completeCallback Function to call once the class has been toggled. */ onChangeActive: function ( active, args ) { // Note: there is a second 'args' parameter being passed, merged on top of this.defaultActiveArguments. @@ -1052,7 +1074,7 @@ * This string can be used to compare whether or not the form has all of the same fields. * * @param {jQuery} inputs - * @return {string} + * @return {string} Signature string for the inputs. * @private */ _getInputsSignature: function( inputs ) { @@ -1075,7 +1097,7 @@ * Get the state for an input depending on its type. * * @param {jQuery|Element} input - * @return {string|boolean|Array|*} + * @return {string|boolean|string[]|*} State of the input. * @private */ _getInputState: function( input ) { @@ -1095,7 +1117,7 @@ * Update an input's state based on its type. * * @param {jQuery|Element} input - * @param {string|boolean|Array|*} state + * @param {string|boolean|string[]|*} state * @private */ _setInputState: function ( input, state ) { @@ -1124,7 +1146,9 @@ **********************************************************************/ /** - * @return {wp.customize.controlConstructor.sidebar_widgets[]} + * Get the sidebar widgets control for the sidebar this widget is in. + * + * @return {wp.customize.Widgets.SidebarControl|undefined} The sidebar widgets control, or undefined if not found. */ getSidebarWidgetsControl: function() { var settingId, sidebarWidgetsControl; @@ -1341,9 +1365,9 @@ /** * @since 4.1.0 * - * @param {Boolean} expanded + * @param {boolean} expanded * @param {Object} [params] - * @return {Boolean} False if state already applied. + * @return {boolean} False if state already applied. */ _toggleExpanded: api.Section.prototype._toggleExpanded, @@ -1351,7 +1375,7 @@ * @since 4.1.0 * * @param {Object} [params] - * @return {Boolean} False if already expanded. + * @return {boolean} False if already expanded. */ expand: api.Section.prototype.expand, @@ -1368,7 +1392,7 @@ * @since 4.1.0 * * @param {Object} [params] - * @return {Boolean} False if already collapsed. + * @return {boolean} False if already collapsed. */ collapse: api.Section.prototype.collapse, @@ -1498,7 +1522,7 @@ /** * Get the position (index) of the widget in the containing sidebar * - * @return {number} + * @return {number|void} Index of the widget in the sidebar, or undefined if not found */ getWidgetSidebarPosition: function() { var sidebarWidgetIds, position; @@ -1642,7 +1666,7 @@ /** * Determine whether or not the notice should be displayed. * - * @return {boolean} + * @return {boolean} True if the notice should be displayed, false otherwise. */ shouldShowNotice = function() { var activeSectionCount = getActiveSectionCount(); @@ -1712,7 +1736,7 @@ * * @since 4.4.0 * - * @return {boolean} + * @return {boolean} True if the panel is contextually active, false otherwise. */ isContextuallyActive: function() { var panel = this; @@ -2048,7 +2072,7 @@ * Get the widget_form Customize controls associated with the current sidebar. * * @since 3.9.0 - * @return {wp.customize.controlConstructor.widget_form[]} + * @return {wp.customize.Widgets.WidgetControl[]} Widget form controls associated with the current sidebar. */ getWidgetFormControls: function() { var formControls = []; @@ -2065,8 +2089,10 @@ }, /** - * @param {string} widgetId or an id_base for adding a previously non-existing widget. - * @return {Object|false} widget_form control instance, or false on error. + * Add a widget to the sidebar. + * + * @param {string} widgetId Widget ID, or an id_base for adding a previously non-existing widget. + * @return {wp.customize.Widgets.WidgetControl|false} The widget_form control instance, or false on error. */ addWidget: function( widgetId ) { var self = this, controlHtml, $widget, controlType = 'widget_form', controlContainer, controlConstructor, @@ -2247,7 +2273,7 @@ /** * Given a widget control, find the sidebar widgets control that contains it. * @param {string} widgetId - * @return {Object|null} + * @return {Object|null} Sidebar widgets control that contains the widget, or null if not found. */ api.Widgets.getSidebarWidgetControlContainingWidget = function( widgetId ) { var foundControl = null; @@ -2266,7 +2292,7 @@ * Given a widget ID for a widget appearing in the preview, get the widget form control associated with it. * * @param {string} widgetId - * @return {Object|null} + * @return {Object|null} Widget form control associated with the widget, or null if not found. */ api.Widgets.getWidgetFormControlForWidget = function( widgetId ) { var foundControl = null; @@ -2319,8 +2345,8 @@ * * This overrides the back button to serve the purpose of breadcrumb navigation. * - * @param {wp.customize.Section|wp.customize.Panel|wp.customize.Control} focusConstruct - The object to initially focus. - * @param {wp.customize.Section|wp.customize.Panel|wp.customize.Control} returnConstruct - The object to return focus. + * @param {wp.customize.Section|wp.customize.Panel|wp.customize.Control} focusConstruct The object to initially focus. + * @param {wp.customize.Section|wp.customize.Panel|wp.customize.Control} returnConstruct The object to return focus. */ function focusConstructWithBreadcrumb( focusConstruct, returnConstruct ) { focusConstruct.focus(); @@ -2335,7 +2361,7 @@ /** * @param {string} widgetId - * @return {Object} + * @return {Object} Parsed widget ID with id_base and number properties */ function parseWidgetId( widgetId ) { var matches, parsed = { diff --git a/tests/qunit/wp-admin/js/customize-base.js b/tests/qunit/wp-admin/js/customize-base.js index bd3535b3bc3b0..0d093321f81ef 100644 --- a/tests/qunit/wp-admin/js/customize-base.js +++ b/tests/qunit/wp-admin/js/customize-base.js @@ -2,6 +2,7 @@ jQuery( function( $ ) { var FooSuperClass, BarSubClass, foo, bar, ConstructorTestClass, newConstructor, constructorTest, $mockElement, mockString, + ApplicatorTestClass, ArityTestClass, firstInitialValue, firstValueInstance, valuesInstance, wasCallbackFired, mockValueCallback; QUnit.module( 'Customize Base: Class' ); @@ -47,8 +48,64 @@ jQuery( function( $ ) { assert.equal( foo.instanceProp, 'instancePropValue' ); }); - // @todo Test Class.applicator? - // @todo Do we test object.instance? + ApplicatorTestClass = wp.customize.Class.extend({ + initialize: function( firstArg, secondArg ) { + this.firstArg = firstArg; + this.secondArg = secondArg; + + // The instance is extended before initialize() runs. + this.hadExtraPropDuringInitialize = ( 'extraPropValue' === this.extraProp ); + } + }); + QUnit.test( 'Class.applicator supplies the array as the initialize() arguments', function( assert ) { + var applicatorTest = new ApplicatorTestClass( + wp.customize.Class.applicator, + [ 'firstArgValue', 'secondArgValue' ] + ); + assert.equal( applicatorTest.firstArg, 'firstArgValue' ); + assert.equal( applicatorTest.secondArg, 'secondArgValue' ); + }); + QUnit.test( 'Class.applicator extends the instance before initialize() runs', function( assert ) { + var applicatorTest = new ApplicatorTestClass( + wp.customize.Class.applicator, + [ 'firstArgValue' ], + { extraProp: 'extraPropValue' } + ); + assert.equal( applicatorTest.firstArg, 'firstArgValue' ); + assert.equal( applicatorTest.extraProp, 'extraPropValue' ); + assert.ok( applicatorTest.hadExtraPropDuringInitialize ); + }); + + ArityTestClass = wp.customize.Class.extend({ + initialize: function( ...initializeArgs ) { + this.initializeArgCount = initializeArgs.length; + } + }); + QUnit.test( 'Class supplies initialize() with exactly the arguments it was given', function( assert ) { + assert.equal( ( new ArityTestClass() ).initializeArgCount, 0 ); + assert.equal( ( new ArityTestClass( 'a' ) ).initializeArgCount, 1 ); + assert.equal( ( new ArityTestClass( 'a', 'b' ) ).initializeArgCount, 2 ); + assert.equal( ( new ArityTestClass( 'a', 'b', 'c' ) ).initializeArgCount, 3 ); + assert.equal( ( new ArityTestClass( 'a', 'b', 'c', 'd' ) ).initializeArgCount, 4 ); + + // The applicator form supplies the arguments as an array instead. + assert.equal( + ( new ArityTestClass( wp.customize.Class.applicator, [ 'a', 'b' ] ) ).initializeArgCount, + 2 + ); + }); + + QUnit.test( 'Class instance with an instance() method is callable as a function', function( assert ) { + var instanceTest = new wp.customize.Value( 'initialValue' ); + + // Calling with no arguments delegates to get(). + assert.equal( instanceTest(), 'initialValue' ); + + // Calling with arguments delegates to set(). + instanceTest( 'updatedValue' ); + assert.equal( instanceTest.get(), 'updatedValue' ); + assert.equal( instanceTest(), 'updatedValue' ); + }); QUnit.module( 'Customize Base: Subclass' ); @@ -159,6 +216,73 @@ jQuery( function( $ ) { assert.ok( wasCallbackFired ); }); + QUnit.test( '.bind() and .unbind() accept multiple callbacks', function( assert ) { + var value = new wp.customize.Value( 'firstValue' ), + firstCallbackCount = 0, + secondCallbackCount = 0, + firstCallback = function() { + firstCallbackCount++; + }, + secondCallback = function() { + secondCallbackCount++; + }; + + value.bind( firstCallback, secondCallback ); + value.set( 'secondValue' ); + assert.equal( firstCallbackCount, 1 ); + assert.equal( secondCallbackCount, 1 ); + + value.unbind( firstCallback, secondCallback ); + value.set( 'thirdValue' ); + assert.equal( firstCallbackCount, 1, 'First callback no longer fires once unbound.' ); + assert.equal( secondCallbackCount, 1, 'Second callback no longer fires once unbound.' ); + }); + + QUnit.test( '.link() follows multiple values, and .unlink() stops following them', function( assert ) { + var follower = new wp.customize.Value( 'followerValue' ), + firstLeader = new wp.customize.Value( 'firstLeaderValue' ), + secondLeader = new wp.customize.Value( 'secondLeaderValue' ); + + follower.link( firstLeader, secondLeader ); + + firstLeader.set( 'firstLeaderUpdated' ); + assert.equal( follower.get(), 'firstLeaderUpdated' ); + + secondLeader.set( 'secondLeaderUpdated' ); + assert.equal( follower.get(), 'secondLeaderUpdated' ); + + // Linking is one-directional, so the leaders do not follow the follower. + follower.set( 'followerUpdated' ); + assert.equal( firstLeader.get(), 'firstLeaderUpdated' ); + assert.equal( secondLeader.get(), 'secondLeaderUpdated' ); + + follower.unlink( firstLeader, secondLeader ); + firstLeader.set( 'firstLeaderUpdatedAgain' ); + secondLeader.set( 'secondLeaderUpdatedAgain' ); + assert.equal( follower.get(), 'followerUpdated', 'Value stops following once unlinked.' ); + }); + + QUnit.test( '.sync() keeps values updated in both directions, and .unsync() stops them', function( assert ) { + var first = new wp.customize.Value( 'firstValue' ), + second = new wp.customize.Value( 'secondValue' ); + + first.sync( second ); + + second.set( 'setOnSecond' ); + assert.equal( first.get(), 'setOnSecond' ); + + first.set( 'setOnFirst' ); + assert.equal( second.get(), 'setOnFirst' ); + + first.unsync( second ); + + // Both directions have to stop, so check each of them. + second.set( 'setOnSecondAgain' ); + assert.equal( first.get(), 'setOnFirst', 'First value stops following the second once unsynced.' ); + first.set( 'setOnFirstAgain' ); + assert.equal( second.get(), 'setOnSecondAgain', 'Second value stops following the first once unsynced.' ); + }); + QUnit.module( 'Customize Base: Values Class' ); valuesInstance = new wp.customize.Values(); @@ -205,6 +329,44 @@ jQuery( function( $ ) { assert.ok( ! wasEventFiredOnRemoval ); }); + QUnit.test( '.create() passes the extra arguments to the new value\'s initialize()', function( assert ) { + var collection = new wp.customize.Values(); + + collection.create( 'createdValue', 'suppliedInitialValue', { extraProp: 'extraPropValue' } ); + + assert.ok( collection.has( 'createdValue' ) ); + assert.equal( collection( 'createdValue' ).get(), 'suppliedInitialValue' ); + assert.equal( collection( 'createdValue' ).extraProp, 'extraPropValue' ); + }); + + QUnit.test( '.when() invokes the callback once every requested value exists', function( assert ) { + var collection = new wp.customize.Values(), + passedValues = null; + + collection.add( 'existingValue', new wp.customize.Value( 'existingValueContents' ) ); + + collection.when( 'existingValue', 'pendingValue', function( existingValue, pendingValue ) { + passedValues = [ existingValue.get(), pendingValue.get() ]; + } ); + + assert.equal( passedValues, null, 'Callback waits for the value that does not exist yet.' ); + + collection.add( 'pendingValue', new wp.customize.Value( 'pendingValueContents' ) ); + + /* + * The promise returned by when() resolves by way of a timer, and this + * suite wraps every test with sinon's fake timers, so the clock has to + * be advanced before the callback runs. + */ + this.clock.tick( 10 ); + + assert.deepEqual( + passedValues, + [ 'existingValueContents', 'pendingValueContents' ], + 'Callback is invoked with every requested value.' + ); + }); + QUnit.module( 'Customize Base: Notification' ); QUnit.test( 'Notification object exists and has expected properties', function ( assert ) { var notification = new wp.customize.Notification( 'mycode', {