| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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=…] 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 || '…'; 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 ;
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Sat Sep 19 08:20:30 2026 | Cross-referenced by PHPXref |