[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/ -> media-models.js (source)

   1  /******/ (() => { // webpackBootstrap
   2  /******/     var __webpack_modules__ = ({
   3  
   4  /***/ 3343
   5  (module) {
   6  
   7  var $ = Backbone.$,
   8      Attachment;
   9  
  10  /**
  11   * wp.media.model.Attachment
  12   *
  13   * @memberOf wp.media.model
  14   *
  15   * @class
  16   * @augments Backbone.Model
  17   */
  18  Attachment = Backbone.Model.extend(/** @lends wp.media.model.Attachment.prototype */{
  19      /**
  20       * Triggered when attachment details change
  21       * Overrides Backbone.Model.sync
  22       *
  23       * @param {string} method
  24       * @param {wp.media.model.Attachment} model
  25       * @param {Object} [options={}]
  26       *
  27       * @return {Promise}
  28       */
  29      sync: function( method, model, options ) {
  30          // If the attachment does not yet have an `id`, return an instantly
  31          // rejected promise. Otherwise, all of our requests will fail.
  32          if ( _.isUndefined( this.id ) ) {
  33              return $.Deferred().rejectWith( this ).promise();
  34          }
  35  
  36          // Overload the `read` request so Attachment.fetch() functions correctly.
  37          if ( 'read' === method ) {
  38              options = options || {};
  39              options.context = this;
  40              options.data = _.extend( options.data || {}, {
  41                  action: 'get-attachment',
  42                  id: this.id
  43              });
  44              return wp.media.ajax( options );
  45  
  46          // Overload the `update` request so properties can be saved.
  47          } else if ( 'update' === method ) {
  48              // If we do not have the necessary nonce, fail immediately.
  49              if ( ! this.get('nonces') || ! this.get('nonces').update ) {
  50                  return $.Deferred().rejectWith( this ).promise();
  51              }
  52  
  53              options = options || {};
  54              options.context = this;
  55  
  56              // Set the action and ID.
  57              options.data = _.extend( options.data || {}, {
  58                  action:  'save-attachment',
  59                  id:      this.id,
  60                  nonce:   this.get('nonces').update,
  61                  post_id: wp.media.model.settings.post.id
  62              });
  63  
  64              // Record the values of the changed attributes.
  65              if ( model.hasChanged() ) {
  66                  options.data.changes = {};
  67  
  68                  _.each( model.changed, function( value, key ) {
  69                      options.data.changes[ key ] = this.get( key );
  70                  }, this );
  71              }
  72  
  73              return wp.media.ajax( options );
  74  
  75          // Overload the `delete` request so attachments can be removed.
  76          // This will permanently delete an attachment.
  77          } else if ( 'delete' === method ) {
  78              options = options || {};
  79  
  80              if ( ! options.wait ) {
  81                  this.destroyed = true;
  82              }
  83  
  84              options.context = this;
  85              options.data = _.extend( options.data || {}, {
  86                  action:   'delete-post',
  87                  id:       this.id,
  88                  _wpnonce: this.get('nonces')['delete']
  89              });
  90  
  91              return wp.media.ajax( options ).done( function() {
  92                  this.destroyed = true;
  93              }).fail( function() {
  94                  this.destroyed = false;
  95              });
  96  
  97          // Otherwise, fall back to `Backbone.sync()`.
  98          } else {
  99              /**
 100               * Call `sync` directly on Backbone.Model
 101               */
 102              return Backbone.Model.prototype.sync.apply( this, arguments );
 103          }
 104      },
 105      /**
 106       * Convert date strings into Date objects.
 107       *
 108       * @param {Object} resp The raw response object, typically returned by fetch()
 109       * @return {Object} The modified response object, which is the attributes hash
 110       *                  to be set on the model.
 111       */
 112      parse: function( resp ) {
 113          if ( ! resp ) {
 114              return resp;
 115          }
 116  
 117          resp.date = new Date( resp.date );
 118          resp.modified = new Date( resp.modified );
 119          return resp;
 120      },
 121      /**
 122       * @param {Object} data The properties to be saved.
 123       * @param {Object} options Sync options. e.g. patch, wait, success, error.
 124       *
 125       * @this Backbone.Model
 126       *
 127       * @return {Promise}
 128       */
 129      saveCompat: function( data, options ) {
 130          var model = this;
 131  
 132          // If we do not have the necessary nonce, fail immediately.
 133          if ( ! this.get('nonces') || ! this.get('nonces').update ) {
 134              return $.Deferred().rejectWith( this ).promise();
 135          }
 136  
 137          return wp.media.post( 'save-attachment-compat', _.defaults({
 138              id:      this.id,
 139              nonce:   this.get('nonces').update,
 140              post_id: wp.media.model.settings.post.id
 141          }, data ) ).done( function( resp, status, xhr ) {
 142              model.set( model.parse( resp, xhr ), options );
 143          });
 144      }
 145  },/** @lends wp.media.model.Attachment */{
 146      /**
 147       * Create a new model on the static 'all' attachments collection and return it.
 148       *
 149       * @static
 150       *
 151       * @param {Object} attrs
 152       * @return {wp.media.model.Attachment}
 153       */
 154      create: function( attrs ) {
 155          var Attachments = wp.media.model.Attachments;
 156          return Attachments.all.push( attrs );
 157      },
 158      /**
 159       * Create a new model on the static 'all' attachments collection and return it.
 160       *
 161       * If this function has already been called for the id,
 162       * it returns the specified attachment.
 163       *
 164       * @static
 165       * @param {string} id A string used to identify a model.
 166       * @param {Backbone.Model|undefined} attachment
 167       * @return {wp.media.model.Attachment}
 168       */
 169      get: _.memoize( function( id, attachment ) {
 170          var Attachments = wp.media.model.Attachments;
 171          return Attachments.all.push( attachment || { id: id } );
 172      })
 173  });
 174  
 175  module.exports = Attachment;
 176  
 177  
 178  /***/ },
 179  
 180  /***/ 8266
 181  (module) {
 182  
 183  /**
 184   * wp.media.model.Attachments
 185   *
 186   * A collection of attachments.
 187   *
 188   * This collection has no persistence with the server without supplying
 189   * 'options.props.query = true', which will mirror the collection
 190   * to an Attachments Query collection - @see wp.media.model.Attachments.mirror().
 191   *
 192   * @memberOf wp.media.model
 193   *
 194   * @class
 195   * @augments Backbone.Collection
 196   *
 197   * @param {array}  [models]                Models to initialize with the collection.
 198   * @param {object} [options]               Options hash for the collection.
 199   * @param {string} [options.props]         Options hash for the initial query properties.
 200   * @param {string} [options.props.order]   Initial order (ASC or DESC) for the collection.
 201   * @param {string} [options.props.orderby] Initial attribute key to order the collection by.
 202   * @param {string} [options.props.query]   Whether the collection is linked to an attachments query.
 203   * @param {string} [options.observe]
 204   * @param {string} [options.filters]
 205   *
 206   */
 207  var Attachments = Backbone.Collection.extend(/** @lends wp.media.model.Attachments.prototype */{
 208      /**
 209       * @type {wp.media.model.Attachment}
 210       */
 211      model: wp.media.model.Attachment,
 212      /**
 213       * @param {Array} [models=[]] Array of models used to populate the collection.
 214       * @param {Object} [options={}]
 215       */
 216      initialize: function( models, options ) {
 217          var normalizedOrder;
 218  
 219          options = options || {};
 220  
 221          this.props   = new Backbone.Model();
 222          this.filters = options.filters || {};
 223  
 224          // Bind default `change` events to the `props` model.
 225          this.props.on( 'change', this._changeFilteredProps, this );
 226  
 227          this.props.on( 'change:order',   this._changeOrder,   this );
 228          this.props.on( 'change:orderby', this._changeOrderby, this );
 229          this.props.on( 'change:query',   this._changeQuery,   this );
 230  
 231          options.props = options.props || {};
 232  
 233          /*
 234           * Normalize the order, if one is set. `Attachments.comparator()` and the
 235           * `order` filter in `wp.media.model.Query` both test for the literal
 236           * strings 'ASC' and 'DESC', so anything else has to fall back to 'DESC'.
 237           */
 238          if ( ! _.isUndefined( options.props.order ) && ! _.isNull( options.props.order ) ) {
 239              normalizedOrder     = String( options.props.order ).toUpperCase();
 240              options.props.order = ( 'ASC' === normalizedOrder || 'DESC' === normalizedOrder ) ? normalizedOrder : 'DESC';
 241          }
 242  
 243          this.props.set( options.props );
 244  
 245          if ( options.observe ) {
 246              this.observe( options.observe );
 247          }
 248      },
 249      /**
 250       * Sort the collection when the order attribute changes.
 251       *
 252       * @access private
 253       */
 254      _changeOrder: function() {
 255          if ( this.comparator ) {
 256              this.sort();
 257          }
 258      },
 259      /**
 260       * Set the default comparator only when the `orderby` property is set.
 261       *
 262       * @access private
 263       *
 264       * @param {Backbone.Model} model
 265       * @param {string} orderby
 266       */
 267      _changeOrderby: function( model, orderby ) {
 268          // If a different comparator is defined, bail.
 269          if ( this.comparator && this.comparator !== Attachments.comparator ) {
 270              return;
 271          }
 272  
 273          if ( orderby && 'post__in' !== orderby ) {
 274              this.comparator = Attachments.comparator;
 275          } else {
 276              delete this.comparator;
 277          }
 278      },
 279      /**
 280       * If the `query` property is set to true, query the server using
 281       * the `props` values, and sync the results to this collection.
 282       *
 283       * @access private
 284       *
 285       * @param {Backbone.Model} model
 286       * @param {boolean} query
 287       */
 288      _changeQuery: function( model, query ) {
 289          if ( query ) {
 290              this.props.on( 'change', this._requery, this );
 291              this._requery();
 292          } else {
 293              this.props.off( 'change', this._requery, this );
 294          }
 295      },
 296      /**
 297       * @access private
 298       *
 299       * @param {Backbone.Model} model
 300       */
 301      _changeFilteredProps: function( model ) {
 302          // If this is a query, updating the collection will be handled by
 303          // `this._requery()`.
 304          if ( this.props.get('query') ) {
 305              return;
 306          }
 307  
 308          var changed = _.chain( model.changed ).map( function( t, prop ) {
 309              var filter = Attachments.filters[ prop ],
 310                  term = model.get( prop );
 311  
 312              if ( ! filter ) {
 313                  return;
 314              }
 315  
 316              if ( term && ! this.filters[ prop ] ) {
 317                  this.filters[ prop ] = filter;
 318              } else if ( ! term && this.filters[ prop ] === filter ) {
 319                  delete this.filters[ prop ];
 320              } else {
 321                  return;
 322              }
 323  
 324              // Record the change.
 325              return true;
 326          }, this ).any().value();
 327  
 328          if ( ! changed ) {
 329              return;
 330          }
 331  
 332          // If no `Attachments` model is provided to source the searches from,
 333          // then automatically generate a source from the existing models.
 334          if ( ! this._source ) {
 335              this._source = new Attachments( this.models );
 336          }
 337  
 338          this.reset( this._source.filter( this.validator, this ) );
 339      },
 340  
 341      validateDestroyed: false,
 342      /**
 343       * Checks whether an attachment is valid.
 344       *
 345       * @param {wp.media.model.Attachment} attachment
 346       * @return {boolean}
 347       */
 348      validator: function( attachment ) {
 349  
 350          if ( ! this.validateDestroyed && attachment.destroyed ) {
 351              return false;
 352          }
 353          return _.all( this.filters, function( filter ) {
 354              return !! filter.call( this, attachment );
 355          }, this );
 356      },
 357      /**
 358       * Add or remove an attachment to the collection depending on its validity.
 359       *
 360       * @param {wp.media.model.Attachment} attachment
 361       * @param {Object} options
 362       * @return {wp.media.model.Attachments} Returns itself to allow chaining.
 363       */
 364      validate: function( attachment, options ) {
 365          var valid = this.validator( attachment ),
 366              hasAttachment = !! this.get( attachment.cid );
 367  
 368          if ( ! valid && hasAttachment ) {
 369              this.remove( attachment, options );
 370          } else if ( valid && ! hasAttachment ) {
 371              this.add( attachment, options );
 372          }
 373  
 374          return this;
 375      },
 376  
 377      /**
 378       * Add or remove all attachments from another collection depending on each one's validity.
 379       *
 380       * @param {wp.media.model.Attachments} attachments
 381       * @param {Object} [options={}]
 382       *
 383       * @fires wp.media.model.Attachments#reset
 384       *
 385       * @return {wp.media.model.Attachments} Returns itself to allow chaining.
 386       */
 387      validateAll: function( attachments, options ) {
 388          options = options || {};
 389  
 390          _.each( attachments.models, function( attachment ) {
 391              this.validate( attachment, { silent: true });
 392          }, this );
 393  
 394          if ( ! options.silent ) {
 395              this.trigger( 'reset', this, options );
 396          }
 397          return this;
 398      },
 399      /**
 400       * Start observing another attachments collection change events
 401       * and replicate them on this collection.
 402       *
 403       * @param {wp.media.model.Attachments} The attachments collection to observe.
 404       * @return {wp.media.model.Attachments} Returns itself to allow chaining.
 405       */
 406      observe: function( attachments ) {
 407          this.observers = this.observers || [];
 408          this.observers.push( attachments );
 409  
 410          attachments.on( 'add change remove', this._validateHandler, this );
 411          attachments.on( 'reset', this._validateAllHandler, this );
 412          this.validateAll( attachments );
 413          return this;
 414      },
 415      /**
 416       * Stop replicating collection change events from another attachments collection.
 417       *
 418       * @param {wp.media.model.Attachments} The attachments collection to stop observing.
 419       * @return {wp.media.model.Attachments} Returns itself to allow chaining.
 420       */
 421      unobserve: function( attachments ) {
 422          if ( attachments ) {
 423              attachments.off( null, null, this );
 424              this.observers = _.without( this.observers, attachments );
 425  
 426          } else {
 427              _.each( this.observers, function( attachments ) {
 428                  attachments.off( null, null, this );
 429              }, this );
 430              delete this.observers;
 431          }
 432  
 433          return this;
 434      },
 435      /**
 436       * Update total attachment count when items are added to a collection.
 437       *
 438       * @access private
 439       *
 440       * @since 5.8.0
 441       */
 442      _removeFromTotalAttachments: function() {
 443          if ( this.mirroring ) {
 444              this.mirroring.totalAttachments = this.mirroring.totalAttachments - 1;
 445          }
 446      },
 447      /**
 448       * Update total attachment count when items are added to a collection.
 449       *
 450       * @access private
 451       *
 452       * @since 5.8.0
 453       */
 454      _addToTotalAttachments: function() {
 455          if ( this.mirroring ) {
 456              this.mirroring.totalAttachments = this.mirroring.totalAttachments + 1;
 457          }
 458      },
 459      /**
 460       * @access private
 461       *
 462       * @param {wp.media.model.Attachments} attachment
 463       * @param {wp.media.model.Attachments} attachments
 464       * @param {Object} options
 465       *
 466       * @return {wp.media.model.Attachments} Returns itself to allow chaining.
 467       */
 468      _validateHandler: function( attachment, attachments, options ) {
 469          // If we're not mirroring this `attachments` collection,
 470          // only retain the `silent` option.
 471          options = attachments === this.mirroring ? options : {
 472              silent: options && options.silent
 473          };
 474  
 475          return this.validate( attachment, options );
 476      },
 477      /**
 478       * @access private
 479       *
 480       * @param {wp.media.model.Attachments} attachments
 481       * @param {Object} options
 482       * @return {wp.media.model.Attachments} Returns itself to allow chaining.
 483       */
 484      _validateAllHandler: function( attachments, options ) {
 485          return this.validateAll( attachments, options );
 486      },
 487      /**
 488       * Start mirroring another attachments collection, clearing out any models already
 489       * in the collection.
 490       *
 491       * @param {wp.media.model.Attachments} The attachments collection to mirror.
 492       * @return {wp.media.model.Attachments} Returns itself to allow chaining.
 493       */
 494      mirror: function( attachments ) {
 495          if ( this.mirroring && this.mirroring === attachments ) {
 496              return this;
 497          }
 498  
 499          this.unmirror();
 500          this.mirroring = attachments;
 501  
 502          // Clear the collection silently. A `reset` event will be fired
 503          // when `observe()` calls `validateAll()`.
 504          this.reset( [], { silent: true } );
 505          this.observe( attachments );
 506  
 507          // Bind total attachment count tracking only to the mirrored query
 508          // collection, not to additional observed collections (e.g. selection).
 509          // See Trac #65053.
 510          attachments.on( 'add', this._addToTotalAttachments, this );
 511          attachments.on( 'remove', this._removeFromTotalAttachments, this );
 512  
 513          // Used for the search results.
 514          this.trigger( 'attachments:received', this );
 515          return this;
 516      },
 517      /**
 518       * Stop mirroring another attachments collection.
 519       */
 520      unmirror: function() {
 521          if ( ! this.mirroring ) {
 522              return;
 523          }
 524  
 525          this.unobserve( this.mirroring );
 526          delete this.mirroring;
 527      },
 528      /**
 529       * Retrieve more attachments from the server for the collection.
 530       *
 531       * Only works if the collection is mirroring a Query Attachments collection,
 532       * and forwards to its `more` method. This collection class doesn't have
 533       * server persistence by itself.
 534       *
 535       * @param {Object} options
 536       * @return {Promise}
 537       */
 538      more: function( options ) {
 539          var deferred = jQuery.Deferred(),
 540              mirroring = this.mirroring,
 541              attachments = this;
 542  
 543          if ( ! mirroring || ! mirroring.more ) {
 544              return deferred.resolveWith( this ).promise();
 545          }
 546          /*
 547           * If we're mirroring another collection, forward `more` to
 548           * the mirrored collection. Account for a race condition by
 549           * checking if we're still mirroring that collection when
 550           * the request resolves.
 551           */
 552          mirroring.more( options ).done( function() {
 553              if ( this === attachments.mirroring ) {
 554                  deferred.resolveWith( this );
 555              }
 556  
 557              // Used for the search results.
 558              attachments.trigger( 'attachments:received', this );
 559          });
 560  
 561          return deferred.promise();
 562      },
 563      /**
 564       * Whether there are more attachments that haven't been sync'd from the server
 565       * that match the collection's query.
 566       *
 567       * Only works if the collection is mirroring a Query Attachments collection,
 568       * and forwards to its `hasMore` method. This collection class doesn't have
 569       * server persistence by itself.
 570       *
 571       * @return {boolean}
 572       */
 573      hasMore: function() {
 574          return this.mirroring ? this.mirroring.hasMore() : false;
 575      },
 576      /**
 577       * Holds the total number of attachments.
 578       *
 579       * @since 5.8.0
 580       */
 581      totalAttachments: 0,
 582  
 583      /**
 584       * Gets the total number of attachments.
 585       *
 586       * @since 5.8.0
 587       *
 588       * @return {number} The total number of attachments.
 589       */
 590      getTotalAttachments: function() {
 591          return this.mirroring ? this.mirroring.totalAttachments : 0;
 592      },
 593  
 594      /**
 595       * A custom Ajax-response parser.
 596       *
 597       * See trac ticket #24753.
 598       *
 599       * Called automatically by Backbone whenever a collection's models are returned
 600       * by the server, in fetch. The default implementation is a no-op, simply
 601       * passing through the JSON response. We override this to add attributes to
 602       * the collection items.
 603       *
 604       * @param {Object|Array} response The raw response Object/Array.
 605       * @param {Object} xhr
 606       * @return {Array} The array of model attributes to be added to the collection
 607       */
 608      parse: function( response, xhr ) {
 609          if ( ! _.isArray( response ) ) {
 610                response = [response];
 611          }
 612          return _.map( response, function( attrs ) {
 613              var id, attachment, newAttributes;
 614  
 615              if ( attrs instanceof Backbone.Model ) {
 616                  id = attrs.get( 'id' );
 617                  attrs = attrs.attributes;
 618              } else {
 619                  id = attrs.id;
 620              }
 621  
 622              attachment = wp.media.model.Attachment.get( id );
 623              newAttributes = attachment.parse( attrs, xhr );
 624  
 625              if ( ! _.isEqual( attachment.attributes, newAttributes ) ) {
 626                  attachment.set( newAttributes );
 627              }
 628  
 629              return attachment;
 630          });
 631      },
 632  
 633      /**
 634       * If the collection is a query, create and mirror an Attachments Query collection.
 635       *
 636       * @access private
 637       * @param {Boolean} refresh Deprecated, refresh parameter no longer used.
 638       */
 639      _requery: function() {
 640          var props;
 641          if ( this.props.get('query') ) {
 642              props = this.props.toJSON();
 643              this.mirror( wp.media.model.Query.get( props ) );
 644          }
 645      },
 646      /**
 647       * If this collection is sorted by `menuOrder`, recalculates and saves
 648       * the menu order to the database.
 649       *
 650       * @return {undefined|Promise}
 651       */
 652      saveMenuOrder: function() {
 653          if ( 'menuOrder' !== this.props.get('orderby') ) {
 654              return;
 655          }
 656  
 657          /*
 658           * Removes any uploading attachments, updates each attachment's
 659           * menu order, and returns an object with an { id: menuOrder }
 660           * mapping to pass to the request.
 661           */
 662          var attachments = this.chain().filter( function( attachment ) {
 663              return ! _.isUndefined( attachment.id );
 664          }).map( function( attachment, index ) {
 665              // Indices start at 1.
 666              index = index + 1;
 667              attachment.set( 'menuOrder', index );
 668              return [ attachment.id, index ];
 669          }).object().value();
 670  
 671          if ( _.isEmpty( attachments ) ) {
 672              return;
 673          }
 674  
 675          return wp.media.post( 'save-attachment-order', {
 676              nonce:       wp.media.model.settings.post.nonce,
 677              post_id:     wp.media.model.settings.post.id,
 678              attachments: attachments
 679          });
 680      }
 681  },/** @lends wp.media.model.Attachments */{
 682      /**
 683       * A function to compare two attachment models in an attachments collection.
 684       *
 685       * Used as the default comparator for instances of wp.media.model.Attachments
 686       * and its subclasses. @see wp.media.model.Attachments._changeOrderby().
 687       *
 688       * @param {Backbone.Model} a
 689       * @param {Backbone.Model} b
 690       * @param {Object} options
 691       * @return {number} -1 if the first model should come before the second,
 692       *                   0 if they are of the same rank and
 693       *                   1 if the first model should come after.
 694       */
 695      comparator: function( a, b, options ) {
 696          var key   = this.props.get('orderby'),
 697              order = this.props.get('order') || 'DESC',
 698              ac    = a.cid,
 699              bc    = b.cid;
 700  
 701          a = a.get( key );
 702          b = b.get( key );
 703  
 704          if ( 'date' === key || 'modified' === key ) {
 705              a = a || new Date();
 706              b = b || new Date();
 707          }
 708  
 709          // If `options.ties` is set, don't enforce the `cid` tiebreaker.
 710          if ( options && options.ties ) {
 711              ac = bc = null;
 712          }
 713  
 714          return ( 'DESC' === order ) ? wp.media.compare( a, b, ac, bc ) : wp.media.compare( b, a, bc, ac );
 715      },
 716      /** @namespace wp.media.model.Attachments.filters */
 717      filters: {
 718          /**
 719           * @static
 720           * Note that this client-side searching is *not* equivalent
 721           * to our server-side searching.
 722           *
 723           * @param {wp.media.model.Attachment} attachment
 724           *
 725           * @this wp.media.model.Attachments
 726           *
 727           * @return {Boolean}
 728           */
 729          search: function( attachment ) {
 730              if ( ! this.props.get('search') ) {
 731                  return true;
 732              }
 733  
 734              return _.any(['title','filename','description','caption','name'], function( key ) {
 735                  var value = attachment.get( key );
 736                  return value && -1 !== value.search( this.props.get('search') );
 737              }, this );
 738          },
 739          /**
 740           * @static
 741           * @param {wp.media.model.Attachment} attachment
 742           *
 743           * @this wp.media.model.Attachments
 744           *
 745           * @return {boolean}
 746           */
 747          type: function( attachment ) {
 748              var type = this.props.get('type'), atts = attachment.toJSON(), mime, found;
 749  
 750              if ( ! type || ( _.isArray( type ) && ! type.length ) ) {
 751                  return true;
 752              }
 753  
 754              mime = atts.mime || ( atts.file && atts.file.type ) || '';
 755  
 756              if ( _.isArray( type ) ) {
 757                  found = _.find( type, function (t) {
 758                      return -1 !== mime.indexOf( t );
 759                  } );
 760              } else {
 761                  found = -1 !== mime.indexOf( type );
 762              }
 763  
 764              return found;
 765          },
 766          /**
 767           * @static
 768           * @param {wp.media.model.Attachment} attachment
 769           *
 770           * @this wp.media.model.Attachments
 771           *
 772           * @return {boolean}
 773           */
 774          uploadedTo: function( attachment ) {
 775              var uploadedTo = this.props.get('uploadedTo');
 776              if ( _.isUndefined( uploadedTo ) ) {
 777                  return true;
 778              }
 779  
 780              return uploadedTo === attachment.get('uploadedTo');
 781          },
 782          /**
 783           * @static
 784           * @param {wp.media.model.Attachment} attachment
 785           *
 786           * @this wp.media.model.Attachments
 787           *
 788           * @return {boolean}
 789           */
 790          status: function( attachment ) {
 791              var status = this.props.get('status');
 792              if ( _.isUndefined( status ) ) {
 793                  return true;
 794              }
 795  
 796              return status === attachment.get('status');
 797          }
 798      }
 799  });
 800  
 801  module.exports = Attachments;
 802  
 803  
 804  /***/ },
 805  
 806  /***/ 9104
 807  (module) {
 808  
 809  /**
 810   * wp.media.model.PostImage
 811   *
 812   * An instance of an image that's been embedded into a post.
 813   *
 814   * Used in the embedded image attachment display settings modal - @see wp.media.view.MediaFrame.ImageDetails.
 815   *
 816   * @memberOf wp.media.model
 817   *
 818   * @class
 819   * @augments Backbone.Model
 820   *
 821   * @param {int} [attributes]               Initial model attributes.
 822   * @param {int} [attributes.attachment_id] ID of the attachment.
 823   **/
 824  var PostImage = Backbone.Model.extend(/** @lends wp.media.model.PostImage.prototype */{
 825  
 826      initialize: function( attributes ) {
 827          var Attachment = wp.media.model.Attachment;
 828          this.attachment = false;
 829  
 830          if ( attributes.attachment_id ) {
 831              this.attachment = Attachment.get( attributes.attachment_id );
 832              if ( this.attachment.get( 'url' ) ) {
 833                  this.dfd = jQuery.Deferred();
 834                  this.dfd.resolve();
 835              } else {
 836                  this.dfd = this.attachment.fetch();
 837              }
 838              this.bindAttachmentListeners();
 839          }
 840  
 841          // Keep URL in sync with changes to the type of link.
 842          this.on( 'change:link', this.updateLinkUrl, this );
 843          this.on( 'change:size', this.updateSize, this );
 844  
 845          this.setLinkTypeFromUrl();
 846          this.setAspectRatio();
 847  
 848          this.set( 'originalUrl', attributes.url );
 849      },
 850  
 851      bindAttachmentListeners: function() {
 852          this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );
 853          this.listenTo( this.attachment, 'sync', this.setAspectRatio );
 854          this.listenTo( this.attachment, 'change', this.updateSize );
 855      },
 856  
 857      changeAttachment: function( attachment, props ) {
 858          this.stopListening( this.attachment );
 859          this.attachment = attachment;
 860          this.bindAttachmentListeners();
 861  
 862          this.set( 'attachment_id', this.attachment.get( 'id' ) );
 863          this.set( 'caption', this.attachment.get( 'caption' ) );
 864          this.set( 'alt', this.attachment.get( 'alt' ) );
 865          this.set( 'size', props.get( 'size' ) );
 866          this.set( 'align', props.get( 'align' ) );
 867          this.set( 'link', props.get( 'link' ) );
 868          this.updateLinkUrl();
 869          this.updateSize();
 870      },
 871  
 872      setLinkTypeFromUrl: function() {
 873          var linkUrl = this.get( 'linkUrl' ),
 874              type;
 875  
 876          if ( ! linkUrl ) {
 877              this.set( 'link', 'none' );
 878              return;
 879          }
 880  
 881          // Default to custom if there is a linkUrl.
 882          type = 'custom';
 883  
 884          if ( this.attachment ) {
 885              if ( this.attachment.get( 'url' ) === linkUrl ) {
 886                  type = 'file';
 887              } else if ( this.attachment.get( 'link' ) === linkUrl ) {
 888                  type = 'post';
 889              }
 890          } else {
 891              if ( this.get( 'url' ) === linkUrl ) {
 892                  type = 'file';
 893              }
 894          }
 895  
 896          this.set( 'link', type );
 897      },
 898  
 899      updateLinkUrl: function() {
 900          var link = this.get( 'link' ),
 901              url;
 902  
 903          switch( link ) {
 904              case 'file':
 905                  if ( this.attachment ) {
 906                      url = this.attachment.get( 'url' );
 907                  } else {
 908                      url = this.get( 'url' );
 909                  }
 910                  this.set( 'linkUrl', url );
 911                  break;
 912              case 'post':
 913                  this.set( 'linkUrl', this.attachment.get( 'link' ) );
 914                  break;
 915              case 'none':
 916                  this.set( 'linkUrl', '' );
 917                  break;
 918          }
 919      },
 920  
 921      updateSize: function() {
 922          var size;
 923  
 924          if ( ! this.attachment ) {
 925              return;
 926          }
 927  
 928          if ( this.get( 'size' ) === 'custom' ) {
 929              this.set( 'width', this.get( 'customWidth' ) );
 930              this.set( 'height', this.get( 'customHeight' ) );
 931              this.set( 'url', this.get( 'originalUrl' ) );
 932              return;
 933          }
 934  
 935          size = this.attachment.get( 'sizes' )[ this.get( 'size' ) ];
 936  
 937          if ( ! size ) {
 938              return;
 939          }
 940  
 941          this.set( 'url', size.url );
 942          this.set( 'width', size.width );
 943          this.set( 'height', size.height );
 944      },
 945  
 946      setAspectRatio: function() {
 947          var full;
 948  
 949          if ( this.attachment && this.attachment.get( 'sizes' ) ) {
 950              full = this.attachment.get( 'sizes' ).full;
 951  
 952              if ( full ) {
 953                  this.set( 'aspectRatio', full.width / full.height );
 954                  return;
 955              }
 956          }
 957  
 958          this.set( 'aspectRatio', this.get( 'customWidth' ) / this.get( 'customHeight' ) );
 959      }
 960  });
 961  
 962  module.exports = PostImage;
 963  
 964  
 965  /***/ },
 966  
 967  /***/ 1288
 968  (module) {
 969  
 970  var Attachments = wp.media.model.Attachments,
 971      Query;
 972  
 973  /**
 974   * wp.media.model.Query
 975   *
 976   * A collection of attachments that match the supplied query arguments.
 977   *
 978   * Note: Do NOT change this.args after the query has been initialized.
 979   *       Things will break.
 980   *
 981   * @memberOf wp.media.model
 982   *
 983   * @class
 984   * @augments wp.media.model.Attachments
 985   * @augments Backbone.Collection
 986   *
 987   * @param {array}  [models]                      Models to initialize with the collection.
 988   * @param {object} [options]                     Options hash.
 989   * @param {object} [options.args]                Attachments query arguments.
 990   * @param {object} [options.args.posts_per_page]
 991   */
 992  Query = Attachments.extend(/** @lends wp.media.model.Query.prototype */{
 993      /**
 994       * @param {Array}  [models=[]]  Array of initial models to populate the collection.
 995       * @param {Object} [options={}]
 996       */
 997      initialize: function( models, options ) {
 998          var allowed;
 999  
1000          options = options || {};
1001          Attachments.prototype.initialize.apply( this, arguments );
1002  
1003          this.args     = options.args;
1004          this._hasMore = true;
1005          this.created  = new Date();
1006  
1007          this.filters.order = function( attachment ) {
1008              var orderby = this.props.get('orderby'),
1009                  order = this.props.get('order');
1010  
1011              if ( ! this.comparator ) {
1012                  return true;
1013              }
1014  
1015              /*
1016               * We want any items that can be placed before the last
1017               * item in the set. If we add any items after the last
1018               * item, then we can't guarantee the set is complete.
1019               */
1020              if ( this.length ) {
1021                  return 1 !== this.comparator( attachment, this.last(), { ties: true });
1022  
1023              /*
1024               * Handle the case where there are no items yet and
1025               * we're sorting for recent items. In that case, we want
1026               * changes that occurred after we created the query.
1027               */
1028              } else if ( 'DESC' === order && ( 'date' === orderby || 'modified' === orderby ) ) {
1029                  return attachment.get( orderby ) >= this.created;
1030  
1031              // If we're sorting by menu order and we have no items,
1032              // accept any items that have the default menu order (0).
1033              } else if ( 'ASC' === order && 'menuOrder' === orderby ) {
1034                  return attachment.get( orderby ) === 0;
1035              }
1036  
1037              // Otherwise, we don't want any items yet.
1038              return false;
1039          };
1040  
1041          /*
1042           * Observe the central `wp.Uploader.queue` collection to watch for
1043           * new matches for the query.
1044           *
1045           * Only observe when a limited number of query args are set. There
1046           * are no filters for other properties, so observing will result in
1047           * false positives in those queries.
1048           */
1049          allowed = [ 's', 'order', 'orderby', 'posts_per_page', 'post_mime_type', 'post_parent', 'author' ];
1050          if ( wp.Uploader && _( this.args ).chain().keys().difference( allowed ).isEmpty().value() ) {
1051              this.observe( wp.Uploader.queue );
1052          }
1053      },
1054      /**
1055       * Whether there are more attachments that haven't been sync'd from the server
1056       * that match the collection's query.
1057       *
1058       * @return {boolean}
1059       */
1060      hasMore: function() {
1061          return this._hasMore;
1062      },
1063      /**
1064       * Fetch more attachments from the server for the collection.
1065       *
1066       * @param {Object} [options={}]
1067       * @return {Promise}
1068       */
1069      more: function( options ) {
1070          var query = this;
1071  
1072          // If there is already a request pending, return early with the Deferred object.
1073          if ( this._more && 'pending' === this._more.state() ) {
1074              return this._more;
1075          }
1076  
1077          if ( ! this.hasMore() ) {
1078              return jQuery.Deferred().resolveWith( this ).promise();
1079          }
1080  
1081          options = options || {};
1082          options.remove = false;
1083  
1084          return this._more = this.fetch( options ).done( function( response ) {
1085              if ( _.isEmpty( response ) || -1 === query.args.posts_per_page || response.length < query.args.posts_per_page ) {
1086                  query._hasMore = false;
1087              }
1088          });
1089      },
1090      /**
1091       * Overrides Backbone.Collection.sync
1092       * Overrides wp.media.model.Attachments.sync
1093       *
1094       * @param {string} method
1095       * @param {Backbone.Model} model
1096       * @param {Object} [options={}]
1097       * @return {Promise}
1098       */
1099      sync: function( method, model, options ) {
1100          var args, fallback;
1101  
1102          // Overload the read method so Attachment.fetch() functions correctly.
1103          if ( 'read' === method ) {
1104              options = options || {};
1105              options.context = this;
1106              options.data = _.extend( options.data || {}, {
1107                  action:  'query-attachments',
1108                  post_id: wp.media.model.settings.post.id
1109              });
1110  
1111              // Clone the args so manipulation is non-destructive.
1112              args = _.clone( this.args );
1113  
1114              // Determine which page to query.
1115              if ( -1 !== args.posts_per_page ) {
1116                  args.paged = Math.round( this.length / args.posts_per_page ) + 1;
1117              }
1118  
1119              options.data.query = args;
1120              return wp.media.ajax( options );
1121  
1122          // Otherwise, fall back to `Backbone.sync()`.
1123          } else {
1124              /**
1125               * Call wp.media.model.Attachments.sync or Backbone.sync
1126               */
1127              fallback = Attachments.prototype.sync ? Attachments.prototype : Backbone;
1128              return fallback.sync.apply( this, arguments );
1129          }
1130      }
1131  }, /** @lends wp.media.model.Query */{
1132      /**
1133       * @readonly
1134       */
1135      defaultProps: {
1136          orderby: 'date',
1137          order:   'DESC'
1138      },
1139      /**
1140       * @readonly
1141       */
1142      defaultArgs: {
1143          posts_per_page: 80
1144      },
1145      /**
1146       * @readonly
1147       */
1148      orderby: {
1149          allowed:  [ 'name', 'author', 'date', 'title', 'modified', 'uploadedTo', 'id', 'post__in', 'menuOrder' ],
1150          /**
1151           * A map of JavaScript orderby values to their WP_Query equivalents.
1152           * @type {Object}
1153           */
1154          valuemap: {
1155              'id':         'ID',
1156              'uploadedTo': 'parent',
1157              'menuOrder':  'menu_order ID'
1158          }
1159      },
1160      /**
1161       * A map of JavaScript query properties to their WP_Query equivalents.
1162       *
1163       * @readonly
1164       */
1165      propmap: {
1166          'search':        's',
1167          'type':            'post_mime_type',
1168          'perPage':        'posts_per_page',
1169          'menuOrder':    'menu_order',
1170          'uploadedTo':    'post_parent',
1171          'status':        'post_status',
1172          'include':        'post__in',
1173          'exclude':        'post__not_in',
1174          'author':        'author'
1175      },
1176      /**
1177       * Creates and returns an Attachments Query collection given the properties.
1178       *
1179       * Caches query objects and reuses where possible.
1180       *
1181       * @static
1182       * @method
1183       *
1184       * @param {object} [props]
1185       * @param {Object} [props.order]
1186       * @param {Object} [props.orderby]
1187       * @param {Object} [props.include]
1188       * @param {Object} [props.exclude]
1189       * @param {Object} [props.s]
1190       * @param {Object} [props.post_mime_type]
1191       * @param {Object} [props.posts_per_page]
1192       * @param {Object} [props.menu_order]
1193       * @param {Object} [props.post_parent]
1194       * @param {Object} [props.post_status]
1195       * @param {Object} [props.author]
1196       * @param {Object} [options]
1197       *
1198       * @return {wp.media.model.Query} A new Attachments Query collection.
1199       */
1200      get: (function(){
1201          /**
1202           * @static
1203           * @type Array
1204           */
1205          var queries = [];
1206  
1207          /**
1208           * @return {Query}
1209           */
1210          return function( props, options ) {
1211              var args     = {},
1212                  orderby  = Query.orderby,
1213                  defaults = Query.defaultProps,
1214                  query;
1215  
1216              // Remove the `query` property. This isn't linked to a query,
1217              // this *is* the query.
1218              delete props.query;
1219  
1220              // Fill default args.
1221              _.defaults( props, defaults );
1222  
1223              // Ensure we have a valid orderby value.
1224              if ( ! _.contains( orderby.allowed, props.orderby ) ) {
1225                  props.orderby = defaults.orderby;
1226              }
1227  
1228              _.each( [ 'include', 'exclude' ], function( prop ) {
1229                  if ( props[ prop ] && ! _.isArray( props[ prop ] ) ) {
1230                      props[ prop ] = [ props[ prop ] ];
1231                  }
1232              } );
1233  
1234              // Generate the query `args` object.
1235              // Correct any differing property names.
1236              _.each( props, function( value, prop ) {
1237                  if ( _.isNull( value ) ) {
1238                      return;
1239                  }
1240  
1241                  args[ Query.propmap[ prop ] || prop ] = value;
1242              });
1243  
1244              // Fill any other default query args.
1245              _.defaults( args, Query.defaultArgs );
1246  
1247              // `props.orderby` does not always map directly to `args.orderby`.
1248              // Substitute exceptions specified in orderby.keymap.
1249              args.orderby = orderby.valuemap[ props.orderby ] || props.orderby;
1250  
1251              queries = [];
1252  
1253              // Otherwise, create a new query and add it to the cache.
1254              if ( ! query ) {
1255                  query = new Query( [], _.extend( options || {}, {
1256                      props: props,
1257                      args:  args
1258                  } ) );
1259                  queries.push( query );
1260              }
1261  
1262              return query;
1263          };
1264      }())
1265  });
1266  
1267  module.exports = Query;
1268  
1269  
1270  /***/ },
1271  
1272  /***/ 4134
1273  (module) {
1274  
1275  var Attachments = wp.media.model.Attachments,
1276      Selection;
1277  
1278  /**
1279   * wp.media.model.Selection
1280   *
1281   * A selection of attachments.
1282   *
1283   * @memberOf wp.media.model
1284   *
1285   * @class
1286   * @augments wp.media.model.Attachments
1287   * @augments Backbone.Collection
1288   */
1289  Selection = Attachments.extend(/** @lends wp.media.model.Selection.prototype */{
1290      /**
1291       * Refresh the `single` model whenever the selection changes.
1292       * Binds `single` instead of using the context argument to ensure
1293       * it receives no parameters.
1294       *
1295       * @param {Array} [models=[]] Array of models used to populate the collection.
1296       * @param {Object} [options={}]
1297       */
1298      initialize: function( models, options ) {
1299          /**
1300           * call 'initialize' directly on the parent class
1301           */
1302          Attachments.prototype.initialize.apply( this, arguments );
1303          this.multiple = options && options.multiple;
1304  
1305          this.on( 'add remove reset', _.bind( this.single, this, false ) );
1306      },
1307  
1308      /**
1309       * If the workflow does not support multi-select, clear out the selection
1310       * before adding a new attachment to it.
1311       *
1312       * @param {Array} models
1313       * @param {Object} options
1314       * @return {wp.media.model.Attachment[]}
1315       */
1316      add: function( models, options ) {
1317          if ( ! this.multiple ) {
1318              this.remove( this.models );
1319          }
1320          /**
1321           * call 'add' directly on the parent class
1322           */
1323          return Attachments.prototype.add.call( this, models, options );
1324      },
1325  
1326      /**
1327       * Fired when toggling (clicking on) an attachment in the modal.
1328       *
1329       * @param {undefined|boolean|wp.media.model.Attachment} model
1330       *
1331       * @fires wp.media.model.Selection#selection:single
1332       * @fires wp.media.model.Selection#selection:unsingle
1333       *
1334       * @return {Backbone.Model}
1335       */
1336      single: function( model ) {
1337          var previous = this._single;
1338  
1339          // If a `model` is provided, use it as the single model.
1340          if ( model ) {
1341              this._single = model;
1342          }
1343          // If the single model isn't in the selection, remove it.
1344          if ( this._single && ! this.get( this._single.cid ) ) {
1345              delete this._single;
1346          }
1347  
1348          this._single = this._single || this.last();
1349  
1350          // If single has changed, fire an event.
1351          if ( this._single !== previous ) {
1352              if ( previous ) {
1353                  previous.trigger( 'selection:unsingle', previous, this );
1354  
1355                  // If the model was already removed, trigger the collection
1356                  // event manually.
1357                  if ( ! this.get( previous.cid ) ) {
1358                      this.trigger( 'selection:unsingle', previous, this );
1359                  }
1360              }
1361              if ( this._single ) {
1362                  this._single.trigger( 'selection:single', this._single, this );
1363              }
1364          }
1365  
1366          // Return the single model, or the last model as a fallback.
1367          return this._single;
1368      }
1369  });
1370  
1371  module.exports = Selection;
1372  
1373  
1374  /***/ }
1375  
1376  /******/     });
1377  /************************************************************************/
1378  /******/     // The module cache
1379  /******/     const __webpack_module_cache__ = {};
1380  /******/     
1381  /******/     // The require function
1382  /******/ 	function __webpack_require__(moduleId) {
1383  /******/         // Check if module is in cache
1384  /******/         const cachedModule = __webpack_module_cache__[moduleId];
1385  /******/         if (cachedModule !== undefined) {
1386  /******/             return cachedModule.exports;
1387  /******/         }
1388  /******/         // Create a new module (and put it into the cache)
1389  /******/         const module = __webpack_module_cache__[moduleId] = {
1390  /******/             // no module.id needed
1391  /******/             // no module.loaded needed
1392  /******/             exports: {}
1393  /******/         };
1394  /******/     
1395  /******/         // Execute the module function
1396  /******/         __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
1397  /******/     
1398  /******/         // Return the exports of the module
1399  /******/         return module.exports;
1400  /******/     }
1401  /******/     
1402  /************************************************************************/
1403  /**
1404   * @output wp-includes/js/media-models.js
1405   */
1406  
1407  var Attachment, Attachments, l10n, media;
1408  
1409  /** @namespace wp */
1410  window.wp = window.wp || {};
1411  
1412  /**
1413   * Create and return a media frame.
1414   *
1415   * Handles the default media experience.
1416   *
1417   * @alias wp.media
1418   * @memberOf wp
1419   * @namespace
1420   *
1421   * @param {Object} attributes The properties passed to the main media controller.
1422   * @return {wp.media.view.MediaFrame} A media workflow.
1423   */
1424  media = wp.media = function( attributes ) {
1425      var MediaFrame = media.view.MediaFrame,
1426          frame;
1427  
1428      if ( ! MediaFrame ) {
1429          return;
1430      }
1431  
1432      attributes = _.defaults( attributes || {}, {
1433          frame: 'select'
1434      });
1435  
1436      if ( 'select' === attributes.frame && MediaFrame.Select ) {
1437          frame = new MediaFrame.Select( attributes );
1438      } else if ( 'post' === attributes.frame && MediaFrame.Post ) {
1439          frame = new MediaFrame.Post( attributes );
1440      } else if ( 'manage' === attributes.frame && MediaFrame.Manage ) {
1441          frame = new MediaFrame.Manage( attributes );
1442      } else if ( 'image' === attributes.frame && MediaFrame.ImageDetails ) {
1443          frame = new MediaFrame.ImageDetails( attributes );
1444      } else if ( 'audio' === attributes.frame && MediaFrame.AudioDetails ) {
1445          frame = new MediaFrame.AudioDetails( attributes );
1446      } else if ( 'video' === attributes.frame && MediaFrame.VideoDetails ) {
1447          frame = new MediaFrame.VideoDetails( attributes );
1448      } else if ( 'edit-attachments' === attributes.frame && MediaFrame.EditAttachments ) {
1449          frame = new MediaFrame.EditAttachments( attributes );
1450      }
1451  
1452      delete attributes.frame;
1453  
1454      media.frame = frame;
1455  
1456      return frame;
1457  };
1458  
1459  /** @namespace wp.media.model */
1460  /** @namespace wp.media.view */
1461  /** @namespace wp.media.controller */
1462  /** @namespace wp.media.frames */
1463  _.extend( media, { model: {}, view: {}, controller: {}, frames: {} });
1464  
1465  // Link any localized strings.
1466  l10n = media.model.l10n = window._wpMediaModelsL10n || {};
1467  
1468  // Link any settings.
1469  media.model.settings = l10n.settings || {};
1470  delete l10n.settings;
1471  
1472  Attachment = media.model.Attachment = __webpack_require__( 3343 );
1473  Attachments = media.model.Attachments = __webpack_require__( 8266 );
1474  
1475  media.model.Query = __webpack_require__( 1288 );
1476  media.model.PostImage = __webpack_require__( 9104 );
1477  media.model.Selection = __webpack_require__( 4134 );
1478  
1479  /**
1480   * ========================================================================
1481   * UTILITIES
1482   * ========================================================================
1483   */
1484  
1485  /**
1486   * A basic equality comparator for Backbone models.
1487   *
1488   * Used to order models within a collection - @see wp.media.model.Attachments.comparator().
1489   *
1490   * @param {mixed}  a  The primary parameter to compare.
1491   * @param {mixed}  b  The primary parameter to compare.
1492   * @param {string} ac The fallback parameter to compare, a's cid.
1493   * @param {string} bc The fallback parameter to compare, b's cid.
1494   * @return {number} -1: a should come before b.
1495   *                   0: a and b are of the same rank.
1496   *                   1: b should come before a.
1497   */
1498  media.compare = function( a, b, ac, bc ) {
1499      if ( _.isEqual( a, b ) ) {
1500          return ac === bc ? 0 : (ac > bc ? -1 : 1);
1501      } else {
1502          return a > b ? -1 : 1;
1503      }
1504  };
1505  
1506  _.extend( media, /** @lends wp.media */{
1507      /**
1508       * media.template( id )
1509       *
1510       * Fetch a JavaScript template for an id, and return a templating function for it.
1511       *
1512       * See wp.template() in `wp-includes/js/wp-util.js`.
1513       *
1514       * @borrows wp.template as template
1515       */
1516      template: wp.template,
1517  
1518      /**
1519       * media.post( [action], [data] )
1520       *
1521       * Sends a POST request to WordPress.
1522       * See wp.ajax.post() in `wp-includes/js/wp-util.js`.
1523       *
1524       * @borrows wp.ajax.post as post
1525       */
1526      post: wp.ajax.post,
1527  
1528      /**
1529       * media.ajax( [action], [options] )
1530       *
1531       * Sends an XHR request to WordPress.
1532       * See wp.ajax.send() in `wp-includes/js/wp-util.js`.
1533       *
1534       * @borrows wp.ajax.send as ajax
1535       */
1536      ajax: wp.ajax.send,
1537  
1538      /**
1539       * Scales a set of dimensions to fit within bounding dimensions.
1540       *
1541       * @param {Object} dimensions
1542       * @return {Object}
1543       */
1544      fit: function( dimensions ) {
1545          var width     = dimensions.width,
1546              height    = dimensions.height,
1547              maxWidth  = dimensions.maxWidth,
1548              maxHeight = dimensions.maxHeight,
1549              constraint;
1550  
1551          /*
1552           * Compare ratios between the two values to determine
1553           * which max to constrain by. If a max value doesn't exist,
1554           * then the opposite side is the constraint.
1555           */
1556          if ( ! _.isUndefined( maxWidth ) && ! _.isUndefined( maxHeight ) ) {
1557              constraint = ( width / height > maxWidth / maxHeight ) ? 'width' : 'height';
1558          } else if ( _.isUndefined( maxHeight ) ) {
1559              constraint = 'width';
1560          } else if (  _.isUndefined( maxWidth ) && height > maxHeight ) {
1561              constraint = 'height';
1562          }
1563  
1564          // If the value of the constrained side is larger than the max,
1565          // then scale the values. Otherwise return the originals; they fit.
1566          if ( 'width' === constraint && width > maxWidth ) {
1567              return {
1568                  width : maxWidth,
1569                  height: Math.round( maxWidth * height / width )
1570              };
1571          } else if ( 'height' === constraint && height > maxHeight ) {
1572              return {
1573                  width : Math.round( maxHeight * width / height ),
1574                  height: maxHeight
1575              };
1576          } else {
1577              return {
1578                  width : width,
1579                  height: height
1580              };
1581          }
1582      },
1583      /**
1584       * Truncates a string by injecting an ellipsis into the middle.
1585       * Useful for filenames.
1586       *
1587       * @param {string} string
1588       * @param {number} [length=30]
1589       * @param {string} [replacement=&hellip;]
1590       * @return {string} The string, unless length is greater than string.length.
1591       */
1592      truncate: function( string, length, replacement ) {
1593          length = length || 30;
1594          replacement = replacement || '&hellip;';
1595  
1596          if ( string.length <= length ) {
1597              return string;
1598          }
1599  
1600          return string.substr( 0, length / 2 ) + replacement + string.substr( -1 * length / 2 );
1601      }
1602  });
1603  
1604  /**
1605   * ========================================================================
1606   * MODELS
1607   * ========================================================================
1608   */
1609  /**
1610   * wp.media.attachment
1611   *
1612   * @static
1613   * @param {string} id A string used to identify a model.
1614   * @return {wp.media.model.Attachment}
1615   */
1616  media.attachment = function( id ) {
1617      return Attachment.get( id );
1618  };
1619  
1620  /**
1621   * A collection of all attachments that have been fetched from the server.
1622   *
1623   * @static
1624   * @member {wp.media.model.Attachments}
1625   */
1626  Attachments.all = new Attachments();
1627  
1628  /**
1629   * wp.media.query
1630   *
1631   * Shorthand for creating a new Attachments Query.
1632   *
1633   * @param {Object} [props]
1634   * @return {wp.media.model.Attachments}
1635   */
1636  media.query = function( props ) {
1637      return new Attachments( null, {
1638          props: _.extend( _.defaults( props || {}, { orderby: 'date' } ), { query: true } )
1639      });
1640  };
1641  
1642  /******/ })()
1643  ;


Generated : Mon Aug 10 08:20:22 2026 Cross-referenced by PHPXref