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