[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-includes/js/ -> wp-backbone.js (source)

   1  /**
   2   * @output wp-includes/js/wp-backbone.js
   3   */
   4  
   5  /** @namespace wp */
   6  window.wp = window.wp || {};
   7  
   8  (function ($) {
   9      /**
  10       * Create the WordPress Backbone namespace.
  11       *
  12       * @namespace wp.Backbone
  13       */
  14      wp.Backbone = {};
  15  
  16      /**
  17       * A backbone subview manager.
  18       *
  19       * @since 3.5.0
  20       * @since 3.6.0 Moved wp.media.Views to wp.Backbone.Subviews.
  21       *
  22       * @memberOf wp.Backbone
  23       *
  24       * @class
  25       *
  26       * @param {wp.Backbone.View} view  The main view.
  27       * @param {Array|Object}     views The subviews for the main view.
  28       */
  29      wp.Backbone.Subviews = function( view, views ) {
  30          this.view = view;
  31          this._views = _.isArray( views ) ? { '': views } : views || {};
  32      };
  33  
  34      wp.Backbone.Subviews.extend = Backbone.Model.extend;
  35  
  36      _.extend( wp.Backbone.Subviews.prototype, {
  37          /**
  38           * Fetches all of the subviews.
  39           *
  40           * @since 3.5.0
  41           *
  42           * @return {Array} All the subviews.
  43           */
  44          all: function() {
  45              return _.flatten( _.values( this._views ) );
  46          },
  47  
  48          /**
  49           * Fetches all subviews that match a given `selector`.
  50           *
  51           * If no `selector` is provided, it will grab all subviews attached
  52           * to the view's root.
  53           *
  54           * @since 3.5.0
  55           *
  56           * @param {string} selector A jQuery selector.
  57           *
  58           * @return {Array} All the subviews that match the selector.
  59           */
  60          get: function( selector ) {
  61              selector = selector || '';
  62              return this._views[ selector ];
  63          },
  64  
  65          /**
  66           * Fetches the first subview that matches a given `selector`.
  67           *
  68           * If no `selector` is provided, it will grab the first subview attached to the
  69           * view's root.
  70           *
  71           * Useful when a selector only has one subview at a time.
  72           *
  73           * @since 3.5.0
  74           *
  75           * @param {string} selector A jQuery selector.
  76           *
  77           * @return {Backbone.View} The view.
  78           */
  79          first: function( selector ) {
  80              var views = this.get( selector );
  81              return views && views.length ? views[0] : null;
  82          },
  83  
  84          /**
  85           * Registers subview(s).
  86           *
  87           * Registers any number of `views` to a `selector`.
  88           *
  89           * When no `selector` is provided, the root selector (the empty string)
  90           * is used. `views` accepts a `Backbone.View` instance or an array of
  91           * `Backbone.View` instances.
  92           *
  93           * ---
  94           *
  95           * Accepts an `options` object, which has a significant effect on the
  96           * resulting behavior.
  97           *
  98           * `options.silent` - *boolean, `false`*
  99           * If `options.silent` is true, no DOM modifications will be made.
 100           *
 101           * `options.add` - *boolean, `false`*
 102           * Use `Views.add()` as a shortcut for setting `options.add` to true.
 103           *
 104           * By default, the provided `views` will replace any existing views
 105           * associated with the selector. If `options.add` is true, the provided
 106           * `views` will be added to the existing views.
 107           *
 108           * `options.at` - *integer, `undefined`*
 109           * When adding, to insert `views` at a specific index, use `options.at`.
 110           * By default, `views` are added to the end of the array.
 111           *
 112           * @since 3.5.0
 113           *
 114           * @param {string}       selector A jQuery selector.
 115           * @param {Array|Object} views    The subviews for the main view.
 116           * @param {Object}       options  Options for call. If `options.silent` is true,
 117           *                                no DOM  modifications will be made. Use
 118           *                                `Views.add()` as a shortcut for setting
 119           *                                `options.add` to true. If `options.add` is
 120           *                                true, the provided `views` will be added to
 121           *                                the existing views. When adding, to insert
 122           *                                `views` at a specific index, use `options.at`.
 123           *
 124           * @return {wp.Backbone.Subviews} The current Subviews instance.
 125           */
 126          set: function( selector, views, options ) {
 127              var existing, next;
 128  
 129              if ( ! _.isString( selector ) ) {
 130                  options  = views;
 131                  views    = selector;
 132                  selector = '';
 133              }
 134  
 135              options  = options || {};
 136              views    = _.isArray( views ) ? views : [ views ];
 137              existing = this.get( selector );
 138              next     = views;
 139  
 140              if ( existing ) {
 141                  if ( options.add ) {
 142                      if ( _.isUndefined( options.at ) ) {
 143                          next = existing.concat( views );
 144                      } else {
 145                          next = existing;
 146                          next.splice.apply( next, [ options.at, 0 ].concat( views ) );
 147                      }
 148                  } else {
 149                      _.each( next, function( view ) {
 150                          view.__detach = true;
 151                      });
 152  
 153                      _.each( existing, function( view ) {
 154                          if ( view.__detach )
 155                              view.$el.detach();
 156                          else
 157                              view.remove();
 158                      });
 159  
 160                      _.each( next, function( view ) {
 161                          delete view.__detach;
 162                      });
 163                  }
 164              }
 165  
 166              this._views[ selector ] = next;
 167  
 168              _.each( views, function( subview ) {
 169                  var constructor = subview.Views || wp.Backbone.Subviews,
 170                      subviews = subview.views = subview.views || new constructor( subview );
 171                  subviews.parent   = this.view;
 172                  subviews.selector = selector;
 173              }, this );
 174  
 175              if ( ! options.silent )
 176                  this._attach( selector, views, _.extend({ ready: this._isReady() }, options ) );
 177  
 178              return this;
 179          },
 180  
 181          /**
 182           * Add subview(s) to existing subviews.
 183           *
 184           * An alias to `Views.set()`, which defaults `options.add` to true.
 185           *
 186           * Adds any number of `views` to a `selector`.
 187           *
 188           * When no `selector` is provided, the root selector (the empty string)
 189           * is used. `views` accepts a `Backbone.View` instance or an array of
 190           * `Backbone.View` instances.
 191           *
 192           * Uses `Views.set()` when setting `options.add` to `false`.
 193           *
 194           * Accepts an `options` object. By default, provided `views` will be
 195           * inserted at the end of the array of existing views. To insert
 196           * `views` at a specific index, use `options.at`. If `options.silent`
 197           * is true, no DOM modifications will be made.
 198           *
 199           * For more information on the `options` object, see `Views.set()`.
 200           *
 201           * @since 3.5.0
 202           *
 203           * @param {string}       selector A jQuery selector.
 204           * @param {Array|Object} views    The subviews for the main view.
 205           * @param {Object}       options  Options for call.  To insert `views` at a
 206           *                                specific index, use `options.at`. If
 207           *                                `options.silent` is true, no DOM modifications
 208           *                                will be made.
 209           *
 210           * @return {wp.Backbone.Subviews} The current subviews instance.
 211           */
 212          add: function( selector, views, options ) {
 213              if ( ! _.isString( selector ) ) {
 214                  options  = views;
 215                  views    = selector;
 216                  selector = '';
 217              }
 218  
 219              return this.set( selector, views, _.extend({ add: true }, options ) );
 220          },
 221  
 222          /**
 223           * Removes an added subview.
 224           *
 225           * Stops tracking `views` registered to a `selector`. If no `views` are
 226           * set, then all of the `selector`'s subviews will be unregistered and
 227           * removed.
 228           *
 229           * Accepts an `options` object. If `options.silent` is set, `remove`
 230           * will *not* be triggered on the unregistered views.
 231           *
 232           * @since 3.5.0
 233           *
 234           * @param {string}       selector A jQuery selector.
 235           * @param {Array|Object} views    The subviews for the main view.
 236           * @param {Object}       options  Options for call. If `options.silent` is set,
 237           *                                `remove` will *not* be triggered on the
 238           *                                unregistered views.
 239           *
 240           * @return {wp.Backbone.Subviews} The current Subviews instance.
 241           */
 242          unset: function( selector, views, options ) {
 243              var existing;
 244  
 245              if ( ! _.isString( selector ) ) {
 246                  options = views;
 247                  views = selector;
 248                  selector = '';
 249              }
 250  
 251              views = views || [];
 252  
 253              if ( existing = this.get( selector ) ) {
 254                  views = _.isArray( views ) ? views : [ views ];
 255                  this._views[ selector ] = views.length ? _.difference( existing, views ) : [];
 256              }
 257  
 258              if ( ! options || ! options.silent )
 259                  _.invoke( views, 'remove' );
 260  
 261              return this;
 262          },
 263  
 264          /**
 265           * Detaches all subviews.
 266           *
 267           * Helps to preserve all subview events when re-rendering the master
 268           * view. Used in conjunction with `Views.render()`.
 269           *
 270           * @since 3.5.0
 271           *
 272           * @return {wp.Backbone.Subviews} The current Subviews instance.
 273           */
 274          detach: function() {
 275              $( _.pluck( this.all(), 'el' ) ).detach();
 276              return this;
 277          },
 278  
 279          /**
 280           * Renders all subviews.
 281           *
 282           * Used in conjunction with `Views.detach()`.
 283           *
 284           * @since 3.5.0
 285           *
 286           * @return {wp.Backbone.Subviews} The current Subviews instance.
 287          */
 288          render: function() {
 289              var options = {
 290                      ready: this._isReady()
 291                  };
 292  
 293              _.each( this._views, function( views, selector ) {
 294                  this._attach( selector, views, options );
 295              }, this );
 296  
 297              this.rendered = true;
 298              return this;
 299          },
 300  
 301          /**
 302           * Removes all subviews.
 303           *
 304           * Triggers the `remove()` method on all subviews. Detaches the master
 305           * view from its parent. Resets the internals of the views manager.
 306           *
 307           * Accepts an `options` object. If `options.silent` is set, `unset`
 308           * will *not* be triggered on the master view's parent.
 309           *
 310           * @since 3.6.0
 311           *
 312           * @param {Object}  options        Options for call.
 313           * @param {boolean} options.silent If true, `unset` wil *not* be triggered on
 314           *                                 the master views' parent.
 315           *
 316           * @return {wp.Backbone.Subviews} The current Subviews instance.
 317          */
 318          remove: function( options ) {
 319              if ( ! options || ! options.silent ) {
 320                  if ( this.parent && this.parent.views )
 321                      this.parent.views.unset( this.selector, this.view, { silent: true });
 322                  delete this.parent;
 323                  delete this.selector;
 324              }
 325  
 326              _.invoke( this.all(), 'remove' );
 327              this._views = [];
 328              return this;
 329          },
 330  
 331          /**
 332           * Replaces a selector's subviews
 333           *
 334           * By default, sets the `$target` selector's html to the subview `els`.
 335           *
 336           * Can be overridden in subclasses.
 337           *
 338           * @since 3.5.0
 339           *
 340           * @param {string} $target Selector where to put the elements.
 341           * @param {*} els HTML or elements to put into the selector's HTML.
 342           *
 343           * @return {wp.Backbone.Subviews} The current Subviews instance.
 344           */
 345          replace: function( $target, els ) {
 346              $target.html( els );
 347              return this;
 348          },
 349  
 350          /**
 351           * Insert subviews into a selector.
 352           *
 353           * By default, appends the subview `els` to the end of the `$target`
 354           * selector. If `options.at` is set, inserts the subview `els` at the
 355           * provided index.
 356           *
 357           * Can be overridden in subclasses.
 358           *
 359           * @since 3.5.0
 360           *
 361           * @param {string}  $target    Selector where to put the elements.
 362           * @param {*}       els        HTML or elements to put at the end of the
 363           *                             $target.
 364           * @param {?Object} options    Options for call.
 365           * @param {?number} options.at At which index to put the elements.
 366           *
 367           * @return {wp.Backbone.Subviews} The current Subviews instance.
 368           */
 369          insert: function( $target, els, options ) {
 370              var at = options && options.at,
 371                  $children;
 372  
 373              if ( _.isNumber( at ) && ($children = $target.children()).length > at )
 374                  $children.eq( at ).before( els );
 375              else
 376                  $target.append( els );
 377  
 378              return this;
 379          },
 380  
 381          /**
 382           * Triggers the ready event.
 383           *
 384           * Only use this method if you know what you're doing. For performance reasons,
 385           * this method does not check if the view is actually attached to the DOM. It's
 386           * taking your word for it.
 387           *
 388           * Fires the ready event on the current view and all attached subviews.
 389           *
 390           * @since 3.5.0
 391           */
 392          ready: function() {
 393              this.view.trigger('ready');
 394  
 395              // Find all attached subviews, and call ready on them.
 396              _.chain( this.all() ).map( function( view ) {
 397                  return view.views;
 398              }).flatten().where({ attached: true }).invoke('ready');
 399          },
 400          /**
 401           * Attaches a series of views to a selector. Internal.
 402           *
 403           * Checks to see if a matching selector exists, renders the views,
 404           * performs the proper DOM operation, and then checks if the view is
 405           * attached to the document.
 406           *
 407           * @since 3.5.0
 408           *
 409           * @private
 410           *
 411           * @param {string}       selector    A jQuery selector.
 412           * @param {Array|Object} views       The subviews for the main view.
 413           * @param {Object}       options     Options for call.
 414           * @param {boolean}      options.add If true the provided views will be added.
 415           *
 416           * @return {wp.Backbone.Subviews} The current Subviews instance.
 417           */
 418          _attach: function( selector, views, options ) {
 419              var $selector = selector ? this.view.$( selector ) : this.view.$el,
 420                  managers;
 421  
 422              // Check if we found a location to attach the views.
 423              if ( ! $selector.length )
 424                  return this;
 425  
 426              managers = _.chain( views ).pluck('views').flatten().value();
 427  
 428              // Render the views if necessary.
 429              _.each( managers, function( manager ) {
 430                  if ( manager.rendered )
 431                      return;
 432  
 433                  manager.view.render();
 434                  manager.rendered = true;
 435              }, this );
 436  
 437              // Insert or replace the views.
 438              this[ options.add ? 'insert' : 'replace' ]( $selector, _.pluck( views, 'el' ), options );
 439  
 440              /*
 441               * Set attached and trigger ready if the current view is already
 442               * attached to the DOM.
 443               */
 444              _.each( managers, function( manager ) {
 445                  manager.attached = true;
 446  
 447                  if ( options.ready )
 448                      manager.ready();
 449              }, this );
 450  
 451              return this;
 452          },
 453  
 454          /**
 455           * Determines whether or not the current view is in the DOM.
 456           *
 457           * @since 3.5.0
 458           *
 459           * @private
 460           *
 461           * @return {boolean} Whether or not the current view is in the DOM.
 462           */
 463          _isReady: function() {
 464              var node = this.view.el;
 465              while ( node ) {
 466                  if ( node === document.body )
 467                      return true;
 468                  node = node.parentNode;
 469              }
 470  
 471              return false;
 472          }
 473      });
 474  
 475      wp.Backbone.View = Backbone.View.extend({
 476  
 477          // The constructor for the `Views` manager.
 478          Subviews: wp.Backbone.Subviews,
 479  
 480          /**
 481           * The base view class.
 482           *
 483           * This extends the backbone view to have a build-in way to use subviews. This
 484           * makes it easier to have nested views.
 485           *
 486           * @since 3.5.0
 487           * @since 3.6.0 Moved wp.media.View to wp.Backbone.View
 488           *
 489           * @constructs
 490           * @augments Backbone.View
 491           *
 492           * @memberOf wp.Backbone
 493           *
 494           *
 495           * @param {Object} options The options for this view.
 496           */
 497          constructor: function( options ) {
 498              this.views = new this.Subviews( this, this.views );
 499              this.on( 'ready', this.ready, this );
 500  
 501              this.options = options || {};
 502  
 503              Backbone.View.apply( this, arguments );
 504          },
 505  
 506          /**
 507           * Removes this view and all subviews.
 508           *
 509           * @since 3.5.0
 510           *
 511           * @return {wp.Backbone.Subviews} The current Subviews instance.
 512           */
 513          remove: function() {
 514              var result = Backbone.View.prototype.remove.apply( this, arguments );
 515  
 516              // Recursively remove child views.
 517              if ( this.views )
 518                  this.views.remove();
 519  
 520              return result;
 521          },
 522  
 523          /**
 524           * Renders this view and all subviews.
 525           *
 526           * @since 3.5.0
 527           *
 528           * @return {wp.Backbone.View} The current instance of the view.
 529           */
 530          render: function() {
 531              var options;
 532  
 533              if ( this.prepare )
 534                  options = this.prepare();
 535  
 536              this.views.detach();
 537  
 538              if ( this.template ) {
 539                  options = options || {};
 540                  this.trigger( 'prepare', options );
 541                  this.$el.html( this.template( options ) );
 542              }
 543  
 544              this.views.render();
 545              return this;
 546          },
 547  
 548          /**
 549           * Returns the options for this view.
 550           *
 551           * @since 3.5.0
 552           *
 553           * @return {Object} The options for this view.
 554           */
 555          prepare: function() {
 556              return this.options;
 557          },
 558  
 559          /**
 560           * Method that is called when the ready event is triggered.
 561           *
 562           * @since 3.5.0
 563           */
 564          ready: function() {}
 565      });
 566  }(jQuery));


Generated: Tue Dec 3 01:00:02 2024 Cross-referenced by PHPXref 0.7.1