summaryrefslogtreecommitdiffstats
path: root/wp-includes/js/customize-base.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:56:49 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 07:56:49 +0000
commita415c29efee45520ae252d2aa28f1083a521cd7b (patch)
treef4ade4b6668ecc0765de7e1424f7c1427ad433ff /wp-includes/js/customize-base.js
parentInitial commit. (diff)
downloadwordpress-a415c29efee45520ae252d2aa28f1083a521cd7b.tar.xz
wordpress-a415c29efee45520ae252d2aa28f1083a521cd7b.zip
Adding upstream version 6.4.3+dfsg1.upstream/6.4.3+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'wp-includes/js/customize-base.js')
-rw-r--r--wp-includes/js/customize-base.js994
1 files changed, 994 insertions, 0 deletions
diff --git a/wp-includes/js/customize-base.js b/wp-includes/js/customize-base.js
new file mode 100644
index 0000000..4afaa94
--- /dev/null
+++ b/wp-includes/js/customize-base.js
@@ -0,0 +1,994 @@
+/**
+ * @output wp-includes/js/customize-base.js
+ */
+
+/** @namespace wp */
+window.wp = window.wp || {};
+
+(function( exports, $ ){
+ var api = {}, ctor, inherits,
+ slice = Array.prototype.slice;
+
+ // Shared empty constructor function to aid in prototype-chain creation.
+ ctor = function() {};
+
+ /**
+ * Helper function to correctly set up the prototype chain, for subclasses.
+ * Similar to `goog.inherits`, but uses a hash of prototype properties and
+ * class properties to be extended.
+ *
+ * @param object parent Parent class constructor to inherit from.
+ * @param object protoProps Properties to apply to the prototype for use as class instance properties.
+ * @param object staticProps Properties to apply directly to the class constructor.
+ * @return child The subclassed constructor.
+ */
+ inherits = function( parent, protoProps, staticProps ) {
+ var child;
+
+ /*
+ * The constructor function for the new subclass is either defined by you
+ * (the "constructor" property in your `extend` definition), or defaulted
+ * by us to simply call `super()`.
+ */
+ if ( protoProps && protoProps.hasOwnProperty( 'constructor' ) ) {
+ child = protoProps.constructor;
+ } else {
+ child = function() {
+ /*
+ * 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 );
+ return result;
+ };
+ }
+
+ // Inherit class (static) properties from parent.
+ $.extend( child, parent );
+
+ // Set the prototype chain to inherit from `parent`,
+ // without calling `parent`'s constructor function.
+ ctor.prototype = parent.prototype;
+ child.prototype = new ctor();
+
+ // Add prototype properties (instance properties) to the subclass,
+ // if supplied.
+ if ( protoProps ) {
+ $.extend( child.prototype, protoProps );
+ }
+
+ // Add static properties to the constructor function, if supplied.
+ if ( staticProps ) {
+ $.extend( child, staticProps );
+ }
+
+ // Correctly set child's `prototype.constructor`.
+ child.prototype.constructor = child;
+
+ // Set a convenience property in case the parent's prototype is needed later.
+ child.__super__ = parent.prototype;
+
+ return child;
+ };
+
+ /**
+ * Base class for object inheritance.
+ */
+ api.Class = function( applicator, argsArray, options ) {
+ var magic, args = arguments;
+
+ if ( applicator && argsArray && api.Class.applicator === applicator ) {
+ args = argsArray;
+ $.extend( this, options || {} );
+ }
+
+ magic = this;
+
+ /*
+ * If the class has a method called "instance",
+ * the return value from the class' constructor will be a function that
+ * calls the "instance" method.
+ *
+ * It is also an object that has properties and methods inside it.
+ */
+ if ( this.instance ) {
+ magic = function() {
+ return magic.instance.apply( magic, arguments );
+ };
+
+ $.extend( magic, this );
+ }
+
+ magic.initialize.apply( magic, args );
+ return magic;
+ };
+
+ /**
+ * Creates a subclass of the class.
+ *
+ * @param object protoProps Properties to apply to the prototype.
+ * @param object staticProps Properties to apply directly to the class.
+ * @return child The subclass.
+ */
+ api.Class.extend = function( protoProps, staticProps ) {
+ var child = inherits( this, protoProps, staticProps );
+ child.extend = this.extend;
+ return child;
+ };
+
+ api.Class.applicator = {};
+
+ /**
+ * Initialize a class instance.
+ *
+ * Override this function in a subclass as needed.
+ */
+ api.Class.prototype.initialize = function() {};
+
+ /*
+ * Checks whether a given instance extended a constructor.
+ *
+ * The magic surrounding the instance parameter causes the instanceof
+ * keyword to return inaccurate results; it defaults to the function's
+ * prototype instead of the constructor chain. Hence this function.
+ */
+ api.Class.prototype.extended = function( constructor ) {
+ var proto = this;
+
+ while ( typeof proto.constructor !== 'undefined' ) {
+ if ( proto.constructor === constructor ) {
+ return true;
+ }
+ if ( typeof proto.constructor.__super__ === 'undefined' ) {
+ return false;
+ }
+ proto = proto.constructor.__super__;
+ }
+ return false;
+ };
+
+ /**
+ * An events manager object, offering the ability to bind to and trigger events.
+ *
+ * Used as a mixin.
+ */
+ api.Events = {
+ trigger: function( id ) {
+ if ( this.topics && this.topics[ id ] ) {
+ this.topics[ id ].fireWith( this, slice.call( arguments, 1 ) );
+ }
+ return this;
+ },
+
+ bind: function( id ) {
+ this.topics = this.topics || {};
+ this.topics[ id ] = this.topics[ id ] || $.Callbacks();
+ this.topics[ id ].add.apply( this.topics[ id ], slice.call( arguments, 1 ) );
+ return this;
+ },
+
+ unbind: function( id ) {
+ if ( this.topics && this.topics[ id ] ) {
+ this.topics[ id ].remove.apply( this.topics[ id ], slice.call( arguments, 1 ) );
+ }
+ return this;
+ }
+ };
+
+ /**
+ * Observable values that support two-way binding.
+ *
+ * @memberOf wp.customize
+ * @alias wp.customize.Value
+ *
+ * @constructor
+ */
+ api.Value = api.Class.extend(/** @lends wp.customize.Value.prototype */{
+ /**
+ * @param {mixed} initial The initial value.
+ * @param {Object} options
+ */
+ initialize: function( initial, options ) {
+ this._value = initial; // @todo Potentially change this to a this.set() call.
+ this.callbacks = $.Callbacks();
+ this._dirty = false;
+
+ $.extend( this, options || {} );
+
+ this.set = this.set.bind( this );
+ },
+
+ /*
+ * 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();
+ },
+
+ /**
+ * Get the value.
+ *
+ * @return {mixed}
+ */
+ get: function() {
+ return this._value;
+ },
+
+ /**
+ * Set the value and trigger all bound callbacks.
+ *
+ * @param {Object} to New value.
+ */
+ set: function( to ) {
+ var from = this._value;
+
+ to = this._setter.apply( this, arguments );
+ to = this.validate( to );
+
+ // Bail if the sanitized value is null or unchanged.
+ if ( null === to || _.isEqual( from, to ) ) {
+ return this;
+ }
+
+ this._value = to;
+ this._dirty = true;
+
+ this.callbacks.fireWith( this, [ to, from ] );
+
+ return this;
+ },
+
+ _setter: function( to ) {
+ return to;
+ },
+
+ setter: function( callback ) {
+ var from = this.get();
+ this._setter = callback;
+ // Temporarily clear value so setter can decide if it's valid.
+ this._value = null;
+ this.set( from );
+ return this;
+ },
+
+ resetSetter: function() {
+ this._setter = this.constructor.prototype._setter;
+ this.set( this.get() );
+ return this;
+ },
+
+ validate: function( value ) {
+ return value;
+ },
+
+ /**
+ * Bind a function to be invoked whenever the value changes.
+ *
+ * @param {...Function} A function, or multiple functions, to add to the callback stack.
+ */
+ bind: function() {
+ this.callbacks.add.apply( this.callbacks, arguments );
+ return this;
+ },
+
+ /**
+ * Unbind a previously bound function.
+ *
+ * @param {...Function} A function, or multiple functions, to remove from the callback stack.
+ */
+ unbind: function() {
+ this.callbacks.remove.apply( this.callbacks, arguments );
+ return this;
+ },
+
+ link: function() { // values*
+ var set = this.set;
+ $.each( arguments, function() {
+ this.bind( set );
+ });
+ return this;
+ },
+
+ unlink: function() { // values*
+ var set = this.set;
+ $.each( arguments, function() {
+ this.unbind( set );
+ });
+ return this;
+ },
+
+ sync: function() { // values*
+ var that = this;
+ $.each( arguments, function() {
+ that.link( this );
+ this.link( that );
+ });
+ return this;
+ },
+
+ unsync: function() { // values*
+ var that = this;
+ $.each( arguments, function() {
+ that.unlink( this );
+ this.unlink( that );
+ });
+ return this;
+ }
+ });
+
+ /**
+ * A collection of observable values.
+ *
+ * @memberOf wp.customize
+ * @alias wp.customize.Values
+ *
+ * @constructor
+ * @augments wp.customize.Class
+ * @mixes wp.customize.Events
+ */
+ api.Values = api.Class.extend(/** @lends wp.customize.Values.prototype */{
+
+ /**
+ * The default constructor for items of the collection.
+ *
+ * @type {object}
+ */
+ defaultConstructor: api.Value,
+
+ initialize: function( options ) {
+ $.extend( this, options || {} );
+
+ this._value = {};
+ this._deferreds = {};
+ },
+
+ /**
+ * Get the instance of an item from the collection if only ID is specified.
+ *
+ * If more than one argument is supplied, all are expected to be IDs and
+ * the last to be a function callback that will be invoked when the requested
+ * items are available.
+ *
+ * @see {api.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.
+ */
+ instance: function( id ) {
+ if ( arguments.length === 1 ) {
+ return this.value( id );
+ }
+
+ return this.when.apply( this, arguments );
+ },
+
+ /**
+ * Get the instance of an item.
+ *
+ * @param {string} id The ID of the item.
+ * @return {[type]} [description]
+ */
+ value: function( id ) {
+ return this._value[ id ];
+ },
+
+ /**
+ * Whether the collection has an item with the given ID.
+ *
+ * @param {string} id The ID of the item to look for.
+ * @return {boolean}
+ */
+ has: function( id ) {
+ return typeof this._value[ id ] !== 'undefined';
+ },
+
+ /**
+ * 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.
+ * @return {wp.customize.Class} The new item's instance, or an existing instance if already added.
+ */
+ add: function( item, itemObject ) {
+ var collection = this, id, instance;
+ if ( 'string' === typeof item ) {
+ id = item;
+ instance = itemObject;
+ } else {
+ if ( 'string' !== typeof item.id ) {
+ throw new Error( 'Unknown key' );
+ }
+ id = item.id;
+ instance = item;
+ }
+
+ if ( collection.has( id ) ) {
+ return collection.value( id );
+ }
+
+ collection._value[ id ] = instance;
+ instance.parent = collection;
+
+ // Propagate a 'change' event on an item up to the collection.
+ if ( instance.extended( api.Value ) ) {
+ instance.bind( collection._change );
+ }
+
+ collection.trigger( 'add', instance );
+
+ // If a deferred object exists for this item,
+ // resolve it.
+ if ( collection._deferreds[ id ] ) {
+ collection._deferreds[ id ].resolve();
+ }
+
+ return collection._value[ id ];
+ },
+
+ /**
+ * 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.
+ */
+ create: function( id ) {
+ return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) );
+ },
+
+ /**
+ * 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.
+ */
+ each: function( callback, context ) {
+ context = typeof context === 'undefined' ? this : context;
+
+ $.each( this._value, function( key, obj ) {
+ callback.call( context, obj, key );
+ });
+ },
+
+ /**
+ * Remove an item from the collection.
+ *
+ * @param {string} id The ID of the item to remove.
+ */
+ remove: function( id ) {
+ var value = this.value( id );
+
+ if ( value ) {
+
+ // Trigger event right before the element is removed from the collection.
+ this.trigger( 'remove', value );
+
+ if ( value.extended( api.Value ) ) {
+ value.unbind( this._change );
+ }
+ delete value.parent;
+ }
+
+ delete this._value[ id ];
+ delete this._deferreds[ id ];
+
+ // Trigger removed event after the item has been eliminated from the collection.
+ if ( value ) {
+ this.trigger( 'removed', value );
+ }
+ },
+
+ /**
+ * Runs a callback once all requested values exist.
+ *
+ * when( ids*, [callback] );
+ *
+ * For example:
+ * when( id1, id2, id3, function( value1, value2, value3 ) {} );
+ *
+ * @return $.Deferred.promise();
+ */
+ when: function() {
+ var self = this,
+ ids = slice.call( arguments ),
+ dfd = $.Deferred();
+
+ // If the last argument is a callback, bind it to .done().
+ if ( typeof ids[ ids.length - 1 ] === 'function' ) {
+ dfd.done( ids.pop() );
+ }
+
+ /*
+ * Create a stack of deferred objects for each item that is not
+ * yet available, and invoke the supplied callback when they are.
+ */
+ $.when.apply( $, $.map( ids, function( id ) {
+ if ( self.has( id ) ) {
+ return;
+ }
+
+ /*
+ * The requested item is not available yet, create a deferred
+ * object to resolve when it becomes available.
+ */
+ return self._deferreds[ id ] = self._deferreds[ id ] || $.Deferred();
+ })).done( function() {
+ var values = $.map( ids, function( id ) {
+ return self( id );
+ });
+
+ // If a value is missing, we've used at least one expired deferred.
+ // Call Values.when again to generate a new deferred.
+ if ( values.length !== ids.length ) {
+ // ids.push( callback );
+ self.when.apply( self, ids ).done( function() {
+ dfd.resolveWith( self, values );
+ });
+ return;
+ }
+
+ dfd.resolveWith( self, values );
+ });
+
+ return dfd.promise();
+ },
+
+ /**
+ * A helper function to propagate a 'change' event from an item
+ * to the collection itself.
+ */
+ _change: function() {
+ this.parent.trigger( 'change', this );
+ }
+ });
+
+ // Create a global events bus on the Customizer.
+ $.extend( api.Values.prototype, api.Events );
+
+
+ /**
+ * Cast a string to a jQuery collection if it isn't already.
+ *
+ * @param {string|jQuery collection} element
+ */
+ api.ensure = function( element ) {
+ return typeof element === 'string' ? $( element ) : element;
+ };
+
+ /**
+ * An observable value that syncs with an element.
+ *
+ * Handles inputs, selects, and textareas by default.
+ *
+ * @memberOf wp.customize
+ * @alias wp.customize.Element
+ *
+ * @constructor
+ * @augments wp.customize.Value
+ * @augments wp.customize.Class
+ */
+ api.Element = api.Value.extend(/** @lends wp.customize.Element */{
+ initialize: function( element, options ) {
+ var self = this,
+ synchronizer = api.Element.synchronizer.html,
+ type, update, refresh;
+
+ this.element = api.ensure( element );
+ this.events = '';
+
+ if ( this.element.is( 'input, select, textarea' ) ) {
+ type = this.element.prop( 'type' );
+ this.events += ' change input';
+ synchronizer = api.Element.synchronizer.val;
+
+ if ( this.element.is( 'input' ) && api.Element.synchronizer[ type ] ) {
+ synchronizer = api.Element.synchronizer[ type ];
+ }
+ }
+
+ api.Value.prototype.initialize.call( this, null, $.extend( options || {}, synchronizer ) );
+ this._value = this.get();
+
+ update = this.update;
+ refresh = this.refresh;
+
+ this.update = function( to ) {
+ if ( to !== refresh.call( self ) ) {
+ update.apply( this, arguments );
+ }
+ };
+ this.refresh = function() {
+ self.set( refresh.call( self ) );
+ };
+
+ this.bind( this.update );
+ this.element.on( this.events, this.refresh );
+ },
+
+ find: function( selector ) {
+ return $( selector, this.element );
+ },
+
+ refresh: function() {},
+
+ update: function() {}
+ });
+
+ api.Element.synchronizer = {};
+
+ $.each( [ 'html', 'val' ], function( index, method ) {
+ api.Element.synchronizer[ method ] = {
+ update: function( to ) {
+ this.element[ method ]( to );
+ },
+ refresh: function() {
+ return this.element[ method ]();
+ }
+ };
+ });
+
+ api.Element.synchronizer.checkbox = {
+ update: function( to ) {
+ this.element.prop( 'checked', to );
+ },
+ refresh: function() {
+ return this.element.prop( 'checked' );
+ }
+ };
+
+ api.Element.synchronizer.radio = {
+ update: function( to ) {
+ this.element.filter( function() {
+ return this.value === to;
+ }).prop( 'checked', true );
+ },
+ refresh: function() {
+ return this.element.filter( ':checked' ).val();
+ }
+ };
+
+ $.support.postMessage = !! window.postMessage;
+
+ /**
+ * A communicator for sending data from one window to another over postMessage.
+ *
+ * @memberOf wp.customize
+ * @alias wp.customize.Messenger
+ *
+ * @constructor
+ * @augments wp.customize.Class
+ * @mixes wp.customize.Events
+ */
+ api.Messenger = api.Class.extend(/** @lends wp.customize.Messenger.prototype */{
+ /**
+ * Create a new Value.
+ *
+ * @param {string} key Unique identifier.
+ * @param {mixed} initial Initial value.
+ * @param {mixed} options Options hash. Optional.
+ * @return {Value} Class instance of the Value.
+ */
+ add: function( key, initial, options ) {
+ return this[ key ] = new api.Value( initial, options );
+ },
+
+ /**
+ * 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.
+ */
+ initialize: function( params, options ) {
+ // Target the parent frame by default, but only if a parent frame exists.
+ var defaultTarget = window.parent === window ? null : window.parent;
+
+ $.extend( this, options || {} );
+
+ this.add( 'channel', params.channel );
+ this.add( 'url', params.url || '' );
+ this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
+ var urlParser = document.createElement( 'a' );
+ urlParser.href = to;
+ // Port stripping needed by IE since it adds to host but not to event.origin.
+ return urlParser.protocol + '//' + urlParser.host.replace( /:(80|443)$/, '' );
+ });
+
+ // 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 ) {
+ var from = this._value;
+
+ to = this._setter.apply( this, arguments );
+ to = this.validate( to );
+
+ if ( null === to || from === to ) {
+ return this;
+ }
+
+ this._value = to;
+ this._dirty = true;
+
+ this.callbacks.fireWith( this, [ to, from ] );
+
+ return this;
+ };
+ // Now set it.
+ this.targetWindow( params.targetWindow || defaultTarget );
+
+
+ /*
+ * Since we want jQuery to treat the receive function as unique
+ * to this instance, we give the function a new guid.
+ *
+ * This will prevent every Messenger's receive function from being
+ * unbound when calling $.off( 'message', this.receive );
+ */
+ this.receive = this.receive.bind( this );
+ this.receive.guid = $.guid++;
+
+ $( window ).on( 'message', this.receive );
+ },
+
+ destroy: function() {
+ $( window ).off( 'message', this.receive );
+ },
+
+ /**
+ * Receive data from the other window.
+ *
+ * @param {jQuery.Event} event Event with embedded data.
+ */
+ receive: function( event ) {
+ var message;
+
+ event = event.originalEvent;
+
+ if ( ! this.targetWindow || ! this.targetWindow() ) {
+ return;
+ }
+
+ // Check to make sure the origin is valid.
+ if ( this.origin() && event.origin !== this.origin() ) {
+ return;
+ }
+
+ // Ensure we have a string that's JSON.parse-able.
+ if ( typeof event.data !== 'string' || event.data[0] !== '{' ) {
+ return;
+ }
+
+ message = JSON.parse( event.data );
+
+ // Check required message properties.
+ if ( ! message || ! message.id || typeof message.data === 'undefined' ) {
+ return;
+ }
+
+ // Check if channel names match.
+ if ( ( message.channel || this.channel() ) && this.channel() !== message.channel ) {
+ return;
+ }
+
+ this.trigger( message.id, message.data );
+ },
+
+ /**
+ * Send data to the other window.
+ *
+ * @param {string} id The event name.
+ * @param {Object} data Data.
+ */
+ send: function( id, data ) {
+ var message;
+
+ data = typeof data === 'undefined' ? null : data;
+
+ if ( ! this.url() || ! this.targetWindow() ) {
+ return;
+ }
+
+ message = { id: id, data: data };
+ if ( this.channel() ) {
+ message.channel = this.channel();
+ }
+
+ this.targetWindow().postMessage( JSON.stringify( message ), this.origin() );
+ }
+ });
+
+ // Add the Events mixin to api.Messenger.
+ $.extend( api.Messenger.prototype, api.Events );
+
+ /**
+ * Notification.
+ *
+ * @class
+ * @augments wp.customize.Class
+ * @since 4.6.0
+ *
+ * @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.
+ */
+ api.Notification = api.Class.extend(/** @lends wp.customize.Notification.prototype */{
+
+ /**
+ * Template function for rendering the notification.
+ *
+ * This will be populated with template option or else it will be populated with template from the ID.
+ *
+ * @since 4.9.0
+ * @var {Function}
+ */
+ template: null,
+
+ /**
+ * ID for the template to render the notification.
+ *
+ * @since 4.9.0
+ * @var {string}
+ */
+ templateId: 'customize-notification',
+
+ /**
+ * Additional class names to add to the notification container.
+ *
+ * @since 4.9.0
+ * @var {string}
+ */
+ containerClasses: '',
+
+ /**
+ * Initialize notification.
+ *
+ * @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.
+ */
+ initialize: function( code, params ) {
+ var _params;
+ this.code = code;
+ _params = _.extend(
+ {
+ message: null,
+ type: 'error',
+ fromServer: false,
+ data: null,
+ setting: null,
+ template: null,
+ dismissible: false,
+ containerClasses: ''
+ },
+ params
+ );
+ delete _params.code;
+ _.extend( this, _params );
+ },
+
+ /**
+ * Render the notification.
+ *
+ * @since 4.9.0
+ *
+ * @return {jQuery} Notification container element.
+ */
+ render: function() {
+ var notification = this, container, data;
+ if ( ! notification.template ) {
+ notification.template = wp.template( notification.templateId );
+ }
+ data = _.extend( {}, notification, {
+ alt: notification.parent && notification.parent.alt
+ } );
+ container = $( notification.template( data ) );
+
+ if ( notification.dismissible ) {
+ container.find( '.notice-dismiss' ).on( 'click keydown', function( event ) {
+ if ( 'keydown' === event.type && 13 !== event.which ) {
+ return;
+ }
+
+ if ( notification.parent ) {
+ notification.parent.remove( notification.code );
+ } else {
+ container.remove();
+ }
+ });
+ }
+
+ return container;
+ }
+ });
+
+ // The main API object is also a collection of all customizer settings.
+ api = $.extend( new api.Values(), api );
+
+ /**
+ * Get all customize settings.
+ *
+ * @alias wp.customize.get
+ *
+ * @return {Object}
+ */
+ api.get = function() {
+ var result = {};
+
+ this.each( function( obj, key ) {
+ result[ key ] = obj.get();
+ });
+
+ return result;
+ };
+
+ /**
+ * Utility function namespace
+ *
+ * @namespace wp.customize.utils
+ */
+ api.utils = {};
+
+ /**
+ * Parse query string.
+ *
+ * @since 4.7.0
+ * @access public
+ *
+ * @alias wp.customize.utils.parseQueryString
+ *
+ * @param {string} queryString Query string.
+ * @return {Object} Parsed query string.
+ */
+ api.utils.parseQueryString = function parseQueryString( queryString ) {
+ var queryParams = {};
+ _.each( queryString.split( '&' ), function( pair ) {
+ var parts, key, value;
+ parts = pair.split( '=', 2 );
+ if ( ! parts[0] ) {
+ return;
+ }
+ key = decodeURIComponent( parts[0].replace( /\+/g, ' ' ) );
+ key = key.replace( / /g, '_' ); // What PHP does.
+ if ( _.isUndefined( parts[1] ) ) {
+ value = null;
+ } else {
+ value = decodeURIComponent( parts[1].replace( /\+/g, ' ' ) );
+ }
+ queryParams[ key ] = value;
+ } );
+ return queryParams;
+ };
+
+ /**
+ * Expose the API publicly on window.wp.customize
+ *
+ * @namespace wp.customize
+ */
+ exports.customize = api;
+})( wp, jQuery );