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


Generated : Sat Sep 19 08:20:30 2026 Cross-referenced by PHPXref