Make WordPress Core

Changeset 31494


Ignore:
Timestamp:
02/22/2015 08:47:01 AM (10 years ago)
Author:
wonderboymusic
Message:

Make sure the grid build does not load files from the views build.

Fix the errant back-compat assignment for wp.media.view.Frame.

See #28510.

Location:
trunk/src/wp-includes/js/media
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/js/media/controllers/edit-attachment-metadata.js

    r31492 r31494  
    1010 * @augments Backbone.Model
    1111 */
    12 var State = require( './state.js' ),
     12var State = wp.media.controller.State,
    1313    l10n = wp.media.view.l10n,
    1414    EditAttachmentMetadata;
  • trunk/src/wp-includes/js/media/grid.js

    r31492 r31494  
    1111 * @augments Backbone.Model
    1212 */
    13 var State = require( './state.js' ),
     13var State = wp.media.controller.State,
    1414    l10n = wp.media.view.l10n,
    1515    EditAttachmentMetadata;
     
    3030module.exports = EditAttachmentMetadata;
    3131
    32 },{"./state.js":6}],2:[function(require,module,exports){
    33 /*globals wp */
    34 
    35 /**
    36  * wp.media.controller.EditImage
    37  *
    38  * A state for editing (cropping, etc.) an image.
    39  *
    40  * @class
    41  * @augments wp.media.controller.State
    42  * @augments Backbone.Model
    43  *
    44  * @param {object}                    attributes                      The attributes hash passed to the state.
    45  * @param {wp.media.model.Attachment} attributes.model                The attachment.
    46  * @param {string}                    [attributes.id=edit-image]      Unique identifier.
    47  * @param {string}                    [attributes.title=Edit Image]   Title for the state. Displays in the media menu and the frame's title region.
    48  * @param {string}                    [attributes.content=edit-image] Initial mode for the content region.
    49  * @param {string}                    [attributes.toolbar=edit-image] Initial mode for the toolbar region.
    50  * @param {string}                    [attributes.menu=false]         Initial mode for the menu region.
    51  * @param {string}                    [attributes.url]                Unused. @todo Consider removal.
    52  */
    53 var State = require( './state.js' ),
    54     ToolbarView = require( '../views/toolbar.js' ),
    55     l10n = wp.media.view.l10n,
    56     EditImage;
    57 
    58 EditImage = State.extend({
    59     defaults: {
    60         id:      'edit-image',
    61         title:   l10n.editImage,
    62         menu:    false,
    63         toolbar: 'edit-image',
    64         content: 'edit-image',
    65         url:     ''
    66     },
    67 
    68     /**
    69      * @since 3.9.0
    70      */
    71     activate: function() {
    72         this.listenTo( this.frame, 'toolbar:render:edit-image', this.toolbar );
    73     },
    74 
    75     /**
    76      * @since 3.9.0
    77      */
    78     deactivate: function() {
    79         this.stopListening( this.frame );
    80     },
    81 
    82     /**
    83      * @since 3.9.0
    84      */
    85     toolbar: function() {
    86         var frame = this.frame,
    87             lastState = frame.lastState(),
    88             previous = lastState && lastState.id;
    89 
    90         frame.toolbar.set( new ToolbarView({
    91             controller: frame,
    92             items: {
    93                 back: {
    94                     style: 'primary',
    95                     text:     l10n.back,
    96                     priority: 20,
    97                     click:    function() {
    98                         if ( previous ) {
    99                             frame.setState( previous );
    100                         } else {
    101                             frame.close();
    102                         }
    103                     }
    104                 }
    105             }
    106         }) );
    107     }
    108 });
    109 
    110 module.exports = EditImage;
    111 
    112 },{"../views/toolbar.js":44,"./state.js":6}],3:[function(require,module,exports){
    113 /*globals wp, _, Backbone */
    114 
    115 /**
    116  * wp.media.controller.Library
    117  *
    118  * A state for choosing an attachment or group of attachments from the media library.
    119  *
    120  * @class
    121  * @augments wp.media.controller.State
    122  * @augments Backbone.Model
    123  * @mixes media.selectionSync
    124  *
    125  * @param {object}                          [attributes]                         The attributes hash passed to the state.
    126  * @param {string}                          [attributes.id=library]              Unique identifier.
    127  * @param {string}                          [attributes.title=Media library]     Title for the state. Displays in the media menu and the frame's title region.
    128  * @param {wp.media.model.Attachments}      [attributes.library]                 The attachments collection to browse.
    129  *                                                                               If one is not supplied, a collection of all attachments will be created.
    130  * @param {wp.media.model.Selection|object} [attributes.selection]               A collection to contain attachment selections within the state.
    131  *                                                                               If the 'selection' attribute is a plain JS object,
    132  *                                                                               a Selection will be created using its values as the selection instance's `props` model.
    133  *                                                                               Otherwise, it will copy the library's `props` model.
    134  * @param {boolean}                         [attributes.multiple=false]          Whether multi-select is enabled.
    135  * @param {string}                          [attributes.content=upload]          Initial mode for the content region.
    136  *                                                                               Overridden by persistent user setting if 'contentUserSetting' is true.
    137  * @param {string}                          [attributes.menu=default]            Initial mode for the menu region.
    138  * @param {string}                          [attributes.router=browse]           Initial mode for the router region.
    139  * @param {string}                          [attributes.toolbar=select]          Initial mode for the toolbar region.
    140  * @param {boolean}                         [attributes.searchable=true]         Whether the library is searchable.
    141  * @param {boolean|string}                  [attributes.filterable=false]        Whether the library is filterable, and if so what filters should be shown.
    142  *                                                                               Accepts 'all', 'uploaded', or 'unattached'.
    143  * @param {boolean}                         [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
    144  * @param {boolean}                         [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
    145  * @param {boolean}                         [attributes.describe=false]          Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
    146  * @param {boolean}                         [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
    147  * @param {boolean}                         [attributes.syncSelection=true]      Whether the Attachments selection should be persisted from the last state.
    148  */
    149 var selectionSync = require( '../utils/selection-sync.js' ),
    150     State = require( './state.js' ),
    151     l10n = wp.media.view.l10n,
    152     getUserSetting = window.getUserSetting,
    153     setUserSetting = window.setUserSetting,
    154     Library;
    155 
    156 Library = State.extend({
    157     defaults: {
    158         id:                 'library',
    159         title:              l10n.mediaLibraryTitle,
    160         multiple:           false,
    161         content:            'upload',
    162         menu:               'default',
    163         router:             'browse',
    164         toolbar:            'select',
    165         searchable:         true,
    166         filterable:         false,
    167         sortable:           true,
    168         autoSelect:         true,
    169         describe:           false,
    170         contentUserSetting: true,
    171         syncSelection:      true
    172     },
    173 
    174     /**
    175      * If a library isn't provided, query all media items.
    176      * If a selection instance isn't provided, create one.
    177      *
    178      * @since 3.5.0
    179      */
    180     initialize: function() {
    181         var selection = this.get('selection'),
    182             props;
    183 
    184         if ( ! this.get('library') ) {
    185             this.set( 'library', wp.media.query() );
    186         }
    187 
    188         if ( ! ( selection instanceof wp.media.model.Selection ) ) {
    189             props = selection;
    190 
    191             if ( ! props ) {
    192                 props = this.get('library').props.toJSON();
    193                 props = _.omit( props, 'orderby', 'query' );
    194             }
    195 
    196             this.set( 'selection', new wp.media.model.Selection( null, {
    197                 multiple: this.get('multiple'),
    198                 props: props
    199             }) );
    200         }
    201 
    202         this.resetDisplays();
    203     },
    204 
    205     /**
    206      * @since 3.5.0
    207      */
    208     activate: function() {
    209         this.syncSelection();
    210 
    211         wp.Uploader.queue.on( 'add', this.uploading, this );
    212 
    213         this.get('selection').on( 'add remove reset', this.refreshContent, this );
    214 
    215         if ( this.get( 'router' ) && this.get('contentUserSetting') ) {
    216             this.frame.on( 'content:activate', this.saveContentMode, this );
    217             this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
    218         }
    219     },
    220 
    221     /**
    222      * @since 3.5.0
    223      */
    224     deactivate: function() {
    225         this.recordSelection();
    226 
    227         this.frame.off( 'content:activate', this.saveContentMode, this );
    228 
    229         // Unbind all event handlers that use this state as the context
    230         // from the selection.
    231         this.get('selection').off( null, null, this );
    232 
    233         wp.Uploader.queue.off( null, null, this );
    234     },
    235 
    236     /**
    237      * Reset the library to its initial state.
    238      *
    239      * @since 3.5.0
    240      */
    241     reset: function() {
    242         this.get('selection').reset();
    243         this.resetDisplays();
    244         this.refreshContent();
    245     },
    246 
    247     /**
    248      * Reset the attachment display settings defaults to the site options.
    249      *
    250      * If site options don't define them, fall back to a persistent user setting.
    251      *
    252      * @since 3.5.0
    253      */
    254     resetDisplays: function() {
    255         var defaultProps = wp.media.view.settings.defaultProps;
    256         this._displays = [];
    257         this._defaultDisplaySettings = {
    258             align: defaultProps.align || getUserSetting( 'align', 'none' ),
    259             size:  defaultProps.size  || getUserSetting( 'imgsize', 'medium' ),
    260             link:  defaultProps.link  || getUserSetting( 'urlbutton', 'file' )
    261         };
    262     },
    263 
    264     /**
    265      * Create a model to represent display settings (alignment, etc.) for an attachment.
    266      *
    267      * @since 3.5.0
    268      *
    269      * @param {wp.media.model.Attachment} attachment
    270      * @returns {Backbone.Model}
    271      */
    272     display: function( attachment ) {
    273         var displays = this._displays;
    274 
    275         if ( ! displays[ attachment.cid ] ) {
    276             displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) );
    277         }
    278         return displays[ attachment.cid ];
    279     },
    280 
    281     /**
    282      * Given an attachment, create attachment display settings properties.
    283      *
    284      * @since 3.6.0
    285      *
    286      * @param {wp.media.model.Attachment} attachment
    287      * @returns {Object}
    288      */
    289     defaultDisplaySettings: function( attachment ) {
    290         var settings = this._defaultDisplaySettings;
    291         if ( settings.canEmbed = this.canEmbed( attachment ) ) {
    292             settings.link = 'embed';
    293         }
    294         return settings;
    295     },
    296 
    297     /**
    298      * Whether an attachment can be embedded (audio or video).
    299      *
    300      * @since 3.6.0
    301      *
    302      * @param {wp.media.model.Attachment} attachment
    303      * @returns {Boolean}
    304      */
    305     canEmbed: function( attachment ) {
    306         // If uploading, we know the filename but not the mime type.
    307         if ( ! attachment.get('uploading') ) {
    308             var type = attachment.get('type');
    309             if ( type !== 'audio' && type !== 'video' ) {
    310                 return false;
    311             }
    312         }
    313 
    314         return _.contains( wp.media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
    315     },
    316 
    317 
    318     /**
    319      * If the state is active, no items are selected, and the current
    320      * content mode is not an option in the state's router (provided
    321      * the state has a router), reset the content mode to the default.
    322      *
    323      * @since 3.5.0
    324      */
    325     refreshContent: function() {
    326         var selection = this.get('selection'),
    327             frame = this.frame,
    328             router = frame.router.get(),
    329             mode = frame.content.mode();
    330 
    331         if ( this.active && ! selection.length && router && ! router.get( mode ) ) {
    332             this.frame.content.render( this.get('content') );
    333         }
    334     },
    335 
    336     /**
    337      * Callback handler when an attachment is uploaded.
    338      *
    339      * Switch to the Media Library if uploaded from the 'Upload Files' tab.
    340      *
    341      * Adds any uploading attachments to the selection.
    342      *
    343      * If the state only supports one attachment to be selected and multiple
    344      * attachments are uploaded, the last attachment in the upload queue will
    345      * be selected.
    346      *
    347      * @since 3.5.0
    348      *
    349      * @param {wp.media.model.Attachment} attachment
    350      */
    351     uploading: function( attachment ) {
    352         var content = this.frame.content;
    353 
    354         if ( 'upload' === content.mode() ) {
    355             this.frame.content.mode('browse');
    356         }
    357 
    358         if ( this.get( 'autoSelect' ) ) {
    359             this.get('selection').add( attachment );
    360             this.frame.trigger( 'library:selection:add' );
    361         }
    362     },
    363 
    364     /**
    365      * Persist the mode of the content region as a user setting.
    366      *
    367      * @since 3.5.0
    368      */
    369     saveContentMode: function() {
    370         if ( 'browse' !== this.get('router') ) {
    371             return;
    372         }
    373 
    374         var mode = this.frame.content.mode(),
    375             view = this.frame.router.get();
    376 
    377         if ( view && view.get( mode ) ) {
    378             setUserSetting( 'libraryContent', mode );
    379         }
    380     }
    381 });
    382 
    383 // Make selectionSync available on any Media Library state.
    384 _.extend( Library.prototype, selectionSync );
    385 
    386 module.exports = Library;
    387 
    388 },{"../utils/selection-sync.js":9,"./state.js":6}],4:[function(require,module,exports){
    389 /*globals Backbone, _ */
    390 
    391 /**
    392  * wp.media.controller.Region
    393  *
    394  * A region is a persistent application layout area.
    395  *
    396  * A region assumes one mode at any time, and can be switched to another.
    397  *
    398  * When mode changes, events are triggered on the region's parent view.
    399  * The parent view will listen to specific events and fill the region with an
    400  * appropriate view depending on mode. For example, a frame listens for the
    401  * 'browse' mode t be activated on the 'content' view and then fills the region
    402  * with an AttachmentsBrowser view.
    403  *
    404  * @class
    405  *
    406  * @param {object}        options          Options hash for the region.
    407  * @param {string}        options.id       Unique identifier for the region.
    408  * @param {Backbone.View} options.view     A parent view the region exists within.
    409  * @param {string}        options.selector jQuery selector for the region within the parent view.
    410  */
    411 var Region = function( options ) {
    412     _.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
    413 };
    414 
    415 // Use Backbone's self-propagating `extend` inheritance method.
    416 Region.extend = Backbone.Model.extend;
    417 
    418 _.extend( Region.prototype, {
    419     /**
    420      * Activate a mode.
    421      *
    422      * @since 3.5.0
    423      *
    424      * @param {string} mode
    425      *
    426      * @fires this.view#{this.id}:activate:{this._mode}
    427      * @fires this.view#{this.id}:activate
    428      * @fires this.view#{this.id}:deactivate:{this._mode}
    429      * @fires this.view#{this.id}:deactivate
    430      *
    431      * @returns {wp.media.controller.Region} Returns itself to allow chaining.
    432      */
    433     mode: function( mode ) {
    434         if ( ! mode ) {
    435             return this._mode;
    436         }
    437         // Bail if we're trying to change to the current mode.
    438         if ( mode === this._mode ) {
    439             return this;
    440         }
    441 
    442         /**
    443          * Region mode deactivation event.
    444          *
    445          * @event this.view#{this.id}:deactivate:{this._mode}
    446          * @event this.view#{this.id}:deactivate
    447          */
    448         this.trigger('deactivate');
    449 
    450         this._mode = mode;
    451         this.render( mode );
    452 
    453         /**
    454          * Region mode activation event.
    455          *
    456          * @event this.view#{this.id}:activate:{this._mode}
    457          * @event this.view#{this.id}:activate
    458          */
    459         this.trigger('activate');
    460         return this;
    461     },
    462     /**
    463      * Render a mode.
    464      *
    465      * @since 3.5.0
    466      *
    467      * @param {string} mode
    468      *
    469      * @fires this.view#{this.id}:create:{this._mode}
    470      * @fires this.view#{this.id}:create
    471      * @fires this.view#{this.id}:render:{this._mode}
    472      * @fires this.view#{this.id}:render
    473      *
    474      * @returns {wp.media.controller.Region} Returns itself to allow chaining
    475      */
    476     render: function( mode ) {
    477         // If the mode isn't active, activate it.
    478         if ( mode && mode !== this._mode ) {
    479             return this.mode( mode );
    480         }
    481 
    482         var set = { view: null },
    483             view;
    484 
    485         /**
    486          * Create region view event.
    487          *
    488          * Region view creation takes place in an event callback on the frame.
    489          *
    490          * @event this.view#{this.id}:create:{this._mode}
    491          * @event this.view#{this.id}:create
    492          */
    493         this.trigger( 'create', set );
    494         view = set.view;
    495 
    496         /**
    497          * Render region view event.
    498          *
    499          * Region view creation takes place in an event callback on the frame.
    500          *
    501          * @event this.view#{this.id}:create:{this._mode}
    502          * @event this.view#{this.id}:create
    503          */
    504         this.trigger( 'render', view );
    505         if ( view ) {
    506             this.set( view );
    507         }
    508         return this;
    509     },
    510 
    511     /**
    512      * Get the region's view.
    513      *
    514      * @since 3.5.0
    515      *
    516      * @returns {wp.media.View}
    517      */
    518     get: function() {
    519         return this.view.views.first( this.selector );
    520     },
    521 
    522     /**
    523      * Set the region's view as a subview of the frame.
    524      *
    525      * @since 3.5.0
    526      *
    527      * @param {Array|Object} views
    528      * @param {Object} [options={}]
    529      * @returns {wp.Backbone.Subviews} Subviews is returned to allow chaining
    530      */
    531     set: function( views, options ) {
    532         if ( options ) {
    533             options.add = false;
    534         }
    535         return this.view.views.set( this.selector, views, options );
    536     },
    537 
    538     /**
    539      * Trigger regional view events on the frame.
    540      *
    541      * @since 3.5.0
    542      *
    543      * @param {string} event
    544      * @returns {undefined|wp.media.controller.Region} Returns itself to allow chaining.
    545      */
    546     trigger: function( event ) {
    547         var base, args;
    548 
    549         if ( ! this._mode ) {
    550             return;
    551         }
    552 
    553         args = _.toArray( arguments );
    554         base = this.id + ':' + event;
    555 
    556         // Trigger `{this.id}:{event}:{this._mode}` event on the frame.
    557         args[0] = base + ':' + this._mode;
    558         this.view.trigger.apply( this.view, args );
    559 
    560         // Trigger `{this.id}:{event}` event on the frame.
    561         args[0] = base;
    562         this.view.trigger.apply( this.view, args );
    563         return this;
    564     }
    565 });
    566 
    567 module.exports = Region;
    568 
    569 },{}],5:[function(require,module,exports){
    570 /*globals _, Backbone */
    571 
    572 /**
    573  * wp.media.controller.StateMachine
    574  *
    575  * A state machine keeps track of state. It is in one state at a time,
    576  * and can change from one state to another.
    577  *
    578  * States are stored as models in a Backbone collection.
    579  *
    580  * @since 3.5.0
    581  *
    582  * @class
    583  * @augments Backbone.Model
    584  * @mixin
    585  * @mixes Backbone.Events
    586  *
    587  * @param {Array} states
    588  */
    589 var StateMachine = function( states ) {
    590     // @todo This is dead code. The states collection gets created in media.view.Frame._createStates.
    591     this.states = new Backbone.Collection( states );
    592 };
    593 
    594 // Use Backbone's self-propagating `extend` inheritance method.
    595 StateMachine.extend = Backbone.Model.extend;
    596 
    597 _.extend( StateMachine.prototype, Backbone.Events, {
    598     /**
    599      * Fetch a state.
    600      *
    601      * If no `id` is provided, returns the active state.
    602      *
    603      * Implicitly creates states.
    604      *
    605      * Ensure that the `states` collection exists so the `StateMachine`
    606      *   can be used as a mixin.
    607      *
    608      * @since 3.5.0
    609      *
    610      * @param {string} id
    611      * @returns {wp.media.controller.State} Returns a State model
    612      *   from the StateMachine collection
    613      */
    614     state: function( id ) {
    615         this.states = this.states || new Backbone.Collection();
    616 
    617         // Default to the active state.
    618         id = id || this._state;
    619 
    620         if ( id && ! this.states.get( id ) ) {
    621             this.states.add({ id: id });
    622         }
    623         return this.states.get( id );
    624     },
    625 
    626     /**
    627      * Sets the active state.
    628      *
    629      * Bail if we're trying to select the current state, if we haven't
    630      * created the `states` collection, or are trying to select a state
    631      * that does not exist.
    632      *
    633      * @since 3.5.0
    634      *
    635      * @param {string} id
    636      *
    637      * @fires wp.media.controller.State#deactivate
    638      * @fires wp.media.controller.State#activate
    639      *
    640      * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining
    641      */
    642     setState: function( id ) {
    643         var previous = this.state();
    644 
    645         if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) {
    646             return this;
    647         }
    648 
    649         if ( previous ) {
    650             previous.trigger('deactivate');
    651             this._lastState = previous.id;
    652         }
    653 
    654         this._state = id;
    655         this.state().trigger('activate');
    656 
    657         return this;
    658     },
    659 
    660     /**
    661      * Returns the previous active state.
    662      *
    663      * Call the `state()` method with no parameters to retrieve the current
    664      * active state.
    665      *
    666      * @since 3.5.0
    667      *
    668      * @returns {wp.media.controller.State} Returns a State model
    669      *    from the StateMachine collection
    670      */
    671     lastState: function() {
    672         if ( this._lastState ) {
    673             return this.state( this._lastState );
    674         }
    675     }
    676 });
    677 
    678 // Map all event binding and triggering on a StateMachine to its `states` collection.
    679 _.each([ 'on', 'off', 'trigger' ], function( method ) {
    680     /**
    681      * @returns {wp.media.controller.StateMachine} Returns itself to allow chaining.
    682      */
    683     StateMachine.prototype[ method ] = function() {
    684         // Ensure that the `states` collection exists so the `StateMachine`
    685         // can be used as a mixin.
    686         this.states = this.states || new Backbone.Collection();
    687         // Forward the method to the `states` collection.
    688         this.states[ method ].apply( this.states, arguments );
    689         return this;
    690     };
    691 });
    692 
    693 module.exports = StateMachine;
    694 
    695 },{}],6:[function(require,module,exports){
    696 /*globals _, Backbone */
    697 
    698 /**
    699  * wp.media.controller.State
    700  *
    701  * A state is a step in a workflow that when set will trigger the controllers
    702  * for the regions to be updated as specified in the frame.
    703  *
    704  * A state has an event-driven lifecycle:
    705  *
    706  *     'ready'      triggers when a state is added to a state machine's collection.
    707  *     'activate'   triggers when a state is activated by a state machine.
    708  *     'deactivate' triggers when a state is deactivated by a state machine.
    709  *     'reset'      is not triggered automatically. It should be invoked by the
    710  *                  proper controller to reset the state to its default.
    711  *
    712  * @class
    713  * @augments Backbone.Model
    714  */
    715 var State = Backbone.Model.extend({
    716     /**
    717      * Constructor.
    718      *
    719      * @since 3.5.0
    720      */
    721     constructor: function() {
    722         this.on( 'activate', this._preActivate, this );
    723         this.on( 'activate', this.activate, this );
    724         this.on( 'activate', this._postActivate, this );
    725         this.on( 'deactivate', this._deactivate, this );
    726         this.on( 'deactivate', this.deactivate, this );
    727         this.on( 'reset', this.reset, this );
    728         this.on( 'ready', this._ready, this );
    729         this.on( 'ready', this.ready, this );
    730         /**
    731          * Call parent constructor with passed arguments
    732          */
    733         Backbone.Model.apply( this, arguments );
    734         this.on( 'change:menu', this._updateMenu, this );
    735     },
    736     /**
    737      * Ready event callback.
    738      *
    739      * @abstract
    740      * @since 3.5.0
    741      */
    742     ready: function() {},
    743 
    744     /**
    745      * Activate event callback.
    746      *
    747      * @abstract
    748      * @since 3.5.0
    749      */
    750     activate: function() {},
    751 
    752     /**
    753      * Deactivate event callback.
    754      *
    755      * @abstract
    756      * @since 3.5.0
    757      */
    758     deactivate: function() {},
    759 
    760     /**
    761      * Reset event callback.
    762      *
    763      * @abstract
    764      * @since 3.5.0
    765      */
    766     reset: function() {},
    767 
    768     /**
    769      * @access private
    770      * @since 3.5.0
    771      */
    772     _ready: function() {
    773         this._updateMenu();
    774     },
    775 
    776     /**
    777      * @access private
    778      * @since 3.5.0
    779     */
    780     _preActivate: function() {
    781         this.active = true;
    782     },
    783 
    784     /**
    785      * @access private
    786      * @since 3.5.0
    787      */
    788     _postActivate: function() {
    789         this.on( 'change:menu', this._menu, this );
    790         this.on( 'change:titleMode', this._title, this );
    791         this.on( 'change:content', this._content, this );
    792         this.on( 'change:toolbar', this._toolbar, this );
    793 
    794         this.frame.on( 'title:render:default', this._renderTitle, this );
    795 
    796         this._title();
    797         this._menu();
    798         this._toolbar();
    799         this._content();
    800         this._router();
    801     },
    802 
    803     /**
    804      * @access private
    805      * @since 3.5.0
    806      */
    807     _deactivate: function() {
    808         this.active = false;
    809 
    810         this.frame.off( 'title:render:default', this._renderTitle, this );
    811 
    812         this.off( 'change:menu', this._menu, this );
    813         this.off( 'change:titleMode', this._title, this );
    814         this.off( 'change:content', this._content, this );
    815         this.off( 'change:toolbar', this._toolbar, this );
    816     },
    817 
    818     /**
    819      * @access private
    820      * @since 3.5.0
    821      */
    822     _title: function() {
    823         this.frame.title.render( this.get('titleMode') || 'default' );
    824     },
    825 
    826     /**
    827      * @access private
    828      * @since 3.5.0
    829      */
    830     _renderTitle: function( view ) {
    831         view.$el.text( this.get('title') || '' );
    832     },
    833 
    834     /**
    835      * @access private
    836      * @since 3.5.0
    837      */
    838     _router: function() {
    839         var router = this.frame.router,
    840             mode = this.get('router'),
    841             view;
    842 
    843         this.frame.$el.toggleClass( 'hide-router', ! mode );
    844         if ( ! mode ) {
    845             return;
    846         }
    847 
    848         this.frame.router.render( mode );
    849 
    850         view = router.get();
    851         if ( view && view.select ) {
    852             view.select( this.frame.content.mode() );
    853         }
    854     },
    855 
    856     /**
    857      * @access private
    858      * @since 3.5.0
    859      */
    860     _menu: function() {
    861         var menu = this.frame.menu,
    862             mode = this.get('menu'),
    863             view;
    864 
    865         this.frame.$el.toggleClass( 'hide-menu', ! mode );
    866         if ( ! mode ) {
    867             return;
    868         }
    869 
    870         menu.mode( mode );
    871 
    872         view = menu.get();
    873         if ( view && view.select ) {
    874             view.select( this.id );
    875         }
    876     },
    877 
    878     /**
    879      * @access private
    880      * @since 3.5.0
    881      */
    882     _updateMenu: function() {
    883         var previous = this.previous('menu'),
    884             menu = this.get('menu');
    885 
    886         if ( previous ) {
    887             this.frame.off( 'menu:render:' + previous, this._renderMenu, this );
    888         }
    889 
    890         if ( menu ) {
    891             this.frame.on( 'menu:render:' + menu, this._renderMenu, this );
    892         }
    893     },
    894 
    895     /**
    896      * Create a view in the media menu for the state.
    897      *
    898      * @access private
    899      * @since 3.5.0
    900      *
    901      * @param {media.view.Menu} view The menu view.
    902      */
    903     _renderMenu: function( view ) {
    904         var menuItem = this.get('menuItem'),
    905             title = this.get('title'),
    906             priority = this.get('priority');
    907 
    908         if ( ! menuItem && title ) {
    909             menuItem = { text: title };
    910 
    911             if ( priority ) {
    912                 menuItem.priority = priority;
    913             }
    914         }
    915 
    916         if ( ! menuItem ) {
    917             return;
    918         }
    919 
    920         view.set( this.id, menuItem );
    921     }
    922 });
    923 
    924 _.each(['toolbar','content'], function( region ) {
    925     /**
    926      * @access private
    927      */
    928     State.prototype[ '_' + region ] = function() {
    929         var mode = this.get( region );
    930         if ( mode ) {
    931             this.frame[ region ].render( mode );
    932         }
    933     };
    934 });
    935 
    936 module.exports = State;
    937 
    938 },{}],7:[function(require,module,exports){
     32},{}],2:[function(require,module,exports){
    93933/*globals wp */
    94034
     
    95145media.view.DeleteSelectedPermanentlyButton = require( './views/button/delete-selected-permanently.js' );
    95246
    953 },{"./controllers/edit-attachment-metadata.js":1,"./routers/manage.js":8,"./views/attachment/details-two-column.js":16,"./views/button/delete-selected-permanently.js":22,"./views/button/delete-selected.js":23,"./views/button/select-mode-toggle.js":24,"./views/edit-image-details.js":25,"./views/frame/edit-attachments.js":28,"./views/frame/manage.js":29}],8:[function(require,module,exports){
     47},{"./controllers/edit-attachment-metadata.js":1,"./routers/manage.js":3,"./views/attachment/details-two-column.js":4,"./views/button/delete-selected-permanently.js":5,"./views/button/delete-selected.js":6,"./views/button/select-mode-toggle.js":7,"./views/edit-image-details.js":8,"./views/frame/edit-attachments.js":9,"./views/frame/manage.js":10}],3:[function(require,module,exports){
    95448/*globals wp, Backbone */
    95549
     
    100195module.exports = Router;
    100296
    1003 },{}],9:[function(require,module,exports){
    1004 /*globals _ */
    1005 
    1006 /**
    1007  * wp.media.selectionSync
    1008  *
    1009  * Sync an attachments selection in a state with another state.
    1010  *
    1011  * Allows for selecting multiple images in the Insert Media workflow, and then
    1012  * switching to the Insert Gallery workflow while preserving the attachments selection.
    1013  *
    1014  * @mixin
    1015  */
    1016 var selectionSync = {
    1017     /**
    1018      * @since 3.5.0
    1019      */
    1020     syncSelection: function() {
    1021         var selection = this.get('selection'),
    1022             manager = this.frame._selection;
    1023 
    1024         if ( ! this.get('syncSelection') || ! manager || ! selection ) {
    1025             return;
    1026         }
    1027 
    1028         // If the selection supports multiple items, validate the stored
    1029         // attachments based on the new selection's conditions. Record
    1030         // the attachments that are not included; we'll maintain a
    1031         // reference to those. Other attachments are considered in flux.
    1032         if ( selection.multiple ) {
    1033             selection.reset( [], { silent: true });
    1034             selection.validateAll( manager.attachments );
    1035             manager.difference = _.difference( manager.attachments.models, selection.models );
    1036         }
    1037 
    1038         // Sync the selection's single item with the master.
    1039         selection.single( manager.single );
    1040     },
    1041 
    1042     /**
    1043      * Record the currently active attachments, which is a combination
    1044      * of the selection's attachments and the set of selected
    1045      * attachments that this specific selection considered invalid.
    1046      * Reset the difference and record the single attachment.
    1047      *
    1048      * @since 3.5.0
    1049      */
    1050     recordSelection: function() {
    1051         var selection = this.get('selection'),
    1052             manager = this.frame._selection;
    1053 
    1054         if ( ! this.get('syncSelection') || ! manager || ! selection ) {
    1055             return;
    1056         }
    1057 
    1058         if ( selection.multiple ) {
    1059             manager.attachments.reset( selection.toArray().concat( manager.difference ) );
    1060             manager.difference = [];
    1061         } else {
    1062             manager.attachments.add( selection.toArray() );
    1063         }
    1064 
    1065         manager.single = selection._single;
    1066     }
    1067 };
    1068 
    1069 module.exports = selectionSync;
    1070 
    1071 },{}],10:[function(require,module,exports){
    1072 /*globals _ */
    1073 
    1074 /**
    1075  * wp.media.view.AttachmentCompat
    1076  *
    1077  * A view to display fields added via the `attachment_fields_to_edit` filter.
    1078  *
    1079  * @class
    1080  * @augments wp.media.View
    1081  * @augments wp.Backbone.View
    1082  * @augments Backbone.View
    1083  */
    1084 var View = require( './view.js' ),
    1085     AttachmentCompat;
    1086 
    1087 AttachmentCompat = View.extend({
    1088     tagName:   'form',
    1089     className: 'compat-item',
    1090 
    1091     events: {
    1092         'submit':          'preventDefault',
    1093         'change input':    'save',
    1094         'change select':   'save',
    1095         'change textarea': 'save'
    1096     },
    1097 
    1098     initialize: function() {
    1099         this.listenTo( this.model, 'change:compat', this.render );
    1100     },
    1101     /**
    1102      * @returns {wp.media.view.AttachmentCompat} Returns itself to allow chaining
    1103      */
    1104     dispose: function() {
    1105         if ( this.$(':focus').length ) {
    1106             this.save();
    1107         }
    1108         /**
    1109          * call 'dispose' directly on the parent class
    1110          */
    1111         return View.prototype.dispose.apply( this, arguments );
    1112     },
    1113     /**
    1114      * @returns {wp.media.view.AttachmentCompat} Returns itself to allow chaining
    1115      */
    1116     render: function() {
    1117         var compat = this.model.get('compat');
    1118         if ( ! compat || ! compat.item ) {
    1119             return;
    1120         }
    1121 
    1122         this.views.detach();
    1123         this.$el.html( compat.item );
    1124         this.views.render();
    1125         return this;
    1126     },
    1127     /**
    1128      * @param {Object} event
    1129      */
    1130     preventDefault: function( event ) {
    1131         event.preventDefault();
    1132     },
    1133     /**
    1134      * @param {Object} event
    1135      */
    1136     save: function( event ) {
    1137         var data = {};
    1138 
    1139         if ( event ) {
    1140             event.preventDefault();
    1141         }
    1142 
    1143         _.each( this.$el.serializeArray(), function( pair ) {
    1144             data[ pair.name ] = pair.value;
    1145         });
    1146 
    1147         this.controller.trigger( 'attachment:compat:waiting', ['waiting'] );
    1148         this.model.saveCompat( data ).always( _.bind( this.postSave, this ) );
    1149     },
    1150 
    1151     postSave: function() {
    1152         this.controller.trigger( 'attachment:compat:ready', ['ready'] );
    1153     }
    1154 });
    1155 
    1156 module.exports = AttachmentCompat;
    1157 
    1158 },{"./view.js":49}],11:[function(require,module,exports){
    1159 /*globals _, jQuery */
    1160 
    1161 /**
    1162  * wp.media.view.AttachmentFilters
    1163  *
    1164  * @class
    1165  * @augments wp.media.View
    1166  * @augments wp.Backbone.View
    1167  * @augments Backbone.View
    1168  */
    1169 var View = require( './view.js' ),
    1170     $ = jQuery,
    1171     AttachmentFilters;
    1172 
    1173 AttachmentFilters = View.extend({
    1174     tagName:   'select',
    1175     className: 'attachment-filters',
    1176     id:        'media-attachment-filters',
    1177 
    1178     events: {
    1179         change: 'change'
    1180     },
    1181 
    1182     keys: [],
    1183 
    1184     initialize: function() {
    1185         this.createFilters();
    1186         _.extend( this.filters, this.options.filters );
    1187 
    1188         // Build `<option>` elements.
    1189         this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
    1190             return {
    1191                 el: $( '<option></option>' ).val( value ).html( filter.text )[0],
    1192                 priority: filter.priority || 50
    1193             };
    1194         }, this ).sortBy('priority').pluck('el').value() );
    1195 
    1196         this.listenTo( this.model, 'change', this.select );
    1197         this.select();
    1198     },
    1199 
    1200     /**
    1201      * @abstract
    1202      */
    1203     createFilters: function() {
    1204         this.filters = {};
    1205     },
    1206 
    1207     /**
    1208      * When the selected filter changes, update the Attachment Query properties to match.
    1209      */
    1210     change: function() {
    1211         var filter = this.filters[ this.el.value ];
    1212         if ( filter ) {
    1213             this.model.set( filter.props );
    1214         }
    1215     },
    1216 
    1217     select: function() {
    1218         var model = this.model,
    1219             value = 'all',
    1220             props = model.toJSON();
    1221 
    1222         _.find( this.filters, function( filter, id ) {
    1223             var equal = _.all( filter.props, function( prop, key ) {
    1224                 return prop === ( _.isUndefined( props[ key ] ) ? null : props[ key ] );
    1225             });
    1226 
    1227             if ( equal ) {
    1228                 return value = id;
    1229             }
    1230         });
    1231 
    1232         this.$el.val( value );
    1233     }
    1234 });
    1235 
    1236 module.exports = AttachmentFilters;
    1237 
    1238 },{"./view.js":49}],12:[function(require,module,exports){
    1239 /*globals wp */
    1240 
    1241 /**
    1242  * wp.media.view.AttachmentFilters.All
    1243  *
    1244  * @class
    1245  * @augments wp.media.view.AttachmentFilters
    1246  * @augments wp.media.View
    1247  * @augments wp.Backbone.View
    1248  * @augments Backbone.View
    1249  */
    1250 var AttachmentFilters = require( '../attachment-filters.js' ),
    1251     l10n = wp.media.view.l10n,
    1252     All;
    1253 
    1254 All = AttachmentFilters.extend({
    1255     createFilters: function() {
    1256         var filters = {};
    1257 
    1258         _.each( wp.media.view.settings.mimeTypes || {}, function( text, key ) {
    1259             filters[ key ] = {
    1260                 text: text,
    1261                 props: {
    1262                     status:  null,
    1263                     type:    key,
    1264                     uploadedTo: null,
    1265                     orderby: 'date',
    1266                     order:   'DESC'
    1267                 }
    1268             };
    1269         });
    1270 
    1271         filters.all = {
    1272             text:  l10n.allMediaItems,
    1273             props: {
    1274                 status:  null,
    1275                 type:    null,
    1276                 uploadedTo: null,
    1277                 orderby: 'date',
    1278                 order:   'DESC'
    1279             },
    1280             priority: 10
    1281         };
    1282 
    1283         if ( wp.media.view.settings.post.id ) {
    1284             filters.uploaded = {
    1285                 text:  l10n.uploadedToThisPost,
    1286                 props: {
    1287                     status:  null,
    1288                     type:    null,
    1289                     uploadedTo: wp.media.view.settings.post.id,
    1290                     orderby: 'menuOrder',
    1291                     order:   'ASC'
    1292                 },
    1293                 priority: 20
    1294             };
    1295         }
    1296 
    1297         filters.unattached = {
    1298             text:  l10n.unattached,
    1299             props: {
    1300                 status:     null,
    1301                 uploadedTo: 0,
    1302                 type:       null,
    1303                 orderby:    'menuOrder',
    1304                 order:      'ASC'
    1305             },
    1306             priority: 50
    1307         };
    1308 
    1309         if ( wp.media.view.settings.mediaTrash &&
    1310             this.controller.isModeActive( 'grid' ) ) {
    1311 
    1312             filters.trash = {
    1313                 text:  l10n.trash,
    1314                 props: {
    1315                     uploadedTo: null,
    1316                     status:     'trash',
    1317                     type:       null,
    1318                     orderby:    'date',
    1319                     order:      'DESC'
    1320                 },
    1321                 priority: 50
    1322             };
    1323         }
    1324 
    1325         this.filters = filters;
    1326     }
    1327 });
    1328 
    1329 module.exports = All;
    1330 
    1331 },{"../attachment-filters.js":11}],13:[function(require,module,exports){
    1332 /*globals wp, _ */
    1333 
    1334 /**
    1335  * A filter dropdown for month/dates.
    1336  *
    1337  * @class
    1338  * @augments wp.media.view.AttachmentFilters
    1339  * @augments wp.media.View
    1340  * @augments wp.Backbone.View
    1341  * @augments Backbone.View
    1342  */
    1343 var AttachmentFilters = require( '../attachment-filters.js' ),
    1344     l10n = wp.media.view.l10n,
    1345     DateFilter;
    1346 
    1347 DateFilter = AttachmentFilters.extend({
    1348     id: 'media-attachment-date-filters',
    1349 
    1350     createFilters: function() {
    1351         var filters = {};
    1352         _.each( wp.media.view.settings.months || {}, function( value, index ) {
    1353             filters[ index ] = {
    1354                 text: value.text,
    1355                 props: {
    1356                     year: value.year,
    1357                     monthnum: value.month
    1358                 }
    1359             };
    1360         });
    1361         filters.all = {
    1362             text:  l10n.allDates,
    1363             props: {
    1364                 monthnum: false,
    1365                 year:  false
    1366             },
    1367             priority: 10
    1368         };
    1369         this.filters = filters;
    1370     }
    1371 });
    1372 
    1373 module.exports = DateFilter;
    1374 
    1375 },{"../attachment-filters.js":11}],14:[function(require,module,exports){
    1376 /*globals wp */
    1377 
    1378 /**
    1379  * wp.media.view.AttachmentFilters.Uploaded
    1380  *
    1381  * @class
    1382  * @augments wp.media.view.AttachmentFilters
    1383  * @augments wp.media.View
    1384  * @augments wp.Backbone.View
    1385  * @augments Backbone.View
    1386  */
    1387 var AttachmentFilters = require( '../attachment-filters.js' ),
    1388     l10n = wp.media.view.l10n,
    1389     Uploaded;
    1390 
    1391 Uploaded = AttachmentFilters.extend({
    1392     createFilters: function() {
    1393         var type = this.model.get('type'),
    1394             types = wp.media.view.settings.mimeTypes,
    1395             text;
    1396 
    1397         if ( types && type ) {
    1398             text = types[ type ];
    1399         }
    1400 
    1401         this.filters = {
    1402             all: {
    1403                 text:  text || l10n.allMediaItems,
    1404                 props: {
    1405                     uploadedTo: null,
    1406                     orderby: 'date',
    1407                     order:   'DESC'
    1408                 },
    1409                 priority: 10
    1410             },
    1411 
    1412             uploaded: {
    1413                 text:  l10n.uploadedToThisPost,
    1414                 props: {
    1415                     uploadedTo: wp.media.view.settings.post.id,
    1416                     orderby: 'menuOrder',
    1417                     order:   'ASC'
    1418                 },
    1419                 priority: 20
    1420             },
    1421 
    1422             unattached: {
    1423                 text:  l10n.unattached,
    1424                 props: {
    1425                     uploadedTo: 0,
    1426                     orderby: 'menuOrder',
    1427                     order:   'ASC'
    1428                 },
    1429                 priority: 50
    1430             }
    1431         };
    1432     }
    1433 });
    1434 
    1435 module.exports = Uploaded;
    1436 
    1437 },{"../attachment-filters.js":11}],15:[function(require,module,exports){
    1438 /*globals wp, _, jQuery */
    1439 
    1440 /**
    1441  * wp.media.view.Attachment
    1442  *
    1443  * @class
    1444  * @augments wp.media.View
    1445  * @augments wp.Backbone.View
    1446  * @augments Backbone.View
    1447  */
    1448 var View = require( './view.js' ),
    1449     $ = jQuery,
    1450     Attachment;
    1451 
    1452 Attachment = View.extend({
    1453     tagName:   'li',
    1454     className: 'attachment',
    1455     template:  wp.template('attachment'),
    1456 
    1457     attributes: function() {
    1458         return {
    1459             'tabIndex':     0,
    1460             'role':         'checkbox',
    1461             'aria-label':   this.model.get( 'title' ),
    1462             'aria-checked': false,
    1463             'data-id':      this.model.get( 'id' )
    1464         };
    1465     },
    1466 
    1467     events: {
    1468         'click .js--select-attachment':   'toggleSelectionHandler',
    1469         'change [data-setting]':          'updateSetting',
    1470         'change [data-setting] input':    'updateSetting',
    1471         'change [data-setting] select':   'updateSetting',
    1472         'change [data-setting] textarea': 'updateSetting',
    1473         'click .close':                   'removeFromLibrary',
    1474         'click .check':                   'checkClickHandler',
    1475         'click a':                        'preventDefault',
    1476         'keydown .close':                 'removeFromLibrary',
    1477         'keydown':                        'toggleSelectionHandler'
    1478     },
    1479 
    1480     buttons: {},
    1481 
    1482     initialize: function() {
    1483         var selection = this.options.selection,
    1484             options = _.defaults( this.options, {
    1485                 rerenderOnModelChange: true
    1486             } );
    1487 
    1488         if ( options.rerenderOnModelChange ) {
    1489             this.listenTo( this.model, 'change', this.render );
    1490         } else {
    1491             this.listenTo( this.model, 'change:percent', this.progress );
    1492         }
    1493         this.listenTo( this.model, 'change:title', this._syncTitle );
    1494         this.listenTo( this.model, 'change:caption', this._syncCaption );
    1495         this.listenTo( this.model, 'change:artist', this._syncArtist );
    1496         this.listenTo( this.model, 'change:album', this._syncAlbum );
    1497 
    1498         // Update the selection.
    1499         this.listenTo( this.model, 'add', this.select );
    1500         this.listenTo( this.model, 'remove', this.deselect );
    1501         if ( selection ) {
    1502             selection.on( 'reset', this.updateSelect, this );
    1503             // Update the model's details view.
    1504             this.listenTo( this.model, 'selection:single selection:unsingle', this.details );
    1505             this.details( this.model, this.controller.state().get('selection') );
    1506         }
    1507 
    1508         this.listenTo( this.controller, 'attachment:compat:waiting attachment:compat:ready', this.updateSave );
    1509     },
    1510     /**
    1511      * @returns {wp.media.view.Attachment} Returns itself to allow chaining
    1512      */
    1513     dispose: function() {
    1514         var selection = this.options.selection;
    1515 
    1516         // Make sure all settings are saved before removing the view.
    1517         this.updateAll();
    1518 
    1519         if ( selection ) {
    1520             selection.off( null, null, this );
    1521         }
    1522         /**
    1523          * call 'dispose' directly on the parent class
    1524          */
    1525         View.prototype.dispose.apply( this, arguments );
    1526         return this;
    1527     },
    1528     /**
    1529      * @returns {wp.media.view.Attachment} Returns itself to allow chaining
    1530      */
    1531     render: function() {
    1532         var options = _.defaults( this.model.toJSON(), {
    1533                 orientation:   'landscape',
    1534                 uploading:     false,
    1535                 type:          '',
    1536                 subtype:       '',
    1537                 icon:          '',
    1538                 filename:      '',
    1539                 caption:       '',
    1540                 title:         '',
    1541                 dateFormatted: '',
    1542                 width:         '',
    1543                 height:        '',
    1544                 compat:        false,
    1545                 alt:           '',
    1546                 description:   ''
    1547             }, this.options );
    1548 
    1549         options.buttons  = this.buttons;
    1550         options.describe = this.controller.state().get('describe');
    1551 
    1552         if ( 'image' === options.type ) {
    1553             options.size = this.imageSize();
    1554         }
    1555 
    1556         options.can = {};
    1557         if ( options.nonces ) {
    1558             options.can.remove = !! options.nonces['delete'];
    1559             options.can.save = !! options.nonces.update;
    1560         }
    1561 
    1562         if ( this.controller.state().get('allowLocalEdits') ) {
    1563             options.allowLocalEdits = true;
    1564         }
    1565 
    1566         if ( options.uploading && ! options.percent ) {
    1567             options.percent = 0;
    1568         }
    1569 
    1570         this.views.detach();
    1571         this.$el.html( this.template( options ) );
    1572 
    1573         this.$el.toggleClass( 'uploading', options.uploading );
    1574 
    1575         if ( options.uploading ) {
    1576             this.$bar = this.$('.media-progress-bar div');
    1577         } else {
    1578             delete this.$bar;
    1579         }
    1580 
    1581         // Check if the model is selected.
    1582         this.updateSelect();
    1583 
    1584         // Update the save status.
    1585         this.updateSave();
    1586 
    1587         this.views.render();
    1588 
    1589         return this;
    1590     },
    1591 
    1592     progress: function() {
    1593         if ( this.$bar && this.$bar.length ) {
    1594             this.$bar.width( this.model.get('percent') + '%' );
    1595         }
    1596     },
    1597 
    1598     /**
    1599      * @param {Object} event
    1600      */
    1601     toggleSelectionHandler: function( event ) {
    1602         var method;
    1603 
    1604         // Don't do anything inside inputs.
    1605         if ( 'INPUT' === event.target.nodeName ) {
    1606             return;
    1607         }
    1608 
    1609         // Catch arrow events
    1610         if ( 37 === event.keyCode || 38 === event.keyCode || 39 === event.keyCode || 40 === event.keyCode ) {
    1611             this.controller.trigger( 'attachment:keydown:arrow', event );
    1612             return;
    1613         }
    1614 
    1615         // Catch enter and space events
    1616         if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
    1617             return;
    1618         }
    1619 
    1620         event.preventDefault();
    1621 
    1622         // In the grid view, bubble up an edit:attachment event to the controller.
    1623         if ( this.controller.isModeActive( 'grid' ) ) {
    1624             if ( this.controller.isModeActive( 'edit' ) ) {
    1625                 // Pass the current target to restore focus when closing
    1626                 this.controller.trigger( 'edit:attachment', this.model, event.currentTarget );
    1627                 return;
    1628             }
    1629 
    1630             if ( this.controller.isModeActive( 'select' ) ) {
    1631                 method = 'toggle';
    1632             }
    1633         }
    1634 
    1635         if ( event.shiftKey ) {
    1636             method = 'between';
    1637         } else if ( event.ctrlKey || event.metaKey ) {
    1638             method = 'toggle';
    1639         }
    1640 
    1641         this.toggleSelection({
    1642             method: method
    1643         });
    1644 
    1645         this.controller.trigger( 'selection:toggle' );
    1646     },
    1647     /**
    1648      * @param {Object} options
    1649      */
    1650     toggleSelection: function( options ) {
    1651         var collection = this.collection,
    1652             selection = this.options.selection,
    1653             model = this.model,
    1654             method = options && options.method,
    1655             single, models, singleIndex, modelIndex;
    1656 
    1657         if ( ! selection ) {
    1658             return;
    1659         }
    1660 
    1661         single = selection.single();
    1662         method = _.isUndefined( method ) ? selection.multiple : method;
    1663 
    1664         // If the `method` is set to `between`, select all models that
    1665         // exist between the current and the selected model.
    1666         if ( 'between' === method && single && selection.multiple ) {
    1667             // If the models are the same, short-circuit.
    1668             if ( single === model ) {
    1669                 return;
    1670             }
    1671 
    1672             singleIndex = collection.indexOf( single );
    1673             modelIndex  = collection.indexOf( this.model );
    1674 
    1675             if ( singleIndex < modelIndex ) {
    1676                 models = collection.models.slice( singleIndex, modelIndex + 1 );
    1677             } else {
    1678                 models = collection.models.slice( modelIndex, singleIndex + 1 );
    1679             }
    1680 
    1681             selection.add( models );
    1682             selection.single( model );
    1683             return;
    1684 
    1685         // If the `method` is set to `toggle`, just flip the selection
    1686         // status, regardless of whether the model is the single model.
    1687         } else if ( 'toggle' === method ) {
    1688             selection[ this.selected() ? 'remove' : 'add' ]( model );
    1689             selection.single( model );
    1690             return;
    1691         } else if ( 'add' === method ) {
    1692             selection.add( model );
    1693             selection.single( model );
    1694             return;
    1695         }
    1696 
    1697         // Fixes bug that loses focus when selecting a featured image
    1698         if ( ! method ) {
    1699             method = 'add';
    1700         }
    1701 
    1702         if ( method !== 'add' ) {
    1703             method = 'reset';
    1704         }
    1705 
    1706         if ( this.selected() ) {
    1707             // If the model is the single model, remove it.
    1708             // If it is not the same as the single model,
    1709             // it now becomes the single model.
    1710             selection[ single === model ? 'remove' : 'single' ]( model );
    1711         } else {
    1712             // If the model is not selected, run the `method` on the
    1713             // selection. By default, we `reset` the selection, but the
    1714             // `method` can be set to `add` the model to the selection.
    1715             selection[ method ]( model );
    1716             selection.single( model );
    1717         }
    1718     },
    1719 
    1720     updateSelect: function() {
    1721         this[ this.selected() ? 'select' : 'deselect' ]();
    1722     },
    1723     /**
    1724      * @returns {unresolved|Boolean}
    1725      */
    1726     selected: function() {
    1727         var selection = this.options.selection;
    1728         if ( selection ) {
    1729             return !! selection.get( this.model.cid );
    1730         }
    1731     },
    1732     /**
    1733      * @param {Backbone.Model} model
    1734      * @param {Backbone.Collection} collection
    1735      */
    1736     select: function( model, collection ) {
    1737         var selection = this.options.selection,
    1738             controller = this.controller;
    1739 
    1740         // Check if a selection exists and if it's the collection provided.
    1741         // If they're not the same collection, bail; we're in another
    1742         // selection's event loop.
    1743         if ( ! selection || ( collection && collection !== selection ) ) {
    1744             return;
    1745         }
    1746 
    1747         // Bail if the model is already selected.
    1748         if ( this.$el.hasClass( 'selected' ) ) {
    1749             return;
    1750         }
    1751 
    1752         // Add 'selected' class to model, set aria-checked to true.
    1753         this.$el.addClass( 'selected' ).attr( 'aria-checked', true );
    1754         //  Make the checkbox tabable, except in media grid (bulk select mode).
    1755         if ( ! ( controller.isModeActive( 'grid' ) && controller.isModeActive( 'select' ) ) ) {
    1756             this.$( '.check' ).attr( 'tabindex', '0' );
    1757         }
    1758     },
    1759     /**
    1760      * @param {Backbone.Model} model
    1761      * @param {Backbone.Collection} collection
    1762      */
    1763     deselect: function( model, collection ) {
    1764         var selection = this.options.selection;
    1765 
    1766         // Check if a selection exists and if it's the collection provided.
    1767         // If they're not the same collection, bail; we're in another
    1768         // selection's event loop.
    1769         if ( ! selection || ( collection && collection !== selection ) ) {
    1770             return;
    1771         }
    1772         this.$el.removeClass( 'selected' ).attr( 'aria-checked', false )
    1773             .find( '.check' ).attr( 'tabindex', '-1' );
    1774     },
    1775     /**
    1776      * @param {Backbone.Model} model
    1777      * @param {Backbone.Collection} collection
    1778      */
    1779     details: function( model, collection ) {
    1780         var selection = this.options.selection,
    1781             details;
    1782 
    1783         if ( selection !== collection ) {
    1784             return;
    1785         }
    1786 
    1787         details = selection.single();
    1788         this.$el.toggleClass( 'details', details === this.model );
    1789     },
    1790     /**
    1791      * @param {Object} event
    1792      */
    1793     preventDefault: function( event ) {
    1794         event.preventDefault();
    1795     },
    1796     /**
    1797      * @param {string} size
    1798      * @returns {Object}
    1799      */
    1800     imageSize: function( size ) {
    1801         var sizes = this.model.get('sizes'), matched = false;
    1802 
    1803         size = size || 'medium';
    1804 
    1805         // Use the provided image size if possible.
    1806         if ( sizes ) {
    1807             if ( sizes[ size ] ) {
    1808                 matched = sizes[ size ];
    1809             } else if ( sizes.large ) {
    1810                 matched = sizes.large;
    1811             } else if ( sizes.thumbnail ) {
    1812                 matched = sizes.thumbnail;
    1813             } else if ( sizes.full ) {
    1814                 matched = sizes.full;
    1815             }
    1816 
    1817             if ( matched ) {
    1818                 return _.clone( matched );
    1819             }
    1820         }
    1821 
    1822         return {
    1823             url:         this.model.get('url'),
    1824             width:       this.model.get('width'),
    1825             height:      this.model.get('height'),
    1826             orientation: this.model.get('orientation')
    1827         };
    1828     },
    1829     /**
    1830      * @param {Object} event
    1831      */
    1832     updateSetting: function( event ) {
    1833         var $setting = $( event.target ).closest('[data-setting]'),
    1834             setting, value;
    1835 
    1836         if ( ! $setting.length ) {
    1837             return;
    1838         }
    1839 
    1840         setting = $setting.data('setting');
    1841         value   = event.target.value;
    1842 
    1843         if ( this.model.get( setting ) !== value ) {
    1844             this.save( setting, value );
    1845         }
    1846     },
    1847 
    1848     /**
    1849      * Pass all the arguments to the model's save method.
    1850      *
    1851      * Records the aggregate status of all save requests and updates the
    1852      * view's classes accordingly.
    1853      */
    1854     save: function() {
    1855         var view = this,
    1856             save = this._save = this._save || { status: 'ready' },
    1857             request = this.model.save.apply( this.model, arguments ),
    1858             requests = save.requests ? $.when( request, save.requests ) : request;
    1859 
    1860         // If we're waiting to remove 'Saved.', stop.
    1861         if ( save.savedTimer ) {
    1862             clearTimeout( save.savedTimer );
    1863         }
    1864 
    1865         this.updateSave('waiting');
    1866         save.requests = requests;
    1867         requests.always( function() {
    1868             // If we've performed another request since this one, bail.
    1869             if ( save.requests !== requests ) {
    1870                 return;
    1871             }
    1872 
    1873             view.updateSave( requests.state() === 'resolved' ? 'complete' : 'error' );
    1874             save.savedTimer = setTimeout( function() {
    1875                 view.updateSave('ready');
    1876                 delete save.savedTimer;
    1877             }, 2000 );
    1878         });
    1879     },
    1880     /**
    1881      * @param {string} status
    1882      * @returns {wp.media.view.Attachment} Returns itself to allow chaining
    1883      */
    1884     updateSave: function( status ) {
    1885         var save = this._save = this._save || { status: 'ready' };
    1886 
    1887         if ( status && status !== save.status ) {
    1888             this.$el.removeClass( 'save-' + save.status );
    1889             save.status = status;
    1890         }
    1891 
    1892         this.$el.addClass( 'save-' + save.status );
    1893         return this;
    1894     },
    1895 
    1896     updateAll: function() {
    1897         var $settings = this.$('[data-setting]'),
    1898             model = this.model,
    1899             changed;
    1900 
    1901         changed = _.chain( $settings ).map( function( el ) {
    1902             var $input = $('input, textarea, select, [value]', el ),
    1903                 setting, value;
    1904 
    1905             if ( ! $input.length ) {
    1906                 return;
    1907             }
    1908 
    1909             setting = $(el).data('setting');
    1910             value = $input.val();
    1911 
    1912             // Record the value if it changed.
    1913             if ( model.get( setting ) !== value ) {
    1914                 return [ setting, value ];
    1915             }
    1916         }).compact().object().value();
    1917 
    1918         if ( ! _.isEmpty( changed ) ) {
    1919             model.save( changed );
    1920         }
    1921     },
    1922     /**
    1923      * @param {Object} event
    1924      */
    1925     removeFromLibrary: function( event ) {
    1926         // Catch enter and space events
    1927         if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
    1928             return;
    1929         }
    1930 
    1931         // Stop propagation so the model isn't selected.
    1932         event.stopPropagation();
    1933 
    1934         this.collection.remove( this.model );
    1935     },
    1936 
    1937     /**
    1938      * Add the model if it isn't in the selection, if it is in the selection,
    1939      * remove it.
    1940      *
    1941      * @param  {[type]} event [description]
    1942      * @return {[type]}       [description]
    1943      */
    1944     checkClickHandler: function ( event ) {
    1945         var selection = this.options.selection;
    1946         if ( ! selection ) {
    1947             return;
    1948         }
    1949         event.stopPropagation();
    1950         if ( selection.where( { id: this.model.get( 'id' ) } ).length ) {
    1951             selection.remove( this.model );
    1952             // Move focus back to the attachment tile (from the check).
    1953             this.$el.focus();
    1954         } else {
    1955             selection.add( this.model );
    1956         }
    1957     }
    1958 });
    1959 
    1960 // Ensure settings remain in sync between attachment views.
    1961 _.each({
    1962     caption: '_syncCaption',
    1963     title:   '_syncTitle',
    1964     artist:  '_syncArtist',
    1965     album:   '_syncAlbum'
    1966 }, function( method, setting ) {
    1967     /**
    1968      * @param {Backbone.Model} model
    1969      * @param {string} value
    1970      * @returns {wp.media.view.Attachment} Returns itself to allow chaining
    1971      */
    1972     Attachment.prototype[ method ] = function( model, value ) {
    1973         var $setting = this.$('[data-setting="' + setting + '"]');
    1974 
    1975         if ( ! $setting.length ) {
    1976             return this;
    1977         }
    1978 
    1979         // If the updated value is in sync with the value in the DOM, there
    1980         // is no need to re-render. If we're currently editing the value,
    1981         // it will automatically be in sync, suppressing the re-render for
    1982         // the view we're editing, while updating any others.
    1983         if ( value === $setting.find('input, textarea, select, [value]').val() ) {
    1984             return this;
    1985         }
    1986 
    1987         return this.render();
    1988     };
    1989 });
    1990 
    1991 module.exports = Attachment;
    1992 
    1993 },{"./view.js":49}],16:[function(require,module,exports){
     97},{}],4:[function(require,module,exports){
    199498/*globals wp */
    199599
     
    2007111 * @augments Backbone.View
    2008112 */
    2009 var Details = require( './details.js' ),
     113var Details = wp.media.view.Attachment.Details,
    2010114    TwoColumn;
    2011115
     
    2036140module.exports = TwoColumn;
    2037141
    2038 },{"./details.js":17}],17:[function(require,module,exports){
    2039 /*globals wp, _ */
    2040 
    2041 /**
    2042  * wp.media.view.Attachment.Details
    2043  *
    2044  * @class
    2045  * @augments wp.media.view.Attachment
    2046  * @augments wp.media.View
    2047  * @augments wp.Backbone.View
    2048  * @augments Backbone.View
    2049  */
    2050 var Attachment = require( '../attachment.js' ),
    2051     l10n = wp.media.view.l10n,
    2052     Details;
    2053 
    2054 Details = Attachment.extend({
    2055     tagName:   'div',
    2056     className: 'attachment-details',
    2057     template:  wp.template('attachment-details'),
    2058 
    2059     attributes: function() {
    2060         return {
    2061             'tabIndex':     0,
    2062             'data-id':      this.model.get( 'id' )
    2063         };
    2064     },
    2065 
    2066     events: {
    2067         'change [data-setting]':          'updateSetting',
    2068         'change [data-setting] input':    'updateSetting',
    2069         'change [data-setting] select':   'updateSetting',
    2070         'change [data-setting] textarea': 'updateSetting',
    2071         'click .delete-attachment':       'deleteAttachment',
    2072         'click .trash-attachment':        'trashAttachment',
    2073         'click .untrash-attachment':      'untrashAttachment',
    2074         'click .edit-attachment':         'editAttachment',
    2075         'click .refresh-attachment':      'refreshAttachment',
    2076         'keydown':                        'toggleSelectionHandler'
    2077     },
    2078 
    2079     initialize: function() {
    2080         this.options = _.defaults( this.options, {
    2081             rerenderOnModelChange: false
    2082         });
    2083 
    2084         this.on( 'ready', this.initialFocus );
    2085         // Call 'initialize' directly on the parent class.
    2086         Attachment.prototype.initialize.apply( this, arguments );
    2087     },
    2088 
    2089     initialFocus: function() {
    2090         if ( ! wp.media.isTouchDevice ) {
    2091             this.$( ':input' ).eq( 0 ).focus();
    2092         }
    2093     },
    2094     /**
    2095      * @param {Object} event
    2096      */
    2097     deleteAttachment: function( event ) {
    2098         event.preventDefault();
    2099 
    2100         if ( window.confirm( l10n.warnDelete ) ) {
    2101             this.model.destroy();
    2102             // Keep focus inside media modal
    2103             // after image is deleted
    2104             this.controller.modal.focusManager.focus();
    2105         }
    2106     },
    2107     /**
    2108      * @param {Object} event
    2109      */
    2110     trashAttachment: function( event ) {
    2111         var library = this.controller.library;
    2112         event.preventDefault();
    2113 
    2114         if ( wp.media.view.settings.mediaTrash &&
    2115             'edit-metadata' === this.controller.content.mode() ) {
    2116 
    2117             this.model.set( 'status', 'trash' );
    2118             this.model.save().done( function() {
    2119                 library._requery( true );
    2120             } );
    2121         }  else {
    2122             this.model.destroy();
    2123         }
    2124     },
    2125     /**
    2126      * @param {Object} event
    2127      */
    2128     untrashAttachment: function( event ) {
    2129         var library = this.controller.library;
    2130         event.preventDefault();
    2131 
    2132         this.model.set( 'status', 'inherit' );
    2133         this.model.save().done( function() {
    2134             library._requery( true );
    2135         } );
    2136     },
    2137     /**
    2138      * @param {Object} event
    2139      */
    2140     editAttachment: function( event ) {
    2141         var editState = this.controller.states.get( 'edit-image' );
    2142         if ( window.imageEdit && editState ) {
    2143             event.preventDefault();
    2144 
    2145             editState.set( 'image', this.model );
    2146             this.controller.setState( 'edit-image' );
    2147         } else {
    2148             this.$el.addClass('needs-refresh');
    2149         }
    2150     },
    2151     /**
    2152      * @param {Object} event
    2153      */
    2154     refreshAttachment: function( event ) {
    2155         this.$el.removeClass('needs-refresh');
    2156         event.preventDefault();
    2157         this.model.fetch();
    2158     },
    2159     /**
    2160      * When reverse tabbing(shift+tab) out of the right details panel, deliver
    2161      * the focus to the item in the list that was being edited.
    2162      *
    2163      * @param {Object} event
    2164      */
    2165     toggleSelectionHandler: function( event ) {
    2166         if ( 'keydown' === event.type && 9 === event.keyCode && event.shiftKey && event.target === this.$( ':tabbable' ).get( 0 ) ) {
    2167             this.controller.trigger( 'attachment:details:shift-tab', event );
    2168             return false;
    2169         }
    2170 
    2171         if ( 37 === event.keyCode || 38 === event.keyCode || 39 === event.keyCode || 40 === event.keyCode ) {
    2172             this.controller.trigger( 'attachment:keydown:arrow', event );
    2173             return;
    2174         }
    2175     }
    2176 });
    2177 
    2178 module.exports = Details;
    2179 
    2180 },{"../attachment.js":15}],18:[function(require,module,exports){
    2181 /**
    2182  * wp.media.view.Attachment.Library
    2183  *
    2184  * @class
    2185  * @augments wp.media.view.Attachment
    2186  * @augments wp.media.View
    2187  * @augments wp.Backbone.View
    2188  * @augments Backbone.View
    2189  */
    2190 var Attachment = require( '../attachment.js' ),
    2191     Library;
    2192 
    2193 Library = Attachment.extend({
    2194     buttons: {
    2195         check: true
    2196     }
    2197 });
    2198 
    2199 module.exports = Library;
    2200 
    2201 },{"../attachment.js":15}],19:[function(require,module,exports){
    2202 /*globals wp, _, jQuery */
    2203 
    2204 /**
    2205  * wp.media.view.Attachments
    2206  *
    2207  * @class
    2208  * @augments wp.media.View
    2209  * @augments wp.Backbone.View
    2210  * @augments Backbone.View
    2211  */
    2212 var View = require( './view.js' ),
    2213     Attachment = require( './attachment.js' ),
    2214     $ = jQuery,
    2215     Attachments;
    2216 
    2217 Attachments = View.extend({
    2218     tagName:   'ul',
    2219     className: 'attachments',
    2220 
    2221     attributes: {
    2222         tabIndex: -1
    2223     },
    2224 
    2225     initialize: function() {
    2226         this.el.id = _.uniqueId('__attachments-view-');
    2227 
    2228         _.defaults( this.options, {
    2229             refreshSensitivity: wp.media.isTouchDevice ? 300 : 200,
    2230             refreshThreshold:   3,
    2231             AttachmentView:     Attachment,
    2232             sortable:           false,
    2233             resize:             true,
    2234             idealColumnWidth:   $( window ).width() < 640 ? 135 : 150
    2235         });
    2236 
    2237         this._viewsByCid = {};
    2238         this.$window = $( window );
    2239         this.resizeEvent = 'resize.media-modal-columns';
    2240 
    2241         this.collection.on( 'add', function( attachment ) {
    2242             this.views.add( this.createAttachmentView( attachment ), {
    2243                 at: this.collection.indexOf( attachment )
    2244             });
    2245         }, this );
    2246 
    2247         this.collection.on( 'remove', function( attachment ) {
    2248             var view = this._viewsByCid[ attachment.cid ];
    2249             delete this._viewsByCid[ attachment.cid ];
    2250 
    2251             if ( view ) {
    2252                 view.remove();
    2253             }
    2254         }, this );
    2255 
    2256         this.collection.on( 'reset', this.render, this );
    2257 
    2258         this.listenTo( this.controller, 'library:selection:add',    this.attachmentFocus );
    2259 
    2260         // Throttle the scroll handler and bind this.
    2261         this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
    2262 
    2263         this.options.scrollElement = this.options.scrollElement || this.el;
    2264         $( this.options.scrollElement ).on( 'scroll', this.scroll );
    2265 
    2266         this.initSortable();
    2267 
    2268         _.bindAll( this, 'setColumns' );
    2269 
    2270         if ( this.options.resize ) {
    2271             this.on( 'ready', this.bindEvents );
    2272             this.controller.on( 'open', this.setColumns );
    2273 
    2274             // Call this.setColumns() after this view has been rendered in the DOM so
    2275             // attachments get proper width applied.
    2276             _.defer( this.setColumns, this );
    2277         }
    2278     },
    2279 
    2280     bindEvents: function() {
    2281         this.$window.off( this.resizeEvent ).on( this.resizeEvent, _.debounce( this.setColumns, 50 ) );
    2282     },
    2283 
    2284     attachmentFocus: function() {
    2285         this.$( 'li:first' ).focus();
    2286     },
    2287 
    2288     restoreFocus: function() {
    2289         this.$( 'li.selected:first' ).focus();
    2290     },
    2291 
    2292     arrowEvent: function( event ) {
    2293         var attachments = this.$el.children( 'li' ),
    2294             perRow = this.columns,
    2295             index = attachments.filter( ':focus' ).index(),
    2296             row = ( index + 1 ) <= perRow ? 1 : Math.ceil( ( index + 1 ) / perRow );
    2297 
    2298         if ( index === -1 ) {
    2299             return;
    2300         }
    2301 
    2302         // Left arrow
    2303         if ( 37 === event.keyCode ) {
    2304             if ( 0 === index ) {
    2305                 return;
    2306             }
    2307             attachments.eq( index - 1 ).focus();
    2308         }
    2309 
    2310         // Up arrow
    2311         if ( 38 === event.keyCode ) {
    2312             if ( 1 === row ) {
    2313                 return;
    2314             }
    2315             attachments.eq( index - perRow ).focus();
    2316         }
    2317 
    2318         // Right arrow
    2319         if ( 39 === event.keyCode ) {
    2320             if ( attachments.length === index ) {
    2321                 return;
    2322             }
    2323             attachments.eq( index + 1 ).focus();
    2324         }
    2325 
    2326         // Down arrow
    2327         if ( 40 === event.keyCode ) {
    2328             if ( Math.ceil( attachments.length / perRow ) === row ) {
    2329                 return;
    2330             }
    2331             attachments.eq( index + perRow ).focus();
    2332         }
    2333     },
    2334 
    2335     dispose: function() {
    2336         this.collection.props.off( null, null, this );
    2337         if ( this.options.resize ) {
    2338             this.$window.off( this.resizeEvent );
    2339         }
    2340 
    2341         /**
    2342          * call 'dispose' directly on the parent class
    2343          */
    2344         View.prototype.dispose.apply( this, arguments );
    2345     },
    2346 
    2347     setColumns: function() {
    2348         var prev = this.columns,
    2349             width = this.$el.width();
    2350 
    2351         if ( width ) {
    2352             this.columns = Math.min( Math.round( width / this.options.idealColumnWidth ), 12 ) || 1;
    2353 
    2354             if ( ! prev || prev !== this.columns ) {
    2355                 this.$el.closest( '.media-frame-content' ).attr( 'data-columns', this.columns );
    2356             }
    2357         }
    2358     },
    2359 
    2360     initSortable: function() {
    2361         var collection = this.collection;
    2362 
    2363         if ( wp.media.isTouchDevice || ! this.options.sortable || ! $.fn.sortable ) {
    2364             return;
    2365         }
    2366 
    2367         this.$el.sortable( _.extend({
    2368             // If the `collection` has a `comparator`, disable sorting.
    2369             disabled: !! collection.comparator,
    2370 
    2371             // Change the position of the attachment as soon as the
    2372             // mouse pointer overlaps a thumbnail.
    2373             tolerance: 'pointer',
    2374 
    2375             // Record the initial `index` of the dragged model.
    2376             start: function( event, ui ) {
    2377                 ui.item.data('sortableIndexStart', ui.item.index());
    2378             },
    2379 
    2380             // Update the model's index in the collection.
    2381             // Do so silently, as the view is already accurate.
    2382             update: function( event, ui ) {
    2383                 var model = collection.at( ui.item.data('sortableIndexStart') ),
    2384                     comparator = collection.comparator;
    2385 
    2386                 // Temporarily disable the comparator to prevent `add`
    2387                 // from re-sorting.
    2388                 delete collection.comparator;
    2389 
    2390                 // Silently shift the model to its new index.
    2391                 collection.remove( model, {
    2392                     silent: true
    2393                 });
    2394                 collection.add( model, {
    2395                     silent: true,
    2396                     at:     ui.item.index()
    2397                 });
    2398 
    2399                 // Restore the comparator.
    2400                 collection.comparator = comparator;
    2401 
    2402                 // Fire the `reset` event to ensure other collections sync.
    2403                 collection.trigger( 'reset', collection );
    2404 
    2405                 // If the collection is sorted by menu order,
    2406                 // update the menu order.
    2407                 collection.saveMenuOrder();
    2408             }
    2409         }, this.options.sortable ) );
    2410 
    2411         // If the `orderby` property is changed on the `collection`,
    2412         // check to see if we have a `comparator`. If so, disable sorting.
    2413         collection.props.on( 'change:orderby', function() {
    2414             this.$el.sortable( 'option', 'disabled', !! collection.comparator );
    2415         }, this );
    2416 
    2417         this.collection.props.on( 'change:orderby', this.refreshSortable, this );
    2418         this.refreshSortable();
    2419     },
    2420 
    2421     refreshSortable: function() {
    2422         if ( wp.media.isTouchDevice || ! this.options.sortable || ! $.fn.sortable ) {
    2423             return;
    2424         }
    2425 
    2426         // If the `collection` has a `comparator`, disable sorting.
    2427         var collection = this.collection,
    2428             orderby = collection.props.get('orderby'),
    2429             enabled = 'menuOrder' === orderby || ! collection.comparator;
    2430 
    2431         this.$el.sortable( 'option', 'disabled', ! enabled );
    2432     },
    2433 
    2434     /**
    2435      * @param {wp.media.model.Attachment} attachment
    2436      * @returns {wp.media.View}
    2437      */
    2438     createAttachmentView: function( attachment ) {
    2439         var view = new this.options.AttachmentView({
    2440             controller:           this.controller,
    2441             model:                attachment,
    2442             collection:           this.collection,
    2443             selection:            this.options.selection
    2444         });
    2445 
    2446         return this._viewsByCid[ attachment.cid ] = view;
    2447     },
    2448 
    2449     prepare: function() {
    2450         // Create all of the Attachment views, and replace
    2451         // the list in a single DOM operation.
    2452         if ( this.collection.length ) {
    2453             this.views.set( this.collection.map( this.createAttachmentView, this ) );
    2454 
    2455         // If there are no elements, clear the views and load some.
    2456         } else {
    2457             this.views.unset();
    2458             this.collection.more().done( this.scroll );
    2459         }
    2460     },
    2461 
    2462     ready: function() {
    2463         // Trigger the scroll event to check if we're within the
    2464         // threshold to query for additional attachments.
    2465         this.scroll();
    2466     },
    2467 
    2468     scroll: function() {
    2469         var view = this,
    2470             el = this.options.scrollElement,
    2471             scrollTop = el.scrollTop,
    2472             toolbar;
    2473 
    2474         // The scroll event occurs on the document, but the element
    2475         // that should be checked is the document body.
    2476         if ( el === document ) {
    2477             el = document.body;
    2478             scrollTop = $(document).scrollTop();
    2479         }
    2480 
    2481         if ( ! $(el).is(':visible') || ! this.collection.hasMore() ) {
    2482             return;
    2483         }
    2484 
    2485         toolbar = this.views.parent.toolbar;
    2486 
    2487         // Show the spinner only if we are close to the bottom.
    2488         if ( el.scrollHeight - ( scrollTop + el.clientHeight ) < el.clientHeight / 3 ) {
    2489             toolbar.get('spinner').show();
    2490         }
    2491 
    2492         if ( el.scrollHeight < scrollTop + ( el.clientHeight * this.options.refreshThreshold ) ) {
    2493             this.collection.more().done(function() {
    2494                 view.scroll();
    2495                 toolbar.get('spinner').hide();
    2496             });
    2497         }
    2498     }
    2499 });
    2500 
    2501 module.exports = Attachments;
    2502 
    2503 },{"./attachment.js":15,"./view.js":49}],20:[function(require,module,exports){
    2504 /*globals wp, _, jQuery */
    2505 
    2506 /**
    2507  * wp.media.view.AttachmentsBrowser
    2508  *
    2509  * @class
    2510  * @augments wp.media.View
    2511  * @augments wp.Backbone.View
    2512  * @augments Backbone.View
    2513  *
    2514  * @param {object}      options
    2515  * @param {object}      [options.filters=false] Which filters to show in the browser's toolbar.
    2516  *                                              Accepts 'uploaded' and 'all'.
    2517  * @param {object}      [options.search=true]   Whether to show the search interface in the
    2518  *                                              browser's toolbar.
    2519  * @param {object}      [options.date=true]     Whether to show the date filter in the
    2520  *                                              browser's toolbar.
    2521  * @param {object}      [options.display=false] Whether to show the attachments display settings
    2522  *                                              view in the sidebar.
    2523  * @param {bool|string} [options.sidebar=true]  Whether to create a sidebar for the browser.
    2524  *                                              Accepts true, false, and 'errors'.
    2525  */
    2526 var View = require( '../view.js' ),
    2527     Library = require( '../attachment/library.js' ),
    2528     Toolbar = require( '../toolbar.js' ),
    2529     Spinner = require( '../spinner.js' ),
    2530     Search = require( '../search.js' ),
    2531     Label = require( '../label.js' ),
    2532     Uploaded = require( '../attachment-filters/uploaded.js' ),
    2533     All = require( '../attachment-filters/all.js' ),
    2534     DateFilter = require( '../attachment-filters/date.js' ),
    2535     UploaderInline = require( '../uploader/inline.js' ),
    2536     Attachments = require( '../attachments.js' ),
    2537     Sidebar = require( '../sidebar.js' ),
    2538     UploaderStatus = require( '../uploader/status.js' ),
    2539     Details = require( '../attachment/details.js' ),
    2540     AttachmentCompat = require( '../attachment-compat.js' ),
    2541     AttachmentDisplay = require( '../settings/attachment-display.js' ),
    2542     mediaTrash = wp.media.view.settings.mediaTrash,
    2543     l10n = wp.media.view.l10n,
    2544     $ = jQuery,
    2545     AttachmentsBrowser;
    2546 
    2547 AttachmentsBrowser = View.extend({
    2548     tagName:   'div',
    2549     className: 'attachments-browser',
    2550 
    2551     initialize: function() {
    2552         _.defaults( this.options, {
    2553             filters: false,
    2554             search:  true,
    2555             date:    true,
    2556             display: false,
    2557             sidebar: true,
    2558             AttachmentView: Library
    2559         });
    2560 
    2561         this.listenTo( this.controller, 'toggle:upload:attachment', _.bind( this.toggleUploader, this ) );
    2562         this.controller.on( 'edit:selection', this.editSelection );
    2563         this.createToolbar();
    2564         if ( this.options.sidebar ) {
    2565             this.createSidebar();
    2566         }
    2567         this.createUploader();
    2568         this.createAttachments();
    2569         this.updateContent();
    2570 
    2571         if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
    2572             this.$el.addClass( 'hide-sidebar' );
    2573 
    2574             if ( 'errors' === this.options.sidebar ) {
    2575                 this.$el.addClass( 'sidebar-for-errors' );
    2576             }
    2577         }
    2578 
    2579         this.collection.on( 'add remove reset', this.updateContent, this );
    2580     },
    2581 
    2582     editSelection: function( modal ) {
    2583         modal.$( '.media-button-backToLibrary' ).focus();
    2584     },
    2585 
    2586     /**
    2587      * @returns {wp.media.view.AttachmentsBrowser} Returns itself to allow chaining
    2588      */
    2589     dispose: function() {
    2590         this.options.selection.off( null, null, this );
    2591         View.prototype.dispose.apply( this, arguments );
    2592         return this;
    2593     },
    2594 
    2595     createToolbar: function() {
    2596         var LibraryViewSwitcher, Filters, toolbarOptions;
    2597 
    2598         toolbarOptions = {
    2599             controller: this.controller
    2600         };
    2601 
    2602         if ( this.controller.isModeActive( 'grid' ) ) {
    2603             toolbarOptions.className = 'media-toolbar wp-filter';
    2604         }
    2605 
    2606         /**
    2607         * @member {wp.media.view.Toolbar}
    2608         */
    2609         this.toolbar = new Toolbar( toolbarOptions );
    2610 
    2611         this.views.add( this.toolbar );
    2612 
    2613         this.toolbar.set( 'spinner', new Spinner({
    2614             priority: -60
    2615         }) );
    2616 
    2617         if ( -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] ) ) {
    2618             // "Filters" will return a <select>, need to render
    2619             // screen reader text before
    2620             this.toolbar.set( 'filtersLabel', new Label({
    2621                 value: l10n.filterByType,
    2622                 attributes: {
    2623                     'for':  'media-attachment-filters'
    2624                 },
    2625                 priority:   -80
    2626             }).render() );
    2627 
    2628             if ( 'uploaded' === this.options.filters ) {
    2629                 this.toolbar.set( 'filters', new Uploaded({
    2630                     controller: this.controller,
    2631                     model:      this.collection.props,
    2632                     priority:   -80
    2633                 }).render() );
    2634             } else {
    2635                 Filters = new All({
    2636                     controller: this.controller,
    2637                     model:      this.collection.props,
    2638                     priority:   -80
    2639                 });
    2640 
    2641                 this.toolbar.set( 'filters', Filters.render() );
    2642             }
    2643         }
    2644 
    2645         // Feels odd to bring the global media library switcher into the Attachment
    2646         // browser view. Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
    2647         // which the controller can tap into and add this view?
    2648         if ( this.controller.isModeActive( 'grid' ) ) {
    2649             LibraryViewSwitcher = View.extend({
    2650                 className: 'view-switch media-grid-view-switch',
    2651                 template: wp.template( 'media-library-view-switcher')
    2652             });
    2653 
    2654             this.toolbar.set( 'libraryViewSwitcher', new LibraryViewSwitcher({
    2655                 controller: this.controller,
    2656                 priority: -90
    2657             }).render() );
    2658 
    2659             // DateFilter is a <select>, screen reader text needs to be rendered before
    2660             this.toolbar.set( 'dateFilterLabel', new Label({
    2661                 value: l10n.filterByDate,
    2662                 attributes: {
    2663                     'for': 'media-attachment-date-filters'
    2664                 },
    2665                 priority: -75
    2666             }).render() );
    2667             this.toolbar.set( 'dateFilter', new DateFilter({
    2668                 controller: this.controller,
    2669                 model:      this.collection.props,
    2670                 priority: -75
    2671             }).render() );
    2672 
    2673             // BulkSelection is a <div> with subviews, including screen reader text
    2674             this.toolbar.set( 'selectModeToggleButton', new wp.media.view.SelectModeToggleButton({
    2675                 text: l10n.bulkSelect,
    2676                 controller: this.controller,
    2677                 priority: -70
    2678             }).render() );
    2679 
    2680             this.toolbar.set( 'deleteSelectedButton', new wp.media.view.DeleteSelectedButton({
    2681                 filters: Filters,
    2682                 style: 'primary',
    2683                 disabled: true,
    2684                 text: mediaTrash ? l10n.trashSelected : l10n.deleteSelected,
    2685                 controller: this.controller,
    2686                 priority: -60,
    2687                 click: function() {
    2688                     var changed = [], removed = [],
    2689                         selection = this.controller.state().get( 'selection' ),
    2690                         library = this.controller.state().get( 'library' );
    2691 
    2692                     if ( ! selection.length ) {
    2693                         return;
    2694                     }
    2695 
    2696                     if ( ! mediaTrash && ! window.confirm( l10n.warnBulkDelete ) ) {
    2697                         return;
    2698                     }
    2699 
    2700                     if ( mediaTrash &&
    2701                         'trash' !== selection.at( 0 ).get( 'status' ) &&
    2702                         ! window.confirm( l10n.warnBulkTrash ) ) {
    2703 
    2704                         return;
    2705                     }
    2706 
    2707                     selection.each( function( model ) {
    2708                         if ( ! model.get( 'nonces' )['delete'] ) {
    2709                             removed.push( model );
    2710                             return;
    2711                         }
    2712 
    2713                         if ( mediaTrash && 'trash' === model.get( 'status' ) ) {
    2714                             model.set( 'status', 'inherit' );
    2715                             changed.push( model.save() );
    2716                             removed.push( model );
    2717                         } else if ( mediaTrash ) {
    2718                             model.set( 'status', 'trash' );
    2719                             changed.push( model.save() );
    2720                             removed.push( model );
    2721                         } else {
    2722                             model.destroy({wait: true});
    2723                         }
    2724                     } );
    2725 
    2726                     if ( changed.length ) {
    2727                         selection.remove( removed );
    2728 
    2729                         $.when.apply( null, changed ).then( _.bind( function() {
    2730                             library._requery( true );
    2731                             this.controller.trigger( 'selection:action:done' );
    2732                         }, this ) );
    2733                     } else {
    2734                         this.controller.trigger( 'selection:action:done' );
    2735                     }
    2736                 }
    2737             }).render() );
    2738 
    2739             if ( mediaTrash ) {
    2740                 this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
    2741                     filters: Filters,
    2742                     style: 'primary',
    2743                     disabled: true,
    2744                     text: l10n.deleteSelected,
    2745                     controller: this.controller,
    2746                     priority: -55,
    2747                     click: function() {
    2748                         var removed = [], selection = this.controller.state().get( 'selection' );
    2749 
    2750                         if ( ! selection.length || ! window.confirm( l10n.warnBulkDelete ) ) {
    2751                             return;
    2752                         }
    2753 
    2754                         selection.each( function( model ) {
    2755                             if ( ! model.get( 'nonces' )['delete'] ) {
    2756                                 removed.push( model );
    2757                                 return;
    2758                             }
    2759 
    2760                             model.destroy();
    2761                         } );
    2762 
    2763                         selection.remove( removed );
    2764                         this.controller.trigger( 'selection:action:done' );
    2765                     }
    2766                 }).render() );
    2767             }
    2768 
    2769         } else if ( this.options.date ) {
    2770             // DateFilter is a <select>, screen reader text needs to be rendered before
    2771             this.toolbar.set( 'dateFilterLabel', new Label({
    2772                 value: l10n.filterByDate,
    2773                 attributes: {
    2774                     'for': 'media-attachment-date-filters'
    2775                 },
    2776                 priority: -75
    2777             }).render() );
    2778             this.toolbar.set( 'dateFilter', new DateFilter({
    2779                 controller: this.controller,
    2780                 model:      this.collection.props,
    2781                 priority: -75
    2782             }).render() );
    2783         }
    2784 
    2785         if ( this.options.search ) {
    2786             // Search is an input, screen reader text needs to be rendered before
    2787             this.toolbar.set( 'searchLabel', new Label({
    2788                 value: l10n.searchMediaLabel,
    2789                 attributes: {
    2790                     'for': 'media-search-input'
    2791                 },
    2792                 priority:   60
    2793             }).render() );
    2794             this.toolbar.set( 'search', new Search({
    2795                 controller: this.controller,
    2796                 model:      this.collection.props,
    2797                 priority:   60
    2798             }).render() );
    2799         }
    2800 
    2801         if ( this.options.dragInfo ) {
    2802             this.toolbar.set( 'dragInfo', new View({
    2803                 el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
    2804                 priority: -40
    2805             }) );
    2806         }
    2807 
    2808         if ( this.options.suggestedWidth && this.options.suggestedHeight ) {
    2809             this.toolbar.set( 'suggestedDimensions', new View({
    2810                 el: $( '<div class="instructions">' + l10n.suggestedDimensions + ' ' + this.options.suggestedWidth + ' &times; ' + this.options.suggestedHeight + '</div>' )[0],
    2811                 priority: -40
    2812             }) );
    2813         }
    2814     },
    2815 
    2816     updateContent: function() {
    2817         var view = this,
    2818             noItemsView;
    2819 
    2820         if ( this.controller.isModeActive( 'grid' ) ) {
    2821             noItemsView = view.attachmentsNoResults;
    2822         } else {
    2823             noItemsView = view.uploader;
    2824         }
    2825 
    2826         if ( ! this.collection.length ) {
    2827             this.toolbar.get( 'spinner' ).show();
    2828             this.dfd = this.collection.more().done( function() {
    2829                 if ( ! view.collection.length ) {
    2830                     noItemsView.$el.removeClass( 'hidden' );
    2831                 } else {
    2832                     noItemsView.$el.addClass( 'hidden' );
    2833                 }
    2834                 view.toolbar.get( 'spinner' ).hide();
    2835             } );
    2836         } else {
    2837             noItemsView.$el.addClass( 'hidden' );
    2838             view.toolbar.get( 'spinner' ).hide();
    2839         }
    2840     },
    2841 
    2842     createUploader: function() {
    2843         this.uploader = new UploaderInline({
    2844             controller: this.controller,
    2845             status:     false,
    2846             message:    this.controller.isModeActive( 'grid' ) ? '' : l10n.noItemsFound,
    2847             canClose:   this.controller.isModeActive( 'grid' )
    2848         });
    2849 
    2850         this.uploader.hide();
    2851         this.views.add( this.uploader );
    2852     },
    2853 
    2854     toggleUploader: function() {
    2855         if ( this.uploader.$el.hasClass( 'hidden' ) ) {
    2856             this.uploader.show();
    2857         } else {
    2858             this.uploader.hide();
    2859         }
    2860     },
    2861 
    2862     createAttachments: function() {
    2863         this.attachments = new Attachments({
    2864             controller:           this.controller,
    2865             collection:           this.collection,
    2866             selection:            this.options.selection,
    2867             model:                this.model,
    2868             sortable:             this.options.sortable,
    2869             scrollElement:        this.options.scrollElement,
    2870             idealColumnWidth:     this.options.idealColumnWidth,
    2871 
    2872             // The single `Attachment` view to be used in the `Attachments` view.
    2873             AttachmentView: this.options.AttachmentView
    2874         });
    2875 
    2876         // Add keydown listener to the instance of the Attachments view
    2877         this.attachments.listenTo( this.controller, 'attachment:keydown:arrow',     this.attachments.arrowEvent );
    2878         this.attachments.listenTo( this.controller, 'attachment:details:shift-tab', this.attachments.restoreFocus );
    2879 
    2880         this.views.add( this.attachments );
    2881 
    2882 
    2883         if ( this.controller.isModeActive( 'grid' ) ) {
    2884             this.attachmentsNoResults = new View({
    2885                 controller: this.controller,
    2886                 tagName: 'p'
    2887             });
    2888 
    2889             this.attachmentsNoResults.$el.addClass( 'hidden no-media' );
    2890             this.attachmentsNoResults.$el.html( l10n.noMedia );
    2891 
    2892             this.views.add( this.attachmentsNoResults );
    2893         }
    2894     },
    2895 
    2896     createSidebar: function() {
    2897         var options = this.options,
    2898             selection = options.selection,
    2899             sidebar = this.sidebar = new Sidebar({
    2900                 controller: this.controller
    2901             });
    2902 
    2903         this.views.add( sidebar );
    2904 
    2905         if ( this.controller.uploader ) {
    2906             sidebar.set( 'uploads', new UploaderStatus({
    2907                 controller: this.controller,
    2908                 priority:   40
    2909             }) );
    2910         }
    2911 
    2912         selection.on( 'selection:single', this.createSingle, this );
    2913         selection.on( 'selection:unsingle', this.disposeSingle, this );
    2914 
    2915         if ( selection.single() ) {
    2916             this.createSingle();
    2917         }
    2918     },
    2919 
    2920     createSingle: function() {
    2921         var sidebar = this.sidebar,
    2922             single = this.options.selection.single();
    2923 
    2924         sidebar.set( 'details', new Details({
    2925             controller: this.controller,
    2926             model:      single,
    2927             priority:   80
    2928         }) );
    2929 
    2930         sidebar.set( 'compat', new AttachmentCompat({
    2931             controller: this.controller,
    2932             model:      single,
    2933             priority:   120
    2934         }) );
    2935 
    2936         if ( this.options.display ) {
    2937             sidebar.set( 'display', new AttachmentDisplay({
    2938                 controller:   this.controller,
    2939                 model:        this.model.display( single ),
    2940                 attachment:   single,
    2941                 priority:     160,
    2942                 userSettings: this.model.get('displayUserSettings')
    2943             }) );
    2944         }
    2945 
    2946         // Show the sidebar on mobile
    2947         if ( this.model.id === 'insert' ) {
    2948             sidebar.$el.addClass( 'visible' );
    2949         }
    2950     },
    2951 
    2952     disposeSingle: function() {
    2953         var sidebar = this.sidebar;
    2954         sidebar.unset('details');
    2955         sidebar.unset('compat');
    2956         sidebar.unset('display');
    2957         // Hide the sidebar on mobile
    2958         sidebar.$el.removeClass( 'visible' );
    2959     }
    2960 });
    2961 
    2962 module.exports = AttachmentsBrowser;
    2963 
    2964 },{"../attachment-compat.js":10,"../attachment-filters/all.js":12,"../attachment-filters/date.js":13,"../attachment-filters/uploaded.js":14,"../attachment/details.js":17,"../attachment/library.js":18,"../attachments.js":19,"../label.js":31,"../search.js":39,"../settings/attachment-display.js":41,"../sidebar.js":42,"../spinner.js":43,"../toolbar.js":44,"../uploader/inline.js":45,"../uploader/status.js":47,"../view.js":49}],21:[function(require,module,exports){
    2965 /*globals _, Backbone */
    2966 
    2967 /**
    2968  * wp.media.view.Button
    2969  *
    2970  * @class
    2971  * @augments wp.media.View
    2972  * @augments wp.Backbone.View
    2973  * @augments Backbone.View
    2974  */
    2975 var View = require( './view.js' ),
    2976     Button;
    2977 
    2978 Button = View.extend({
    2979     tagName:    'a',
    2980     className:  'media-button',
    2981     attributes: { href: '#' },
    2982 
    2983     events: {
    2984         'click': 'click'
    2985     },
    2986 
    2987     defaults: {
    2988         text:     '',
    2989         style:    '',
    2990         size:     'large',
    2991         disabled: false
    2992     },
    2993 
    2994     initialize: function() {
    2995         /**
    2996          * Create a model with the provided `defaults`.
    2997          *
    2998          * @member {Backbone.Model}
    2999          */
    3000         this.model = new Backbone.Model( this.defaults );
    3001 
    3002         // If any of the `options` have a key from `defaults`, apply its
    3003         // value to the `model` and remove it from the `options object.
    3004         _.each( this.defaults, function( def, key ) {
    3005             var value = this.options[ key ];
    3006             if ( _.isUndefined( value ) ) {
    3007                 return;
    3008             }
    3009 
    3010             this.model.set( key, value );
    3011             delete this.options[ key ];
    3012         }, this );
    3013 
    3014         this.listenTo( this.model, 'change', this.render );
    3015     },
    3016     /**
    3017      * @returns {wp.media.view.Button} Returns itself to allow chaining
    3018      */
    3019     render: function() {
    3020         var classes = [ 'button', this.className ],
    3021             model = this.model.toJSON();
    3022 
    3023         if ( model.style ) {
    3024             classes.push( 'button-' + model.style );
    3025         }
    3026 
    3027         if ( model.size ) {
    3028             classes.push( 'button-' + model.size );
    3029         }
    3030 
    3031         classes = _.uniq( classes.concat( this.options.classes ) );
    3032         this.el.className = classes.join(' ');
    3033 
    3034         this.$el.attr( 'disabled', model.disabled );
    3035         this.$el.text( this.model.get('text') );
    3036 
    3037         return this;
    3038     },
    3039     /**
    3040      * @param {Object} event
    3041      */
    3042     click: function( event ) {
    3043         if ( '#' === this.attributes.href ) {
    3044             event.preventDefault();
    3045         }
    3046 
    3047         if ( this.options.click && ! this.model.get('disabled') ) {
    3048             this.options.click.apply( this, arguments );
    3049         }
    3050     }
    3051 });
    3052 
    3053 module.exports = Button;
    3054 
    3055 },{"./view.js":49}],22:[function(require,module,exports){
     142},{}],5:[function(require,module,exports){
    3056143/**
    3057144 * wp.media.view.DeleteSelectedPermanentlyButton
     
    3066153 * @augments Backbone.View
    3067154 */
    3068 var Button = require( '../button.js' ),
     155var Button = wp.media.view.Button,
    3069156    DeleteSelected = require( './delete-selected.js' ),
    3070157    DeleteSelectedPermanently;
     
    3100187module.exports = DeleteSelectedPermanently;
    3101188
    3102 },{"../button.js":21,"./delete-selected.js":23}],23:[function(require,module,exports){
     189},{"./delete-selected.js":6}],6:[function(require,module,exports){
    3103190/*globals wp */
    3104191
     
    3114201 * @augments Backbone.View
    3115202 */
    3116 var Button = require( '../button.js' ),
     203var Button = wp.media.view.Button,
    3117204    l10n = wp.media.view.l10n,
    3118205    DeleteSelected;
     
    3155242module.exports = DeleteSelected;
    3156243
    3157 },{"../button.js":21}],24:[function(require,module,exports){
     244},{}],7:[function(require,module,exports){
    3158245/*globals wp */
    3159246
     
    3167254 * @augments Backbone.View
    3168255 */
    3169 var Button = require( '../button.js' ),
     256var Button = wp.media.view.Button,
    3170257    l10n = wp.media.view.l10n,
    3171258    SelectModeToggle;
     
    3221308module.exports = SelectModeToggle;
    3222309
    3223 },{"../button.js":21}],25:[function(require,module,exports){
     310},{}],8:[function(require,module,exports){
    3224311/*globals wp, _ */
    3225312
     
    3228315 *
    3229316 * @class
    3230  * @augments wp.media.view.EditImage.Details
     317 * @augments wp.media.view.EditImage
    3231318 * @augments wp.media.View
    3232319 * @augments wp.Backbone.View
    3233320 * @augments Backbone.View
    3234321 */
    3235 var View = require( './view.js' ),
     322var View = wp.media.View,
    3236323    EditImage = wp.media.view.EditImage,
    3237324    Details;
     
    3258345module.exports = Details;
    3259346
    3260 },{"./view.js":49}],26:[function(require,module,exports){
    3261 /**
    3262  * wp.media.view.FocusManager
    3263  *
    3264  * @class
    3265  * @augments wp.media.View
    3266  * @augments wp.Backbone.View
    3267  * @augments Backbone.View
    3268  */
    3269 var View = require( './view.js' ),
    3270     FocusManager;
    3271 
    3272 FocusManager = View.extend({
    3273 
    3274     events: {
    3275         'keydown': 'constrainTabbing'
    3276     },
    3277 
    3278     focus: function() { // Reset focus on first left menu item
    3279         this.$('.media-menu-item').first().focus();
    3280     },
    3281     /**
    3282      * @param {Object} event
    3283      */
    3284     constrainTabbing: function( event ) {
    3285         var tabbables;
    3286 
    3287         // Look for the tab key.
    3288         if ( 9 !== event.keyCode ) {
    3289             return;
    3290         }
    3291 
    3292         // Skip the file input added by Plupload.
    3293         tabbables = this.$( ':tabbable' ).not( '.moxie-shim input[type="file"]' );
    3294 
    3295         // Keep tab focus within media modal while it's open
    3296         if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
    3297             tabbables.first().focus();
    3298             return false;
    3299         } else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
    3300             tabbables.last().focus();
    3301             return false;
    3302         }
    3303     }
    3304 
    3305 });
    3306 
    3307 module.exports = FocusManager;
    3308 
    3309 },{"./view.js":49}],27:[function(require,module,exports){
    3310 /*globals _, Backbone */
    3311 
    3312 /**
    3313  * wp.media.view.Frame
    3314  *
    3315  * A frame is a composite view consisting of one or more regions and one or more
    3316  * states.
    3317  *
    3318  * @see wp.media.controller.State
    3319  * @see wp.media.controller.Region
    3320  *
    3321  * @class
    3322  * @augments wp.media.View
    3323  * @augments wp.Backbone.View
    3324  * @augments Backbone.View
    3325  * @mixes wp.media.controller.StateMachine
    3326  */
    3327 var StateMachine = require( '../controllers/state-machine.js' ),
    3328     State = require( '../controllers/state.js' ),
    3329     Region = require( '../controllers/region.js' ),
    3330     View = require( './view.js' ),
    3331     Frame;
    3332 
    3333 Frame = View.extend({
    3334     initialize: function() {
    3335         _.defaults( this.options, {
    3336             mode: [ 'select' ]
    3337         });
    3338         this._createRegions();
    3339         this._createStates();
    3340         this._createModes();
    3341     },
    3342 
    3343     _createRegions: function() {
    3344         // Clone the regions array.
    3345         this.regions = this.regions ? this.regions.slice() : [];
    3346 
    3347         // Initialize regions.
    3348         _.each( this.regions, function( region ) {
    3349             this[ region ] = new Region({
    3350                 view:     this,
    3351                 id:       region,
    3352                 selector: '.media-frame-' + region
    3353             });
    3354         }, this );
    3355     },
    3356     /**
    3357      * Create the frame's states.
    3358      *
    3359      * @see wp.media.controller.State
    3360      * @see wp.media.controller.StateMachine
    3361      *
    3362      * @fires wp.media.controller.State#ready
    3363      */
    3364     _createStates: function() {
    3365         // Create the default `states` collection.
    3366         this.states = new Backbone.Collection( null, {
    3367             model: State
    3368         });
    3369 
    3370         // Ensure states have a reference to the frame.
    3371         this.states.on( 'add', function( model ) {
    3372             model.frame = this;
    3373             model.trigger('ready');
    3374         }, this );
    3375 
    3376         if ( this.options.states ) {
    3377             this.states.add( this.options.states );
    3378         }
    3379     },
    3380 
    3381     /**
    3382      * A frame can be in a mode or multiple modes at one time.
    3383      *
    3384      * For example, the manage media frame can be in the `Bulk Select` or `Edit` mode.
    3385      */
    3386     _createModes: function() {
    3387         // Store active "modes" that the frame is in. Unrelated to region modes.
    3388         this.activeModes = new Backbone.Collection();
    3389         this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
    3390 
    3391         _.each( this.options.mode, function( mode ) {
    3392             this.activateMode( mode );
    3393         }, this );
    3394     },
    3395     /**
    3396      * Reset all states on the frame to their defaults.
    3397      *
    3398      * @returns {wp.media.view.Frame} Returns itself to allow chaining
    3399      */
    3400     reset: function() {
    3401         this.states.invoke( 'trigger', 'reset' );
    3402         return this;
    3403     },
    3404     /**
    3405      * Map activeMode collection events to the frame.
    3406      */
    3407     triggerModeEvents: function( model, collection, options ) {
    3408         var collectionEvent,
    3409             modeEventMap = {
    3410                 add: 'activate',
    3411                 remove: 'deactivate'
    3412             },
    3413             eventToTrigger;
    3414         // Probably a better way to do this.
    3415         _.each( options, function( value, key ) {
    3416             if ( value ) {
    3417                 collectionEvent = key;
    3418             }
    3419         } );
    3420 
    3421         if ( ! _.has( modeEventMap, collectionEvent ) ) {
    3422             return;
    3423         }
    3424 
    3425         eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
    3426         this.trigger( eventToTrigger );
    3427     },
    3428     /**
    3429      * Activate a mode on the frame.
    3430      *
    3431      * @param string mode Mode ID.
    3432      * @returns {this} Returns itself to allow chaining.
    3433      */
    3434     activateMode: function( mode ) {
    3435         // Bail if the mode is already active.
    3436         if ( this.isModeActive( mode ) ) {
    3437             return;
    3438         }
    3439         this.activeModes.add( [ { id: mode } ] );
    3440         // Add a CSS class to the frame so elements can be styled for the mode.
    3441         this.$el.addClass( 'mode-' + mode );
    3442 
    3443         return this;
    3444     },
    3445     /**
    3446      * Deactivate a mode on the frame.
    3447      *
    3448      * @param string mode Mode ID.
    3449      * @returns {this} Returns itself to allow chaining.
    3450      */
    3451     deactivateMode: function( mode ) {
    3452         // Bail if the mode isn't active.
    3453         if ( ! this.isModeActive( mode ) ) {
    3454             return this;
    3455         }
    3456         this.activeModes.remove( this.activeModes.where( { id: mode } ) );
    3457         this.$el.removeClass( 'mode-' + mode );
    3458         /**
    3459          * Frame mode deactivation event.
    3460          *
    3461          * @event this#{mode}:deactivate
    3462          */
    3463         this.trigger( mode + ':deactivate' );
    3464 
    3465         return this;
    3466     },
    3467     /**
    3468      * Check if a mode is enabled on the frame.
    3469      *
    3470      * @param  string mode Mode ID.
    3471      * @return bool
    3472      */
    3473     isModeActive: function( mode ) {
    3474         return Boolean( this.activeModes.where( { id: mode } ).length );
    3475     }
    3476 });
    3477 
    3478 // Make the `Frame` a `StateMachine`.
    3479 _.extend( Frame.prototype, StateMachine.prototype );
    3480 
    3481 module.exports = Frame;
    3482 
    3483 },{"../controllers/region.js":4,"../controllers/state-machine.js":5,"../controllers/state.js":6,"./view.js":49}],28:[function(require,module,exports){
     347},{}],9:[function(require,module,exports){
    3484348/*globals wp, _, jQuery */
    3485349
     
    3500364 * @mixes wp.media.controller.StateMachine
    3501365 */
    3502 var Frame = require( '../frame.js' ),
    3503     MediaFrame = require( '../media-frame.js' ),
    3504     Modal = require( '../modal.js' ),
     366var Frame = wp.media.view.Frame,
     367    MediaFrame = wp.media.view.MediaFrame,
     368    Modal = wp.media.view.Modal,
     369    AttachmentCompat = wp.media.view.AttachmentCompat,
     370    EditImageController = wp.media.controller.EditImage,
     371
    3505372    EditAttachmentMetadata = require( '../../controllers/edit-attachment-metadata.js' ),
    3506373    TwoColumn = require( '../attachment/details-two-column.js' ),
    3507     AttachmentCompat = require( '../attachment-compat.js' ),
    3508     EditImageController = require( '../../controllers/edit-image.js' ),
    3509374    DetailsView = require( '../edit-image-details.js' ),
     375
    3510376    $ = jQuery,
    3511377    EditAttachments;
     
    3731597module.exports = EditAttachments;
    3732598
    3733 },{"../../controllers/edit-attachment-metadata.js":1,"../../controllers/edit-image.js":2,"../attachment-compat.js":10,"../attachment/details-two-column.js":16,"../edit-image-details.js":25,"../frame.js":27,"../media-frame.js":32,"../modal.js":35}],29:[function(require,module,exports){
     599},{"../../controllers/edit-attachment-metadata.js":1,"../attachment/details-two-column.js":4,"../edit-image-details.js":8}],10:[function(require,module,exports){
    3734600/*globals wp, _, jQuery, Backbone */
    3735601
     
    3749615 * @mixes wp.media.controller.StateMachine
    3750616 */
    3751 var MediaFrame = require( '../media-frame.js' ),
    3752     UploaderWindow = require( '../uploader/window.js' ),
    3753     AttachmentsBrowser = require( '../attachments/browser.js' ),
     617var MediaFrame = wp.media.view.MediaFrame,
     618    UploaderWindow = wp.media.view.UploaderWindow,
     619    AttachmentsBrowser = wp.media.view.AttachmentsBrowser,
     620    Library = wp.media.controller.Library,
     621
    3754622    Router = require( '../../routers/manage.js' ),
    3755     Library = require( '../../controllers/library.js' ),
     623
    3756624    $ = jQuery,
    3757625    Manage;
     
    3980848module.exports = Manage;
    3981849
    3982 },{"../../controllers/library.js":3,"../../routers/manage.js":8,"../attachments/browser.js":20,"../media-frame.js":32,"../uploader/window.js":48}],30:[function(require,module,exports){
    3983 /**
    3984  * wp.media.view.Iframe
    3985  *
    3986  * @class
    3987  * @augments wp.media.View
    3988  * @augments wp.Backbone.View
    3989  * @augments Backbone.View
    3990  */
    3991 var View = require( './view.js' ),
    3992     Iframe;
    3993 
    3994 Iframe = View.extend({
    3995     className: 'media-iframe',
    3996     /**
    3997      * @returns {wp.media.view.Iframe} Returns itself to allow chaining
    3998      */
    3999     render: function() {
    4000         this.views.detach();
    4001         this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
    4002         this.views.render();
    4003         return this;
    4004     }
    4005 });
    4006 
    4007 module.exports = Iframe;
    4008 
    4009 },{"./view.js":49}],31:[function(require,module,exports){
    4010 /**
    4011  * wp.media.view.Label
    4012  *
    4013  * @class
    4014  * @augments wp.media.View
    4015  * @augments wp.Backbone.View
    4016  * @augments Backbone.View
    4017  */
    4018 var View = require( './view.js' ),
    4019     Label;
    4020 
    4021 Label = View.extend({
    4022     tagName: 'label',
    4023     className: 'screen-reader-text',
    4024 
    4025     initialize: function() {
    4026         this.value = this.options.value;
    4027     },
    4028 
    4029     render: function() {
    4030         this.$el.html( this.value );
    4031 
    4032         return this;
    4033     }
    4034 });
    4035 
    4036 module.exports = Label;
    4037 
    4038 },{"./view.js":49}],32:[function(require,module,exports){
    4039 /*globals wp, _, jQuery */
    4040 
    4041 /**
    4042  * wp.media.view.MediaFrame
    4043  *
    4044  * The frame used to create the media modal.
    4045  *
    4046  * @class
    4047  * @augments wp.media.view.Frame
    4048  * @augments wp.media.View
    4049  * @augments wp.Backbone.View
    4050  * @augments Backbone.View
    4051  * @mixes wp.media.controller.StateMachine
    4052  */
    4053 var View = require( './view.js' ),
    4054     Frame = require( './frame.js' ),
    4055     Modal = require( './modal.js' ),
    4056     UploaderWindow = require( './uploader/window.js' ),
    4057     Menu = require( './menu.js' ),
    4058     Toolbar = require( './toolbar.js' ),
    4059     Router = require( './router.js' ),
    4060     Iframe = require( './iframe.js' ),
    4061     $ = jQuery,
    4062     MediaFrame;
    4063 
    4064 MediaFrame = Frame.extend({
    4065     className: 'media-frame',
    4066     template:  wp.template('media-frame'),
    4067     regions:   ['menu','title','content','toolbar','router'],
    4068 
    4069     events: {
    4070         'click div.media-frame-title h1': 'toggleMenu'
    4071     },
    4072 
    4073     /**
    4074      * @global wp.Uploader
    4075      */
    4076     initialize: function() {
    4077         Frame.prototype.initialize.apply( this, arguments );
    4078 
    4079         _.defaults( this.options, {
    4080             title:    '',
    4081             modal:    true,
    4082             uploader: true
    4083         });
    4084 
    4085         // Ensure core UI is enabled.
    4086         this.$el.addClass('wp-core-ui');
    4087 
    4088         // Initialize modal container view.
    4089         if ( this.options.modal ) {
    4090             this.modal = new Modal({
    4091                 controller: this,
    4092                 title:      this.options.title
    4093             });
    4094 
    4095             this.modal.content( this );
    4096         }
    4097 
    4098         // Force the uploader off if the upload limit has been exceeded or
    4099         // if the browser isn't supported.
    4100         if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
    4101             this.options.uploader = false;
    4102         }
    4103 
    4104         // Initialize window-wide uploader.
    4105         if ( this.options.uploader ) {
    4106             this.uploader = new UploaderWindow({
    4107                 controller: this,
    4108                 uploader: {
    4109                     dropzone:  this.modal ? this.modal.$el : this.$el,
    4110                     container: this.$el
    4111                 }
    4112             });
    4113             this.views.set( '.media-frame-uploader', this.uploader );
    4114         }
    4115 
    4116         this.on( 'attach', _.bind( this.views.ready, this.views ), this );
    4117 
    4118         // Bind default title creation.
    4119         this.on( 'title:create:default', this.createTitle, this );
    4120         this.title.mode('default');
    4121 
    4122         this.on( 'title:render', function( view ) {
    4123             view.$el.append( '<span class="dashicons dashicons-arrow-down"></span>' );
    4124         });
    4125 
    4126         // Bind default menu.
    4127         this.on( 'menu:create:default', this.createMenu, this );
    4128     },
    4129     /**
    4130      * @returns {wp.media.view.MediaFrame} Returns itself to allow chaining
    4131      */
    4132     render: function() {
    4133         // Activate the default state if no active state exists.
    4134         if ( ! this.state() && this.options.state ) {
    4135             this.setState( this.options.state );
    4136         }
    4137         /**
    4138          * call 'render' directly on the parent class
    4139          */
    4140         return Frame.prototype.render.apply( this, arguments );
    4141     },
    4142     /**
    4143      * @param {Object} title
    4144      * @this wp.media.controller.Region
    4145      */
    4146     createTitle: function( title ) {
    4147         title.view = new View({
    4148             controller: this,
    4149             tagName: 'h1'
    4150         });
    4151     },
    4152     /**
    4153      * @param {Object} menu
    4154      * @this wp.media.controller.Region
    4155      */
    4156     createMenu: function( menu ) {
    4157         menu.view = new Menu({
    4158             controller: this
    4159         });
    4160     },
    4161 
    4162     toggleMenu: function() {
    4163         this.$el.find( '.media-menu' ).toggleClass( 'visible' );
    4164     },
    4165 
    4166     /**
    4167      * @param {Object} toolbar
    4168      * @this wp.media.controller.Region
    4169      */
    4170     createToolbar: function( toolbar ) {
    4171         toolbar.view = new Toolbar({
    4172             controller: this
    4173         });
    4174     },
    4175     /**
    4176      * @param {Object} router
    4177      * @this wp.media.controller.Region
    4178      */
    4179     createRouter: function( router ) {
    4180         router.view = new Router({
    4181             controller: this
    4182         });
    4183     },
    4184     /**
    4185      * @param {Object} options
    4186      */
    4187     createIframeStates: function( options ) {
    4188         var settings = wp.media.view.settings,
    4189             tabs = settings.tabs,
    4190             tabUrl = settings.tabUrl,
    4191             $postId;
    4192 
    4193         if ( ! tabs || ! tabUrl ) {
    4194             return;
    4195         }
    4196 
    4197         // Add the post ID to the tab URL if it exists.
    4198         $postId = $('#post_ID');
    4199         if ( $postId.length ) {
    4200             tabUrl += '&post_id=' + $postId.val();
    4201         }
    4202 
    4203         // Generate the tab states.
    4204         _.each( tabs, function( title, id ) {
    4205             this.state( 'iframe:' + id ).set( _.defaults({
    4206                 tab:     id,
    4207                 src:     tabUrl + '&tab=' + id,
    4208                 title:   title,
    4209                 content: 'iframe',
    4210                 menu:    'default'
    4211             }, options ) );
    4212         }, this );
    4213 
    4214         this.on( 'content:create:iframe', this.iframeContent, this );
    4215         this.on( 'content:deactivate:iframe', this.iframeContentCleanup, this );
    4216         this.on( 'menu:render:default', this.iframeMenu, this );
    4217         this.on( 'open', this.hijackThickbox, this );
    4218         this.on( 'close', this.restoreThickbox, this );
    4219     },
    4220 
    4221     /**
    4222      * @param {Object} content
    4223      * @this wp.media.controller.Region
    4224      */
    4225     iframeContent: function( content ) {
    4226         this.$el.addClass('hide-toolbar');
    4227         content.view = new Iframe({
    4228             controller: this
    4229         });
    4230     },
    4231 
    4232     iframeContentCleanup: function() {
    4233         this.$el.removeClass('hide-toolbar');
    4234     },
    4235 
    4236     iframeMenu: function( view ) {
    4237         var views = {};
    4238 
    4239         if ( ! view ) {
    4240             return;
    4241         }
    4242 
    4243         _.each( wp.media.view.settings.tabs, function( title, id ) {
    4244             views[ 'iframe:' + id ] = {
    4245                 text: this.state( 'iframe:' + id ).get('title'),
    4246                 priority: 200
    4247             };
    4248         }, this );
    4249 
    4250         view.set( views );
    4251     },
    4252 
    4253     hijackThickbox: function() {
    4254         var frame = this;
    4255 
    4256         if ( ! window.tb_remove || this._tb_remove ) {
    4257             return;
    4258         }
    4259 
    4260         this._tb_remove = window.tb_remove;
    4261         window.tb_remove = function() {
    4262             frame.close();
    4263             frame.reset();
    4264             frame.setState( frame.options.state );
    4265             frame._tb_remove.call( window );
    4266         };
    4267     },
    4268 
    4269     restoreThickbox: function() {
    4270         if ( ! this._tb_remove ) {
    4271             return;
    4272         }
    4273 
    4274         window.tb_remove = this._tb_remove;
    4275         delete this._tb_remove;
    4276     }
    4277 });
    4278 
    4279 // Map some of the modal's methods to the frame.
    4280 _.each(['open','close','attach','detach','escape'], function( method ) {
    4281     /**
    4282      * @returns {wp.media.view.MediaFrame} Returns itself to allow chaining
    4283      */
    4284     MediaFrame.prototype[ method ] = function() {
    4285         if ( this.modal ) {
    4286             this.modal[ method ].apply( this.modal, arguments );
    4287         }
    4288         return this;
    4289     };
    4290 });
    4291 
    4292 module.exports = MediaFrame;
    4293 
    4294 },{"./frame.js":27,"./iframe.js":30,"./menu.js":34,"./modal.js":35,"./router.js":38,"./toolbar.js":44,"./uploader/window.js":48,"./view.js":49}],33:[function(require,module,exports){
    4295 /*globals jQuery */
    4296 
    4297 /**
    4298  * wp.media.view.MenuItem
    4299  *
    4300  * @class
    4301  * @augments wp.media.View
    4302  * @augments wp.Backbone.View
    4303  * @augments Backbone.View
    4304  */
    4305 var View = require( './view.js' ),
    4306     $ = jQuery,
    4307     MenuItem;
    4308 
    4309 MenuItem = View.extend({
    4310     tagName:   'a',
    4311     className: 'media-menu-item',
    4312 
    4313     attributes: {
    4314         href: '#'
    4315     },
    4316 
    4317     events: {
    4318         'click': '_click'
    4319     },
    4320     /**
    4321      * @param {Object} event
    4322      */
    4323     _click: function( event ) {
    4324         var clickOverride = this.options.click;
    4325 
    4326         if ( event ) {
    4327             event.preventDefault();
    4328         }
    4329 
    4330         if ( clickOverride ) {
    4331             clickOverride.call( this );
    4332         } else {
    4333             this.click();
    4334         }
    4335 
    4336         // When selecting a tab along the left side,
    4337         // focus should be transferred into the main panel
    4338         if ( ! wp.media.isTouchDevice ) {
    4339             $('.media-frame-content input').first().focus();
    4340         }
    4341     },
    4342 
    4343     click: function() {
    4344         var state = this.options.state;
    4345 
    4346         if ( state ) {
    4347             this.controller.setState( state );
    4348             this.views.parent.$el.removeClass( 'visible' ); // TODO: or hide on any click, see below
    4349         }
    4350     },
    4351     /**
    4352      * @returns {wp.media.view.MenuItem} returns itself to allow chaining
    4353      */
    4354     render: function() {
    4355         var options = this.options;
    4356 
    4357         if ( options.text ) {
    4358             this.$el.text( options.text );
    4359         } else if ( options.html ) {
    4360             this.$el.html( options.html );
    4361         }
    4362 
    4363         return this;
    4364     }
    4365 });
    4366 
    4367 module.exports = MenuItem;
    4368 
    4369 },{"./view.js":49}],34:[function(require,module,exports){
    4370 /**
    4371  * wp.media.view.Menu
    4372  *
    4373  * @class
    4374  * @augments wp.media.view.PriorityList
    4375  * @augments wp.media.View
    4376  * @augments wp.Backbone.View
    4377  * @augments Backbone.View
    4378  */
    4379 var MenuItem = require( './menu-item.js' ),
    4380     PriorityList = require( './priority-list.js' ),
    4381     Menu;
    4382 
    4383 Menu = PriorityList.extend({
    4384     tagName:   'div',
    4385     className: 'media-menu',
    4386     property:  'state',
    4387     ItemView:  MenuItem,
    4388     region:    'menu',
    4389 
    4390     /* TODO: alternatively hide on any click anywhere
    4391     events: {
    4392         'click': 'click'
    4393     },
    4394 
    4395     click: function() {
    4396         this.$el.removeClass( 'visible' );
    4397     },
    4398     */
    4399 
    4400     /**
    4401      * @param {Object} options
    4402      * @param {string} id
    4403      * @returns {wp.media.View}
    4404      */
    4405     toView: function( options, id ) {
    4406         options = options || {};
    4407         options[ this.property ] = options[ this.property ] || id;
    4408         return new this.ItemView( options ).render();
    4409     },
    4410 
    4411     ready: function() {
    4412         /**
    4413          * call 'ready' directly on the parent class
    4414          */
    4415         PriorityList.prototype.ready.apply( this, arguments );
    4416         this.visibility();
    4417     },
    4418 
    4419     set: function() {
    4420         /**
    4421          * call 'set' directly on the parent class
    4422          */
    4423         PriorityList.prototype.set.apply( this, arguments );
    4424         this.visibility();
    4425     },
    4426 
    4427     unset: function() {
    4428         /**
    4429          * call 'unset' directly on the parent class
    4430          */
    4431         PriorityList.prototype.unset.apply( this, arguments );
    4432         this.visibility();
    4433     },
    4434 
    4435     visibility: function() {
    4436         var region = this.region,
    4437             view = this.controller[ region ].get(),
    4438             views = this.views.get(),
    4439             hide = ! views || views.length < 2;
    4440 
    4441         if ( this === view ) {
    4442             this.controller.$el.toggleClass( 'hide-' + region, hide );
    4443         }
    4444     },
    4445     /**
    4446      * @param {string} id
    4447      */
    4448     select: function( id ) {
    4449         var view = this.get( id );
    4450 
    4451         if ( ! view ) {
    4452             return;
    4453         }
    4454 
    4455         this.deselect();
    4456         view.$el.addClass('active');
    4457     },
    4458 
    4459     deselect: function() {
    4460         this.$el.children().removeClass('active');
    4461     },
    4462 
    4463     hide: function( id ) {
    4464         var view = this.get( id );
    4465 
    4466         if ( ! view ) {
    4467             return;
    4468         }
    4469 
    4470         view.$el.addClass('hidden');
    4471     },
    4472 
    4473     show: function( id ) {
    4474         var view = this.get( id );
    4475 
    4476         if ( ! view ) {
    4477             return;
    4478         }
    4479 
    4480         view.$el.removeClass('hidden');
    4481     }
    4482 });
    4483 
    4484 module.exports = Menu;
    4485 
    4486 },{"./menu-item.js":33,"./priority-list.js":36}],35:[function(require,module,exports){
    4487 /*globals wp, _, jQuery */
    4488 
    4489 /**
    4490  * wp.media.view.Modal
    4491  *
    4492  * A modal view, which the media modal uses as its default container.
    4493  *
    4494  * @class
    4495  * @augments wp.media.View
    4496  * @augments wp.Backbone.View
    4497  * @augments Backbone.View
    4498  */
    4499 var View = require( './view.js' ),
    4500     FocusManager = require( './focus-manager.js' ),
    4501     $ = jQuery,
    4502     Modal;
    4503 
    4504 Modal = View.extend({
    4505     tagName:  'div',
    4506     template: wp.template('media-modal'),
    4507 
    4508     attributes: {
    4509         tabindex: 0
    4510     },
    4511 
    4512     events: {
    4513         'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
    4514         'keydown': 'keydown'
    4515     },
    4516 
    4517     initialize: function() {
    4518         _.defaults( this.options, {
    4519             container: document.body,
    4520             title:     '',
    4521             propagate: true,
    4522             freeze:    true
    4523         });
    4524 
    4525         this.focusManager = new FocusManager({
    4526             el: this.el
    4527         });
    4528     },
    4529     /**
    4530      * @returns {Object}
    4531      */
    4532     prepare: function() {
    4533         return {
    4534             title: this.options.title
    4535         };
    4536     },
    4537 
    4538     /**
    4539      * @returns {wp.media.view.Modal} Returns itself to allow chaining
    4540      */
    4541     attach: function() {
    4542         if ( this.views.attached ) {
    4543             return this;
    4544         }
    4545 
    4546         if ( ! this.views.rendered ) {
    4547             this.render();
    4548         }
    4549 
    4550         this.$el.appendTo( this.options.container );
    4551 
    4552         // Manually mark the view as attached and trigger ready.
    4553         this.views.attached = true;
    4554         this.views.ready();
    4555 
    4556         return this.propagate('attach');
    4557     },
    4558 
    4559     /**
    4560      * @returns {wp.media.view.Modal} Returns itself to allow chaining
    4561      */
    4562     detach: function() {
    4563         if ( this.$el.is(':visible') ) {
    4564             this.close();
    4565         }
    4566 
    4567         this.$el.detach();
    4568         this.views.attached = false;
    4569         return this.propagate('detach');
    4570     },
    4571 
    4572     /**
    4573      * @returns {wp.media.view.Modal} Returns itself to allow chaining
    4574      */
    4575     open: function() {
    4576         var $el = this.$el,
    4577             options = this.options,
    4578             mceEditor;
    4579 
    4580         if ( $el.is(':visible') ) {
    4581             return this;
    4582         }
    4583 
    4584         if ( ! this.views.attached ) {
    4585             this.attach();
    4586         }
    4587 
    4588         // If the `freeze` option is set, record the window's scroll position.
    4589         if ( options.freeze ) {
    4590             this._freeze = {
    4591                 scrollTop: $( window ).scrollTop()
    4592             };
    4593         }
    4594 
    4595         // Disable page scrolling.
    4596         $( 'body' ).addClass( 'modal-open' );
    4597 
    4598         $el.show();
    4599 
    4600         // Try to close the onscreen keyboard
    4601         if ( 'ontouchend' in document ) {
    4602             if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor )  && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
    4603                 mceEditor.iframeElement.focus();
    4604                 mceEditor.iframeElement.blur();
    4605 
    4606                 setTimeout( function() {
    4607                     mceEditor.iframeElement.blur();
    4608                 }, 100 );
    4609             }
    4610         }
    4611 
    4612         this.$el.focus();
    4613 
    4614         return this.propagate('open');
    4615     },
    4616 
    4617     /**
    4618      * @param {Object} options
    4619      * @returns {wp.media.view.Modal} Returns itself to allow chaining
    4620      */
    4621     close: function( options ) {
    4622         var freeze = this._freeze;
    4623 
    4624         if ( ! this.views.attached || ! this.$el.is(':visible') ) {
    4625             return this;
    4626         }
    4627 
    4628         // Enable page scrolling.
    4629         $( 'body' ).removeClass( 'modal-open' );
    4630 
    4631         // Hide modal and remove restricted media modal tab focus once it's closed
    4632         this.$el.hide().undelegate( 'keydown' );
    4633 
    4634         // Put focus back in useful location once modal is closed
    4635         $('#wpbody-content').focus();
    4636 
    4637         this.propagate('close');
    4638 
    4639         // If the `freeze` option is set, restore the container's scroll position.
    4640         if ( freeze ) {
    4641             $( window ).scrollTop( freeze.scrollTop );
    4642         }
    4643 
    4644         if ( options && options.escape ) {
    4645             this.propagate('escape');
    4646         }
    4647 
    4648         return this;
    4649     },
    4650     /**
    4651      * @returns {wp.media.view.Modal} Returns itself to allow chaining
    4652      */
    4653     escape: function() {
    4654         return this.close({ escape: true });
    4655     },
    4656     /**
    4657      * @param {Object} event
    4658      */
    4659     escapeHandler: function( event ) {
    4660         event.preventDefault();
    4661         this.escape();
    4662     },
    4663 
    4664     /**
    4665      * @param {Array|Object} content Views to register to '.media-modal-content'
    4666      * @returns {wp.media.view.Modal} Returns itself to allow chaining
    4667      */
    4668     content: function( content ) {
    4669         this.views.set( '.media-modal-content', content );
    4670         return this;
    4671     },
    4672 
    4673     /**
    4674      * Triggers a modal event and if the `propagate` option is set,
    4675      * forwards events to the modal's controller.
    4676      *
    4677      * @param {string} id
    4678      * @returns {wp.media.view.Modal} Returns itself to allow chaining
    4679      */
    4680     propagate: function( id ) {
    4681         this.trigger( id );
    4682 
    4683         if ( this.options.propagate ) {
    4684             this.controller.trigger( id );
    4685         }
    4686 
    4687         return this;
    4688     },
    4689     /**
    4690      * @param {Object} event
    4691      */
    4692     keydown: function( event ) {
    4693         // Close the modal when escape is pressed.
    4694         if ( 27 === event.which && this.$el.is(':visible') ) {
    4695             this.escape();
    4696             event.stopImmediatePropagation();
    4697         }
    4698     }
    4699 });
    4700 
    4701 module.exports = Modal;
    4702 
    4703 },{"./focus-manager.js":26,"./view.js":49}],36:[function(require,module,exports){
    4704 /*globals _, Backbone */
    4705 
    4706 /**
    4707  * wp.media.view.PriorityList
    4708  *
    4709  * @class
    4710  * @augments wp.media.View
    4711  * @augments wp.Backbone.View
    4712  * @augments Backbone.View
    4713  */
    4714 var View = require( './view.js' ),
    4715     PriorityList;
    4716 
    4717 PriorityList = View.extend({
    4718     tagName:   'div',
    4719 
    4720     initialize: function() {
    4721         this._views = {};
    4722 
    4723         this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
    4724         delete this.options.views;
    4725 
    4726         if ( ! this.options.silent ) {
    4727             this.render();
    4728         }
    4729     },
    4730     /**
    4731      * @param {string} id
    4732      * @param {wp.media.View|Object} view
    4733      * @param {Object} options
    4734      * @returns {wp.media.view.PriorityList} Returns itself to allow chaining
    4735      */
    4736     set: function( id, view, options ) {
    4737         var priority, views, index;
    4738 
    4739         options = options || {};
    4740 
    4741         // Accept an object with an `id` : `view` mapping.
    4742         if ( _.isObject( id ) ) {
    4743             _.each( id, function( view, id ) {
    4744                 this.set( id, view );
    4745             }, this );
    4746             return this;
    4747         }
    4748 
    4749         if ( ! (view instanceof Backbone.View) ) {
    4750             view = this.toView( view, id, options );
    4751         }
    4752         view.controller = view.controller || this.controller;
    4753 
    4754         this.unset( id );
    4755 
    4756         priority = view.options.priority || 10;
    4757         views = this.views.get() || [];
    4758 
    4759         _.find( views, function( existing, i ) {
    4760             if ( existing.options.priority > priority ) {
    4761                 index = i;
    4762                 return true;
    4763             }
    4764         });
    4765 
    4766         this._views[ id ] = view;
    4767         this.views.add( view, {
    4768             at: _.isNumber( index ) ? index : views.length || 0
    4769         });
    4770 
    4771         return this;
    4772     },
    4773     /**
    4774      * @param {string} id
    4775      * @returns {wp.media.View}
    4776      */
    4777     get: function( id ) {
    4778         return this._views[ id ];
    4779     },
    4780     /**
    4781      * @param {string} id
    4782      * @returns {wp.media.view.PriorityList}
    4783      */
    4784     unset: function( id ) {
    4785         var view = this.get( id );
    4786 
    4787         if ( view ) {
    4788             view.remove();
    4789         }
    4790 
    4791         delete this._views[ id ];
    4792         return this;
    4793     },
    4794     /**
    4795      * @param {Object} options
    4796      * @returns {wp.media.View}
    4797      */
    4798     toView: function( options ) {
    4799         return new View( options );
    4800     }
    4801 });
    4802 
    4803 module.exports = PriorityList;
    4804 
    4805 },{"./view.js":49}],37:[function(require,module,exports){
    4806 /**
    4807  * wp.media.view.RouterItem
    4808  *
    4809  * @class
    4810  * @augments wp.media.view.MenuItem
    4811  * @augments wp.media.View
    4812  * @augments wp.Backbone.View
    4813  * @augments Backbone.View
    4814  */
    4815 var MenuItem = require( './menu-item.js' ),
    4816     RouterItem;
    4817 
    4818 RouterItem = MenuItem.extend({
    4819     /**
    4820      * On click handler to activate the content region's corresponding mode.
    4821      */
    4822     click: function() {
    4823         var contentMode = this.options.contentMode;
    4824         if ( contentMode ) {
    4825             this.controller.content.mode( contentMode );
    4826         }
    4827     }
    4828 });
    4829 
    4830 module.exports = RouterItem;
    4831 
    4832 },{"./menu-item.js":33}],38:[function(require,module,exports){
    4833 /**
    4834  * wp.media.view.Router
    4835  *
    4836  * @class
    4837  * @augments wp.media.view.Menu
    4838  * @augments wp.media.view.PriorityList
    4839  * @augments wp.media.View
    4840  * @augments wp.Backbone.View
    4841  * @augments Backbone.View
    4842  */
    4843 var Menu = require( './menu.js' ),
    4844     RouterItem = require( './router-item.js' ),
    4845     Router;
    4846 
    4847 Router = Menu.extend({
    4848     tagName:   'div',
    4849     className: 'media-router',
    4850     property:  'contentMode',
    4851     ItemView:  RouterItem,
    4852     region:    'router',
    4853 
    4854     initialize: function() {
    4855         this.controller.on( 'content:render', this.update, this );
    4856         // Call 'initialize' directly on the parent class.
    4857         Menu.prototype.initialize.apply( this, arguments );
    4858     },
    4859 
    4860     update: function() {
    4861         var mode = this.controller.content.mode();
    4862         if ( mode ) {
    4863             this.select( mode );
    4864         }
    4865     }
    4866 });
    4867 
    4868 module.exports = Router;
    4869 
    4870 },{"./menu.js":34,"./router-item.js":37}],39:[function(require,module,exports){
    4871 /*globals wp */
    4872 
    4873 /**
    4874  * wp.media.view.Search
    4875  *
    4876  * @class
    4877  * @augments wp.media.View
    4878  * @augments wp.Backbone.View
    4879  * @augments Backbone.View
    4880  */
    4881 var View = require( './view.js' ),
    4882     l10n = wp.media.view.l10n,
    4883     Search;
    4884 
    4885 Search = View.extend({
    4886     tagName:   'input',
    4887     className: 'search',
    4888     id:        'media-search-input',
    4889 
    4890     attributes: {
    4891         type:        'search',
    4892         placeholder: l10n.search
    4893     },
    4894 
    4895     events: {
    4896         'input':  'search',
    4897         'keyup':  'search',
    4898         'change': 'search',
    4899         'search': 'search'
    4900     },
    4901 
    4902     /**
    4903      * @returns {wp.media.view.Search} Returns itself to allow chaining
    4904      */
    4905     render: function() {
    4906         this.el.value = this.model.escape('search');
    4907         return this;
    4908     },
    4909 
    4910     search: function( event ) {
    4911         if ( event.target.value ) {
    4912             this.model.set( 'search', event.target.value );
    4913         } else {
    4914             this.model.unset('search');
    4915         }
    4916     }
    4917 });
    4918 
    4919 module.exports = Search;
    4920 
    4921 },{"./view.js":49}],40:[function(require,module,exports){
    4922 /*globals _, jQuery, Backbone */
    4923 
    4924 /**
    4925  * wp.media.view.Settings
    4926  *
    4927  * @class
    4928  * @augments wp.media.View
    4929  * @augments wp.Backbone.View
    4930  * @augments Backbone.View
    4931  */
    4932 var View = require( './view.js' ),
    4933     $ = jQuery,
    4934     Settings;
    4935 
    4936 Settings = View.extend({
    4937     events: {
    4938         'click button':    'updateHandler',
    4939         'change input':    'updateHandler',
    4940         'change select':   'updateHandler',
    4941         'change textarea': 'updateHandler'
    4942     },
    4943 
    4944     initialize: function() {
    4945         this.model = this.model || new Backbone.Model();
    4946         this.listenTo( this.model, 'change', this.updateChanges );
    4947     },
    4948 
    4949     prepare: function() {
    4950         return _.defaults({
    4951             model: this.model.toJSON()
    4952         }, this.options );
    4953     },
    4954     /**
    4955      * @returns {wp.media.view.Settings} Returns itself to allow chaining
    4956      */
    4957     render: function() {
    4958         View.prototype.render.apply( this, arguments );
    4959         // Select the correct values.
    4960         _( this.model.attributes ).chain().keys().each( this.update, this );
    4961         return this;
    4962     },
    4963     /**
    4964      * @param {string} key
    4965      */
    4966     update: function( key ) {
    4967         var value = this.model.get( key ),
    4968             $setting = this.$('[data-setting="' + key + '"]'),
    4969             $buttons, $value;
    4970 
    4971         // Bail if we didn't find a matching setting.
    4972         if ( ! $setting.length ) {
    4973             return;
    4974         }
    4975 
    4976         // Attempt to determine how the setting is rendered and update
    4977         // the selected value.
    4978 
    4979         // Handle dropdowns.
    4980         if ( $setting.is('select') ) {
    4981             $value = $setting.find('[value="' + value + '"]');
    4982 
    4983             if ( $value.length ) {
    4984                 $setting.find('option').prop( 'selected', false );
    4985                 $value.prop( 'selected', true );
    4986             } else {
    4987                 // If we can't find the desired value, record what *is* selected.
    4988                 this.model.set( key, $setting.find(':selected').val() );
    4989             }
    4990 
    4991         // Handle button groups.
    4992         } else if ( $setting.hasClass('button-group') ) {
    4993             $buttons = $setting.find('button').removeClass('active');
    4994             $buttons.filter( '[value="' + value + '"]' ).addClass('active');
    4995 
    4996         // Handle text inputs and textareas.
    4997         } else if ( $setting.is('input[type="text"], textarea') ) {
    4998             if ( ! $setting.is(':focus') ) {
    4999                 $setting.val( value );
    5000             }
    5001         // Handle checkboxes.
    5002         } else if ( $setting.is('input[type="checkbox"]') ) {
    5003             $setting.prop( 'checked', !! value && 'false' !== value );
    5004         }
    5005     },
    5006     /**
    5007      * @param {Object} event
    5008      */
    5009     updateHandler: function( event ) {
    5010         var $setting = $( event.target ).closest('[data-setting]'),
    5011             value = event.target.value,
    5012             userSetting;
    5013 
    5014         event.preventDefault();
    5015 
    5016         if ( ! $setting.length ) {
    5017             return;
    5018         }
    5019 
    5020         // Use the correct value for checkboxes.
    5021         if ( $setting.is('input[type="checkbox"]') ) {
    5022             value = $setting[0].checked;
    5023         }
    5024 
    5025         // Update the corresponding setting.
    5026         this.model.set( $setting.data('setting'), value );
    5027 
    5028         // If the setting has a corresponding user setting,
    5029         // update that as well.
    5030         if ( userSetting = $setting.data('userSetting') ) {
    5031             window.setUserSetting( userSetting, value );
    5032         }
    5033     },
    5034 
    5035     updateChanges: function( model ) {
    5036         if ( model.hasChanged() ) {
    5037             _( model.changed ).chain().keys().each( this.update, this );
    5038         }
    5039     }
    5040 });
    5041 
    5042 module.exports = Settings;
    5043 
    5044 },{"./view.js":49}],41:[function(require,module,exports){
    5045 /*globals wp, _ */
    5046 
    5047 /**
    5048  * wp.media.view.Settings.AttachmentDisplay
    5049  *
    5050  * @class
    5051  * @augments wp.media.view.Settings
    5052  * @augments wp.media.View
    5053  * @augments wp.Backbone.View
    5054  * @augments Backbone.View
    5055  */
    5056 var Settings = require( '../settings.js' ),
    5057     AttachmentDisplay;
    5058 
    5059 AttachmentDisplay = Settings.extend({
    5060     className: 'attachment-display-settings',
    5061     template:  wp.template('attachment-display-settings'),
    5062 
    5063     initialize: function() {
    5064         var attachment = this.options.attachment;
    5065 
    5066         _.defaults( this.options, {
    5067             userSettings: false
    5068         });
    5069         // Call 'initialize' directly on the parent class.
    5070         Settings.prototype.initialize.apply( this, arguments );
    5071         this.listenTo( this.model, 'change:link', this.updateLinkTo );
    5072 
    5073         if ( attachment ) {
    5074             attachment.on( 'change:uploading', this.render, this );
    5075         }
    5076     },
    5077 
    5078     dispose: function() {
    5079         var attachment = this.options.attachment;
    5080         if ( attachment ) {
    5081             attachment.off( null, null, this );
    5082         }
    5083         /**
    5084          * call 'dispose' directly on the parent class
    5085          */
    5086         Settings.prototype.dispose.apply( this, arguments );
    5087     },
    5088     /**
    5089      * @returns {wp.media.view.AttachmentDisplay} Returns itself to allow chaining
    5090      */
    5091     render: function() {
    5092         var attachment = this.options.attachment;
    5093         if ( attachment ) {
    5094             _.extend( this.options, {
    5095                 sizes: attachment.get('sizes'),
    5096                 type:  attachment.get('type')
    5097             });
    5098         }
    5099         /**
    5100          * call 'render' directly on the parent class
    5101          */
    5102         Settings.prototype.render.call( this );
    5103         this.updateLinkTo();
    5104         return this;
    5105     },
    5106 
    5107     updateLinkTo: function() {
    5108         var linkTo = this.model.get('link'),
    5109             $input = this.$('.link-to-custom'),
    5110             attachment = this.options.attachment;
    5111 
    5112         if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
    5113             $input.addClass( 'hidden' );
    5114             return;
    5115         }
    5116 
    5117         if ( attachment ) {
    5118             if ( 'post' === linkTo ) {
    5119                 $input.val( attachment.get('link') );
    5120             } else if ( 'file' === linkTo ) {
    5121                 $input.val( attachment.get('url') );
    5122             } else if ( ! this.model.get('linkUrl') ) {
    5123                 $input.val('http://');
    5124             }
    5125 
    5126             $input.prop( 'readonly', 'custom' !== linkTo );
    5127         }
    5128 
    5129         $input.removeClass( 'hidden' );
    5130 
    5131         // If the input is visible, focus and select its contents.
    5132         if ( ! wp.media.isTouchDevice && $input.is(':visible') ) {
    5133             $input.focus()[0].select();
    5134         }
    5135     }
    5136 });
    5137 
    5138 module.exports = AttachmentDisplay;
    5139 
    5140 },{"../settings.js":40}],42:[function(require,module,exports){
    5141 /**
    5142  * wp.media.view.Sidebar
    5143  *
    5144  * @class
    5145  * @augments wp.media.view.PriorityList
    5146  * @augments wp.media.View
    5147  * @augments wp.Backbone.View
    5148  * @augments Backbone.View
    5149  */
    5150 var PriorityList = require( './priority-list.js' ),
    5151     Sidebar;
    5152 
    5153 Sidebar = PriorityList.extend({
    5154     className: 'media-sidebar'
    5155 });
    5156 
    5157 module.exports = Sidebar;
    5158 
    5159 },{"./priority-list.js":36}],43:[function(require,module,exports){
    5160 /*globals _ */
    5161 
    5162 /**
    5163  * wp.media.view.Spinner
    5164  *
    5165  * @class
    5166  * @augments wp.media.View
    5167  * @augments wp.Backbone.View
    5168  * @augments Backbone.View
    5169  */
    5170 var View = require( './view.js' ),
    5171     Spinner;
    5172 
    5173 Spinner = View.extend({
    5174     tagName:   'span',
    5175     className: 'spinner',
    5176     spinnerTimeout: false,
    5177     delay: 400,
    5178 
    5179     show: function() {
    5180         if ( ! this.spinnerTimeout ) {
    5181             this.spinnerTimeout = _.delay(function( $el ) {
    5182                 $el.show();
    5183             }, this.delay, this.$el );
    5184         }
    5185 
    5186         return this;
    5187     },
    5188 
    5189     hide: function() {
    5190         this.$el.hide();
    5191         this.spinnerTimeout = clearTimeout( this.spinnerTimeout );
    5192 
    5193         return this;
    5194     }
    5195 });
    5196 
    5197 module.exports = Spinner;
    5198 
    5199 },{"./view.js":49}],44:[function(require,module,exports){
    5200 /*globals _, Backbone */
    5201 
    5202 /**
    5203  * wp.media.view.Toolbar
    5204  *
    5205  * A toolbar which consists of a primary and a secondary section. Each sections
    5206  * can be filled with views.
    5207  *
    5208  * @class
    5209  * @augments wp.media.View
    5210  * @augments wp.Backbone.View
    5211  * @augments Backbone.View
    5212  */
    5213 var View = require( './view.js' ),
    5214     Button = require( './button.js' ),
    5215     PriorityList = require( './priority-list.js' ),
    5216     Toolbar;
    5217 
    5218 Toolbar = View.extend({
    5219     tagName:   'div',
    5220     className: 'media-toolbar',
    5221 
    5222     initialize: function() {
    5223         var state = this.controller.state(),
    5224             selection = this.selection = state.get('selection'),
    5225             library = this.library = state.get('library');
    5226 
    5227         this._views = {};
    5228 
    5229         // The toolbar is composed of two `PriorityList` views.
    5230         this.primary   = new PriorityList();
    5231         this.secondary = new PriorityList();
    5232         this.primary.$el.addClass('media-toolbar-primary search-form');
    5233         this.secondary.$el.addClass('media-toolbar-secondary');
    5234 
    5235         this.views.set([ this.secondary, this.primary ]);
    5236 
    5237         if ( this.options.items ) {
    5238             this.set( this.options.items, { silent: true });
    5239         }
    5240 
    5241         if ( ! this.options.silent ) {
    5242             this.render();
    5243         }
    5244 
    5245         if ( selection ) {
    5246             selection.on( 'add remove reset', this.refresh, this );
    5247         }
    5248 
    5249         if ( library ) {
    5250             library.on( 'add remove reset', this.refresh, this );
    5251         }
    5252     },
    5253     /**
    5254      * @returns {wp.media.view.Toolbar} Returns itsef to allow chaining
    5255      */
    5256     dispose: function() {
    5257         if ( this.selection ) {
    5258             this.selection.off( null, null, this );
    5259         }
    5260 
    5261         if ( this.library ) {
    5262             this.library.off( null, null, this );
    5263         }
    5264         /**
    5265          * call 'dispose' directly on the parent class
    5266          */
    5267         return View.prototype.dispose.apply( this, arguments );
    5268     },
    5269 
    5270     ready: function() {
    5271         this.refresh();
    5272     },
    5273 
    5274     /**
    5275      * @param {string} id
    5276      * @param {Backbone.View|Object} view
    5277      * @param {Object} [options={}]
    5278      * @returns {wp.media.view.Toolbar} Returns itself to allow chaining
    5279      */
    5280     set: function( id, view, options ) {
    5281         var list;
    5282         options = options || {};
    5283 
    5284         // Accept an object with an `id` : `view` mapping.
    5285         if ( _.isObject( id ) ) {
    5286             _.each( id, function( view, id ) {
    5287                 this.set( id, view, { silent: true });
    5288             }, this );
    5289 
    5290         } else {
    5291             if ( ! ( view instanceof Backbone.View ) ) {
    5292                 view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
    5293                 view = new Button( view ).render();
    5294             }
    5295 
    5296             view.controller = view.controller || this.controller;
    5297 
    5298             this._views[ id ] = view;
    5299 
    5300             list = view.options.priority < 0 ? 'secondary' : 'primary';
    5301             this[ list ].set( id, view, options );
    5302         }
    5303 
    5304         if ( ! options.silent ) {
    5305             this.refresh();
    5306         }
    5307 
    5308         return this;
    5309     },
    5310     /**
    5311      * @param {string} id
    5312      * @returns {wp.media.view.Button}
    5313      */
    5314     get: function( id ) {
    5315         return this._views[ id ];
    5316     },
    5317     /**
    5318      * @param {string} id
    5319      * @param {Object} options
    5320      * @returns {wp.media.view.Toolbar} Returns itself to allow chaining
    5321      */
    5322     unset: function( id, options ) {
    5323         delete this._views[ id ];
    5324         this.primary.unset( id, options );
    5325         this.secondary.unset( id, options );
    5326 
    5327         if ( ! options || ! options.silent ) {
    5328             this.refresh();
    5329         }
    5330         return this;
    5331     },
    5332 
    5333     refresh: function() {
    5334         var state = this.controller.state(),
    5335             library = state.get('library'),
    5336             selection = state.get('selection');
    5337 
    5338         _.each( this._views, function( button ) {
    5339             if ( ! button.model || ! button.options || ! button.options.requires ) {
    5340                 return;
    5341             }
    5342 
    5343             var requires = button.options.requires,
    5344                 disabled = false;
    5345 
    5346             // Prevent insertion of attachments if any of them are still uploading
    5347             disabled = _.some( selection.models, function( attachment ) {
    5348                 return attachment.get('uploading') === true;
    5349             });
    5350 
    5351             if ( requires.selection && selection && ! selection.length ) {
    5352                 disabled = true;
    5353             } else if ( requires.library && library && ! library.length ) {
    5354                 disabled = true;
    5355             }
    5356             button.model.set( 'disabled', disabled );
    5357         });
    5358     }
    5359 });
    5360 
    5361 module.exports = Toolbar;
    5362 
    5363 },{"./button.js":21,"./priority-list.js":36,"./view.js":49}],45:[function(require,module,exports){
    5364 /*globals wp, _ */
    5365 
    5366 /**
    5367  * wp.media.view.UploaderInline
    5368  *
    5369  * The inline uploader that shows up in the 'Upload Files' tab.
    5370  *
    5371  * @class
    5372  * @augments wp.media.View
    5373  * @augments wp.Backbone.View
    5374  * @augments Backbone.View
    5375  */
    5376 var View = require( '../view.js' ),
    5377     UploaderStatus = require( './status.js' ),
    5378     UploaderInline;
    5379 
    5380 UploaderInline = View.extend({
    5381     tagName:   'div',
    5382     className: 'uploader-inline',
    5383     template:  wp.template('uploader-inline'),
    5384 
    5385     events: {
    5386         'click .close': 'hide'
    5387     },
    5388 
    5389     initialize: function() {
    5390         _.defaults( this.options, {
    5391             message: '',
    5392             status:  true,
    5393             canClose: false
    5394         });
    5395 
    5396         if ( ! this.options.$browser && this.controller.uploader ) {
    5397             this.options.$browser = this.controller.uploader.$browser;
    5398         }
    5399 
    5400         if ( _.isUndefined( this.options.postId ) ) {
    5401             this.options.postId = wp.media.view.settings.post.id;
    5402         }
    5403 
    5404         if ( this.options.status ) {
    5405             this.views.set( '.upload-inline-status', new UploaderStatus({
    5406                 controller: this.controller
    5407             }) );
    5408         }
    5409     },
    5410 
    5411     prepare: function() {
    5412         var suggestedWidth = this.controller.state().get('suggestedWidth'),
    5413             suggestedHeight = this.controller.state().get('suggestedHeight'),
    5414             data = {};
    5415 
    5416         data.message = this.options.message;
    5417         data.canClose = this.options.canClose;
    5418 
    5419         if ( suggestedWidth && suggestedHeight ) {
    5420             data.suggestedWidth = suggestedWidth;
    5421             data.suggestedHeight = suggestedHeight;
    5422         }
    5423 
    5424         return data;
    5425     },
    5426     /**
    5427      * @returns {wp.media.view.UploaderInline} Returns itself to allow chaining
    5428      */
    5429     dispose: function() {
    5430         if ( this.disposing ) {
    5431             /**
    5432              * call 'dispose' directly on the parent class
    5433              */
    5434             return View.prototype.dispose.apply( this, arguments );
    5435         }
    5436 
    5437         // Run remove on `dispose`, so we can be sure to refresh the
    5438         // uploader with a view-less DOM. Track whether we're disposing
    5439         // so we don't trigger an infinite loop.
    5440         this.disposing = true;
    5441         return this.remove();
    5442     },
    5443     /**
    5444      * @returns {wp.media.view.UploaderInline} Returns itself to allow chaining
    5445      */
    5446     remove: function() {
    5447         /**
    5448          * call 'remove' directly on the parent class
    5449          */
    5450         var result = View.prototype.remove.apply( this, arguments );
    5451 
    5452         _.defer( _.bind( this.refresh, this ) );
    5453         return result;
    5454     },
    5455 
    5456     refresh: function() {
    5457         var uploader = this.controller.uploader;
    5458 
    5459         if ( uploader ) {
    5460             uploader.refresh();
    5461         }
    5462     },
    5463     /**
    5464      * @returns {wp.media.view.UploaderInline}
    5465      */
    5466     ready: function() {
    5467         var $browser = this.options.$browser,
    5468             $placeholder;
    5469 
    5470         if ( this.controller.uploader ) {
    5471             $placeholder = this.$('.browser');
    5472 
    5473             // Check if we've already replaced the placeholder.
    5474             if ( $placeholder[0] === $browser[0] ) {
    5475                 return;
    5476             }
    5477 
    5478             $browser.detach().text( $placeholder.text() );
    5479             $browser[0].className = $placeholder[0].className;
    5480             $placeholder.replaceWith( $browser.show() );
    5481         }
    5482 
    5483         this.refresh();
    5484         return this;
    5485     },
    5486     show: function() {
    5487         this.$el.removeClass( 'hidden' );
    5488     },
    5489     hide: function() {
    5490         this.$el.addClass( 'hidden' );
    5491     }
    5492 
    5493 });
    5494 
    5495 module.exports = UploaderInline;
    5496 
    5497 },{"../view.js":49,"./status.js":47}],46:[function(require,module,exports){
    5498 /*globals wp */
    5499 
    5500 /**
    5501  * wp.media.view.UploaderStatusError
    5502  *
    5503  * @class
    5504  * @augments wp.media.View
    5505  * @augments wp.Backbone.View
    5506  * @augments Backbone.View
    5507  */
    5508 var View = require( '../view.js' ),
    5509     UploaderStatusError;
    5510 
    5511 UploaderStatusError = View.extend({
    5512     className: 'upload-error',
    5513     template:  wp.template('uploader-status-error')
    5514 });
    5515 
    5516 module.exports = UploaderStatusError;
    5517 
    5518 },{"../view.js":49}],47:[function(require,module,exports){
    5519 /*globals wp, _ */
    5520 
    5521 /**
    5522  * wp.media.view.UploaderStatus
    5523  *
    5524  * An uploader status for on-going uploads.
    5525  *
    5526  * @class
    5527  * @augments wp.media.View
    5528  * @augments wp.Backbone.View
    5529  * @augments Backbone.View
    5530  */
    5531 var View = require( '../view.js' ),
    5532     UploaderStatusError = require( './status-error.js' ),
    5533     UploaderStatus;
    5534 
    5535 UploaderStatus = View.extend({
    5536     className: 'media-uploader-status',
    5537     template:  wp.template('uploader-status'),
    5538 
    5539     events: {
    5540         'click .upload-dismiss-errors': 'dismiss'
    5541     },
    5542 
    5543     initialize: function() {
    5544         this.queue = wp.Uploader.queue;
    5545         this.queue.on( 'add remove reset', this.visibility, this );
    5546         this.queue.on( 'add remove reset change:percent', this.progress, this );
    5547         this.queue.on( 'add remove reset change:uploading', this.info, this );
    5548 
    5549         this.errors = wp.Uploader.errors;
    5550         this.errors.reset();
    5551         this.errors.on( 'add remove reset', this.visibility, this );
    5552         this.errors.on( 'add', this.error, this );
    5553     },
    5554     /**
    5555      * @global wp.Uploader
    5556      * @returns {wp.media.view.UploaderStatus}
    5557      */
    5558     dispose: function() {
    5559         wp.Uploader.queue.off( null, null, this );
    5560         /**
    5561          * call 'dispose' directly on the parent class
    5562          */
    5563         View.prototype.dispose.apply( this, arguments );
    5564         return this;
    5565     },
    5566 
    5567     visibility: function() {
    5568         this.$el.toggleClass( 'uploading', !! this.queue.length );
    5569         this.$el.toggleClass( 'errors', !! this.errors.length );
    5570         this.$el.toggle( !! this.queue.length || !! this.errors.length );
    5571     },
    5572 
    5573     ready: function() {
    5574         _.each({
    5575             '$bar':      '.media-progress-bar div',
    5576             '$index':    '.upload-index',
    5577             '$total':    '.upload-total',
    5578             '$filename': '.upload-filename'
    5579         }, function( selector, key ) {
    5580             this[ key ] = this.$( selector );
    5581         }, this );
    5582 
    5583         this.visibility();
    5584         this.progress();
    5585         this.info();
    5586     },
    5587 
    5588     progress: function() {
    5589         var queue = this.queue,
    5590             $bar = this.$bar;
    5591 
    5592         if ( ! $bar || ! queue.length ) {
    5593             return;
    5594         }
    5595 
    5596         $bar.width( ( queue.reduce( function( memo, attachment ) {
    5597             if ( ! attachment.get('uploading') ) {
    5598                 return memo + 100;
    5599             }
    5600 
    5601             var percent = attachment.get('percent');
    5602             return memo + ( _.isNumber( percent ) ? percent : 100 );
    5603         }, 0 ) / queue.length ) + '%' );
    5604     },
    5605 
    5606     info: function() {
    5607         var queue = this.queue,
    5608             index = 0, active;
    5609 
    5610         if ( ! queue.length ) {
    5611             return;
    5612         }
    5613 
    5614         active = this.queue.find( function( attachment, i ) {
    5615             index = i;
    5616             return attachment.get('uploading');
    5617         });
    5618 
    5619         this.$index.text( index + 1 );
    5620         this.$total.text( queue.length );
    5621         this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
    5622     },
    5623     /**
    5624      * @param {string} filename
    5625      * @returns {string}
    5626      */
    5627     filename: function( filename ) {
    5628         return wp.media.truncate( _.escape( filename ), 24 );
    5629     },
    5630     /**
    5631      * @param {Backbone.Model} error
    5632      */
    5633     error: function( error ) {
    5634         this.views.add( '.upload-errors', new UploaderStatusError({
    5635             filename: this.filename( error.get('file').name ),
    5636             message:  error.get('message')
    5637         }), { at: 0 });
    5638     },
    5639 
    5640     /**
    5641      * @global wp.Uploader
    5642      *
    5643      * @param {Object} event
    5644      */
    5645     dismiss: function( event ) {
    5646         var errors = this.views.get('.upload-errors');
    5647 
    5648         event.preventDefault();
    5649 
    5650         if ( errors ) {
    5651             _.invoke( errors, 'remove' );
    5652         }
    5653         wp.Uploader.errors.reset();
    5654     }
    5655 });
    5656 
    5657 module.exports = UploaderStatus;
    5658 
    5659 },{"../view.js":49,"./status-error.js":46}],48:[function(require,module,exports){
    5660 /*globals wp, _, jQuery */
    5661 
    5662 /**
    5663  * wp.media.view.UploaderWindow
    5664  *
    5665  * An uploader window that allows for dragging and dropping media.
    5666  *
    5667  * @class
    5668  * @augments wp.media.View
    5669  * @augments wp.Backbone.View
    5670  * @augments Backbone.View
    5671  *
    5672  * @param {object} [options]                   Options hash passed to the view.
    5673  * @param {object} [options.uploader]          Uploader properties.
    5674  * @param {jQuery} [options.uploader.browser]
    5675  * @param {jQuery} [options.uploader.dropzone] jQuery collection of the dropzone.
    5676  * @param {object} [options.uploader.params]
    5677  */
    5678 var View = require( '../view.js' ),
    5679     $ = jQuery,
    5680     UploaderWindow;
    5681 
    5682 UploaderWindow = View.extend({
    5683     tagName:   'div',
    5684     className: 'uploader-window',
    5685     template:  wp.template('uploader-window'),
    5686 
    5687     initialize: function() {
    5688         var uploader;
    5689 
    5690         this.$browser = $('<a href="#" class="browser" />').hide().appendTo('body');
    5691 
    5692         uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
    5693             dropzone:  this.$el,
    5694             browser:   this.$browser,
    5695             params:    {}
    5696         });
    5697 
    5698         // Ensure the dropzone is a jQuery collection.
    5699         if ( uploader.dropzone && ! (uploader.dropzone instanceof $) ) {
    5700             uploader.dropzone = $( uploader.dropzone );
    5701         }
    5702 
    5703         this.controller.on( 'activate', this.refresh, this );
    5704 
    5705         this.controller.on( 'detach', function() {
    5706             this.$browser.remove();
    5707         }, this );
    5708     },
    5709 
    5710     refresh: function() {
    5711         if ( this.uploader ) {
    5712             this.uploader.refresh();
    5713         }
    5714     },
    5715 
    5716     ready: function() {
    5717         var postId = wp.media.view.settings.post.id,
    5718             dropzone;
    5719 
    5720         // If the uploader already exists, bail.
    5721         if ( this.uploader ) {
    5722             return;
    5723         }
    5724 
    5725         if ( postId ) {
    5726             this.options.uploader.params.post_id = postId;
    5727         }
    5728         this.uploader = new wp.Uploader( this.options.uploader );
    5729 
    5730         dropzone = this.uploader.dropzone;
    5731         dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
    5732         dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
    5733 
    5734         $( this.uploader ).on( 'uploader:ready', _.bind( this._ready, this ) );
    5735     },
    5736 
    5737     _ready: function() {
    5738         this.controller.trigger( 'uploader:ready' );
    5739     },
    5740 
    5741     show: function() {
    5742         var $el = this.$el.show();
    5743 
    5744         // Ensure that the animation is triggered by waiting until
    5745         // the transparent element is painted into the DOM.
    5746         _.defer( function() {
    5747             $el.css({ opacity: 1 });
    5748         });
    5749     },
    5750 
    5751     hide: function() {
    5752         var $el = this.$el.css({ opacity: 0 });
    5753 
    5754         wp.media.transition( $el ).done( function() {
    5755             // Transition end events are subject to race conditions.
    5756             // Make sure that the value is set as intended.
    5757             if ( '0' === $el.css('opacity') ) {
    5758                 $el.hide();
    5759             }
    5760         });
    5761 
    5762         // https://core.trac.wordpress.org/ticket/27341
    5763         _.delay( function() {
    5764             if ( '0' === $el.css('opacity') && $el.is(':visible') ) {
    5765                 $el.hide();
    5766             }
    5767         }, 500 );
    5768     }
    5769 });
    5770 
    5771 module.exports = UploaderWindow;
    5772 
    5773 },{"../view.js":49}],49:[function(require,module,exports){
    5774 /*globals wp */
    5775 
    5776 /**
    5777  * wp.media.View
    5778  *
    5779  * The base view class for media.
    5780  *
    5781  * Undelegating events, removing events from the model, and
    5782  * removing events from the controller mirror the code for
    5783  * `Backbone.View.dispose` in Backbone 0.9.8 development.
    5784  *
    5785  * This behavior has since been removed, and should not be used
    5786  * outside of the media manager.
    5787  *
    5788  * @class
    5789  * @augments wp.Backbone.View
    5790  * @augments Backbone.View
    5791  */
    5792 var View = wp.Backbone.View.extend({
    5793     constructor: function( options ) {
    5794         if ( options && options.controller ) {
    5795             this.controller = options.controller;
    5796         }
    5797         wp.Backbone.View.apply( this, arguments );
    5798     },
    5799     /**
    5800      * @todo The internal comment mentions this might have been a stop-gap
    5801      *       before Backbone 0.9.8 came out. Figure out if Backbone core takes
    5802      *       care of this in Backbone.View now.
    5803      *
    5804      * @returns {wp.media.View} Returns itself to allow chaining
    5805      */
    5806     dispose: function() {
    5807         // Undelegating events, removing events from the model, and
    5808         // removing events from the controller mirror the code for
    5809         // `Backbone.View.dispose` in Backbone 0.9.8 development.
    5810         this.undelegateEvents();
    5811 
    5812         if ( this.model && this.model.off ) {
    5813             this.model.off( null, null, this );
    5814         }
    5815 
    5816         if ( this.collection && this.collection.off ) {
    5817             this.collection.off( null, null, this );
    5818         }
    5819 
    5820         // Unbind controller events.
    5821         if ( this.controller && this.controller.off ) {
    5822             this.controller.off( null, null, this );
    5823         }
    5824 
    5825         return this;
    5826     },
    5827     /**
    5828      * @returns {wp.media.View} Returns itself to allow chaining
    5829      */
    5830     remove: function() {
    5831         this.dispose();
    5832         /**
    5833          * call 'remove' directly on the parent class
    5834          */
    5835         return wp.Backbone.View.prototype.remove.apply( this, arguments );
    5836     }
    5837 });
    5838 
    5839 module.exports = View;
    5840 
    5841 },{}]},{},[7]);
     850},{"../../routers/manage.js":3}]},{},[2]);
  • trunk/src/wp-includes/js/media/views.js

    r31492 r31494  
    21822182
    21832183media.View = require( './views/view.js' );
    2184 media.view.Frame = require( './views/view.js' );
     2184media.view.Frame = require( './views/frame.js' );
    21852185media.view.MediaFrame = require( './views/media-frame.js' );
    21862186media.view.MediaFrame.Select = require( './views/frame/select.js' );
     
    22362236media.view.Spinner = require( './views/spinner.js' );
    22372237
    2238 },{"./controllers/collection-add.js":1,"./controllers/collection-edit.js":2,"./controllers/cropper.js":3,"./controllers/edit-image.js":4,"./controllers/embed.js":5,"./controllers/featured-image.js":6,"./controllers/gallery-add.js":7,"./controllers/gallery-edit.js":8,"./controllers/image-details.js":9,"./controllers/library.js":10,"./controllers/media-library.js":11,"./controllers/region.js":12,"./controllers/replace-image.js":13,"./controllers/state-machine.js":14,"./controllers/state.js":15,"./utils/selection-sync.js":16,"./views/attachment-compat.js":18,"./views/attachment-filters.js":19,"./views/attachment-filters/all.js":20,"./views/attachment-filters/date.js":21,"./views/attachment-filters/uploaded.js":22,"./views/attachment.js":23,"./views/attachment/details.js":24,"./views/attachment/edit-library.js":25,"./views/attachment/edit-selection.js":26,"./views/attachment/library.js":27,"./views/attachment/selection.js":28,"./views/attachments.js":29,"./views/attachments/browser.js":30,"./views/attachments/selection.js":31,"./views/button-group.js":32,"./views/button.js":33,"./views/cropper.js":34,"./views/edit-image.js":35,"./views/embed.js":36,"./views/embed/image.js":37,"./views/embed/link.js":38,"./views/embed/url.js":39,"./views/focus-manager.js":40,"./views/frame/image-details.js":42,"./views/frame/post.js":43,"./views/frame/select.js":44,"./views/iframe.js":45,"./views/image-details.js":46,"./views/label.js":47,"./views/media-frame.js":48,"./views/menu-item.js":49,"./views/menu.js":50,"./views/modal.js":51,"./views/priority-list.js":52,"./views/router-item.js":53,"./views/router.js":54,"./views/search.js":55,"./views/selection.js":56,"./views/settings.js":57,"./views/settings/attachment-display.js":58,"./views/settings/gallery.js":59,"./views/settings/playlist.js":60,"./views/sidebar.js":61,"./views/spinner.js":62,"./views/toolbar.js":63,"./views/toolbar/embed.js":64,"./views/toolbar/select.js":65,"./views/uploader/editor.js":66,"./views/uploader/inline.js":67,"./views/uploader/status-error.js":68,"./views/uploader/status.js":69,"./views/uploader/window.js":70,"./views/view.js":71}],18:[function(require,module,exports){
     2238},{"./controllers/collection-add.js":1,"./controllers/collection-edit.js":2,"./controllers/cropper.js":3,"./controllers/edit-image.js":4,"./controllers/embed.js":5,"./controllers/featured-image.js":6,"./controllers/gallery-add.js":7,"./controllers/gallery-edit.js":8,"./controllers/image-details.js":9,"./controllers/library.js":10,"./controllers/media-library.js":11,"./controllers/region.js":12,"./controllers/replace-image.js":13,"./controllers/state-machine.js":14,"./controllers/state.js":15,"./utils/selection-sync.js":16,"./views/attachment-compat.js":18,"./views/attachment-filters.js":19,"./views/attachment-filters/all.js":20,"./views/attachment-filters/date.js":21,"./views/attachment-filters/uploaded.js":22,"./views/attachment.js":23,"./views/attachment/details.js":24,"./views/attachment/edit-library.js":25,"./views/attachment/edit-selection.js":26,"./views/attachment/library.js":27,"./views/attachment/selection.js":28,"./views/attachments.js":29,"./views/attachments/browser.js":30,"./views/attachments/selection.js":31,"./views/button-group.js":32,"./views/button.js":33,"./views/cropper.js":34,"./views/edit-image.js":35,"./views/embed.js":36,"./views/embed/image.js":37,"./views/embed/link.js":38,"./views/embed/url.js":39,"./views/focus-manager.js":40,"./views/frame.js":41,"./views/frame/image-details.js":42,"./views/frame/post.js":43,"./views/frame/select.js":44,"./views/iframe.js":45,"./views/image-details.js":46,"./views/label.js":47,"./views/media-frame.js":48,"./views/menu-item.js":49,"./views/menu.js":50,"./views/modal.js":51,"./views/priority-list.js":52,"./views/router-item.js":53,"./views/router.js":54,"./views/search.js":55,"./views/selection.js":56,"./views/settings.js":57,"./views/settings/attachment-display.js":58,"./views/settings/gallery.js":59,"./views/settings/playlist.js":60,"./views/sidebar.js":61,"./views/spinner.js":62,"./views/toolbar.js":63,"./views/toolbar/embed.js":64,"./views/toolbar/select.js":65,"./views/uploader/editor.js":66,"./views/uploader/inline.js":67,"./views/uploader/status-error.js":68,"./views/uploader/status.js":69,"./views/uploader/window.js":70,"./views/view.js":71}],18:[function(require,module,exports){
    22392239/*globals _ */
    22402240
  • trunk/src/wp-includes/js/media/views.manifest.js

    r31491 r31494  
    9393
    9494media.View = require( './views/view.js' );
    95 media.view.Frame = require( './views/view.js' );
     95media.view.Frame = require( './views/frame.js' );
    9696media.view.MediaFrame = require( './views/media-frame.js' );
    9797media.view.MediaFrame.Select = require( './views/frame/select.js' );
  • trunk/src/wp-includes/js/media/views/attachment/details-two-column.js

    r31492 r31494  
    1414 * @augments Backbone.View
    1515 */
    16 var Details = require( './details.js' ),
     16var Details = wp.media.view.Attachment.Details,
    1717    TwoColumn;
    1818
  • trunk/src/wp-includes/js/media/views/button/delete-selected-permanently.js

    r31492 r31494  
    1111 * @augments Backbone.View
    1212 */
    13 var Button = require( '../button.js' ),
     13var Button = wp.media.view.Button,
    1414    DeleteSelected = require( './delete-selected.js' ),
    1515    DeleteSelectedPermanently;
  • trunk/src/wp-includes/js/media/views/button/delete-selected.js

    r31492 r31494  
    1212 * @augments Backbone.View
    1313 */
    14 var Button = require( '../button.js' ),
     14var Button = wp.media.view.Button,
    1515    l10n = wp.media.view.l10n,
    1616    DeleteSelected;
  • trunk/src/wp-includes/js/media/views/button/select-mode-toggle.js

    r31492 r31494  
    1010 * @augments Backbone.View
    1111 */
    12 var Button = require( '../button.js' ),
     12var Button = wp.media.view.Button,
    1313    l10n = wp.media.view.l10n,
    1414    SelectModeToggle;
  • trunk/src/wp-includes/js/media/views/edit-image-details.js

    r31492 r31494  
    55 *
    66 * @class
    7  * @augments wp.media.view.EditImage.Details
     7 * @augments wp.media.view.EditImage
    88 * @augments wp.media.View
    99 * @augments wp.Backbone.View
    1010 * @augments Backbone.View
    1111 */
    12 var View = require( './view.js' ),
     12var View = wp.media.View,
    1313    EditImage = wp.media.view.EditImage,
    1414    Details;
  • trunk/src/wp-includes/js/media/views/frame/edit-attachments.js

    r31492 r31494  
    1717 * @mixes wp.media.controller.StateMachine
    1818 */
    19 var Frame = require( '../frame.js' ),
    20     MediaFrame = require( '../media-frame.js' ),
    21     Modal = require( '../modal.js' ),
     19var Frame = wp.media.view.Frame,
     20    MediaFrame = wp.media.view.MediaFrame,
     21    Modal = wp.media.view.Modal,
     22    AttachmentCompat = wp.media.view.AttachmentCompat,
     23    EditImageController = wp.media.controller.EditImage,
     24
    2225    EditAttachmentMetadata = require( '../../controllers/edit-attachment-metadata.js' ),
    2326    TwoColumn = require( '../attachment/details-two-column.js' ),
    24     AttachmentCompat = require( '../attachment-compat.js' ),
    25     EditImageController = require( '../../controllers/edit-image.js' ),
    2627    DetailsView = require( '../edit-image-details.js' ),
     28
    2729    $ = jQuery,
    2830    EditAttachments;
  • trunk/src/wp-includes/js/media/views/frame/manage.js

    r31491 r31494  
    1616 * @mixes wp.media.controller.StateMachine
    1717 */
    18 var MediaFrame = require( '../media-frame.js' ),
    19     UploaderWindow = require( '../uploader/window.js' ),
    20     AttachmentsBrowser = require( '../attachments/browser.js' ),
     18var MediaFrame = wp.media.view.MediaFrame,
     19    UploaderWindow = wp.media.view.UploaderWindow,
     20    AttachmentsBrowser = wp.media.view.AttachmentsBrowser,
     21    Library = wp.media.controller.Library,
     22
    2123    Router = require( '../../routers/manage.js' ),
    22     Library = require( '../../controllers/library.js' ),
     24
    2325    $ = jQuery,
    2426    Manage;
Note: See TracChangeset for help on using the changeset viewer.