Diff: STRATO-apps/wordpress_03/app/wp-includes/js/customize-base.js

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
1 + /**
2 + * @output wp-includes/js/customize-base.js
3 + */
4 +
5 + /** @namespace wp */
6 + window.wp = window.wp || {};
7 +
8 + (function( exports, $ ){
9 + var api = {}, ctor, inherits,
10 + slice = Array.prototype.slice;
11 +
12 + // Shared empty constructor function to aid in prototype-chain creation.
13 + ctor = function() {};
14 +
15 + /**
16 + * Helper function to correctly set up the prototype chain, for subclasses.
17 + * Similar to `goog.inherits`, but uses a hash of prototype properties and
18 + * class properties to be extended.
19 + *
20 + * @param object parent Parent class constructor to inherit from.
21 + * @param object protoProps Properties to apply to the prototype for use as class instance properties.
22 + * @param object staticProps Properties to apply directly to the class constructor.
23 + * @return child The subclassed constructor.
24 + */
25 + inherits = function( parent, protoProps, staticProps ) {
26 + var child;
27 +
28 + /*
29 + * The constructor function for the new subclass is either defined by you
30 + * (the "constructor" property in your `extend` definition), or defaulted
31 + * by us to simply call `super()`.
32 + */
33 + if ( protoProps && protoProps.hasOwnProperty( 'constructor' ) ) {
34 + child = protoProps.constructor;
35 + } else {
36 + child = function() {
37 + /*
38 + * Storing the result `super()` before returning the value
39 + * prevents a bug in Opera where, if the constructor returns
40 + * a function, Opera will reject the return value in favor of
41 + * the original object. This causes all sorts of trouble.
42 + */
43 + var result = parent.apply( this, arguments );
44 + return result;
45 + };
46 + }
47 +
48 + // Inherit class (static) properties from parent.
49 + $.extend( child, parent );
50 +
51 + // Set the prototype chain to inherit from `parent`,
52 + // without calling `parent`'s constructor function.
53 + ctor.prototype = parent.prototype;
54 + child.prototype = new ctor();
55 +
56 + // Add prototype properties (instance properties) to the subclass,
57 + // if supplied.
58 + if ( protoProps ) {
59 + $.extend( child.prototype, protoProps );
60 + }
61 +
62 + // Add static properties to the constructor function, if supplied.
63 + if ( staticProps ) {
64 + $.extend( child, staticProps );
65 + }
66 +
67 + // Correctly set child's `prototype.constructor`.
68 + child.prototype.constructor = child;
69 +
70 + // Set a convenience property in case the parent's prototype is needed later.
71 + child.__super__ = parent.prototype;
72 +
73 + return child;
74 + };
75 +
76 + /**
77 + * Base class for object inheritance.
78 + */
79 + api.Class = function( applicator, argsArray, options ) {
80 + var magic, args = arguments;
81 +
82 + if ( applicator && argsArray && api.Class.applicator === applicator ) {
83 + args = argsArray;
84 + $.extend( this, options || {} );
85 + }
86 +
87 + magic = this;
88 +
89 + /*
90 + * If the class has a method called "instance",
91 + * the return value from the class' constructor will be a function that
92 + * calls the "instance" method.
93 + *
94 + * It is also an object that has properties and methods inside it.
95 + */
96 + if ( this.instance ) {
97 + magic = function() {
98 + return magic.instance.apply( magic, arguments );
99 + };
100 +
101 + $.extend( magic, this );
102 + }
103 +
104 + magic.initialize.apply( magic, args );
105 + return magic;
106 + };
107 +
108 + /**
109 + * Creates a subclass of the class.
110 + *
111 + * @param object protoProps Properties to apply to the prototype.
112 + * @param object staticProps Properties to apply directly to the class.
113 + * @return child The subclass.
114 + */
115 + api.Class.extend = function( protoProps, staticProps ) {
116 + var child = inherits( this, protoProps, staticProps );
117 + child.extend = this.extend;
118 + return child;
119 + };
120 +
121 + api.Class.applicator = {};
122 +
123 + /**
124 + * Initialize a class instance.
125 + *
126 + * Override this function in a subclass as needed.
127 + */
128 + api.Class.prototype.initialize = function() {};
129 +
130 + /*
131 + * Checks whether a given instance extended a constructor.
132 + *
133 + * The magic surrounding the instance parameter causes the instanceof
134 + * keyword to return inaccurate results; it defaults to the function's
135 + * prototype instead of the constructor chain. Hence this function.
136 + */
137 + api.Class.prototype.extended = function( constructor ) {
138 + var proto = this;
139 +
140 + while ( typeof proto.constructor !== 'undefined' ) {
141 + if ( proto.constructor === constructor ) {
142 + return true;
143 + }
144 + if ( typeof proto.constructor.__super__ === 'undefined' ) {
145 + return false;
146 + }
147 + proto = proto.constructor.__super__;
148 + }
149 + return false;
150 + };
151 +
152 + /**
153 + * An events manager object, offering the ability to bind to and trigger events.
154 + *
155 + * Used as a mixin.
156 + */
157 + api.Events = {
158 + trigger: function( id ) {
159 + if ( this.topics && this.topics[ id ] ) {
160 + this.topics[ id ].fireWith( this, slice.call( arguments, 1 ) );
161 + }
162 + return this;
163 + },
164 +
165 + bind: function( id ) {
166 + this.topics = this.topics || {};
167 + this.topics[ id ] = this.topics[ id ] || $.Callbacks();
168 + this.topics[ id ].add.apply( this.topics[ id ], slice.call( arguments, 1 ) );
169 + return this;
170 + },
171 +
172 + unbind: function( id ) {
173 + if ( this.topics && this.topics[ id ] ) {
174 + this.topics[ id ].remove.apply( this.topics[ id ], slice.call( arguments, 1 ) );
175 + }
176 + return this;
177 + }
178 + };
179 +
180 + /**
181 + * Observable values that support two-way binding.
182 + *
183 + * @memberOf wp.customize
184 + * @alias wp.customize.Value
185 + *
186 + * @constructor
187 + */
188 + api.Value = api.Class.extend(/** @lends wp.customize.Value.prototype */{
189 + /**
190 + * @param {mixed} initial The initial value.
191 + * @param {Object} options
192 + */
193 + initialize: function( initial, options ) {
194 + this._value = initial; // @todo Potentially change this to a this.set() call.
195 + this.callbacks = $.Callbacks();
196 + this._dirty = false;
197 +
198 + $.extend( this, options || {} );
199 +
200 + this.set = this.set.bind( this );
201 + },
202 +
203 + /*
204 + * Magic. Returns a function that will become the instance.
205 + * Set to null to prevent the instance from extending a function.
206 + */
207 + instance: function() {
208 + return arguments.length ? this.set.apply( this, arguments ) : this.get();
209 + },
210 +
211 + /**
212 + * Get the value.
213 + *
214 + * @return {mixed}
215 + */
216 + get: function() {
217 + return this._value;
218 + },
219 +
220 + /**
221 + * Set the value and trigger all bound callbacks.
222 + *
223 + * @param {Object} to New value.
224 + */
225 + set: function( to ) {
226 + var from = this._value;
227 +
228 + to = this._setter.apply( this, arguments );
229 + to = this.validate( to );
230 +
231 + // Bail if the sanitized value is null or unchanged.
232 + if ( null === to || _.isEqual( from, to ) ) {
233 + return this;
234 + }
235 +
236 + this._value = to;
237 + this._dirty = true;
238 +
239 + this.callbacks.fireWith( this, [ to, from ] );
240 +
241 + return this;
242 + },
243 +
244 + _setter: function( to ) {
245 + return to;
246 + },
247 +
248 + setter: function( callback ) {
249 + var from = this.get();
250 + this._setter = callback;
251 + // Temporarily clear value so setter can decide if it's valid.
252 + this._value = null;
253 + this.set( from );
254 + return this;
255 + },
256 +
257 + resetSetter: function() {
258 + this._setter = this.constructor.prototype._setter;
259 + this.set( this.get() );
260 + return this;
261 + },
262 +
263 + validate: function( value ) {
264 + return value;
265 + },
266 +
267 + /**
268 + * Bind a function to be invoked whenever the value changes.
269 + *
270 + * @param {...Function} A function, or multiple functions, to add to the callback stack.
271 + */
272 + bind: function() {
273 + this.callbacks.add.apply( this.callbacks, arguments );
274 + return this;
275 + },
276 +
277 + /**
278 + * Unbind a previously bound function.
279 + *
280 + * @param {...Function} A function, or multiple functions, to remove from the callback stack.
281 + */
282 + unbind: function() {
283 + this.callbacks.remove.apply( this.callbacks, arguments );
284 + return this;
285 + },
286 +
287 + link: function() { // values*
288 + var set = this.set;
289 + $.each( arguments, function() {
290 + this.bind( set );
291 + });
292 + return this;
293 + },
294 +
295 + unlink: function() { // values*
296 + var set = this.set;
297 + $.each( arguments, function() {
298 + this.unbind( set );
299 + });
300 + return this;
301 + },
302 +
303 + sync: function() { // values*
304 + var that = this;
305 + $.each( arguments, function() {
306 + that.link( this );
307 + this.link( that );
308 + });
309 + return this;
310 + },
311 +
312 + unsync: function() { // values*
313 + var that = this;
314 + $.each( arguments, function() {
315 + that.unlink( this );
316 + this.unlink( that );
317 + });
318 + return this;
319 + }
320 + });
321 +
322 + /**
323 + * A collection of observable values.
324 + *
325 + * @memberOf wp.customize
326 + * @alias wp.customize.Values
327 + *
328 + * @constructor
329 + * @augments wp.customize.Class
330 + * @mixes wp.customize.Events
331 + */
332 + api.Values = api.Class.extend(/** @lends wp.customize.Values.prototype */{
333 +
334 + /**
335 + * The default constructor for items of the collection.
336 + *
337 + * @type {object}
338 + */
339 + defaultConstructor: api.Value,
340 +
341 + initialize: function( options ) {
342 + $.extend( this, options || {} );
343 +
344 + this._value = {};
345 + this._deferreds = {};
346 + },
347 +
348 + /**
349 + * Get the instance of an item from the collection if only ID is specified.
350 + *
351 + * If more than one argument is supplied, all are expected to be IDs and
352 + * the last to be a function callback that will be invoked when the requested
353 + * items are available.
354 + *
355 + * @see {api.Values.when}
356 + *
357 + * @param {string} id ID of the item.
358 + * @param {...} Zero or more IDs of items to wait for and a callback
359 + * function to invoke when they're available. Optional.
360 + * @return {mixed} The item instance if only one ID was supplied.
361 + * A Deferred Promise object if a callback function is supplied.
362 + */
363 + instance: function( id ) {
364 + if ( arguments.length === 1 ) {
365 + return this.value( id );
366 + }
367 +
368 + return this.when.apply( this, arguments );
369 + },
370 +
371 + /**
372 + * Get the instance of an item.
373 + *
374 + * @param {string} id The ID of the item.
375 + * @return {[type]} [description]
376 + */
377 + value: function( id ) {
378 + return this._value[ id ];
379 + },
380 +
381 + /**
382 + * Whether the collection has an item with the given ID.
383 + *
384 + * @param {string} id The ID of the item to look for.
385 + * @return {boolean}
386 + */
387 + has: function( id ) {
388 + return typeof this._value[ id ] !== 'undefined';
389 + },
390 +
391 + /**
392 + * Add an item to the collection.
393 + *
394 + * @param {string|wp.customize.Class} item - The item instance to add, or the ID for the instance to add.
395 + * When an ID string is supplied, then itemObject must be provided.
396 + * @param {wp.customize.Class} [itemObject] - The item instance when the first argument is an ID string.
397 + * @return {wp.customize.Class} The new item's instance, or an existing instance if already added.
398 + */
399 + add: function( item, itemObject ) {
400 + var collection = this, id, instance;
401 + if ( 'string' === typeof item ) {
402 + id = item;
403 + instance = itemObject;
404 + } else {
405 + if ( 'string' !== typeof item.id ) {
406 + throw new Error( 'Unknown key' );
407 + }
408 + id = item.id;
409 + instance = item;
410 + }
411 +
412 + if ( collection.has( id ) ) {
413 + return collection.value( id );
414 + }
415 +
416 + collection._value[ id ] = instance;
417 + instance.parent = collection;
418 +
419 + // Propagate a 'change' event on an item up to the collection.
420 + if ( instance.extended( api.Value ) ) {
421 + instance.bind( collection._change );
422 + }
423 +
424 + collection.trigger( 'add', instance );
425 +
426 + // If a deferred object exists for this item,
427 + // resolve it.
428 + if ( collection._deferreds[ id ] ) {
429 + collection._deferreds[ id ].resolve();
430 + }
431 +
432 + return collection._value[ id ];
433 + },
434 +
435 + /**
436 + * Create a new item of the collection using the collection's default constructor
437 + * and store it in the collection.
438 + *
439 + * @param {string} id The ID of the item.
440 + * @param {mixed} value Any extra arguments are passed into the item's initialize method.
441 + * @return {mixed} The new item's instance.
442 + */
443 + create: function( id ) {
444 + return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) );
445 + },
446 +
447 + /**
448 + * Iterate over all items in the collection invoking the provided callback.
449 + *
450 + * @param {Function} callback Function to invoke.
451 + * @param {Object} context Object context to invoke the function with. Optional.
452 + */
453 + each: function( callback, context ) {
454 + context = typeof context === 'undefined' ? this : context;
455 +
456 + $.each( this._value, function( key, obj ) {
457 + callback.call( context, obj, key );
458 + });
459 + },
460 +
461 + /**
462 + * Remove an item from the collection.
463 + *
464 + * @param {string} id The ID of the item to remove.
465 + */
466 + remove: function( id ) {
467 + var value = this.value( id );
468 +
469 + if ( value ) {
470 +
471 + // Trigger event right before the element is removed from the collection.
472 + this.trigger( 'remove', value );
473 +
474 + if ( value.extended( api.Value ) ) {
475 + value.unbind( this._change );
476 + }
477 + delete value.parent;
478 + }
479 +
480 + delete this._value[ id ];
481 + delete this._deferreds[ id ];
482 +
483 + // Trigger removed event after the item has been eliminated from the collection.
484 + if ( value ) {
485 + this.trigger( 'removed', value );
486 + }
487 + },
488 +
489 + /**
490 + * Runs a callback once all requested values exist.
491 + *
492 + * when( ids*, [callback] );
493 + *
494 + * For example:
495 + * when( id1, id2, id3, function( value1, value2, value3 ) {} );
496 + *
497 + * @return $.Deferred.promise();
498 + */
499 + when: function() {
500 + var self = this,
501 + ids = slice.call( arguments ),
502 + dfd = $.Deferred();
503 +
504 + // If the last argument is a callback, bind it to .done().
505 + if ( typeof ids[ ids.length - 1 ] === 'function' ) {
506 + dfd.done( ids.pop() );
507 + }
508 +
509 + /*
510 + * Create a stack of deferred objects for each item that is not
511 + * yet available, and invoke the supplied callback when they are.
512 + */
513 + $.when.apply( $, $.map( ids, function( id ) {
514 + if ( self.has( id ) ) {
515 + return;
516 + }
517 +
518 + /*
519 + * The requested item is not available yet, create a deferred
520 + * object to resolve when it becomes available.
521 + */
522 + return self._deferreds[ id ] = self._deferreds[ id ] || $.Deferred();
523 + })).done( function() {
524 + var values = $.map( ids, function( id ) {
525 + return self( id );
526 + });
527 +
528 + // If a value is missing, we've used at least one expired deferred.
529 + // Call Values.when again to generate a new deferred.
530 + if ( values.length !== ids.length ) {
531 + // ids.push( callback );
532 + self.when.apply( self, ids ).done( function() {
533 + dfd.resolveWith( self, values );
534 + });
535 + return;
536 + }
537 +
538 + dfd.resolveWith( self, values );
539 + });
540 +
541 + return dfd.promise();
542 + },
543 +
544 + /**
545 + * A helper function to propagate a 'change' event from an item
546 + * to the collection itself.
547 + */
548 + _change: function() {
549 + this.parent.trigger( 'change', this );
550 + }
551 + });
552 +
553 + // Create a global events bus on the Customizer.
554 + $.extend( api.Values.prototype, api.Events );
555 +
556 +
557 + /**
558 + * Cast a string to a jQuery collection if it isn't already.
559 + *
560 + * @param {string|jQuery collection} element
561 + */
562 + api.ensure = function( element ) {
563 + return typeof element === 'string' ? $( element ) : element;
564 + };
565 +
566 + /**
567 + * An observable value that syncs with an element.
568 + *
569 + * Handles inputs, selects, and textareas by default.
570 + *
571 + * @memberOf wp.customize
572 + * @alias wp.customize.Element
573 + *
574 + * @constructor
575 + * @augments wp.customize.Value
576 + * @augments wp.customize.Class
577 + */
578 + api.Element = api.Value.extend(/** @lends wp.customize.Element */{
579 + initialize: function( element, options ) {
580 + var self = this,
581 + synchronizer = api.Element.synchronizer.html,
582 + type, update, refresh;
583 +
584 + this.element = api.ensure( element );
585 + this.events = '';
586 +
587 + if ( this.element.is( 'input, select, textarea' ) ) {
588 + type = this.element.prop( 'type' );
589 + this.events += ' change input';
590 + synchronizer = api.Element.synchronizer.val;
591 +
592 + if ( this.element.is( 'input' ) && api.Element.synchronizer[ type ] ) {
593 + synchronizer = api.Element.synchronizer[ type ];
594 + }
595 + }
596 +
597 + api.Value.prototype.initialize.call( this, null, $.extend( options || {}, synchronizer ) );
598 + this._value = this.get();
599 +
600 + update = this.update;
601 + refresh = this.refresh;
602 +
603 + this.update = function( to ) {
604 + if ( to !== refresh.call( self ) ) {
605 + update.apply( this, arguments );
606 + }
607 + };
608 + this.refresh = function() {
609 + self.set( refresh.call( self ) );
610 + };
611 +
612 + this.bind( this.update );
613 + this.element.on( this.events, this.refresh );
614 + },
615 +
616 + find: function( selector ) {
617 + return $( selector, this.element );
618 + },
619 +
620 + refresh: function() {},
621 +
622 + update: function() {}
623 + });
624 +
625 + api.Element.synchronizer = {};
626 +
627 + $.each( [ 'html', 'val' ], function( index, method ) {
628 + api.Element.synchronizer[ method ] = {
629 + update: function( to ) {
630 + this.element[ method ]( to );
631 + },
632 + refresh: function() {
633 + return this.element[ method ]();
634 + }
635 + };
636 + });
637 +
638 + api.Element.synchronizer.checkbox = {
639 + update: function( to ) {
640 + this.element.prop( 'checked', to );
641 + },
642 + refresh: function() {
643 + return this.element.prop( 'checked' );
644 + }
645 + };
646 +
647 + api.Element.synchronizer.radio = {
648 + update: function( to ) {
649 + this.element.filter( function() {
650 + return this.value === to;
651 + }).prop( 'checked', true );
652 + },
653 + refresh: function() {
654 + return this.element.filter( ':checked' ).val();
655 + }
656 + };
657 +
658 + $.support.postMessage = !! window.postMessage;
659 +
660 + /**
661 + * A communicator for sending data from one window to another over postMessage.
662 + *
663 + * @memberOf wp.customize
664 + * @alias wp.customize.Messenger
665 + *
666 + * @constructor
667 + * @augments wp.customize.Class
668 + * @mixes wp.customize.Events
669 + */
670 + api.Messenger = api.Class.extend(/** @lends wp.customize.Messenger.prototype */{
671 + /**
672 + * Create a new Value.
673 + *
674 + * @param {string} key Unique identifier.
675 + * @param {mixed} initial Initial value.
676 + * @param {mixed} options Options hash. Optional.
677 + * @return {Value} Class instance of the Value.
678 + */
679 + add: function( key, initial, options ) {
680 + return this[ key ] = new api.Value( initial, options );
681 + },
682 +
683 + /**
684 + * Initialize Messenger.
685 + *
686 + * @param {Object} params - Parameters to configure the messenger.
687 + * {string} params.url - The URL to communicate with.
688 + * {window} params.targetWindow - The window instance to communicate with. Default window.parent.
689 + * {string} params.channel - If provided, will send the channel with each message and only accept messages a matching channel.
690 + * @param {Object} options - Extend any instance parameter or method with this object.
691 + */
692 + initialize: function( params, options ) {
693 + // Target the parent frame by default, but only if a parent frame exists.
694 + var defaultTarget = window.parent === window ? null : window.parent;
695 +
696 + $.extend( this, options || {} );
697 +
698 + this.add( 'channel', params.channel );
699 + this.add( 'url', params.url || '' );
700 + this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
701 + var urlParser = document.createElement( 'a' );
702 + urlParser.href = to;
703 + // Port stripping needed by IE since it adds to host but not to event.origin.
704 + return urlParser.protocol + '//' + urlParser.host.replace( /:(80|443)$/, '' );
705 + });
706 +
707 + // First add with no value.
708 + this.add( 'targetWindow', null );
709 + // This avoids SecurityErrors when setting a window object in x-origin iframe'd scenarios.
710 + this.targetWindow.set = function( to ) {
711 + var from = this._value;
712 +
713 + to = this._setter.apply( this, arguments );
714 + to = this.validate( to );
715 +
716 + if ( null === to || from === to ) {
717 + return this;
718 + }
719 +
720 + this._value = to;
721 + this._dirty = true;
722 +
723 + this.callbacks.fireWith( this, [ to, from ] );
724 +
725 + return this;
726 + };
727 + // Now set it.
728 + this.targetWindow( params.targetWindow || defaultTarget );
729 +
730 +
731 + /*
732 + * Since we want jQuery to treat the receive function as unique
733 + * to this instance, we give the function a new guid.
734 + *
735 + * This will prevent every Messenger's receive function from being
736 + * unbound when calling $.off( 'message', this.receive );
737 + */
738 + this.receive = this.receive.bind( this );
739 + this.receive.guid = $.guid++;
740 +
741 + $( window ).on( 'message', this.receive );
742 + },
743 +
744 + destroy: function() {
745 + $( window ).off( 'message', this.receive );
746 + },
747 +
748 + /**
749 + * Receive data from the other window.
750 + *
751 + * @param {jQuery.Event} event Event with embedded data.
752 + */
753 + receive: function( event ) {
754 + var message;
755 +
756 + event = event.originalEvent;
757 +
758 + if ( ! this.targetWindow || ! this.targetWindow() ) {
759 + return;
760 + }
761 +
762 + // Check to make sure the origin is valid.
763 + if ( this.origin() && event.origin !== this.origin() ) {
764 + return;
765 + }
766 +
767 + // Ensure we have a string that's JSON.parse-able.
768 + if ( typeof event.data !== 'string' || event.data[0] !== '{' ) {
769 + return;
770 + }
771 +
772 + message = JSON.parse( event.data );
773 +
774 + // Check required message properties.
775 + if ( ! message || ! message.id || typeof message.data === 'undefined' ) {
776 + return;
777 + }
778 +
779 + // Check if channel names match.
780 + if ( ( message.channel || this.channel() ) && this.channel() !== message.channel ) {
781 + return;
782 + }
783 +
784 + this.trigger( message.id, message.data );
785 + },
786 +
787 + /**
788 + * Send data to the other window.
789 + *
790 + * @param {string} id The event name.
791 + * @param {Object} data Data.
792 + */
793 + send: function( id, data ) {
794 + var message;
795 +
796 + data = typeof data === 'undefined' ? null : data;
797 +
798 + if ( ! this.url() || ! this.targetWindow() ) {
799 + return;
800 + }
801 +
802 + message = { id: id, data: data };
803 + if ( this.channel() ) {
804 + message.channel = this.channel();
805 + }
806 +
807 + this.targetWindow().postMessage( JSON.stringify( message ), this.origin() );
808 + }
809 + });
810 +
811 + // Add the Events mixin to api.Messenger.
812 + $.extend( api.Messenger.prototype, api.Events );
813 +
814 + /**
815 + * Notification.
816 + *
817 + * @class
818 + * @augments wp.customize.Class
819 + * @since 4.6.0
820 + *
821 + * @memberOf wp.customize
822 + * @alias wp.customize.Notification
823 + *
824 + * @param {string} code - The error code.
825 + * @param {object} params - Params.
826 + * @param {string} params.message=null - The error message.
827 + * @param {string} [params.type=error] - The notification type.
828 + * @param {boolean} [params.fromServer=false] - Whether the notification was server-sent.
829 + * @param {string} [params.setting=null] - The setting ID that the notification is related to.
830 + * @param {*} [params.data=null] - Any additional data.
831 + */
832 + api.Notification = api.Class.extend(/** @lends wp.customize.Notification.prototype */{
833 +
834 + /**
835 + * Template function for rendering the notification.
836 + *
837 + * This will be populated with template option or else it will be populated with template from the ID.
838 + *
839 + * @since 4.9.0
840 + * @var {Function}
841 + */
842 + template: null,
843 +
844 + /**
845 + * ID for the template to render the notification.
846 + *
847 + * @since 4.9.0
848 + * @var {string}
849 + */
850 + templateId: 'customize-notification',
851 +
852 + /**
853 + * Additional class names to add to the notification container.
854 + *
855 + * @since 4.9.0
856 + * @var {string}
857 + */
858 + containerClasses: '',
859 +
860 + /**
861 + * Initialize notification.
862 + *
863 + * @since 4.9.0
864 + *
865 + * @param {string} code - Notification code.
866 + * @param {Object} params - Notification parameters.
867 + * @param {string} params.message - Message.
868 + * @param {string} [params.type=error] - Type.
869 + * @param {string} [params.setting] - Related setting ID.
870 + * @param {Function} [params.template] - Function for rendering template. If not provided, this will come from templateId.
871 + * @param {string} [params.templateId] - ID for template to render the notification.
872 + * @param {string} [params.containerClasses] - Additional class names to add to the notification container.
873 + * @param {boolean} [params.dismissible] - Whether the notification can be dismissed.
874 + */
875 + initialize: function( code, params ) {
876 + var _params;
877 + this.code = code;
878 + _params = _.extend(
879 + {
880 + message: null,
881 + type: 'error',
882 + fromServer: false,
883 + data: null,
884 + setting: null,
885 + template: null,
886 + dismissible: false,
887 + containerClasses: ''
888 + },
889 + params
890 + );
891 + delete _params.code;
892 + _.extend( this, _params );
893 + },
894 +
895 + /**
896 + * Render the notification.
897 + *
898 + * @since 4.9.0
899 + *
900 + * @return {jQuery} Notification container element.
901 + */
902 + render: function() {
903 + var notification = this, container, data;
904 + if ( ! notification.template ) {
905 + notification.template = wp.template( notification.templateId );
906 + }
907 + data = _.extend( {}, notification, {
908 + alt: notification.parent && notification.parent.alt
909 + } );
910 + container = $( notification.template( data ) );
911 +
912 + if ( notification.dismissible ) {
913 + container.find( '.notice-dismiss' ).on( 'click keydown', function( event ) {
914 + if ( 'keydown' === event.type && 13 !== event.which ) {
915 + return;
916 + }
917 +
918 + if ( notification.parent ) {
919 + notification.parent.remove( notification.code );
920 + } else {
921 + container.remove();
922 + }
923 + });
924 + }
925 +
926 + return container;
927 + }
928 + });
929 +
930 + // The main API object is also a collection of all customizer settings.
931 + api = $.extend( new api.Values(), api );
932 +
933 + /**
934 + * Get all customize settings.
935 + *
936 + * @alias wp.customize.get
937 + *
938 + * @return {Object}
939 + */
940 + api.get = function() {
941 + var result = {};
942 +
943 + this.each( function( obj, key ) {
944 + result[ key ] = obj.get();
945 + });
946 +
947 + return result;
948 + };
949 +
950 + /**
951 + * Utility function namespace
952 + *
953 + * @namespace wp.customize.utils
954 + */
955 + api.utils = {};
956 +
957 + /**
958 + * Parse query string.
959 + *
960 + * @since 4.7.0
961 + * @access public
962 + *
963 + * @alias wp.customize.utils.parseQueryString
964 + *
965 + * @param {string} queryString Query string.
966 + * @return {Object} Parsed query string.
967 + */
968 + api.utils.parseQueryString = function parseQueryString( queryString ) {
969 + var queryParams = {};
970 + _.each( queryString.split( '&' ), function( pair ) {
971 + var parts, key, value;
972 + parts = pair.split( '=', 2 );
973 + if ( ! parts[0] ) {
974 + return;
975 + }
976 + key = decodeURIComponent( parts[0].replace( /\+/g, ' ' ) );
977 + key = key.replace( / /g, '_' ); // What PHP does.
978 + if ( _.isUndefined( parts[1] ) ) {
979 + value = null;
980 + } else {
981 + value = decodeURIComponent( parts[1].replace( /\+/g, ' ' ) );
982 + }
983 + queryParams[ key ] = value;
984 + } );
985 + return queryParams;
986 + };
987 +
988 + /**
989 + * Expose the API publicly on window.wp.customize
990 + *
991 + * @namespace wp.customize
992 + */
993 + exports.customize = api;
994 + })( wp, jQuery );
995 +