[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/ -> customize-base.js (source)

   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, classProps ) {
 116          var child = inherits( this, protoProps, classProps );
 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 = $.proxy( this.set, 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. When an ID string is supplied, then itemObject must be provided.
 395           * @param {wp.customize.Class}        [itemObject] - The item instance when the first argument is a ID string.
 396           * @return {wp.customize.Class} The new item's instance, or an existing instance if already added.
 397           */
 398          add: function( item, itemObject ) {
 399              var collection = this, id, instance;
 400              if ( 'string' === typeof item ) {
 401                  id = item;
 402                  instance = itemObject;
 403              } else {
 404                  if ( 'string' !== typeof item.id ) {
 405                      throw new Error( 'Unknown key' );
 406                  }
 407                  id = item.id;
 408                  instance = item;
 409              }
 410  
 411              if ( collection.has( id ) ) {
 412                  return collection.value( id );
 413              }
 414  
 415              collection._value[ id ] = instance;
 416              instance.parent = collection;
 417  
 418              // Propagate a 'change' event on an item up to the collection.
 419              if ( instance.extended( api.Value ) ) {
 420                  instance.bind( collection._change );
 421              }
 422  
 423              collection.trigger( 'add', instance );
 424  
 425              // If a deferred object exists for this item,
 426              // resolve it.
 427              if ( collection._deferreds[ id ] ) {
 428                  collection._deferreds[ id ].resolve();
 429              }
 430  
 431              return collection._value[ id ];
 432          },
 433  
 434          /**
 435           * Create a new item of the collection using the collection's default constructor
 436           * and store it in the collection.
 437           *
 438           * @param {string} id    The ID of the item.
 439           * @param {mixed}  value Any extra arguments are passed into the item's initialize method.
 440           * @return {mixed} The new item's instance.
 441           */
 442          create: function( id ) {
 443              return this.add( id, new this.defaultConstructor( api.Class.applicator, slice.call( arguments, 1 ) ) );
 444          },
 445  
 446          /**
 447           * Iterate over all items in the collection invoking the provided callback.
 448           *
 449           * @param {Function} callback Function to invoke.
 450           * @param {Object}   context  Object context to invoke the function with. Optional.
 451           */
 452          each: function( callback, context ) {
 453              context = typeof context === 'undefined' ? this : context;
 454  
 455              $.each( this._value, function( key, obj ) {
 456                  callback.call( context, obj, key );
 457              });
 458          },
 459  
 460          /**
 461           * Remove an item from the collection.
 462           *
 463           * @param {string} id The ID of the item to remove.
 464           */
 465          remove: function( id ) {
 466              var value = this.value( id );
 467  
 468              if ( value ) {
 469  
 470                  // Trigger event right before the element is removed from the collection.
 471                  this.trigger( 'remove', value );
 472  
 473                  if ( value.extended( api.Value ) ) {
 474                      value.unbind( this._change );
 475                  }
 476                  delete value.parent;
 477              }
 478  
 479              delete this._value[ id ];
 480              delete this._deferreds[ id ];
 481  
 482              // Trigger removed event after the item has been eliminated from the collection.
 483              if ( value ) {
 484                  this.trigger( 'removed', value );
 485              }
 486          },
 487  
 488          /**
 489           * Runs a callback once all requested values exist.
 490           *
 491           * when( ids*, [callback] );
 492           *
 493           * For example:
 494           *     when( id1, id2, id3, function( value1, value2, value3 ) {} );
 495           *
 496           * @return $.Deferred.promise();
 497           */
 498          when: function() {
 499              var self = this,
 500                  ids  = slice.call( arguments ),
 501                  dfd  = $.Deferred();
 502  
 503              // If the last argument is a callback, bind it to .done().
 504              if ( $.isFunction( ids[ ids.length - 1 ] ) ) {
 505                  dfd.done( ids.pop() );
 506              }
 507  
 508              /*
 509               * Create a stack of deferred objects for each item that is not
 510               * yet available, and invoke the supplied callback when they are.
 511               */
 512              $.when.apply( $, $.map( ids, function( id ) {
 513                  if ( self.has( id ) ) {
 514                      return;
 515                  }
 516  
 517                  /*
 518                   * The requested item is not available yet, create a deferred
 519                   * object to resolve when it becomes available.
 520                   */
 521                  return self._deferreds[ id ] = self._deferreds[ id ] || $.Deferred();
 522              })).done( function() {
 523                  var values = $.map( ids, function( id ) {
 524                          return self( id );
 525                      });
 526  
 527                  // If a value is missing, we've used at least one expired deferred.
 528                  // Call Values.when again to generate a new deferred.
 529                  if ( values.length !== ids.length ) {
 530                      // ids.push( callback );
 531                      self.when.apply( self, ids ).done( function() {
 532                          dfd.resolveWith( self, values );
 533                      });
 534                      return;
 535                  }
 536  
 537                  dfd.resolveWith( self, values );
 538              });
 539  
 540              return dfd.promise();
 541          },
 542  
 543          /**
 544           * A helper function to propagate a 'change' event from an item
 545           * to the collection itself.
 546           */
 547          _change: function() {
 548              this.parent.trigger( 'change', this );
 549          }
 550      });
 551  
 552      // Create a global events bus on the Customizer.
 553      $.extend( api.Values.prototype, api.Events );
 554  
 555  
 556      /**
 557       * Cast a string to a jQuery collection if it isn't already.
 558       *
 559       * @param {string|jQuery collection} element
 560       */
 561      api.ensure = function( element ) {
 562          return typeof element === 'string' ? $( element ) : element;
 563      };
 564  
 565      /**
 566       * An observable value that syncs with an element.
 567       *
 568       * Handles inputs, selects, and textareas by default.
 569       *
 570       * @memberOf wp.customize
 571       * @alias wp.customize.Element
 572       *
 573       * @constructor
 574       * @augments wp.customize.Value
 575       * @augments wp.customize.Class
 576       */
 577      api.Element = api.Value.extend(/** @lends wp.customize.Element */{
 578          initialize: function( element, options ) {
 579              var self = this,
 580                  synchronizer = api.Element.synchronizer.html,
 581                  type, update, refresh;
 582  
 583              this.element = api.ensure( element );
 584              this.events = '';
 585  
 586              if ( this.element.is( 'input, select, textarea' ) ) {
 587                  type = this.element.prop( 'type' );
 588                  this.events += ' change input';
 589                  synchronizer = api.Element.synchronizer.val;
 590  
 591                  if ( this.element.is( 'input' ) && api.Element.synchronizer[ type ] ) {
 592                      synchronizer = api.Element.synchronizer[ type ];
 593                  }
 594              }
 595  
 596              api.Value.prototype.initialize.call( this, null, $.extend( options || {}, synchronizer ) );
 597              this._value = this.get();
 598  
 599              update = this.update;
 600              refresh = this.refresh;
 601  
 602              this.update = function( to ) {
 603                  if ( to !== refresh.call( self ) ) {
 604                      update.apply( this, arguments );
 605                  }
 606              };
 607              this.refresh = function() {
 608                  self.set( refresh.call( self ) );
 609              };
 610  
 611              this.bind( this.update );
 612              this.element.bind( this.events, this.refresh );
 613          },
 614  
 615          find: function( selector ) {
 616              return $( selector, this.element );
 617          },
 618  
 619          refresh: function() {},
 620  
 621          update: function() {}
 622      });
 623  
 624      api.Element.synchronizer = {};
 625  
 626      $.each( [ 'html', 'val' ], function( index, method ) {
 627          api.Element.synchronizer[ method ] = {
 628              update: function( to ) {
 629                  this.element[ method ]( to );
 630              },
 631              refresh: function() {
 632                  return this.element[ method ]();
 633              }
 634          };
 635      });
 636  
 637      api.Element.synchronizer.checkbox = {
 638          update: function( to ) {
 639              this.element.prop( 'checked', to );
 640          },
 641          refresh: function() {
 642              return this.element.prop( 'checked' );
 643          }
 644      };
 645  
 646      api.Element.synchronizer.radio = {
 647          update: function( to ) {
 648              this.element.filter( function() {
 649                  return this.value === to;
 650              }).prop( 'checked', true );
 651          },
 652          refresh: function() {
 653              return this.element.filter( ':checked' ).val();
 654          }
 655      };
 656  
 657      $.support.postMessage = !! window.postMessage;
 658  
 659      /**
 660       * A communicator for sending data from one window to another over postMessage.
 661       *
 662       * @memberOf wp.customize
 663       * @alias wp.customize.Messenger
 664       *
 665       * @constructor
 666       * @augments wp.customize.Class
 667       * @mixes wp.customize.Events
 668       */
 669      api.Messenger = api.Class.extend(/** @lends wp.customize.Messenger.prototype */{
 670          /**
 671           * Create a new Value.
 672           *
 673           * @param {string} key     Unique identifier.
 674           * @param {mixed}  initial Initial value.
 675           * @param {mixed}  options Options hash. Optional.
 676           * @return {Value} Class instance of the Value.
 677           */
 678          add: function( key, initial, options ) {
 679              return this[ key ] = new api.Value( initial, options );
 680          },
 681  
 682          /**
 683           * Initialize Messenger.
 684           *
 685           * @param {Object} params  - Parameters to configure the messenger.
 686           *        {string} params.url          - The URL to communicate with.
 687           *        {window} params.targetWindow - The window instance to communicate with. Default window.parent.
 688           *        {string} params.channel      - If provided, will send the channel with each message and only accept messages a matching channel.
 689           * @param {Object} options - Extend any instance parameter or method with this object.
 690           */
 691          initialize: function( params, options ) {
 692              // Target the parent frame by default, but only if a parent frame exists.
 693              var defaultTarget = window.parent === window ? null : window.parent;
 694  
 695              $.extend( this, options || {} );
 696  
 697              this.add( 'channel', params.channel );
 698              this.add( 'url', params.url || '' );
 699              this.add( 'origin', this.url() ).link( this.url ).setter( function( to ) {
 700                  var urlParser = document.createElement( 'a' );
 701                  urlParser.href = to;
 702                  // Port stripping needed by IE since it adds to host but not to event.origin.
 703                  return urlParser.protocol + '//' + urlParser.host.replace( /:(80|443)$/, '' );
 704              });
 705  
 706              // First add with no value.
 707              this.add( 'targetWindow', null );
 708              // This avoids SecurityErrors when setting a window object in x-origin iframe'd scenarios.
 709              this.targetWindow.set = function( to ) {
 710                  var from = this._value;
 711  
 712                  to = this._setter.apply( this, arguments );
 713                  to = this.validate( to );
 714  
 715                  if ( null === to || from === to ) {
 716                      return this;
 717                  }
 718  
 719                  this._value = to;
 720                  this._dirty = true;
 721  
 722                  this.callbacks.fireWith( this, [ to, from ] );
 723  
 724                  return this;
 725              };
 726              // Now set it.
 727              this.targetWindow( params.targetWindow || defaultTarget );
 728  
 729  
 730              /*
 731               * Since we want jQuery to treat the receive function as unique
 732               * to this instance, we give the function a new guid.
 733               *
 734               * This will prevent every Messenger's receive function from being
 735               * unbound when calling $.off( 'message', this.receive );
 736               */
 737              this.receive = $.proxy( this.receive, this );
 738              this.receive.guid = $.guid++;
 739  
 740              $( window ).on( 'message', this.receive );
 741          },
 742  
 743          destroy: function() {
 744              $( window ).off( 'message', this.receive );
 745          },
 746  
 747          /**
 748           * Receive data from the other window.
 749           *
 750           * @param {jQuery.Event} event Event with embedded data.
 751           */
 752          receive: function( event ) {
 753              var message;
 754  
 755              event = event.originalEvent;
 756  
 757              if ( ! this.targetWindow || ! this.targetWindow() ) {
 758                  return;
 759              }
 760  
 761              // Check to make sure the origin is valid.
 762              if ( this.origin() && event.origin !== this.origin() ) {
 763                  return;
 764              }
 765  
 766              // Ensure we have a string that's JSON.parse-able.
 767              if ( typeof event.data !== 'string' || event.data[0] !== '{' ) {
 768                  return;
 769              }
 770  
 771              message = JSON.parse( event.data );
 772  
 773              // Check required message properties.
 774              if ( ! message || ! message.id || typeof message.data === 'undefined' ) {
 775                  return;
 776              }
 777  
 778              // Check if channel names match.
 779              if ( ( message.channel || this.channel() ) && this.channel() !== message.channel ) {
 780                  return;
 781              }
 782  
 783              this.trigger( message.id, message.data );
 784          },
 785  
 786          /**
 787           * Send data to the other window.
 788           *
 789           * @param {string} id   The event name.
 790           * @param {Object} data Data.
 791           */
 792          send: function( id, data ) {
 793              var message;
 794  
 795              data = typeof data === 'undefined' ? null : data;
 796  
 797              if ( ! this.url() || ! this.targetWindow() ) {
 798                  return;
 799              }
 800  
 801              message = { id: id, data: data };
 802              if ( this.channel() ) {
 803                  message.channel = this.channel();
 804              }
 805  
 806              this.targetWindow().postMessage( JSON.stringify( message ), this.origin() );
 807          }
 808      });
 809  
 810      // Add the Events mixin to api.Messenger.
 811      $.extend( api.Messenger.prototype, api.Events );
 812  
 813      /**
 814       * Notification.
 815       *
 816       * @class
 817       * @augments wp.customize.Class
 818       * @since 4.6.0
 819       *
 820       * @memberOf wp.customize
 821       * @alias wp.customize.Notification
 822       *
 823       * @param {string}  code - The error code.
 824       * @param {object}  params - Params.
 825       * @param {string}  params.message=null - The error message.
 826       * @param {string}  [params.type=error] - The notification type.
 827       * @param {boolean} [params.fromServer=false] - Whether the notification was server-sent.
 828       * @param {string}  [params.setting=null] - The setting ID that the notification is related to.
 829       * @param {*}       [params.data=null] - Any additional data.
 830       */
 831      api.Notification = api.Class.extend(/** @lends wp.customize.Notification.prototype */{
 832  
 833          /**
 834           * Template function for rendering the notification.
 835           *
 836           * This will be populated with template option or else it will be populated with template from the ID.
 837           *
 838           * @since 4.9.0
 839           * @var {Function}
 840           */
 841          template: null,
 842  
 843          /**
 844           * ID for the template to render the notification.
 845           *
 846           * @since 4.9.0
 847           * @var {string}
 848           */
 849          templateId: 'customize-notification',
 850  
 851          /**
 852           * Additional class names to add to the notification container.
 853           *
 854           * @since 4.9.0
 855           * @var {string}
 856           */
 857          containerClasses: '',
 858  
 859          /**
 860           * Initialize notification.
 861           *
 862           * @since 4.9.0
 863           *
 864           * @param {string}   code - Notification code.
 865           * @param {Object}   params - Notification parameters.
 866           * @param {string}   params.message - Message.
 867           * @param {string}   [params.type=error] - Type.
 868           * @param {string}   [params.setting] - Related setting ID.
 869           * @param {Function} [params.template] - Function for rendering template. If not provided, this will come from templateId.
 870           * @param {string}   [params.templateId] - ID for template to render the notification.
 871           * @param {string}   [params.containerClasses] - Additional class names to add to the notification container.
 872           * @param {boolean}  [params.dismissible] - Whether the notification can be dismissed.
 873           */
 874          initialize: function( code, params ) {
 875              var _params;
 876              this.code = code;
 877              _params = _.extend(
 878                  {
 879                      message: null,
 880                      type: 'error',
 881                      fromServer: false,
 882                      data: null,
 883                      setting: null,
 884                      template: null,
 885                      dismissible: false,
 886                      containerClasses: ''
 887                  },
 888                  params
 889              );
 890              delete _params.code;
 891              _.extend( this, _params );
 892          },
 893  
 894          /**
 895           * Render the notification.
 896           *
 897           * @since 4.9.0
 898           *
 899           * @return {jQuery} Notification container element.
 900           */
 901          render: function() {
 902              var notification = this, container, data;
 903              if ( ! notification.template ) {
 904                  notification.template = wp.template( notification.templateId );
 905              }
 906              data = _.extend( {}, notification, {
 907                  alt: notification.parent && notification.parent.alt
 908              } );
 909              container = $( notification.template( data ) );
 910  
 911              if ( notification.dismissible ) {
 912                  container.find( '.notice-dismiss' ).on( 'click keydown', function( event ) {
 913                      if ( 'keydown' === event.type && 13 !== event.which ) {
 914                          return;
 915                      }
 916  
 917                      if ( notification.parent ) {
 918                          notification.parent.remove( notification.code );
 919                      } else {
 920                          container.remove();
 921                      }
 922                  });
 923              }
 924  
 925              return container;
 926          }
 927      });
 928  
 929      // The main API object is also a collection of all customizer settings.
 930      api = $.extend( new api.Values(), api );
 931  
 932      /**
 933       * Get all customize settings.
 934       *
 935       * @alias wp.customize.get
 936       *
 937       * @return {Object}
 938       */
 939      api.get = function() {
 940          var result = {};
 941  
 942          this.each( function( obj, key ) {
 943              result[ key ] = obj.get();
 944          });
 945  
 946          return result;
 947      };
 948  
 949      /**
 950       * Utility function namespace
 951       *
 952       * @namespace wp.customize.utils
 953       */
 954      api.utils = {};
 955  
 956      /**
 957       * Parse query string.
 958       *
 959       * @since 4.7.0
 960       * @access public
 961       *
 962       * @alias wp.customize.utils.parseQueryString
 963       *
 964       * @param {string} queryString Query string.
 965       * @return {Object} Parsed query string.
 966       */
 967      api.utils.parseQueryString = function parseQueryString( queryString ) {
 968          var queryParams = {};
 969          _.each( queryString.split( '&' ), function( pair ) {
 970              var parts, key, value;
 971              parts = pair.split( '=', 2 );
 972              if ( ! parts[0] ) {
 973                  return;
 974              }
 975              key = decodeURIComponent( parts[0].replace( /\+/g, ' ' ) );
 976              key = key.replace( / /g, '_' ); // What PHP does.
 977              if ( _.isUndefined( parts[1] ) ) {
 978                  value = null;
 979              } else {
 980                  value = decodeURIComponent( parts[1].replace( /\+/g, ' ' ) );
 981              }
 982              queryParams[ key ] = value;
 983          } );
 984          return queryParams;
 985      };
 986  
 987      /**
 988       * Expose the API publicly on window.wp.customize
 989       *
 990       * @namespace wp.customize
 991       */
 992      exports.customize = api;
 993  })( wp, jQuery );


Generated : Wed Aug 12 08:20:01 2020 Cross-referenced by PHPXref