balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

media-views.js (274484B)


      1 /******/ (function(modules) { // webpackBootstrap
      2 /******/ 	// The module cache
      3 /******/ 	var installedModules = {};
      4 /******/
      5 /******/ 	// The require function
      6 /******/ 	function __webpack_require__(moduleId) {
      7 /******/
      8 /******/ 		// Check if module is in cache
      9 /******/ 		if(installedModules[moduleId]) {
     10 /******/ 			return installedModules[moduleId].exports;
     11 /******/ 		}
     12 /******/ 		// Create a new module (and put it into the cache)
     13 /******/ 		var module = installedModules[moduleId] = {
     14 /******/ 			i: moduleId,
     15 /******/ 			l: false,
     16 /******/ 			exports: {}
     17 /******/ 		};
     18 /******/
     19 /******/ 		// Execute the module function
     20 /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
     21 /******/
     22 /******/ 		// Flag the module as loaded
     23 /******/ 		module.l = true;
     24 /******/
     25 /******/ 		// Return the exports of the module
     26 /******/ 		return module.exports;
     27 /******/ 	}
     28 /******/
     29 /******/
     30 /******/ 	// expose the modules object (__webpack_modules__)
     31 /******/ 	__webpack_require__.m = modules;
     32 /******/
     33 /******/ 	// expose the module cache
     34 /******/ 	__webpack_require__.c = installedModules;
     35 /******/
     36 /******/ 	// define getter function for harmony exports
     37 /******/ 	__webpack_require__.d = function(exports, name, getter) {
     38 /******/ 		if(!__webpack_require__.o(exports, name)) {
     39 /******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
     40 /******/ 		}
     41 /******/ 	};
     42 /******/
     43 /******/ 	// define __esModule on exports
     44 /******/ 	__webpack_require__.r = function(exports) {
     45 /******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
     46 /******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
     47 /******/ 		}
     48 /******/ 		Object.defineProperty(exports, '__esModule', { value: true });
     49 /******/ 	};
     50 /******/
     51 /******/ 	// create a fake namespace object
     52 /******/ 	// mode & 1: value is a module id, require it
     53 /******/ 	// mode & 2: merge all properties of value into the ns
     54 /******/ 	// mode & 4: return value when already ns object
     55 /******/ 	// mode & 8|1: behave like require
     56 /******/ 	__webpack_require__.t = function(value, mode) {
     57 /******/ 		if(mode & 1) value = __webpack_require__(value);
     58 /******/ 		if(mode & 8) return value;
     59 /******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
     60 /******/ 		var ns = Object.create(null);
     61 /******/ 		__webpack_require__.r(ns);
     62 /******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
     63 /******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
     64 /******/ 		return ns;
     65 /******/ 	};
     66 /******/
     67 /******/ 	// getDefaultExport function for compatibility with non-harmony modules
     68 /******/ 	__webpack_require__.n = function(module) {
     69 /******/ 		var getter = module && module.__esModule ?
     70 /******/ 			function getDefault() { return module['default']; } :
     71 /******/ 			function getModuleExports() { return module; };
     72 /******/ 		__webpack_require__.d(getter, 'a', getter);
     73 /******/ 		return getter;
     74 /******/ 	};
     75 /******/
     76 /******/ 	// Object.prototype.hasOwnProperty.call
     77 /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
     78 /******/
     79 /******/ 	// __webpack_public_path__
     80 /******/ 	__webpack_require__.p = "";
     81 /******/
     82 /******/
     83 /******/ 	// Load entry module and return exports
     84 /******/ 	return __webpack_require__(__webpack_require__.s = 3);
     85 /******/ })
     86 /************************************************************************/
     87 /******/ ({
     88 
     89 /***/ "+B8m":
     90 /***/ (function(module, exports) {
     91 
     92 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
     93 	EmbedImage;
     94 
     95 /**
     96  * wp.media.view.EmbedImage
     97  *
     98  * @memberOf wp.media.view
     99  *
    100  * @class
    101  * @augments wp.media.view.Settings.AttachmentDisplay
    102  * @augments wp.media.view.Settings
    103  * @augments wp.media.View
    104  * @augments wp.Backbone.View
    105  * @augments Backbone.View
    106  */
    107 EmbedImage = AttachmentDisplay.extend(/** @lends wp.media.view.EmbedImage.prototype */{
    108 	className: 'embed-media-settings',
    109 	template:  wp.template('embed-image-settings'),
    110 
    111 	initialize: function() {
    112 		/**
    113 		 * Call `initialize` directly on parent class with passed arguments
    114 		 */
    115 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
    116 		this.listenTo( this.model, 'change:url', this.updateImage );
    117 	},
    118 
    119 	updateImage: function() {
    120 		this.$('img').attr( 'src', this.model.get('url') );
    121 	}
    122 });
    123 
    124 module.exports = EmbedImage;
    125 
    126 
    127 /***/ }),
    128 
    129 /***/ "+mQJ":
    130 /***/ (function(module, exports) {
    131 
    132 var View = wp.media.View,
    133 	$ = jQuery,
    134 	l10n = wp.media.view.l10n,
    135 	EmbedUrl;
    136 
    137 /**
    138  * wp.media.view.EmbedUrl
    139  *
    140  * @memberOf wp.media.view
    141  *
    142  * @class
    143  * @augments wp.media.View
    144  * @augments wp.Backbone.View
    145  * @augments Backbone.View
    146  */
    147 EmbedUrl = View.extend(/** @lends wp.media.view.EmbedUrl.prototype */{
    148 	tagName:   'span',
    149 	className: 'embed-url',
    150 
    151 	events: {
    152 		'input': 'url'
    153 	},
    154 
    155 	initialize: function() {
    156 		this.$input = $( '<input id="embed-url-field" type="url" />' )
    157 			.attr( 'aria-label', l10n.insertFromUrlTitle )
    158 			.val( this.model.get('url') );
    159 		this.input = this.$input[0];
    160 
    161 		this.spinner = $('<span class="spinner" />')[0];
    162 		this.$el.append([ this.input, this.spinner ]);
    163 
    164 		this.listenTo( this.model, 'change:url', this.render );
    165 
    166 		if ( this.model.get( 'url' ) ) {
    167 			_.delay( _.bind( function () {
    168 				this.model.trigger( 'change:url' );
    169 			}, this ), 500 );
    170 		}
    171 	},
    172 	/**
    173 	 * @return {wp.media.view.EmbedUrl} Returns itself to allow chaining.
    174 	 */
    175 	render: function() {
    176 		var $input = this.$input;
    177 
    178 		if ( $input.is(':focus') ) {
    179 			return;
    180 		}
    181 
    182 		this.input.value = this.model.get('url') || 'http://';
    183 		/**
    184 		 * Call `render` directly on parent class with passed arguments
    185 		 */
    186 		View.prototype.render.apply( this, arguments );
    187 		return this;
    188 	},
    189 
    190 	url: function( event ) {
    191 		var url = event.target.value || '';
    192 		this.model.set( 'url', url.trim() );
    193 	}
    194 });
    195 
    196 module.exports = EmbedUrl;
    197 
    198 
    199 /***/ }),
    200 
    201 /***/ "04Ix":
    202 /***/ (function(module, exports) {
    203 
    204 var _n = wp.i18n._n,
    205 	sprintf = wp.i18n.sprintf,
    206 	Selection;
    207 
    208 /**
    209  * wp.media.view.Selection
    210  *
    211  * @memberOf wp.media.view
    212  *
    213  * @class
    214  * @augments wp.media.View
    215  * @augments wp.Backbone.View
    216  * @augments Backbone.View
    217  */
    218 Selection = wp.media.View.extend(/** @lends wp.media.view.Selection.prototype */{
    219 	tagName:   'div',
    220 	className: 'media-selection',
    221 	template:  wp.template('media-selection'),
    222 
    223 	events: {
    224 		'click .edit-selection':  'edit',
    225 		'click .clear-selection': 'clear'
    226 	},
    227 
    228 	initialize: function() {
    229 		_.defaults( this.options, {
    230 			editable:  false,
    231 			clearable: true
    232 		});
    233 
    234 		/**
    235 		 * @member {wp.media.view.Attachments.Selection}
    236 		 */
    237 		this.attachments = new wp.media.view.Attachments.Selection({
    238 			controller: this.controller,
    239 			collection: this.collection,
    240 			selection:  this.collection,
    241 			model:      new Backbone.Model()
    242 		});
    243 
    244 		this.views.set( '.selection-view', this.attachments );
    245 		this.collection.on( 'add remove reset', this.refresh, this );
    246 		this.controller.on( 'content:activate', this.refresh, this );
    247 	},
    248 
    249 	ready: function() {
    250 		this.refresh();
    251 	},
    252 
    253 	refresh: function() {
    254 		// If the selection hasn't been rendered, bail.
    255 		if ( ! this.$el.children().length ) {
    256 			return;
    257 		}
    258 
    259 		var collection = this.collection,
    260 			editing = 'edit-selection' === this.controller.content.mode();
    261 
    262 		// If nothing is selected, display nothing.
    263 		this.$el.toggleClass( 'empty', ! collection.length );
    264 		this.$el.toggleClass( 'one', 1 === collection.length );
    265 		this.$el.toggleClass( 'editing', editing );
    266 
    267 		this.$( '.count' ).text(
    268 			/* translators: %s: Number of selected media attachments. */
    269 			sprintf( _n( '%s item selected', '%s items selected', collection.length ), collection.length )
    270 		);
    271 	},
    272 
    273 	edit: function( event ) {
    274 		event.preventDefault();
    275 		if ( this.options.editable ) {
    276 			this.options.editable.call( this, this.collection );
    277 		}
    278 	},
    279 
    280 	clear: function( event ) {
    281 		event.preventDefault();
    282 		this.collection.reset();
    283 
    284 		// Move focus to the modal.
    285 		this.controller.modal.focusManager.focus();
    286 	}
    287 });
    288 
    289 module.exports = Selection;
    290 
    291 
    292 /***/ }),
    293 
    294 /***/ "1S4+":
    295 /***/ (function(module, exports) {
    296 
    297 var $ = jQuery,
    298 	AttachmentFilters;
    299 
    300 /**
    301  * wp.media.view.AttachmentFilters
    302  *
    303  * @memberOf wp.media.view
    304  *
    305  * @class
    306  * @augments wp.media.View
    307  * @augments wp.Backbone.View
    308  * @augments Backbone.View
    309  */
    310 AttachmentFilters = wp.media.View.extend(/** @lends wp.media.view.AttachmentFilters.prototype */{
    311 	tagName:   'select',
    312 	className: 'attachment-filters',
    313 	id:        'media-attachment-filters',
    314 
    315 	events: {
    316 		change: 'change'
    317 	},
    318 
    319 	keys: [],
    320 
    321 	initialize: function() {
    322 		this.createFilters();
    323 		_.extend( this.filters, this.options.filters );
    324 
    325 		// Build `<option>` elements.
    326 		this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
    327 			return {
    328 				el: $( '<option></option>' ).val( value ).html( filter.text )[0],
    329 				priority: filter.priority || 50
    330 			};
    331 		}, this ).sortBy('priority').pluck('el').value() );
    332 
    333 		this.listenTo( this.model, 'change', this.select );
    334 		this.select();
    335 	},
    336 
    337 	/**
    338 	 * @abstract
    339 	 */
    340 	createFilters: function() {
    341 		this.filters = {};
    342 	},
    343 
    344 	/**
    345 	 * When the selected filter changes, update the Attachment Query properties to match.
    346 	 */
    347 	change: function() {
    348 		var filter = this.filters[ this.el.value ];
    349 		if ( filter ) {
    350 			this.model.set( filter.props );
    351 		}
    352 	},
    353 
    354 	select: function() {
    355 		var model = this.model,
    356 			value = 'all',
    357 			props = model.toJSON();
    358 
    359 		_.find( this.filters, function( filter, id ) {
    360 			var equal = _.all( filter.props, function( prop, key ) {
    361 				return prop === ( _.isUndefined( props[ key ] ) ? null : props[ key ] );
    362 			});
    363 
    364 			if ( equal ) {
    365 				return value = id;
    366 			}
    367 		});
    368 
    369 		this.$el.val( value );
    370 	}
    371 });
    372 
    373 module.exports = AttachmentFilters;
    374 
    375 
    376 /***/ }),
    377 
    378 /***/ "2AvB":
    379 /***/ (function(module, exports) {
    380 
    381 var Settings = wp.media.view.Settings,
    382 	AttachmentDisplay;
    383 
    384 /**
    385  * wp.media.view.Settings.AttachmentDisplay
    386  *
    387  * @memberOf wp.media.view.Settings
    388  *
    389  * @class
    390  * @augments wp.media.view.Settings
    391  * @augments wp.media.View
    392  * @augments wp.Backbone.View
    393  * @augments Backbone.View
    394  */
    395 AttachmentDisplay = Settings.extend(/** @lends wp.media.view.Settings.AttachmentDisplay.prototype */{
    396 	className: 'attachment-display-settings',
    397 	template:  wp.template('attachment-display-settings'),
    398 
    399 	initialize: function() {
    400 		var attachment = this.options.attachment;
    401 
    402 		_.defaults( this.options, {
    403 			userSettings: false
    404 		});
    405 		// Call 'initialize' directly on the parent class.
    406 		Settings.prototype.initialize.apply( this, arguments );
    407 		this.listenTo( this.model, 'change:link', this.updateLinkTo );
    408 
    409 		if ( attachment ) {
    410 			attachment.on( 'change:uploading', this.render, this );
    411 		}
    412 	},
    413 
    414 	dispose: function() {
    415 		var attachment = this.options.attachment;
    416 		if ( attachment ) {
    417 			attachment.off( null, null, this );
    418 		}
    419 		/**
    420 		 * call 'dispose' directly on the parent class
    421 		 */
    422 		Settings.prototype.dispose.apply( this, arguments );
    423 	},
    424 	/**
    425 	 * @return {wp.media.view.AttachmentDisplay} Returns itself to allow chaining.
    426 	 */
    427 	render: function() {
    428 		var attachment = this.options.attachment;
    429 		if ( attachment ) {
    430 			_.extend( this.options, {
    431 				sizes: attachment.get('sizes'),
    432 				type:  attachment.get('type')
    433 			});
    434 		}
    435 		/**
    436 		 * call 'render' directly on the parent class
    437 		 */
    438 		Settings.prototype.render.call( this );
    439 		this.updateLinkTo();
    440 		return this;
    441 	},
    442 
    443 	updateLinkTo: function() {
    444 		var linkTo = this.model.get('link'),
    445 			$input = this.$('.link-to-custom'),
    446 			attachment = this.options.attachment;
    447 
    448 		if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
    449 			$input.closest( '.setting' ).addClass( 'hidden' );
    450 			return;
    451 		}
    452 
    453 		if ( attachment ) {
    454 			if ( 'post' === linkTo ) {
    455 				$input.val( attachment.get('link') );
    456 			} else if ( 'file' === linkTo ) {
    457 				$input.val( attachment.get('url') );
    458 			} else if ( ! this.model.get('linkUrl') ) {
    459 				$input.val('http://');
    460 			}
    461 
    462 			$input.prop( 'readonly', 'custom' !== linkTo );
    463 		}
    464 
    465 		$input.closest( '.setting' ).removeClass( 'hidden' );
    466 		if ( $input.length ) {
    467 			$input[0].scrollIntoView();
    468 		}
    469 	}
    470 });
    471 
    472 module.exports = AttachmentDisplay;
    473 
    474 
    475 /***/ }),
    476 
    477 /***/ "2NU8":
    478 /***/ (function(module, exports) {
    479 
    480 var View = wp.media.View,
    481 	Toolbar;
    482 
    483 /**
    484  * wp.media.view.Toolbar
    485  *
    486  * A toolbar which consists of a primary and a secondary section. Each sections
    487  * can be filled with views.
    488  *
    489  * @memberOf wp.media.view
    490  *
    491  * @class
    492  * @augments wp.media.View
    493  * @augments wp.Backbone.View
    494  * @augments Backbone.View
    495  */
    496 Toolbar = View.extend(/** @lends wp.media.view.Toolbar.prototype */{
    497 	tagName:   'div',
    498 	className: 'media-toolbar',
    499 
    500 	initialize: function() {
    501 		var state = this.controller.state(),
    502 			selection = this.selection = state.get('selection'),
    503 			library = this.library = state.get('library');
    504 
    505 		this._views = {};
    506 
    507 		// The toolbar is composed of two `PriorityList` views.
    508 		this.primary   = new wp.media.view.PriorityList();
    509 		this.secondary = new wp.media.view.PriorityList();
    510 		this.primary.$el.addClass('media-toolbar-primary search-form');
    511 		this.secondary.$el.addClass('media-toolbar-secondary');
    512 
    513 		this.views.set([ this.secondary, this.primary ]);
    514 
    515 		if ( this.options.items ) {
    516 			this.set( this.options.items, { silent: true });
    517 		}
    518 
    519 		if ( ! this.options.silent ) {
    520 			this.render();
    521 		}
    522 
    523 		if ( selection ) {
    524 			selection.on( 'add remove reset', this.refresh, this );
    525 		}
    526 
    527 		if ( library ) {
    528 			library.on( 'add remove reset', this.refresh, this );
    529 		}
    530 	},
    531 	/**
    532 	 * @return {wp.media.view.Toolbar} Returns itsef to allow chaining
    533 	 */
    534 	dispose: function() {
    535 		if ( this.selection ) {
    536 			this.selection.off( null, null, this );
    537 		}
    538 
    539 		if ( this.library ) {
    540 			this.library.off( null, null, this );
    541 		}
    542 		/**
    543 		 * call 'dispose' directly on the parent class
    544 		 */
    545 		return View.prototype.dispose.apply( this, arguments );
    546 	},
    547 
    548 	ready: function() {
    549 		this.refresh();
    550 	},
    551 
    552 	/**
    553 	 * @param {string} id
    554 	 * @param {Backbone.View|Object} view
    555 	 * @param {Object} [options={}]
    556 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
    557 	 */
    558 	set: function( id, view, options ) {
    559 		var list;
    560 		options = options || {};
    561 
    562 		// Accept an object with an `id` : `view` mapping.
    563 		if ( _.isObject( id ) ) {
    564 			_.each( id, function( view, id ) {
    565 				this.set( id, view, { silent: true });
    566 			}, this );
    567 
    568 		} else {
    569 			if ( ! ( view instanceof Backbone.View ) ) {
    570 				view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
    571 				view = new wp.media.view.Button( view ).render();
    572 			}
    573 
    574 			view.controller = view.controller || this.controller;
    575 
    576 			this._views[ id ] = view;
    577 
    578 			list = view.options.priority < 0 ? 'secondary' : 'primary';
    579 			this[ list ].set( id, view, options );
    580 		}
    581 
    582 		if ( ! options.silent ) {
    583 			this.refresh();
    584 		}
    585 
    586 		return this;
    587 	},
    588 	/**
    589 	 * @param {string} id
    590 	 * @return {wp.media.view.Button}
    591 	 */
    592 	get: function( id ) {
    593 		return this._views[ id ];
    594 	},
    595 	/**
    596 	 * @param {string} id
    597 	 * @param {Object} options
    598 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
    599 	 */
    600 	unset: function( id, options ) {
    601 		delete this._views[ id ];
    602 		this.primary.unset( id, options );
    603 		this.secondary.unset( id, options );
    604 
    605 		if ( ! options || ! options.silent ) {
    606 			this.refresh();
    607 		}
    608 		return this;
    609 	},
    610 
    611 	refresh: function() {
    612 		var state = this.controller.state(),
    613 			library = state.get('library'),
    614 			selection = state.get('selection');
    615 
    616 		_.each( this._views, function( button ) {
    617 			if ( ! button.model || ! button.options || ! button.options.requires ) {
    618 				return;
    619 			}
    620 
    621 			var requires = button.options.requires,
    622 				disabled = false;
    623 
    624 			// Prevent insertion of attachments if any of them are still uploading.
    625 			if ( selection && selection.models ) {
    626 				disabled = _.some( selection.models, function( attachment ) {
    627 					return attachment.get('uploading') === true;
    628 				});
    629 			}
    630 
    631 			if ( requires.selection && selection && ! selection.length ) {
    632 				disabled = true;
    633 			} else if ( requires.library && library && ! library.length ) {
    634 				disabled = true;
    635 			}
    636 			button.model.set( 'disabled', disabled );
    637 		});
    638 	}
    639 });
    640 
    641 module.exports = Toolbar;
    642 
    643 
    644 /***/ }),
    645 
    646 /***/ "2jku":
    647 /***/ (function(module, exports) {
    648 
    649 /**
    650  * wp.media.view.Attachment.Library
    651  *
    652  * @memberOf wp.media.view.Attachment
    653  *
    654  * @class
    655  * @augments wp.media.view.Attachment
    656  * @augments wp.media.View
    657  * @augments wp.Backbone.View
    658  * @augments Backbone.View
    659  */
    660 var Library = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Library.prototype */{
    661 	buttons: {
    662 		check: true
    663 	}
    664 });
    665 
    666 module.exports = Library;
    667 
    668 
    669 /***/ }),
    670 
    671 /***/ 3:
    672 /***/ (function(module, exports, __webpack_require__) {
    673 
    674 module.exports = __webpack_require__("tg/Y");
    675 
    676 
    677 /***/ }),
    678 
    679 /***/ "3nJM":
    680 /***/ (function(module, exports) {
    681 
    682 var $ = jQuery;
    683 
    684 /**
    685  * wp.media.view.FocusManager
    686  *
    687  * @memberOf wp.media.view
    688  *
    689  * @class
    690  * @augments wp.media.View
    691  * @augments wp.Backbone.View
    692  * @augments Backbone.View
    693  */
    694 var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.prototype */{
    695 
    696 	events: {
    697 		'keydown': 'focusManagementMode'
    698 	},
    699 
    700 	/**
    701 	 * Initializes the Focus Manager.
    702 	 *
    703 	 * @param {Object} options The Focus Manager options.
    704 	 *
    705 	 * @since 5.3.0
    706 	 *
    707 	 * @return {void}
    708 	 */
    709 	initialize: function( options ) {
    710 		this.mode                    = options.mode || 'constrainTabbing';
    711 		this.tabsAutomaticActivation = options.tabsAutomaticActivation || false;
    712 	},
    713 
    714  	/**
    715 	 * Determines which focus management mode to use.
    716 	 *
    717 	 * @since 5.3.0
    718 	 *
    719 	 * @param {Object} event jQuery event object.
    720 	 *
    721 	 * @return {void}
    722 	 */
    723 	focusManagementMode: function( event ) {
    724 		if ( this.mode === 'constrainTabbing' ) {
    725 			this.constrainTabbing( event );
    726 		}
    727 
    728 		if ( this.mode === 'tabsNavigation' ) {
    729 			this.tabsNavigation( event );
    730 		}
    731 	},
    732 
    733 	/**
    734 	 * Gets all the tabbable elements.
    735 	 *
    736 	 * @since 5.3.0
    737 	 *
    738 	 * @return {Object} A jQuery collection of tabbable elements.
    739 	 */
    740 	getTabbables: function() {
    741 		// Skip the file input added by Plupload.
    742 		return this.$( ':tabbable' ).not( '.moxie-shim input[type="file"]' );
    743 	},
    744 
    745 	/**
    746 	 * Moves focus to the modal dialog.
    747 	 *
    748 	 * @since 3.5.0
    749 	 *
    750 	 * @return {void}
    751 	 */
    752 	focus: function() {
    753 		this.$( '.media-modal' ).trigger( 'focus' );
    754 	},
    755 
    756 	/**
    757 	 * Constrains navigation with the Tab key within the media view element.
    758 	 *
    759 	 * @since 4.0.0
    760 	 *
    761 	 * @param {Object} event A keydown jQuery event.
    762 	 *
    763 	 * @return {void}
    764 	 */
    765 	constrainTabbing: function( event ) {
    766 		var tabbables;
    767 
    768 		// Look for the tab key.
    769 		if ( 9 !== event.keyCode ) {
    770 			return;
    771 		}
    772 
    773 		tabbables = this.getTabbables();
    774 
    775 		// Keep tab focus within media modal while it's open.
    776 		if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
    777 			tabbables.first().focus();
    778 			return false;
    779 		} else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
    780 			tabbables.last().focus();
    781 			return false;
    782 		}
    783 	},
    784 
    785 	/**
    786 	 * Hides from assistive technologies all the body children.
    787 	 *
    788 	 * Sets an `aria-hidden="true"` attribute on all the body children except
    789 	 * the provided element and other elements that should not be hidden.
    790 	 *
    791 	 * The reason why we use `aria-hidden` is that `aria-modal="true"` is buggy
    792 	 * in Safari 11.1 and support is spotty in other browsers. Also, `aria-modal="true"`
    793 	 * prevents the `wp.a11y.speak()` ARIA live regions to work as they're outside
    794 	 * of the modal dialog and get hidden from assistive technologies.
    795 	 *
    796 	 * @since 5.2.3
    797 	 *
    798 	 * @param {Object} visibleElement The jQuery object representing the element that should not be hidden.
    799 	 *
    800 	 * @return {void}
    801 	 */
    802 	setAriaHiddenOnBodyChildren: function( visibleElement ) {
    803 		var bodyChildren,
    804 			self = this;
    805 
    806 		if ( this.isBodyAriaHidden ) {
    807 			return;
    808 		}
    809 
    810 		// Get all the body children.
    811 		bodyChildren = document.body.children;
    812 
    813 		// Loop through the body children and hide the ones that should be hidden.
    814 		_.each( bodyChildren, function( element ) {
    815 			// Don't hide the modal element.
    816 			if ( element === visibleElement[0] ) {
    817 				return;
    818 			}
    819 
    820 			// Determine the body children to hide.
    821 			if ( self.elementShouldBeHidden( element ) ) {
    822 				element.setAttribute( 'aria-hidden', 'true' );
    823 				// Store the hidden elements.
    824 				self.ariaHiddenElements.push( element );
    825 			}
    826 		} );
    827 
    828 		this.isBodyAriaHidden = true;
    829 	},
    830 
    831 	/**
    832 	 * Unhides from assistive technologies all the body children.
    833 	 *
    834 	 * Makes visible again to assistive technologies all the body children
    835 	 * previously hidden and stored in this.ariaHiddenElements.
    836 	 *
    837 	 * @since 5.2.3
    838 	 *
    839 	 * @return {void}
    840 	 */
    841 	removeAriaHiddenFromBodyChildren: function() {
    842 		_.each( this.ariaHiddenElements, function( element ) {
    843 			element.removeAttribute( 'aria-hidden' );
    844 		} );
    845 
    846 		this.ariaHiddenElements = [];
    847 		this.isBodyAriaHidden   = false;
    848 	},
    849 
    850 	/**
    851 	 * Determines if the passed element should not be hidden from assistive technologies.
    852 	 *
    853 	 * @since 5.2.3
    854 	 *
    855 	 * @param {Object} element The DOM element that should be checked.
    856 	 *
    857 	 * @return {boolean} Whether the element should not be hidden from assistive technologies.
    858 	 */
    859 	elementShouldBeHidden: function( element ) {
    860 		var role = element.getAttribute( 'role' ),
    861 			liveRegionsRoles = [ 'alert', 'status', 'log', 'marquee', 'timer' ];
    862 
    863 		/*
    864 		 * Don't hide scripts, elements that already have `aria-hidden`, and
    865 		 * ARIA live regions.
    866 		 */
    867 		return ! (
    868 			element.tagName === 'SCRIPT' ||
    869 			element.hasAttribute( 'aria-hidden' ) ||
    870 			element.hasAttribute( 'aria-live' ) ||
    871 			liveRegionsRoles.indexOf( role ) !== -1
    872 		);
    873 	},
    874 
    875 	/**
    876 	 * Whether the body children are hidden from assistive technologies.
    877 	 *
    878 	 * @since 5.2.3
    879 	 */
    880 	isBodyAriaHidden: false,
    881 
    882 	/**
    883 	 * Stores an array of DOM elements that should be hidden from assistive
    884 	 * technologies, for example when the media modal dialog opens.
    885 	 *
    886 	 * @since 5.2.3
    887 	 */
    888 	ariaHiddenElements: [],
    889 
    890 	/**
    891 	 * Holds the jQuery collection of ARIA tabs.
    892 	 *
    893 	 * @since 5.3.0
    894 	 */
    895 	tabs: $(),
    896 
    897 	/**
    898 	 * Sets up tabs in an ARIA tabbed interface.
    899 	 *
    900 	 * @since 5.3.0
    901 	 *
    902 	 * @param {Object} event jQuery event object.
    903 	 *
    904 	 * @return {void}
    905 	 */
    906 	setupAriaTabs: function() {
    907 		this.tabs = this.$( '[role="tab"]' );
    908 
    909 		// Set up initial attributes.
    910 		this.tabs.attr( {
    911 			'aria-selected': 'false',
    912 			tabIndex: '-1'
    913 		} );
    914 
    915 		// Set up attributes on the initially active tab.
    916 		this.tabs.filter( '.active' )
    917 			.removeAttr( 'tabindex' )
    918 			.attr( 'aria-selected', 'true' );
    919 	},
    920 
    921 	/**
    922 	 * Enables arrows navigation within the ARIA tabbed interface.
    923 	 *
    924 	 * @since 5.3.0
    925 	 *
    926 	 * @param {Object} event jQuery event object.
    927 	 *
    928 	 * @return {void}
    929 	 */
    930 	tabsNavigation: function( event ) {
    931 		var orientation = 'horizontal',
    932 			keys = [ 32, 35, 36, 37, 38, 39, 40 ];
    933 
    934 		// Return if not Spacebar, End, Home, or Arrow keys.
    935 		if ( keys.indexOf( event.which ) === -1 ) {
    936 			return;
    937 		}
    938 
    939 		// Determine navigation direction.
    940 		if ( this.$el.attr( 'aria-orientation' ) === 'vertical' ) {
    941 			orientation = 'vertical';
    942 		}
    943 
    944 		// Make Up and Down arrow keys do nothing with horizontal tabs.
    945 		if ( orientation === 'horizontal' && [ 38, 40 ].indexOf( event.which ) !== -1 ) {
    946 			return;
    947 		}
    948 
    949 		// Make Left and Right arrow keys do nothing with vertical tabs.
    950 		if ( orientation === 'vertical' && [ 37, 39 ].indexOf( event.which ) !== -1 ) {
    951 			return;
    952 		}
    953 
    954 		this.switchTabs( event, this.tabs );
    955 	},
    956 
    957 	/**
    958 	 * Switches tabs in the ARIA tabbed interface.
    959 	 *
    960 	 * @since 5.3.0
    961 	 *
    962 	 * @param {Object} event jQuery event object.
    963 	 *
    964 	 * @return {void}
    965 	 */
    966 	switchTabs: function( event ) {
    967 		var key   = event.which,
    968 			index = this.tabs.index( $( event.target ) ),
    969 			newIndex;
    970 
    971 		switch ( key ) {
    972 			// Space bar: Activate current targeted tab.
    973 			case 32: {
    974 				this.activateTab( this.tabs[ index ] );
    975 				break;
    976 			}
    977 			// End key: Activate last tab.
    978 			case 35: {
    979 				event.preventDefault();
    980 				this.activateTab( this.tabs[ this.tabs.length - 1 ] );
    981 				break;
    982 			}
    983 			// Home key: Activate first tab.
    984 			case 36: {
    985 				event.preventDefault();
    986 				this.activateTab( this.tabs[ 0 ] );
    987 				break;
    988 			}
    989 			// Left and up keys: Activate previous tab.
    990 			case 37:
    991 			case 38: {
    992 				event.preventDefault();
    993 				newIndex = ( index - 1 ) < 0 ? this.tabs.length - 1 : index - 1;
    994 				this.activateTab( this.tabs[ newIndex ] );
    995 				break;
    996 			}
    997 			// Right and down keys: Activate next tab.
    998 			case 39:
    999 			case 40: {
   1000 				event.preventDefault();
   1001 				newIndex = ( index + 1 ) === this.tabs.length ? 0 : index + 1;
   1002 				this.activateTab( this.tabs[ newIndex ] );
   1003 				break;
   1004 			}
   1005 		}
   1006 	},
   1007 
   1008 	/**
   1009 	 * Sets a single tab to be focusable and semantically selected.
   1010 	 *
   1011 	 * @since 5.3.0
   1012 	 *
   1013 	 * @param {Object} tab The tab DOM element.
   1014 	 *
   1015 	 * @return {void}
   1016 	 */
   1017 	activateTab: function( tab ) {
   1018 		if ( ! tab ) {
   1019 			return;
   1020 		}
   1021 
   1022 		// The tab is a DOM element: no need for jQuery methods.
   1023 		tab.focus();
   1024 
   1025 		// Handle automatic activation.
   1026 		if ( this.tabsAutomaticActivation ) {
   1027 			tab.removeAttribute( 'tabindex' );
   1028 			tab.setAttribute( 'aria-selected', 'true' );
   1029 			tab.click();
   1030 
   1031 			return;
   1032 		}
   1033 
   1034 		// Handle manual activation.
   1035 		$( tab ).on( 'click', function() {
   1036 			tab.removeAttribute( 'tabindex' );
   1037 			tab.setAttribute( 'aria-selected', 'true' );
   1038 		} );
   1039  	}
   1040 });
   1041 
   1042 module.exports = FocusManager;
   1043 
   1044 
   1045 /***/ }),
   1046 
   1047 /***/ "4jjk":
   1048 /***/ (function(module, exports) {
   1049 
   1050 var l10n = wp.media.view.l10n,
   1051 	Uploaded;
   1052 
   1053 /**
   1054  * wp.media.view.AttachmentFilters.Uploaded
   1055  *
   1056  * @memberOf wp.media.view.AttachmentFilters
   1057  *
   1058  * @class
   1059  * @augments wp.media.view.AttachmentFilters
   1060  * @augments wp.media.View
   1061  * @augments wp.Backbone.View
   1062  * @augments Backbone.View
   1063  */
   1064 Uploaded = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Uploaded.prototype */{
   1065 	createFilters: function() {
   1066 		var type = this.model.get('type'),
   1067 			types = wp.media.view.settings.mimeTypes,
   1068 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0,
   1069 			text;
   1070 
   1071 		if ( types && type ) {
   1072 			text = types[ type ];
   1073 		}
   1074 
   1075 		this.filters = {
   1076 			all: {
   1077 				text:  text || l10n.allMediaItems,
   1078 				props: {
   1079 					uploadedTo: null,
   1080 					orderby: 'date',
   1081 					order:   'DESC',
   1082 					author:	 null
   1083 				},
   1084 				priority: 10
   1085 			},
   1086 
   1087 			uploaded: {
   1088 				text:  l10n.uploadedToThisPost,
   1089 				props: {
   1090 					uploadedTo: wp.media.view.settings.post.id,
   1091 					orderby: 'menuOrder',
   1092 					order:   'ASC',
   1093 					author:	 null
   1094 				},
   1095 				priority: 20
   1096 			},
   1097 
   1098 			unattached: {
   1099 				text:  l10n.unattached,
   1100 				props: {
   1101 					uploadedTo: 0,
   1102 					orderby: 'menuOrder',
   1103 					order:   'ASC',
   1104 					author:	 null
   1105 				},
   1106 				priority: 50
   1107 			}
   1108 		};
   1109 
   1110 		if ( uid ) {
   1111 			this.filters.mine = {
   1112 				text:  l10n.mine,
   1113 				props: {
   1114 					orderby: 'date',
   1115 					order:   'DESC',
   1116 					author:  uid
   1117 				},
   1118 				priority: 50
   1119 			};
   1120 		}
   1121 	}
   1122 });
   1123 
   1124 module.exports = Uploaded;
   1125 
   1126 
   1127 /***/ }),
   1128 
   1129 /***/ "4tHu":
   1130 /***/ (function(module, exports) {
   1131 
   1132 var l10n = wp.media.view.l10n,
   1133 	EditImage;
   1134 
   1135 /**
   1136  * wp.media.controller.EditImage
   1137  *
   1138  * A state for editing (cropping, etc.) an image.
   1139  *
   1140  * @memberOf wp.media.controller
   1141  *
   1142  * @class
   1143  * @augments wp.media.controller.State
   1144  * @augments Backbone.Model
   1145  *
   1146  * @param {object}                    attributes                      The attributes hash passed to the state.
   1147  * @param {wp.media.model.Attachment} attributes.model                The attachment.
   1148  * @param {string}                    [attributes.id=edit-image]      Unique identifier.
   1149  * @param {string}                    [attributes.title=Edit Image]   Title for the state. Displays in the media menu and the frame's title region.
   1150  * @param {string}                    [attributes.content=edit-image] Initial mode for the content region.
   1151  * @param {string}                    [attributes.toolbar=edit-image] Initial mode for the toolbar region.
   1152  * @param {string}                    [attributes.menu=false]         Initial mode for the menu region.
   1153  * @param {string}                    [attributes.url]                Unused. @todo Consider removal.
   1154  */
   1155 EditImage = wp.media.controller.State.extend(/** @lends wp.media.controller.EditImage.prototype */{
   1156 	defaults: {
   1157 		id:      'edit-image',
   1158 		title:   l10n.editImage,
   1159 		menu:    false,
   1160 		toolbar: 'edit-image',
   1161 		content: 'edit-image',
   1162 		url:     ''
   1163 	},
   1164 
   1165 	/**
   1166 	 * Activates a frame for editing a featured image.
   1167 	 *
   1168 	 * @since 3.9.0
   1169 	 *
   1170 	 * @return {void}
   1171 	 */
   1172 	activate: function() {
   1173 		this.frame.on( 'toolbar:render:edit-image', _.bind( this.toolbar, this ) );
   1174 	},
   1175 
   1176 	/**
   1177 	 * Deactivates a frame for editing a featured image.
   1178 	 *
   1179 	 * @since 3.9.0
   1180 	 *
   1181 	 * @return {void}
   1182 	 */
   1183 	deactivate: function() {
   1184 		this.frame.off( 'toolbar:render:edit-image' );
   1185 	},
   1186 
   1187 	/**
   1188 	 * Adds a toolbar with a back button.
   1189 	 *
   1190 	 * When the back button is pressed it checks whether there is a previous state.
   1191 	 * In case there is a previous state it sets that previous state otherwise it
   1192 	 * closes the frame.
   1193 	 *
   1194 	 * @since 3.9.0
   1195 	 *
   1196 	 * @return {void}
   1197 	 */
   1198 	toolbar: function() {
   1199 		var frame = this.frame,
   1200 			lastState = frame.lastState(),
   1201 			previous = lastState && lastState.id;
   1202 
   1203 		frame.toolbar.set( new wp.media.view.Toolbar({
   1204 			controller: frame,
   1205 			items: {
   1206 				back: {
   1207 					style: 'primary',
   1208 					text:     l10n.back,
   1209 					priority: 20,
   1210 					click:    function() {
   1211 						if ( previous ) {
   1212 							frame.setState( previous );
   1213 						} else {
   1214 							frame.close();
   1215 						}
   1216 					}
   1217 				}
   1218 			}
   1219 		}) );
   1220 	}
   1221 });
   1222 
   1223 module.exports = EditImage;
   1224 
   1225 
   1226 /***/ }),
   1227 
   1228 /***/ "6B7g":
   1229 /***/ (function(module, exports) {
   1230 
   1231 var Select = wp.media.view.MediaFrame.Select,
   1232 	Library = wp.media.controller.Library,
   1233 	l10n = wp.media.view.l10n,
   1234 	Post;
   1235 
   1236 /**
   1237  * wp.media.view.MediaFrame.Post
   1238  *
   1239  * The frame for manipulating media on the Edit Post page.
   1240  *
   1241  * @memberOf wp.media.view.MediaFrame
   1242  *
   1243  * @class
   1244  * @augments wp.media.view.MediaFrame.Select
   1245  * @augments wp.media.view.MediaFrame
   1246  * @augments wp.media.view.Frame
   1247  * @augments wp.media.View
   1248  * @augments wp.Backbone.View
   1249  * @augments Backbone.View
   1250  * @mixes wp.media.controller.StateMachine
   1251  */
   1252 Post = Select.extend(/** @lends wp.media.view.MediaFrame.Post.prototype */{
   1253 	initialize: function() {
   1254 		this.counts = {
   1255 			audio: {
   1256 				count: wp.media.view.settings.attachmentCounts.audio,
   1257 				state: 'playlist'
   1258 			},
   1259 			video: {
   1260 				count: wp.media.view.settings.attachmentCounts.video,
   1261 				state: 'video-playlist'
   1262 			}
   1263 		};
   1264 
   1265 		_.defaults( this.options, {
   1266 			multiple:  true,
   1267 			editing:   false,
   1268 			state:    'insert',
   1269 			metadata:  {}
   1270 		});
   1271 
   1272 		// Call 'initialize' directly on the parent class.
   1273 		Select.prototype.initialize.apply( this, arguments );
   1274 		this.createIframeStates();
   1275 
   1276 	},
   1277 
   1278 	/**
   1279 	 * Create the default states.
   1280 	 */
   1281 	createStates: function() {
   1282 		var options = this.options;
   1283 
   1284 		this.states.add([
   1285 			// Main states.
   1286 			new Library({
   1287 				id:         'insert',
   1288 				title:      l10n.insertMediaTitle,
   1289 				priority:   20,
   1290 				toolbar:    'main-insert',
   1291 				filterable: 'all',
   1292 				library:    wp.media.query( options.library ),
   1293 				multiple:   options.multiple ? 'reset' : false,
   1294 				editable:   true,
   1295 
   1296 				// If the user isn't allowed to edit fields,
   1297 				// can they still edit it locally?
   1298 				allowLocalEdits: true,
   1299 
   1300 				// Show the attachment display settings.
   1301 				displaySettings: true,
   1302 				// Update user settings when users adjust the
   1303 				// attachment display settings.
   1304 				displayUserSettings: true
   1305 			}),
   1306 
   1307 			new Library({
   1308 				id:         'gallery',
   1309 				title:      l10n.createGalleryTitle,
   1310 				priority:   40,
   1311 				toolbar:    'main-gallery',
   1312 				filterable: 'uploaded',
   1313 				multiple:   'add',
   1314 				editable:   false,
   1315 
   1316 				library:  wp.media.query( _.defaults({
   1317 					type: 'image'
   1318 				}, options.library ) )
   1319 			}),
   1320 
   1321 			// Embed states.
   1322 			new wp.media.controller.Embed( { metadata: options.metadata } ),
   1323 
   1324 			new wp.media.controller.EditImage( { model: options.editImage } ),
   1325 
   1326 			// Gallery states.
   1327 			new wp.media.controller.GalleryEdit({
   1328 				library: options.selection,
   1329 				editing: options.editing,
   1330 				menu:    'gallery'
   1331 			}),
   1332 
   1333 			new wp.media.controller.GalleryAdd(),
   1334 
   1335 			new Library({
   1336 				id:         'playlist',
   1337 				title:      l10n.createPlaylistTitle,
   1338 				priority:   60,
   1339 				toolbar:    'main-playlist',
   1340 				filterable: 'uploaded',
   1341 				multiple:   'add',
   1342 				editable:   false,
   1343 
   1344 				library:  wp.media.query( _.defaults({
   1345 					type: 'audio'
   1346 				}, options.library ) )
   1347 			}),
   1348 
   1349 			// Playlist states.
   1350 			new wp.media.controller.CollectionEdit({
   1351 				type: 'audio',
   1352 				collectionType: 'playlist',
   1353 				title:          l10n.editPlaylistTitle,
   1354 				SettingsView:   wp.media.view.Settings.Playlist,
   1355 				library:        options.selection,
   1356 				editing:        options.editing,
   1357 				menu:           'playlist',
   1358 				dragInfoText:   l10n.playlistDragInfo,
   1359 				dragInfo:       false
   1360 			}),
   1361 
   1362 			new wp.media.controller.CollectionAdd({
   1363 				type: 'audio',
   1364 				collectionType: 'playlist',
   1365 				title: l10n.addToPlaylistTitle
   1366 			}),
   1367 
   1368 			new Library({
   1369 				id:         'video-playlist',
   1370 				title:      l10n.createVideoPlaylistTitle,
   1371 				priority:   60,
   1372 				toolbar:    'main-video-playlist',
   1373 				filterable: 'uploaded',
   1374 				multiple:   'add',
   1375 				editable:   false,
   1376 
   1377 				library:  wp.media.query( _.defaults({
   1378 					type: 'video'
   1379 				}, options.library ) )
   1380 			}),
   1381 
   1382 			new wp.media.controller.CollectionEdit({
   1383 				type: 'video',
   1384 				collectionType: 'playlist',
   1385 				title:          l10n.editVideoPlaylistTitle,
   1386 				SettingsView:   wp.media.view.Settings.Playlist,
   1387 				library:        options.selection,
   1388 				editing:        options.editing,
   1389 				menu:           'video-playlist',
   1390 				dragInfoText:   l10n.videoPlaylistDragInfo,
   1391 				dragInfo:       false
   1392 			}),
   1393 
   1394 			new wp.media.controller.CollectionAdd({
   1395 				type: 'video',
   1396 				collectionType: 'playlist',
   1397 				title: l10n.addToVideoPlaylistTitle
   1398 			})
   1399 		]);
   1400 
   1401 		if ( wp.media.view.settings.post.featuredImageId ) {
   1402 			this.states.add( new wp.media.controller.FeaturedImage() );
   1403 		}
   1404 	},
   1405 
   1406 	bindHandlers: function() {
   1407 		var handlers, checkCounts;
   1408 
   1409 		Select.prototype.bindHandlers.apply( this, arguments );
   1410 
   1411 		this.on( 'activate', this.activate, this );
   1412 
   1413 		// Only bother checking media type counts if one of the counts is zero.
   1414 		checkCounts = _.find( this.counts, function( type ) {
   1415 			return type.count === 0;
   1416 		} );
   1417 
   1418 		if ( typeof checkCounts !== 'undefined' ) {
   1419 			this.listenTo( wp.media.model.Attachments.all, 'change:type', this.mediaTypeCounts );
   1420 		}
   1421 
   1422 		this.on( 'menu:create:gallery', this.createMenu, this );
   1423 		this.on( 'menu:create:playlist', this.createMenu, this );
   1424 		this.on( 'menu:create:video-playlist', this.createMenu, this );
   1425 		this.on( 'toolbar:create:main-insert', this.createToolbar, this );
   1426 		this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
   1427 		this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
   1428 		this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
   1429 		this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
   1430 		this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
   1431 
   1432 		handlers = {
   1433 			menu: {
   1434 				'default': 'mainMenu',
   1435 				'gallery': 'galleryMenu',
   1436 				'playlist': 'playlistMenu',
   1437 				'video-playlist': 'videoPlaylistMenu'
   1438 			},
   1439 
   1440 			content: {
   1441 				'embed':          'embedContent',
   1442 				'edit-image':     'editImageContent',
   1443 				'edit-selection': 'editSelectionContent'
   1444 			},
   1445 
   1446 			toolbar: {
   1447 				'main-insert':      'mainInsertToolbar',
   1448 				'main-gallery':     'mainGalleryToolbar',
   1449 				'gallery-edit':     'galleryEditToolbar',
   1450 				'gallery-add':      'galleryAddToolbar',
   1451 				'main-playlist':	'mainPlaylistToolbar',
   1452 				'playlist-edit':	'playlistEditToolbar',
   1453 				'playlist-add':		'playlistAddToolbar',
   1454 				'main-video-playlist': 'mainVideoPlaylistToolbar',
   1455 				'video-playlist-edit': 'videoPlaylistEditToolbar',
   1456 				'video-playlist-add': 'videoPlaylistAddToolbar'
   1457 			}
   1458 		};
   1459 
   1460 		_.each( handlers, function( regionHandlers, region ) {
   1461 			_.each( regionHandlers, function( callback, handler ) {
   1462 				this.on( region + ':render:' + handler, this[ callback ], this );
   1463 			}, this );
   1464 		}, this );
   1465 	},
   1466 
   1467 	activate: function() {
   1468 		// Hide menu items for states tied to particular media types if there are no items.
   1469 		_.each( this.counts, function( type ) {
   1470 			if ( type.count < 1 ) {
   1471 				this.menuItemVisibility( type.state, 'hide' );
   1472 			}
   1473 		}, this );
   1474 	},
   1475 
   1476 	mediaTypeCounts: function( model, attr ) {
   1477 		if ( typeof this.counts[ attr ] !== 'undefined' && this.counts[ attr ].count < 1 ) {
   1478 			this.counts[ attr ].count++;
   1479 			this.menuItemVisibility( this.counts[ attr ].state, 'show' );
   1480 		}
   1481 	},
   1482 
   1483 	// Menus.
   1484 	/**
   1485 	 * @param {wp.Backbone.View} view
   1486 	 */
   1487 	mainMenu: function( view ) {
   1488 		view.set({
   1489 			'library-separator': new wp.media.View({
   1490 				className:  'separator',
   1491 				priority:   100,
   1492 				attributes: {
   1493 					role: 'presentation'
   1494 				}
   1495 			})
   1496 		});
   1497 	},
   1498 
   1499 	menuItemVisibility: function( state, visibility ) {
   1500 		var menu = this.menu.get();
   1501 		if ( visibility === 'hide' ) {
   1502 			menu.hide( state );
   1503 		} else if ( visibility === 'show' ) {
   1504 			menu.show( state );
   1505 		}
   1506 	},
   1507 	/**
   1508 	 * @param {wp.Backbone.View} view
   1509 	 */
   1510 	galleryMenu: function( view ) {
   1511 		var lastState = this.lastState(),
   1512 			previous = lastState && lastState.id,
   1513 			frame = this;
   1514 
   1515 		view.set({
   1516 			cancel: {
   1517 				text:     l10n.cancelGalleryTitle,
   1518 				priority: 20,
   1519 				click:    function() {
   1520 					if ( previous ) {
   1521 						frame.setState( previous );
   1522 					} else {
   1523 						frame.close();
   1524 					}
   1525 
   1526 					// Move focus to the modal after canceling a Gallery.
   1527 					this.controller.modal.focusManager.focus();
   1528 				}
   1529 			},
   1530 			separateCancel: new wp.media.View({
   1531 				className: 'separator',
   1532 				priority: 40
   1533 			})
   1534 		});
   1535 	},
   1536 
   1537 	playlistMenu: function( view ) {
   1538 		var lastState = this.lastState(),
   1539 			previous = lastState && lastState.id,
   1540 			frame = this;
   1541 
   1542 		view.set({
   1543 			cancel: {
   1544 				text:     l10n.cancelPlaylistTitle,
   1545 				priority: 20,
   1546 				click:    function() {
   1547 					if ( previous ) {
   1548 						frame.setState( previous );
   1549 					} else {
   1550 						frame.close();
   1551 					}
   1552 
   1553 					// Move focus to the modal after canceling an Audio Playlist.
   1554 					this.controller.modal.focusManager.focus();
   1555 				}
   1556 			},
   1557 			separateCancel: new wp.media.View({
   1558 				className: 'separator',
   1559 				priority: 40
   1560 			})
   1561 		});
   1562 	},
   1563 
   1564 	videoPlaylistMenu: function( view ) {
   1565 		var lastState = this.lastState(),
   1566 			previous = lastState && lastState.id,
   1567 			frame = this;
   1568 
   1569 		view.set({
   1570 			cancel: {
   1571 				text:     l10n.cancelVideoPlaylistTitle,
   1572 				priority: 20,
   1573 				click:    function() {
   1574 					if ( previous ) {
   1575 						frame.setState( previous );
   1576 					} else {
   1577 						frame.close();
   1578 					}
   1579 
   1580 					// Move focus to the modal after canceling a Video Playlist.
   1581 					this.controller.modal.focusManager.focus();
   1582 				}
   1583 			},
   1584 			separateCancel: new wp.media.View({
   1585 				className: 'separator',
   1586 				priority: 40
   1587 			})
   1588 		});
   1589 	},
   1590 
   1591 	// Content.
   1592 	embedContent: function() {
   1593 		var view = new wp.media.view.Embed({
   1594 			controller: this,
   1595 			model:      this.state()
   1596 		}).render();
   1597 
   1598 		this.content.set( view );
   1599 	},
   1600 
   1601 	editSelectionContent: function() {
   1602 		var state = this.state(),
   1603 			selection = state.get('selection'),
   1604 			view;
   1605 
   1606 		view = new wp.media.view.AttachmentsBrowser({
   1607 			controller: this,
   1608 			collection: selection,
   1609 			selection:  selection,
   1610 			model:      state,
   1611 			sortable:   true,
   1612 			search:     false,
   1613 			date:       false,
   1614 			dragInfo:   true,
   1615 
   1616 			AttachmentView: wp.media.view.Attachments.EditSelection
   1617 		}).render();
   1618 
   1619 		view.toolbar.set( 'backToLibrary', {
   1620 			text:     l10n.returnToLibrary,
   1621 			priority: -100,
   1622 
   1623 			click: function() {
   1624 				this.controller.content.mode('browse');
   1625 				// Move focus to the modal when jumping back from Edit Selection to Add Media view.
   1626 				this.controller.modal.focusManager.focus();
   1627 			}
   1628 		});
   1629 
   1630 		// Browse our library of attachments.
   1631 		this.content.set( view );
   1632 
   1633 		// Trigger the controller to set focus.
   1634 		this.trigger( 'edit:selection', this );
   1635 	},
   1636 
   1637 	editImageContent: function() {
   1638 		var image = this.state().get('image'),
   1639 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
   1640 
   1641 		this.content.set( view );
   1642 
   1643 		// After creating the wrapper view, load the actual editor via an Ajax call.
   1644 		view.loadEditor();
   1645 
   1646 	},
   1647 
   1648 	// Toolbars.
   1649 
   1650 	/**
   1651 	 * @param {wp.Backbone.View} view
   1652 	 */
   1653 	selectionStatusToolbar: function( view ) {
   1654 		var editable = this.state().get('editable');
   1655 
   1656 		view.set( 'selection', new wp.media.view.Selection({
   1657 			controller: this,
   1658 			collection: this.state().get('selection'),
   1659 			priority:   -40,
   1660 
   1661 			// If the selection is editable, pass the callback to
   1662 			// switch the content mode.
   1663 			editable: editable && function() {
   1664 				this.controller.content.mode('edit-selection');
   1665 			}
   1666 		}).render() );
   1667 	},
   1668 
   1669 	/**
   1670 	 * @param {wp.Backbone.View} view
   1671 	 */
   1672 	mainInsertToolbar: function( view ) {
   1673 		var controller = this;
   1674 
   1675 		this.selectionStatusToolbar( view );
   1676 
   1677 		view.set( 'insert', {
   1678 			style:    'primary',
   1679 			priority: 80,
   1680 			text:     l10n.insertIntoPost,
   1681 			requires: { selection: true },
   1682 
   1683 			/**
   1684 			 * @ignore
   1685 			 *
   1686 			 * @fires wp.media.controller.State#insert
   1687 			 */
   1688 			click: function() {
   1689 				var state = controller.state(),
   1690 					selection = state.get('selection');
   1691 
   1692 				controller.close();
   1693 				state.trigger( 'insert', selection ).reset();
   1694 			}
   1695 		});
   1696 	},
   1697 
   1698 	/**
   1699 	 * @param {wp.Backbone.View} view
   1700 	 */
   1701 	mainGalleryToolbar: function( view ) {
   1702 		var controller = this;
   1703 
   1704 		this.selectionStatusToolbar( view );
   1705 
   1706 		view.set( 'gallery', {
   1707 			style:    'primary',
   1708 			text:     l10n.createNewGallery,
   1709 			priority: 60,
   1710 			requires: { selection: true },
   1711 
   1712 			click: function() {
   1713 				var selection = controller.state().get('selection'),
   1714 					edit = controller.state('gallery-edit'),
   1715 					models = selection.where({ type: 'image' });
   1716 
   1717 				edit.set( 'library', new wp.media.model.Selection( models, {
   1718 					props:    selection.props.toJSON(),
   1719 					multiple: true
   1720 				}) );
   1721 
   1722 				// Jump to Edit Gallery view.
   1723 				this.controller.setState( 'gallery-edit' );
   1724 
   1725 				// Move focus to the modal after jumping to Edit Gallery view.
   1726 				this.controller.modal.focusManager.focus();
   1727 			}
   1728 		});
   1729 	},
   1730 
   1731 	mainPlaylistToolbar: function( view ) {
   1732 		var controller = this;
   1733 
   1734 		this.selectionStatusToolbar( view );
   1735 
   1736 		view.set( 'playlist', {
   1737 			style:    'primary',
   1738 			text:     l10n.createNewPlaylist,
   1739 			priority: 100,
   1740 			requires: { selection: true },
   1741 
   1742 			click: function() {
   1743 				var selection = controller.state().get('selection'),
   1744 					edit = controller.state('playlist-edit'),
   1745 					models = selection.where({ type: 'audio' });
   1746 
   1747 				edit.set( 'library', new wp.media.model.Selection( models, {
   1748 					props:    selection.props.toJSON(),
   1749 					multiple: true
   1750 				}) );
   1751 
   1752 				// Jump to Edit Audio Playlist view.
   1753 				this.controller.setState( 'playlist-edit' );
   1754 
   1755 				// Move focus to the modal after jumping to Edit Audio Playlist view.
   1756 				this.controller.modal.focusManager.focus();
   1757 			}
   1758 		});
   1759 	},
   1760 
   1761 	mainVideoPlaylistToolbar: function( view ) {
   1762 		var controller = this;
   1763 
   1764 		this.selectionStatusToolbar( view );
   1765 
   1766 		view.set( 'video-playlist', {
   1767 			style:    'primary',
   1768 			text:     l10n.createNewVideoPlaylist,
   1769 			priority: 100,
   1770 			requires: { selection: true },
   1771 
   1772 			click: function() {
   1773 				var selection = controller.state().get('selection'),
   1774 					edit = controller.state('video-playlist-edit'),
   1775 					models = selection.where({ type: 'video' });
   1776 
   1777 				edit.set( 'library', new wp.media.model.Selection( models, {
   1778 					props:    selection.props.toJSON(),
   1779 					multiple: true
   1780 				}) );
   1781 
   1782 				// Jump to Edit Video Playlist view.
   1783 				this.controller.setState( 'video-playlist-edit' );
   1784 
   1785 				// Move focus to the modal after jumping to Edit Video Playlist view.
   1786 				this.controller.modal.focusManager.focus();
   1787 			}
   1788 		});
   1789 	},
   1790 
   1791 	featuredImageToolbar: function( toolbar ) {
   1792 		this.createSelectToolbar( toolbar, {
   1793 			text:  l10n.setFeaturedImage,
   1794 			state: this.options.state
   1795 		});
   1796 	},
   1797 
   1798 	mainEmbedToolbar: function( toolbar ) {
   1799 		toolbar.view = new wp.media.view.Toolbar.Embed({
   1800 			controller: this
   1801 		});
   1802 	},
   1803 
   1804 	galleryEditToolbar: function() {
   1805 		var editing = this.state().get('editing');
   1806 		this.toolbar.set( new wp.media.view.Toolbar({
   1807 			controller: this,
   1808 			items: {
   1809 				insert: {
   1810 					style:    'primary',
   1811 					text:     editing ? l10n.updateGallery : l10n.insertGallery,
   1812 					priority: 80,
   1813 					requires: { library: true },
   1814 
   1815 					/**
   1816 					 * @fires wp.media.controller.State#update
   1817 					 */
   1818 					click: function() {
   1819 						var controller = this.controller,
   1820 							state = controller.state();
   1821 
   1822 						controller.close();
   1823 						state.trigger( 'update', state.get('library') );
   1824 
   1825 						// Restore and reset the default state.
   1826 						controller.setState( controller.options.state );
   1827 						controller.reset();
   1828 					}
   1829 				}
   1830 			}
   1831 		}) );
   1832 	},
   1833 
   1834 	galleryAddToolbar: function() {
   1835 		this.toolbar.set( new wp.media.view.Toolbar({
   1836 			controller: this,
   1837 			items: {
   1838 				insert: {
   1839 					style:    'primary',
   1840 					text:     l10n.addToGallery,
   1841 					priority: 80,
   1842 					requires: { selection: true },
   1843 
   1844 					/**
   1845 					 * @fires wp.media.controller.State#reset
   1846 					 */
   1847 					click: function() {
   1848 						var controller = this.controller,
   1849 							state = controller.state(),
   1850 							edit = controller.state('gallery-edit');
   1851 
   1852 						edit.get('library').add( state.get('selection').models );
   1853 						state.trigger('reset');
   1854 						controller.setState('gallery-edit');
   1855 						// Move focus to the modal when jumping back from Add to Gallery to Edit Gallery view.
   1856 						this.controller.modal.focusManager.focus();
   1857 					}
   1858 				}
   1859 			}
   1860 		}) );
   1861 	},
   1862 
   1863 	playlistEditToolbar: function() {
   1864 		var editing = this.state().get('editing');
   1865 		this.toolbar.set( new wp.media.view.Toolbar({
   1866 			controller: this,
   1867 			items: {
   1868 				insert: {
   1869 					style:    'primary',
   1870 					text:     editing ? l10n.updatePlaylist : l10n.insertPlaylist,
   1871 					priority: 80,
   1872 					requires: { library: true },
   1873 
   1874 					/**
   1875 					 * @fires wp.media.controller.State#update
   1876 					 */
   1877 					click: function() {
   1878 						var controller = this.controller,
   1879 							state = controller.state();
   1880 
   1881 						controller.close();
   1882 						state.trigger( 'update', state.get('library') );
   1883 
   1884 						// Restore and reset the default state.
   1885 						controller.setState( controller.options.state );
   1886 						controller.reset();
   1887 					}
   1888 				}
   1889 			}
   1890 		}) );
   1891 	},
   1892 
   1893 	playlistAddToolbar: function() {
   1894 		this.toolbar.set( new wp.media.view.Toolbar({
   1895 			controller: this,
   1896 			items: {
   1897 				insert: {
   1898 					style:    'primary',
   1899 					text:     l10n.addToPlaylist,
   1900 					priority: 80,
   1901 					requires: { selection: true },
   1902 
   1903 					/**
   1904 					 * @fires wp.media.controller.State#reset
   1905 					 */
   1906 					click: function() {
   1907 						var controller = this.controller,
   1908 							state = controller.state(),
   1909 							edit = controller.state('playlist-edit');
   1910 
   1911 						edit.get('library').add( state.get('selection').models );
   1912 						state.trigger('reset');
   1913 						controller.setState('playlist-edit');
   1914 						// Move focus to the modal when jumping back from Add to Audio Playlist to Edit Audio Playlist view.
   1915 						this.controller.modal.focusManager.focus();
   1916 					}
   1917 				}
   1918 			}
   1919 		}) );
   1920 	},
   1921 
   1922 	videoPlaylistEditToolbar: function() {
   1923 		var editing = this.state().get('editing');
   1924 		this.toolbar.set( new wp.media.view.Toolbar({
   1925 			controller: this,
   1926 			items: {
   1927 				insert: {
   1928 					style:    'primary',
   1929 					text:     editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
   1930 					priority: 140,
   1931 					requires: { library: true },
   1932 
   1933 					click: function() {
   1934 						var controller = this.controller,
   1935 							state = controller.state(),
   1936 							library = state.get('library');
   1937 
   1938 						library.type = 'video';
   1939 
   1940 						controller.close();
   1941 						state.trigger( 'update', library );
   1942 
   1943 						// Restore and reset the default state.
   1944 						controller.setState( controller.options.state );
   1945 						controller.reset();
   1946 					}
   1947 				}
   1948 			}
   1949 		}) );
   1950 	},
   1951 
   1952 	videoPlaylistAddToolbar: function() {
   1953 		this.toolbar.set( new wp.media.view.Toolbar({
   1954 			controller: this,
   1955 			items: {
   1956 				insert: {
   1957 					style:    'primary',
   1958 					text:     l10n.addToVideoPlaylist,
   1959 					priority: 140,
   1960 					requires: { selection: true },
   1961 
   1962 					click: function() {
   1963 						var controller = this.controller,
   1964 							state = controller.state(),
   1965 							edit = controller.state('video-playlist-edit');
   1966 
   1967 						edit.get('library').add( state.get('selection').models );
   1968 						state.trigger('reset');
   1969 						controller.setState('video-playlist-edit');
   1970 						// Move focus to the modal when jumping back from Add to Video Playlist to Edit Video Playlist view.
   1971 						this.controller.modal.focusManager.focus();
   1972 					}
   1973 				}
   1974 			}
   1975 		}) );
   1976 	}
   1977 });
   1978 
   1979 module.exports = Post;
   1980 
   1981 
   1982 /***/ }),
   1983 
   1984 /***/ "72mI":
   1985 /***/ (function(module, exports) {
   1986 
   1987 var View = wp.media.View,
   1988 	mediaTrash = wp.media.view.settings.mediaTrash,
   1989 	l10n = wp.media.view.l10n,
   1990 	$ = jQuery,
   1991 	AttachmentsBrowser,
   1992 	infiniteScrolling = wp.media.view.settings.infiniteScrolling,
   1993 	__ = wp.i18n.__,
   1994 	sprintf = wp.i18n.sprintf;
   1995 
   1996 /**
   1997  * wp.media.view.AttachmentsBrowser
   1998  *
   1999  * @memberOf wp.media.view
   2000  *
   2001  * @class
   2002  * @augments wp.media.View
   2003  * @augments wp.Backbone.View
   2004  * @augments Backbone.View
   2005  *
   2006  * @param {object}         [options]               The options hash passed to the view.
   2007  * @param {boolean|string} [options.filters=false] Which filters to show in the browser's toolbar.
   2008  *                                                 Accepts 'uploaded' and 'all'.
   2009  * @param {boolean}        [options.search=true]   Whether to show the search interface in the
   2010  *                                                 browser's toolbar.
   2011  * @param {boolean}        [options.date=true]     Whether to show the date filter in the
   2012  *                                                 browser's toolbar.
   2013  * @param {boolean}        [options.display=false] Whether to show the attachments display settings
   2014  *                                                 view in the sidebar.
   2015  * @param {boolean|string} [options.sidebar=true]  Whether to create a sidebar for the browser.
   2016  *                                                 Accepts true, false, and 'errors'.
   2017  */
   2018 AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.prototype */{
   2019 	tagName:   'div',
   2020 	className: 'attachments-browser',
   2021 
   2022 	initialize: function() {
   2023 		_.defaults( this.options, {
   2024 			filters: false,
   2025 			search:  true,
   2026 			date:    true,
   2027 			display: false,
   2028 			sidebar: true,
   2029 			AttachmentView: wp.media.view.Attachment.Library
   2030 		});
   2031 
   2032 		this.controller.on( 'toggle:upload:attachment', this.toggleUploader, this );
   2033 		this.controller.on( 'edit:selection', this.editSelection );
   2034 
   2035 		// In the Media Library, the sidebar is used to display errors before the attachments grid.
   2036 		if ( this.options.sidebar && 'errors' === this.options.sidebar ) {
   2037 			this.createSidebar();
   2038 		}
   2039 
   2040 		/*
   2041 		 * In the grid mode (the Media Library), place the Inline Uploader before
   2042 		 * other sections so that the visual order and the DOM order match. This way,
   2043 		 * the Inline Uploader in the Media Library is right after the "Add New"
   2044 		 * button, see ticket #37188.
   2045 		 */
   2046 		if ( this.controller.isModeActive( 'grid' ) ) {
   2047 			this.createUploader();
   2048 
   2049 			/*
   2050 			 * Create a multi-purpose toolbar. Used as main toolbar in the Media Library
   2051 			 * and also for other things, for example the "Drag and drop to reorder" and
   2052 			 * "Suggested dimensions" info in the media modal.
   2053 			 */
   2054 			this.createToolbar();
   2055 		} else {
   2056 			this.createToolbar();
   2057 			this.createUploader();
   2058 		}
   2059 
   2060 		// Add a heading before the attachments list.
   2061 		this.createAttachmentsHeading();
   2062 
   2063 		// Create the attachments wrapper view.
   2064 		this.createAttachmentsWrapperView();
   2065 
   2066 		if ( ! infiniteScrolling ) {
   2067 			this.$el.addClass( 'has-load-more' );
   2068 			this.createLoadMoreView();
   2069 		}
   2070 
   2071 		// For accessibility reasons, place the normal sidebar after the attachments, see ticket #36909.
   2072 		if ( this.options.sidebar && 'errors' !== this.options.sidebar ) {
   2073 			this.createSidebar();
   2074 		}
   2075 
   2076 		this.updateContent();
   2077 
   2078 		if ( ! infiniteScrolling ) {
   2079 			this.updateLoadMoreView();
   2080 		}
   2081 
   2082 		if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
   2083 			this.$el.addClass( 'hide-sidebar' );
   2084 
   2085 			if ( 'errors' === this.options.sidebar ) {
   2086 				this.$el.addClass( 'sidebar-for-errors' );
   2087 			}
   2088 		}
   2089 
   2090 		this.collection.on( 'add remove reset', this.updateContent, this );
   2091 
   2092 		if ( ! infiniteScrolling ) {
   2093 			this.collection.on( 'add remove reset', this.updateLoadMoreView, this );
   2094 		}
   2095 
   2096 		// The non-cached or cached attachments query has completed.
   2097 		this.collection.on( 'attachments:received', this.announceSearchResults, this );
   2098 	},
   2099 
   2100 	/**
   2101 	 * Updates the `wp.a11y.speak()` ARIA live region with a message to communicate
   2102 	 * the number of search results to screen reader users. This function is
   2103 	 * debounced because the collection updates multiple times.
   2104 	 *
   2105 	 * @since 5.3.0
   2106 	 *
   2107 	 * @return {void}
   2108 	 */
   2109 	announceSearchResults: _.debounce( function() {
   2110 		var count,
   2111 			/* translators: Accessibility text. %d: Number of attachments found in a search. */
   2112 			mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Click load more for more results.' );
   2113 
   2114 		if ( infiniteScrolling ) {
   2115 			/* translators: Accessibility text. %d: Number of attachments found in a search. */
   2116 			mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Scroll the page for more results.' );
   2117 		}
   2118 
   2119 		if ( this.collection.mirroring.args.s ) {
   2120 			count = this.collection.length;
   2121 
   2122 			if ( 0 === count ) {
   2123 				wp.a11y.speak( l10n.noMediaTryNewSearch );
   2124 				return;
   2125 			}
   2126 
   2127 			if ( this.collection.hasMore() ) {
   2128 				wp.a11y.speak( mediaFoundHasMoreResultsMessage.replace( '%d', count ) );
   2129 				return;
   2130 			}
   2131 
   2132 			wp.a11y.speak( l10n.mediaFound.replace( '%d', count ) );
   2133 		}
   2134 	}, 200 ),
   2135 
   2136 	editSelection: function( modal ) {
   2137 		// When editing a selection, move focus to the "Go to library" button.
   2138 		modal.$( '.media-button-backToLibrary' ).focus();
   2139 	},
   2140 
   2141 	/**
   2142 	 * @return {wp.media.view.AttachmentsBrowser} Returns itself to allow chaining.
   2143 	 */
   2144 	dispose: function() {
   2145 		this.options.selection.off( null, null, this );
   2146 		View.prototype.dispose.apply( this, arguments );
   2147 		return this;
   2148 	},
   2149 
   2150 	createToolbar: function() {
   2151 		var LibraryViewSwitcher, Filters, toolbarOptions,
   2152 			showFilterByType = -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] );
   2153 
   2154 		toolbarOptions = {
   2155 			controller: this.controller
   2156 		};
   2157 
   2158 		if ( this.controller.isModeActive( 'grid' ) ) {
   2159 			toolbarOptions.className = 'media-toolbar wp-filter';
   2160 		}
   2161 
   2162 		/**
   2163 		* @member {wp.media.view.Toolbar}
   2164 		*/
   2165 		this.toolbar = new wp.media.view.Toolbar( toolbarOptions );
   2166 
   2167 		this.views.add( this.toolbar );
   2168 
   2169 		this.toolbar.set( 'spinner', new wp.media.view.Spinner({
   2170 			priority: -20
   2171 		}) );
   2172 
   2173 		if ( showFilterByType || this.options.date ) {
   2174 			/*
   2175 			 * Create a h2 heading before the select elements that filter attachments.
   2176 			 * This heading is visible in the modal and visually hidden in the grid.
   2177 			 */
   2178 			this.toolbar.set( 'filters-heading', new wp.media.view.Heading( {
   2179 				priority:   -100,
   2180 				text:       l10n.filterAttachments,
   2181 				level:      'h2',
   2182 				className:  'media-attachments-filter-heading'
   2183 			}).render() );
   2184 		}
   2185 
   2186 		if ( showFilterByType ) {
   2187 			// "Filters" is a <select>, a visually hidden label element needs to be rendered before.
   2188 			this.toolbar.set( 'filtersLabel', new wp.media.view.Label({
   2189 				value: l10n.filterByType,
   2190 				attributes: {
   2191 					'for':  'media-attachment-filters'
   2192 				},
   2193 				priority:   -80
   2194 			}).render() );
   2195 
   2196 			if ( 'uploaded' === this.options.filters ) {
   2197 				this.toolbar.set( 'filters', new wp.media.view.AttachmentFilters.Uploaded({
   2198 					controller: this.controller,
   2199 					model:      this.collection.props,
   2200 					priority:   -80
   2201 				}).render() );
   2202 			} else {
   2203 				Filters = new wp.media.view.AttachmentFilters.All({
   2204 					controller: this.controller,
   2205 					model:      this.collection.props,
   2206 					priority:   -80
   2207 				});
   2208 
   2209 				this.toolbar.set( 'filters', Filters.render() );
   2210 			}
   2211 		}
   2212 
   2213 		/*
   2214 		 * Feels odd to bring the global media library switcher into the Attachment browser view.
   2215 		 * Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
   2216 		 * which the controller can tap into and add this view?
   2217 		 */
   2218 		if ( this.controller.isModeActive( 'grid' ) ) {
   2219 			LibraryViewSwitcher = View.extend({
   2220 				className: 'view-switch media-grid-view-switch',
   2221 				template: wp.template( 'media-library-view-switcher')
   2222 			});
   2223 
   2224 			this.toolbar.set( 'libraryViewSwitcher', new LibraryViewSwitcher({
   2225 				controller: this.controller,
   2226 				priority: -90
   2227 			}).render() );
   2228 
   2229 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
   2230 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
   2231 				value: l10n.filterByDate,
   2232 				attributes: {
   2233 					'for': 'media-attachment-date-filters'
   2234 				},
   2235 				priority: -75
   2236 			}).render() );
   2237 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
   2238 				controller: this.controller,
   2239 				model:      this.collection.props,
   2240 				priority: -75
   2241 			}).render() );
   2242 
   2243 			// BulkSelection is a <div> with subviews, including screen reader text.
   2244 			this.toolbar.set( 'selectModeToggleButton', new wp.media.view.SelectModeToggleButton({
   2245 				text: l10n.bulkSelect,
   2246 				controller: this.controller,
   2247 				priority: -70
   2248 			}).render() );
   2249 
   2250 			this.toolbar.set( 'deleteSelectedButton', new wp.media.view.DeleteSelectedButton({
   2251 				filters: Filters,
   2252 				style: 'primary',
   2253 				disabled: true,
   2254 				text: mediaTrash ? l10n.trashSelected : l10n.deletePermanently,
   2255 				controller: this.controller,
   2256 				priority: -80,
   2257 				click: function() {
   2258 					var changed = [], removed = [],
   2259 						selection = this.controller.state().get( 'selection' ),
   2260 						library = this.controller.state().get( 'library' );
   2261 
   2262 					if ( ! selection.length ) {
   2263 						return;
   2264 					}
   2265 
   2266 					if ( ! mediaTrash && ! window.confirm( l10n.warnBulkDelete ) ) {
   2267 						return;
   2268 					}
   2269 
   2270 					if ( mediaTrash &&
   2271 						'trash' !== selection.at( 0 ).get( 'status' ) &&
   2272 						! window.confirm( l10n.warnBulkTrash ) ) {
   2273 
   2274 						return;
   2275 					}
   2276 
   2277 					selection.each( function( model ) {
   2278 						if ( ! model.get( 'nonces' )['delete'] ) {
   2279 							removed.push( model );
   2280 							return;
   2281 						}
   2282 
   2283 						if ( mediaTrash && 'trash' === model.get( 'status' ) ) {
   2284 							model.set( 'status', 'inherit' );
   2285 							changed.push( model.save() );
   2286 							removed.push( model );
   2287 						} else if ( mediaTrash ) {
   2288 							model.set( 'status', 'trash' );
   2289 							changed.push( model.save() );
   2290 							removed.push( model );
   2291 						} else {
   2292 							model.destroy({wait: true});
   2293 						}
   2294 					} );
   2295 
   2296 					if ( changed.length ) {
   2297 						selection.remove( removed );
   2298 
   2299 						$.when.apply( null, changed ).then( _.bind( function() {
   2300 							library._requery( true );
   2301 							this.controller.trigger( 'selection:action:done' );
   2302 						}, this ) );
   2303 					} else {
   2304 						this.controller.trigger( 'selection:action:done' );
   2305 					}
   2306 				}
   2307 			}).render() );
   2308 
   2309 			if ( mediaTrash ) {
   2310 				this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
   2311 					filters: Filters,
   2312 					style: 'link button-link-delete',
   2313 					disabled: true,
   2314 					text: l10n.deletePermanently,
   2315 					controller: this.controller,
   2316 					priority: -55,
   2317 					click: function() {
   2318 						var removed = [],
   2319 							destroy = [],
   2320 							selection = this.controller.state().get( 'selection' );
   2321 
   2322 						if ( ! selection.length || ! window.confirm( l10n.warnBulkDelete ) ) {
   2323 							return;
   2324 						}
   2325 
   2326 						selection.each( function( model ) {
   2327 							if ( ! model.get( 'nonces' )['delete'] ) {
   2328 								removed.push( model );
   2329 								return;
   2330 							}
   2331 
   2332 							destroy.push( model );
   2333 						} );
   2334 
   2335 						if ( removed.length ) {
   2336 							selection.remove( removed );
   2337 						}
   2338 
   2339 						if ( destroy.length ) {
   2340 							$.when.apply( null, destroy.map( function (item) {
   2341 								return item.destroy();
   2342 							} ) ).then( _.bind( function() {
   2343 								this.controller.trigger( 'selection:action:done' );
   2344 							}, this ) );
   2345 						}
   2346 					}
   2347 				}).render() );
   2348 			}
   2349 
   2350 		} else if ( this.options.date ) {
   2351 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
   2352 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
   2353 				value: l10n.filterByDate,
   2354 				attributes: {
   2355 					'for': 'media-attachment-date-filters'
   2356 				},
   2357 				priority: -75
   2358 			}).render() );
   2359 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
   2360 				controller: this.controller,
   2361 				model:      this.collection.props,
   2362 				priority: -75
   2363 			}).render() );
   2364 		}
   2365 
   2366 		if ( this.options.search ) {
   2367 			// Search is an input, a visually hidden label element needs to be rendered before.
   2368 			this.toolbar.set( 'searchLabel', new wp.media.view.Label({
   2369 				value: l10n.searchLabel,
   2370 				className: 'media-search-input-label',
   2371 				attributes: {
   2372 					'for': 'media-search-input'
   2373 				},
   2374 				priority:   60
   2375 			}).render() );
   2376 			this.toolbar.set( 'search', new wp.media.view.Search({
   2377 				controller: this.controller,
   2378 				model:      this.collection.props,
   2379 				priority:   60
   2380 			}).render() );
   2381 		}
   2382 
   2383 		if ( this.options.dragInfo ) {
   2384 			this.toolbar.set( 'dragInfo', new View({
   2385 				el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
   2386 				priority: -40
   2387 			}) );
   2388 		}
   2389 
   2390 		if ( this.options.suggestedWidth && this.options.suggestedHeight ) {
   2391 			this.toolbar.set( 'suggestedDimensions', new View({
   2392 				el: $( '<div class="instructions">' + l10n.suggestedDimensions.replace( '%1$s', this.options.suggestedWidth ).replace( '%2$s', this.options.suggestedHeight ) + '</div>' )[0],
   2393 				priority: -40
   2394 			}) );
   2395 		}
   2396 	},
   2397 
   2398 	updateContent: function() {
   2399 		var view = this,
   2400 			noItemsView;
   2401 
   2402 		if ( this.controller.isModeActive( 'grid' ) ) {
   2403 			// Usually the media library.
   2404 			noItemsView = view.attachmentsNoResults;
   2405 		} else {
   2406 			// Usually the media modal.
   2407 			noItemsView = view.uploader;
   2408 		}
   2409 
   2410 		if ( ! this.collection.length ) {
   2411 			this.toolbar.get( 'spinner' ).show();
   2412 			this.dfd = this.collection.more().done( function() {
   2413 				if ( ! view.collection.length ) {
   2414 					noItemsView.$el.removeClass( 'hidden' );
   2415 				} else {
   2416 					noItemsView.$el.addClass( 'hidden' );
   2417 				}
   2418 				view.toolbar.get( 'spinner' ).hide();
   2419 			} );
   2420 		} else {
   2421 			noItemsView.$el.addClass( 'hidden' );
   2422 			view.toolbar.get( 'spinner' ).hide();
   2423 		}
   2424 	},
   2425 
   2426 	createUploader: function() {
   2427 		this.uploader = new wp.media.view.UploaderInline({
   2428 			controller: this.controller,
   2429 			status:     false,
   2430 			message:    this.controller.isModeActive( 'grid' ) ? '' : l10n.noItemsFound,
   2431 			canClose:   this.controller.isModeActive( 'grid' )
   2432 		});
   2433 
   2434 		this.uploader.$el.addClass( 'hidden' );
   2435 		this.views.add( this.uploader );
   2436 	},
   2437 
   2438 	toggleUploader: function() {
   2439 		if ( this.uploader.$el.hasClass( 'hidden' ) ) {
   2440 			this.uploader.show();
   2441 		} else {
   2442 			this.uploader.hide();
   2443 		}
   2444 	},
   2445 
   2446 	/**
   2447 	 * Creates the Attachments wrapper view.
   2448 	 *
   2449 	 * @since 5.8.0
   2450 	 *
   2451 	 * @return {void}
   2452 	 */
   2453 	createAttachmentsWrapperView: function() {
   2454 		this.attachmentsWrapper = new wp.media.View( {
   2455 			className: 'attachments-wrapper'
   2456 		} );
   2457 
   2458 		// Create the list of attachments.
   2459 		this.views.add( this.attachmentsWrapper );
   2460 		this.createAttachments();
   2461 	},
   2462 
   2463 	createAttachments: function() {
   2464 		this.attachments = new wp.media.view.Attachments({
   2465 			controller:           this.controller,
   2466 			collection:           this.collection,
   2467 			selection:            this.options.selection,
   2468 			model:                this.model,
   2469 			sortable:             this.options.sortable,
   2470 			scrollElement:        this.options.scrollElement,
   2471 			idealColumnWidth:     this.options.idealColumnWidth,
   2472 
   2473 			// The single `Attachment` view to be used in the `Attachments` view.
   2474 			AttachmentView: this.options.AttachmentView
   2475 		});
   2476 
   2477 		// Add keydown listener to the instance of the Attachments view.
   2478 		this.controller.on( 'attachment:keydown:arrow',     _.bind( this.attachments.arrowEvent, this.attachments ) );
   2479 		this.controller.on( 'attachment:details:shift-tab', _.bind( this.attachments.restoreFocus, this.attachments ) );
   2480 
   2481 		this.views.add( '.attachments-wrapper', this.attachments );
   2482 
   2483 		if ( this.controller.isModeActive( 'grid' ) ) {
   2484 			this.attachmentsNoResults = new View({
   2485 				controller: this.controller,
   2486 				tagName: 'p'
   2487 			});
   2488 
   2489 			this.attachmentsNoResults.$el.addClass( 'hidden no-media' );
   2490 			this.attachmentsNoResults.$el.html( l10n.noMedia );
   2491 
   2492 			this.views.add( this.attachmentsNoResults );
   2493 		}
   2494 	},
   2495 
   2496 	/**
   2497 	 * Creates the load more button and attachments counter view.
   2498 	 *
   2499 	 * @since 5.8.0
   2500 	 *
   2501 	 * @return {void}
   2502 	 */
   2503 	createLoadMoreView: function() {
   2504 		var view = this;
   2505 
   2506 		this.loadMoreWrapper = new View( {
   2507 			controller: this.controller,
   2508 			className: 'load-more-wrapper'
   2509 		} );
   2510 
   2511 		this.loadMoreCount = new View( {
   2512 			controller: this.controller,
   2513 			tagName: 'p',
   2514 			className: 'load-more-count hidden'
   2515 		} );
   2516 
   2517 		this.loadMoreButton = new wp.media.view.Button( {
   2518 			text: __( 'Load more' ),
   2519 			className: 'load-more hidden',
   2520 			style: 'primary',
   2521 			size: '',
   2522 			click: function() {
   2523 				view.loadMoreAttachments();
   2524 			}
   2525 		} );
   2526 
   2527 		this.loadMoreSpinner = new wp.media.view.Spinner();
   2528 
   2529 		this.loadMoreJumpToFirst = new wp.media.view.Button( {
   2530 			text: __( 'Jump to first loaded item' ),
   2531 			className: 'load-more-jump hidden',
   2532 			size: '',
   2533 			click: function() {
   2534 				view.jumpToFirstAddedItem();
   2535 			}
   2536 		} );
   2537 
   2538 		this.views.add( '.attachments-wrapper', this.loadMoreWrapper );
   2539 		this.views.add( '.load-more-wrapper', this.loadMoreSpinner );
   2540 		this.views.add( '.load-more-wrapper', this.loadMoreCount );
   2541 		this.views.add( '.load-more-wrapper', this.loadMoreButton );
   2542 		this.views.add( '.load-more-wrapper', this.loadMoreJumpToFirst );
   2543 	},
   2544 
   2545 	/**
   2546 	 * Updates the Load More view. This function is debounced because the
   2547 	 * collection updates multiple times at the add, remove, and reset events.
   2548 	 * We need it to run only once, after all attachments are added or removed.
   2549 	 *
   2550 	 * @since 5.8.0
   2551 	 *
   2552 	 * @return {void}
   2553 	 */
   2554 	updateLoadMoreView: _.debounce( function() {
   2555 		// Ensure the load more view elements are initially hidden at each update.
   2556 		this.loadMoreButton.$el.addClass( 'hidden' );
   2557 		this.loadMoreCount.$el.addClass( 'hidden' );
   2558 		this.loadMoreJumpToFirst.$el.addClass( 'hidden' ).prop( 'disabled', true );
   2559 
   2560 		if ( ! this.collection.getTotalAttachments() ) {
   2561 			return;
   2562 		}
   2563 
   2564 		if ( this.collection.length ) {
   2565 			this.loadMoreCount.$el.text(
   2566 				/* translators: 1: Number of displayed attachments, 2: Number of total attachments. */
   2567 				sprintf(
   2568 					__( 'Showing %1$s of %2$s media items' ),
   2569 					this.collection.length,
   2570 					this.collection.getTotalAttachments()
   2571 				)
   2572 			);
   2573 
   2574 			this.loadMoreCount.$el.removeClass( 'hidden' );
   2575 		}
   2576 
   2577 		/*
   2578 		 * Notice that while the collection updates multiple times hasMore() may
   2579 		 * return true when it's actually not true.
   2580 		 */
   2581 		if ( this.collection.hasMore() ) {
   2582 			this.loadMoreButton.$el.removeClass( 'hidden' );
   2583 		}
   2584 
   2585 		// Find the media item to move focus to. The jQuery `eq()` index is zero-based.
   2586 		this.firstAddedMediaItem = this.$el.find( '.attachment' ).eq( this.firstAddedMediaItemIndex );
   2587 
   2588 		// If there's a media item to move focus to, make the "Jump to" button available.
   2589 		if ( this.firstAddedMediaItem.length ) {
   2590 			this.firstAddedMediaItem.addClass( 'new-media' );
   2591 			this.loadMoreJumpToFirst.$el.removeClass( 'hidden' ).prop( 'disabled', false );
   2592 		}
   2593 
   2594 		// If there are new items added, but no more to be added, move focus to Jump button.
   2595 		if ( this.firstAddedMediaItem.length && ! this.collection.hasMore() ) {
   2596 			this.loadMoreJumpToFirst.$el.trigger( 'focus' );
   2597 		}
   2598 	}, 10 ),
   2599 
   2600 	/**
   2601 	 * Loads more attachments.
   2602 	 *
   2603 	 * @since 5.8.0
   2604 	 *
   2605 	 * @return {void}
   2606 	 */
   2607 	loadMoreAttachments: function() {
   2608 		var view = this;
   2609 
   2610 		if ( ! this.collection.hasMore() ) {
   2611 			return;
   2612 		}
   2613 
   2614 		/*
   2615 		 * The collection index is zero-based while the length counts the actual
   2616 		 * amount of items. Thus the length is equivalent to the position of the
   2617 		 * first added item.
   2618 		 */
   2619 		this.firstAddedMediaItemIndex = this.collection.length;
   2620 
   2621 		this.$el.addClass( 'more-loaded' );
   2622 		this.collection.each( function( attachment ) {
   2623 			var attach_id = attachment.attributes.id;
   2624 			$( '[data-id="' + attach_id + '"]' ).addClass( 'found-media' );
   2625 		});
   2626 
   2627 		view.loadMoreSpinner.show();
   2628 		this.collection.once( 'attachments:received', function() {
   2629 			view.loadMoreSpinner.hide();
   2630 		} );
   2631 		this.collection.more();
   2632 	},
   2633 
   2634 	/**
   2635 	 * Moves focus to the first new added item.	.
   2636 	 *
   2637 	 * @since 5.8.0
   2638 	 *
   2639 	 * @return {void}
   2640 	 */
   2641 	jumpToFirstAddedItem: function() {
   2642 		// Set focus on first added item.
   2643 		this.firstAddedMediaItem.focus();
   2644 	},
   2645 
   2646 	createAttachmentsHeading: function() {
   2647 		this.attachmentsHeading = new wp.media.view.Heading( {
   2648 			text: l10n.attachmentsList,
   2649 			level: 'h2',
   2650 			className: 'media-views-heading screen-reader-text'
   2651 		} );
   2652 		this.views.add( this.attachmentsHeading );
   2653 	},
   2654 
   2655 	createSidebar: function() {
   2656 		var options = this.options,
   2657 			selection = options.selection,
   2658 			sidebar = this.sidebar = new wp.media.view.Sidebar({
   2659 				controller: this.controller
   2660 			});
   2661 
   2662 		this.views.add( sidebar );
   2663 
   2664 		if ( this.controller.uploader ) {
   2665 			sidebar.set( 'uploads', new wp.media.view.UploaderStatus({
   2666 				controller: this.controller,
   2667 				priority:   40
   2668 			}) );
   2669 		}
   2670 
   2671 		selection.on( 'selection:single', this.createSingle, this );
   2672 		selection.on( 'selection:unsingle', this.disposeSingle, this );
   2673 
   2674 		if ( selection.single() ) {
   2675 			this.createSingle();
   2676 		}
   2677 	},
   2678 
   2679 	createSingle: function() {
   2680 		var sidebar = this.sidebar,
   2681 			single = this.options.selection.single();
   2682 
   2683 		sidebar.set( 'details', new wp.media.view.Attachment.Details({
   2684 			controller: this.controller,
   2685 			model:      single,
   2686 			priority:   80
   2687 		}) );
   2688 
   2689 		sidebar.set( 'compat', new wp.media.view.AttachmentCompat({
   2690 			controller: this.controller,
   2691 			model:      single,
   2692 			priority:   120
   2693 		}) );
   2694 
   2695 		if ( this.options.display ) {
   2696 			sidebar.set( 'display', new wp.media.view.Settings.AttachmentDisplay({
   2697 				controller:   this.controller,
   2698 				model:        this.model.display( single ),
   2699 				attachment:   single,
   2700 				priority:     160,
   2701 				userSettings: this.model.get('displayUserSettings')
   2702 			}) );
   2703 		}
   2704 
   2705 		// Show the sidebar on mobile.
   2706 		if ( this.model.id === 'insert' ) {
   2707 			sidebar.$el.addClass( 'visible' );
   2708 		}
   2709 	},
   2710 
   2711 	disposeSingle: function() {
   2712 		var sidebar = this.sidebar;
   2713 		sidebar.unset('details');
   2714 		sidebar.unset('compat');
   2715 		sidebar.unset('display');
   2716 		// Hide the sidebar on mobile.
   2717 		sidebar.$el.removeClass( 'visible' );
   2718 	}
   2719 });
   2720 
   2721 module.exports = AttachmentsBrowser;
   2722 
   2723 
   2724 /***/ }),
   2725 
   2726 /***/ "76BF":
   2727 /***/ (function(module, exports) {
   2728 
   2729 /**
   2730  * wp.media.view.Settings.Playlist
   2731  *
   2732  * @memberOf wp.media.view.Settings
   2733  *
   2734  * @class
   2735  * @augments wp.media.view.Settings
   2736  * @augments wp.media.View
   2737  * @augments wp.Backbone.View
   2738  * @augments Backbone.View
   2739  */
   2740 var Playlist = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Playlist.prototype */{
   2741 	className: 'collection-settings playlist-settings',
   2742 	template:  wp.template('playlist-settings')
   2743 });
   2744 
   2745 module.exports = Playlist;
   2746 
   2747 
   2748 /***/ }),
   2749 
   2750 /***/ "7Bpz":
   2751 /***/ (function(module, exports) {
   2752 
   2753 var View = wp.media.View,
   2754 	UploaderInline;
   2755 
   2756 /**
   2757  * wp.media.view.UploaderInline
   2758  *
   2759  * The inline uploader that shows up in the 'Upload Files' tab.
   2760  *
   2761  * @memberOf wp.media.view
   2762  *
   2763  * @class
   2764  * @augments wp.media.View
   2765  * @augments wp.Backbone.View
   2766  * @augments Backbone.View
   2767  */
   2768 UploaderInline = View.extend(/** @lends wp.media.view.UploaderInline.prototype */{
   2769 	tagName:   'div',
   2770 	className: 'uploader-inline',
   2771 	template:  wp.template('uploader-inline'),
   2772 
   2773 	events: {
   2774 		'click .close': 'hide'
   2775 	},
   2776 
   2777 	initialize: function() {
   2778 		_.defaults( this.options, {
   2779 			message: '',
   2780 			status:  true,
   2781 			canClose: false
   2782 		});
   2783 
   2784 		if ( ! this.options.$browser && this.controller.uploader ) {
   2785 			this.options.$browser = this.controller.uploader.$browser;
   2786 		}
   2787 
   2788 		if ( _.isUndefined( this.options.postId ) ) {
   2789 			this.options.postId = wp.media.view.settings.post.id;
   2790 		}
   2791 
   2792 		if ( this.options.status ) {
   2793 			this.views.set( '.upload-inline-status', new wp.media.view.UploaderStatus({
   2794 				controller: this.controller
   2795 			}) );
   2796 		}
   2797 	},
   2798 
   2799 	prepare: function() {
   2800 		var suggestedWidth = this.controller.state().get('suggestedWidth'),
   2801 			suggestedHeight = this.controller.state().get('suggestedHeight'),
   2802 			data = {};
   2803 
   2804 		data.message = this.options.message;
   2805 		data.canClose = this.options.canClose;
   2806 
   2807 		if ( suggestedWidth && suggestedHeight ) {
   2808 			data.suggestedWidth = suggestedWidth;
   2809 			data.suggestedHeight = suggestedHeight;
   2810 		}
   2811 
   2812 		return data;
   2813 	},
   2814 	/**
   2815 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
   2816 	 */
   2817 	dispose: function() {
   2818 		if ( this.disposing ) {
   2819 			/**
   2820 			 * call 'dispose' directly on the parent class
   2821 			 */
   2822 			return View.prototype.dispose.apply( this, arguments );
   2823 		}
   2824 
   2825 		/*
   2826 		 * Run remove on `dispose`, so we can be sure to refresh the
   2827 		 * uploader with a view-less DOM. Track whether we're disposing
   2828 		 * so we don't trigger an infinite loop.
   2829 		 */
   2830 		this.disposing = true;
   2831 		return this.remove();
   2832 	},
   2833 	/**
   2834 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
   2835 	 */
   2836 	remove: function() {
   2837 		/**
   2838 		 * call 'remove' directly on the parent class
   2839 		 */
   2840 		var result = View.prototype.remove.apply( this, arguments );
   2841 
   2842 		_.defer( _.bind( this.refresh, this ) );
   2843 		return result;
   2844 	},
   2845 
   2846 	refresh: function() {
   2847 		var uploader = this.controller.uploader;
   2848 
   2849 		if ( uploader ) {
   2850 			uploader.refresh();
   2851 		}
   2852 	},
   2853 	/**
   2854 	 * @return {wp.media.view.UploaderInline}
   2855 	 */
   2856 	ready: function() {
   2857 		var $browser = this.options.$browser,
   2858 			$placeholder;
   2859 
   2860 		if ( this.controller.uploader ) {
   2861 			$placeholder = this.$('.browser');
   2862 
   2863 			// Check if we've already replaced the placeholder.
   2864 			if ( $placeholder[0] === $browser[0] ) {
   2865 				return;
   2866 			}
   2867 
   2868 			$browser.detach().text( $placeholder.text() );
   2869 			$browser[0].className = $placeholder[0].className;
   2870 			$browser[0].setAttribute( 'aria-labelledby', $browser[0].id + ' ' + $placeholder[0].getAttribute('aria-labelledby') );
   2871 			$placeholder.replaceWith( $browser.show() );
   2872 		}
   2873 
   2874 		this.refresh();
   2875 		return this;
   2876 	},
   2877 	show: function() {
   2878 		this.$el.removeClass( 'hidden' );
   2879 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
   2880 			this.controller.$uploaderToggler.attr( 'aria-expanded', 'true' );
   2881 		}
   2882 	},
   2883 	hide: function() {
   2884 		this.$el.addClass( 'hidden' );
   2885 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
   2886 			this.controller.$uploaderToggler
   2887 				.attr( 'aria-expanded', 'false' )
   2888 				// Move focus back to the toggle button when closing the uploader.
   2889 				.trigger( 'focus' );
   2890 		}
   2891 	}
   2892 
   2893 });
   2894 
   2895 module.exports = UploaderInline;
   2896 
   2897 
   2898 /***/ }),
   2899 
   2900 /***/ "99yY":
   2901 /***/ (function(module, exports) {
   2902 
   2903 var Library = wp.media.controller.Library,
   2904 	l10n = wp.media.view.l10n,
   2905 	GalleryEdit;
   2906 
   2907 /**
   2908  * wp.media.controller.GalleryEdit
   2909  *
   2910  * A state for editing a gallery's images and settings.
   2911  *
   2912  * @since 3.5.0
   2913  *
   2914  * @class
   2915  * @augments wp.media.controller.Library
   2916  * @augments wp.media.controller.State
   2917  * @augments Backbone.Model
   2918  *
   2919  * @memberOf wp.media.controller
   2920  *
   2921  * @param {Object}                     [attributes]                       The attributes hash passed to the state.
   2922  * @param {string}                     [attributes.id=gallery-edit]       Unique identifier.
   2923  * @param {string}                     [attributes.title=Edit Gallery]    Title for the state. Displays in the frame's title region.
   2924  * @param {wp.media.model.Attachments} [attributes.library]               The collection of attachments in the gallery.
   2925  *                                                                        If one is not supplied, an empty media.model.Selection collection is created.
   2926  * @param {boolean}                    [attributes.multiple=false]        Whether multi-select is enabled.
   2927  * @param {boolean}                    [attributes.searchable=false]      Whether the library is searchable.
   2928  * @param {boolean}                    [attributes.sortable=true]         Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
   2929  * @param {boolean}                    [attributes.date=true]             Whether to show the date filter in the browser's toolbar.
   2930  * @param {string|false}               [attributes.content=browse]        Initial mode for the content region.
   2931  * @param {string|false}               [attributes.toolbar=image-details] Initial mode for the toolbar region.
   2932  * @param {boolean}                    [attributes.describe=true]         Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
   2933  * @param {boolean}                    [attributes.displaySettings=true]  Whether to show the attachment display settings interface.
   2934  * @param {boolean}                    [attributes.dragInfo=true]         Whether to show instructional text about the attachments being sortable.
   2935  * @param {number}                     [attributes.idealColumnWidth=170]  The ideal column width in pixels for attachments.
   2936  * @param {boolean}                    [attributes.editing=false]         Whether the gallery is being created, or editing an existing instance.
   2937  * @param {number}                     [attributes.priority=60]           The priority for the state link in the media menu.
   2938  * @param {boolean}                    [attributes.syncSelection=false]   Whether the Attachments selection should be persisted from the last state.
   2939  *                                                                        Defaults to false for this state, because the library passed in  *is* the selection.
   2940  * @param {view}                       [attributes.AttachmentView]        The single `Attachment` view to be used in the `Attachments`.
   2941  *                                                                        If none supplied, defaults to wp.media.view.Attachment.EditLibrary.
   2942  */
   2943 GalleryEdit = Library.extend(/** @lends wp.media.controller.GalleryEdit.prototype */{
   2944 	defaults: {
   2945 		id:               'gallery-edit',
   2946 		title:            l10n.editGalleryTitle,
   2947 		multiple:         false,
   2948 		searchable:       false,
   2949 		sortable:         true,
   2950 		date:             false,
   2951 		display:          false,
   2952 		content:          'browse',
   2953 		toolbar:          'gallery-edit',
   2954 		describe:         true,
   2955 		displaySettings:  true,
   2956 		dragInfo:         true,
   2957 		idealColumnWidth: 170,
   2958 		editing:          false,
   2959 		priority:         60,
   2960 		syncSelection:    false
   2961 	},
   2962 
   2963 	/**
   2964 	 * Initializes the library.
   2965 	 *
   2966 	 * Creates a selection if a library isn't supplied and creates an attachment
   2967 	 * view if no attachment view is supplied.
   2968 	 *
   2969 	 * @since 3.5.0
   2970 	 *
   2971 	 * @return {void}
   2972 	 */
   2973 	initialize: function() {
   2974 		// If we haven't been provided a `library`, create a `Selection`.
   2975 		if ( ! this.get('library') ) {
   2976 			this.set( 'library', new wp.media.model.Selection() );
   2977 		}
   2978 
   2979 		// The single `Attachment` view to be used in the `Attachments` view.
   2980 		if ( ! this.get('AttachmentView') ) {
   2981 			this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );
   2982 		}
   2983 
   2984 		Library.prototype.initialize.apply( this, arguments );
   2985 	},
   2986 
   2987 	/**
   2988 	 * Activates the library.
   2989 	 *
   2990 	 * Limits the library to images, watches for uploaded attachments. Watches for
   2991 	 * the browse event on the frame and binds it to gallerySettings.
   2992 	 *
   2993 	 * @since 3.5.0
   2994 	 *
   2995 	 * @return {void}
   2996 	 */
   2997 	activate: function() {
   2998 		var library = this.get('library');
   2999 
   3000 		// Limit the library to images only.
   3001 		library.props.set( 'type', 'image' );
   3002 
   3003 		// Watch for uploaded attachments.
   3004 		this.get('library').observe( wp.Uploader.queue );
   3005 
   3006 		this.frame.on( 'content:render:browse', this.gallerySettings, this );
   3007 
   3008 		Library.prototype.activate.apply( this, arguments );
   3009 	},
   3010 
   3011 	/**
   3012 	 * Deactivates the library.
   3013 	 *
   3014 	 * Stops watching for uploaded attachments and browse events.
   3015 	 *
   3016 	 * @since 3.5.0
   3017 	 *
   3018 	 * @return {void}
   3019 	 */
   3020 	deactivate: function() {
   3021 		// Stop watching for uploaded attachments.
   3022 		this.get('library').unobserve( wp.Uploader.queue );
   3023 
   3024 		this.frame.off( 'content:render:browse', this.gallerySettings, this );
   3025 
   3026 		Library.prototype.deactivate.apply( this, arguments );
   3027 	},
   3028 
   3029 	/**
   3030 	 * Adds the gallery settings to the sidebar and adds a reverse button to the
   3031 	 * toolbar.
   3032 	 *
   3033 	 * @since 3.5.0
   3034 	 *
   3035 	 * @param {wp.media.view.Frame} browser The file browser.
   3036 	 *
   3037 	 * @return {void}
   3038 	 */
   3039 	gallerySettings: function( browser ) {
   3040 		if ( ! this.get('displaySettings') ) {
   3041 			return;
   3042 		}
   3043 
   3044 		var library = this.get('library');
   3045 
   3046 		if ( ! library || ! browser ) {
   3047 			return;
   3048 		}
   3049 
   3050 		library.gallery = library.gallery || new Backbone.Model();
   3051 
   3052 		browser.sidebar.set({
   3053 			gallery: new wp.media.view.Settings.Gallery({
   3054 				controller: this,
   3055 				model:      library.gallery,
   3056 				priority:   40
   3057 			})
   3058 		});
   3059 
   3060 		browser.toolbar.set( 'reverse', {
   3061 			text:     l10n.reverseOrder,
   3062 			priority: 80,
   3063 
   3064 			click: function() {
   3065 				library.reset( library.toArray().reverse() );
   3066 			}
   3067 		});
   3068 	}
   3069 });
   3070 
   3071 module.exports = GalleryEdit;
   3072 
   3073 
   3074 /***/ }),
   3075 
   3076 /***/ "9ARG":
   3077 /***/ (function(module, exports) {
   3078 
   3079 /**
   3080  * wp.media.view.Sidebar
   3081  *
   3082  * @memberOf wp.media.view
   3083  *
   3084  * @class
   3085  * @augments wp.media.view.PriorityList
   3086  * @augments wp.media.View
   3087  * @augments wp.Backbone.View
   3088  * @augments Backbone.View
   3089  */
   3090 var Sidebar = wp.media.view.PriorityList.extend(/** @lends wp.media.view.Sidebar.prototype */{
   3091 	className: 'media-sidebar'
   3092 });
   3093 
   3094 module.exports = Sidebar;
   3095 
   3096 
   3097 /***/ }),
   3098 
   3099 /***/ "Bbnu":
   3100 /***/ (function(module, exports) {
   3101 
   3102 /**
   3103  * wp.media.View
   3104  *
   3105  * The base view class for media.
   3106  *
   3107  * Undelegating events, removing events from the model, and
   3108  * removing events from the controller mirror the code for
   3109  * `Backbone.View.dispose` in Backbone 0.9.8 development.
   3110  *
   3111  * This behavior has since been removed, and should not be used
   3112  * outside of the media manager.
   3113  *
   3114  * @memberOf wp.media
   3115  *
   3116  * @class
   3117  * @augments wp.Backbone.View
   3118  * @augments Backbone.View
   3119  */
   3120 var View = wp.Backbone.View.extend(/** @lends wp.media.View.prototype */{
   3121 	constructor: function( options ) {
   3122 		if ( options && options.controller ) {
   3123 			this.controller = options.controller;
   3124 		}
   3125 		wp.Backbone.View.apply( this, arguments );
   3126 	},
   3127 	/**
   3128 	 * @todo The internal comment mentions this might have been a stop-gap
   3129 	 *       before Backbone 0.9.8 came out. Figure out if Backbone core takes
   3130 	 *       care of this in Backbone.View now.
   3131 	 *
   3132 	 * @return {wp.media.View} Returns itself to allow chaining.
   3133 	 */
   3134 	dispose: function() {
   3135 		/*
   3136 		 * Undelegating events, removing events from the model, and
   3137 		 * removing events from the controller mirror the code for
   3138 		 * `Backbone.View.dispose` in Backbone 0.9.8 development.
   3139 		 */
   3140 		this.undelegateEvents();
   3141 
   3142 		if ( this.model && this.model.off ) {
   3143 			this.model.off( null, null, this );
   3144 		}
   3145 
   3146 		if ( this.collection && this.collection.off ) {
   3147 			this.collection.off( null, null, this );
   3148 		}
   3149 
   3150 		// Unbind controller events.
   3151 		if ( this.controller && this.controller.off ) {
   3152 			this.controller.off( null, null, this );
   3153 		}
   3154 
   3155 		return this;
   3156 	},
   3157 	/**
   3158 	 * @return {wp.media.View} Returns itself to allow chaining.
   3159 	 */
   3160 	remove: function() {
   3161 		this.dispose();
   3162 		/**
   3163 		 * call 'remove' directly on the parent class
   3164 		 */
   3165 		return wp.Backbone.View.prototype.remove.apply( this, arguments );
   3166 	}
   3167 });
   3168 
   3169 module.exports = View;
   3170 
   3171 
   3172 /***/ }),
   3173 
   3174 /***/ "EVvK":
   3175 /***/ (function(module, exports) {
   3176 
   3177 var Menu = wp.media.view.Menu,
   3178 	Router;
   3179 
   3180 /**
   3181  * wp.media.view.Router
   3182  *
   3183  * @memberOf wp.media.view
   3184  *
   3185  * @class
   3186  * @augments wp.media.view.Menu
   3187  * @augments wp.media.view.PriorityList
   3188  * @augments wp.media.View
   3189  * @augments wp.Backbone.View
   3190  * @augments Backbone.View
   3191  */
   3192 Router = Menu.extend(/** @lends wp.media.view.Router.prototype */{
   3193 	tagName:   'div',
   3194 	className: 'media-router',
   3195 	property:  'contentMode',
   3196 	ItemView:  wp.media.view.RouterItem,
   3197 	region:    'router',
   3198 
   3199 	attributes: {
   3200 		role:               'tablist',
   3201 		'aria-orientation': 'horizontal'
   3202 	},
   3203 
   3204 	initialize: function() {
   3205 		this.controller.on( 'content:render', this.update, this );
   3206 		// Call 'initialize' directly on the parent class.
   3207 		Menu.prototype.initialize.apply( this, arguments );
   3208 	},
   3209 
   3210 	update: function() {
   3211 		var mode = this.controller.content.mode();
   3212 		if ( mode ) {
   3213 			this.select( mode );
   3214 		}
   3215 	}
   3216 });
   3217 
   3218 module.exports = Router;
   3219 
   3220 
   3221 /***/ }),
   3222 
   3223 /***/ "EvXF":
   3224 /***/ (function(module, exports) {
   3225 
   3226 /**
   3227  * wp.media.view.Attachment.EditLibrary
   3228  *
   3229  * @memberOf wp.media.view.Attachment
   3230  *
   3231  * @class
   3232  * @augments wp.media.view.Attachment
   3233  * @augments wp.media.View
   3234  * @augments wp.Backbone.View
   3235  * @augments Backbone.View
   3236  */
   3237 var EditLibrary = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.EditLibrary.prototype */{
   3238 	buttons: {
   3239 		close: true
   3240 	}
   3241 });
   3242 
   3243 module.exports = EditLibrary;
   3244 
   3245 
   3246 /***/ }),
   3247 
   3248 /***/ "F/kE":
   3249 /***/ (function(module, exports) {
   3250 
   3251 var l10n = wp.media.view.l10n,
   3252 	getUserSetting = window.getUserSetting,
   3253 	setUserSetting = window.setUserSetting,
   3254 	Library;
   3255 
   3256 /**
   3257  * wp.media.controller.Library
   3258  *
   3259  * A state for choosing an attachment or group of attachments from the media library.
   3260  *
   3261  * @memberOf wp.media.controller
   3262  *
   3263  * @class
   3264  * @augments wp.media.controller.State
   3265  * @augments Backbone.Model
   3266  * @mixes media.selectionSync
   3267  *
   3268  * @param {object}                          [attributes]                         The attributes hash passed to the state.
   3269  * @param {string}                          [attributes.id=library]              Unique identifier.
   3270  * @param {string}                          [attributes.title=Media library]     Title for the state. Displays in the media menu and the frame's title region.
   3271  * @param {wp.media.model.Attachments}      [attributes.library]                 The attachments collection to browse.
   3272  *                                                                               If one is not supplied, a collection of all attachments will be created.
   3273  * @param {wp.media.model.Selection|object} [attributes.selection]               A collection to contain attachment selections within the state.
   3274  *                                                                               If the 'selection' attribute is a plain JS object,
   3275  *                                                                               a Selection will be created using its values as the selection instance's `props` model.
   3276  *                                                                               Otherwise, it will copy the library's `props` model.
   3277  * @param {boolean}                         [attributes.multiple=false]          Whether multi-select is enabled.
   3278  * @param {string}                          [attributes.content=upload]          Initial mode for the content region.
   3279  *                                                                               Overridden by persistent user setting if 'contentUserSetting' is true.
   3280  * @param {string}                          [attributes.menu=default]            Initial mode for the menu region.
   3281  * @param {string}                          [attributes.router=browse]           Initial mode for the router region.
   3282  * @param {string}                          [attributes.toolbar=select]          Initial mode for the toolbar region.
   3283  * @param {boolean}                         [attributes.searchable=true]         Whether the library is searchable.
   3284  * @param {boolean|string}                  [attributes.filterable=false]        Whether the library is filterable, and if so what filters should be shown.
   3285  *                                                                               Accepts 'all', 'uploaded', or 'unattached'.
   3286  * @param {boolean}                         [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
   3287  * @param {boolean}                         [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
   3288  * @param {boolean}                         [attributes.describe=false]          Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
   3289  * @param {boolean}                         [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
   3290  * @param {boolean}                         [attributes.syncSelection=true]      Whether the Attachments selection should be persisted from the last state.
   3291  */
   3292 Library = wp.media.controller.State.extend(/** @lends wp.media.controller.Library.prototype */{
   3293 	defaults: {
   3294 		id:                 'library',
   3295 		title:              l10n.mediaLibraryTitle,
   3296 		multiple:           false,
   3297 		content:            'upload',
   3298 		menu:               'default',
   3299 		router:             'browse',
   3300 		toolbar:            'select',
   3301 		searchable:         true,
   3302 		filterable:         false,
   3303 		sortable:           true,
   3304 		autoSelect:         true,
   3305 		describe:           false,
   3306 		contentUserSetting: true,
   3307 		syncSelection:      true
   3308 	},
   3309 
   3310 	/**
   3311 	 * If a library isn't provided, query all media items.
   3312 	 * If a selection instance isn't provided, create one.
   3313 	 *
   3314 	 * @since 3.5.0
   3315 	 */
   3316 	initialize: function() {
   3317 		var selection = this.get('selection'),
   3318 			props;
   3319 
   3320 		if ( ! this.get('library') ) {
   3321 			this.set( 'library', wp.media.query() );
   3322 		}
   3323 
   3324 		if ( ! ( selection instanceof wp.media.model.Selection ) ) {
   3325 			props = selection;
   3326 
   3327 			if ( ! props ) {
   3328 				props = this.get('library').props.toJSON();
   3329 				props = _.omit( props, 'orderby', 'query' );
   3330 			}
   3331 
   3332 			this.set( 'selection', new wp.media.model.Selection( null, {
   3333 				multiple: this.get('multiple'),
   3334 				props: props
   3335 			}) );
   3336 		}
   3337 
   3338 		this.resetDisplays();
   3339 	},
   3340 
   3341 	/**
   3342 	 * @since 3.5.0
   3343 	 */
   3344 	activate: function() {
   3345 		this.syncSelection();
   3346 
   3347 		wp.Uploader.queue.on( 'add', this.uploading, this );
   3348 
   3349 		this.get('selection').on( 'add remove reset', this.refreshContent, this );
   3350 
   3351 		if ( this.get( 'router' ) && this.get('contentUserSetting') ) {
   3352 			this.frame.on( 'content:activate', this.saveContentMode, this );
   3353 			this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
   3354 		}
   3355 	},
   3356 
   3357 	/**
   3358 	 * @since 3.5.0
   3359 	 */
   3360 	deactivate: function() {
   3361 		this.recordSelection();
   3362 
   3363 		this.frame.off( 'content:activate', this.saveContentMode, this );
   3364 
   3365 		// Unbind all event handlers that use this state as the context
   3366 		// from the selection.
   3367 		this.get('selection').off( null, null, this );
   3368 
   3369 		wp.Uploader.queue.off( null, null, this );
   3370 	},
   3371 
   3372 	/**
   3373 	 * Reset the library to its initial state.
   3374 	 *
   3375 	 * @since 3.5.0
   3376 	 */
   3377 	reset: function() {
   3378 		this.get('selection').reset();
   3379 		this.resetDisplays();
   3380 		this.refreshContent();
   3381 	},
   3382 
   3383 	/**
   3384 	 * Reset the attachment display settings defaults to the site options.
   3385 	 *
   3386 	 * If site options don't define them, fall back to a persistent user setting.
   3387 	 *
   3388 	 * @since 3.5.0
   3389 	 */
   3390 	resetDisplays: function() {
   3391 		var defaultProps = wp.media.view.settings.defaultProps;
   3392 		this._displays = [];
   3393 		this._defaultDisplaySettings = {
   3394 			align: getUserSetting( 'align', defaultProps.align ) || 'none',
   3395 			size:  getUserSetting( 'imgsize', defaultProps.size ) || 'medium',
   3396 			link:  getUserSetting( 'urlbutton', defaultProps.link ) || 'none'
   3397 		};
   3398 	},
   3399 
   3400 	/**
   3401 	 * Create a model to represent display settings (alignment, etc.) for an attachment.
   3402 	 *
   3403 	 * @since 3.5.0
   3404 	 *
   3405 	 * @param {wp.media.model.Attachment} attachment
   3406 	 * @return {Backbone.Model}
   3407 	 */
   3408 	display: function( attachment ) {
   3409 		var displays = this._displays;
   3410 
   3411 		if ( ! displays[ attachment.cid ] ) {
   3412 			displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) );
   3413 		}
   3414 		return displays[ attachment.cid ];
   3415 	},
   3416 
   3417 	/**
   3418 	 * Given an attachment, create attachment display settings properties.
   3419 	 *
   3420 	 * @since 3.6.0
   3421 	 *
   3422 	 * @param {wp.media.model.Attachment} attachment
   3423 	 * @return {Object}
   3424 	 */
   3425 	defaultDisplaySettings: function( attachment ) {
   3426 		var settings = _.clone( this._defaultDisplaySettings );
   3427 
   3428 		settings.canEmbed = this.canEmbed( attachment );
   3429 		if ( settings.canEmbed ) {
   3430 			settings.link = 'embed';
   3431 		} else if ( ! this.isImageAttachment( attachment ) && settings.link === 'none' ) {
   3432 			settings.link = 'file';
   3433 		}
   3434 
   3435 		return settings;
   3436 	},
   3437 
   3438 	/**
   3439 	 * Whether an attachment is image.
   3440 	 *
   3441 	 * @since 4.4.1
   3442 	 *
   3443 	 * @param {wp.media.model.Attachment} attachment
   3444 	 * @return {boolean}
   3445 	 */
   3446 	isImageAttachment: function( attachment ) {
   3447 		// If uploading, we know the filename but not the mime type.
   3448 		if ( attachment.get('uploading') ) {
   3449 			return /\.(jpe?g|png|gif)$/i.test( attachment.get('filename') );
   3450 		}
   3451 
   3452 		return attachment.get('type') === 'image';
   3453 	},
   3454 
   3455 	/**
   3456 	 * Whether an attachment can be embedded (audio or video).
   3457 	 *
   3458 	 * @since 3.6.0
   3459 	 *
   3460 	 * @param {wp.media.model.Attachment} attachment
   3461 	 * @return {boolean}
   3462 	 */
   3463 	canEmbed: function( attachment ) {
   3464 		// If uploading, we know the filename but not the mime type.
   3465 		if ( ! attachment.get('uploading') ) {
   3466 			var type = attachment.get('type');
   3467 			if ( type !== 'audio' && type !== 'video' ) {
   3468 				return false;
   3469 			}
   3470 		}
   3471 
   3472 		return _.contains( wp.media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
   3473 	},
   3474 
   3475 
   3476 	/**
   3477 	 * If the state is active, no items are selected, and the current
   3478 	 * content mode is not an option in the state's router (provided
   3479 	 * the state has a router), reset the content mode to the default.
   3480 	 *
   3481 	 * @since 3.5.0
   3482 	 */
   3483 	refreshContent: function() {
   3484 		var selection = this.get('selection'),
   3485 			frame = this.frame,
   3486 			router = frame.router.get(),
   3487 			mode = frame.content.mode();
   3488 
   3489 		if ( this.active && ! selection.length && router && ! router.get( mode ) ) {
   3490 			this.frame.content.render( this.get('content') );
   3491 		}
   3492 	},
   3493 
   3494 	/**
   3495 	 * Callback handler when an attachment is uploaded.
   3496 	 *
   3497 	 * Switch to the Media Library if uploaded from the 'Upload Files' tab.
   3498 	 *
   3499 	 * Adds any uploading attachments to the selection.
   3500 	 *
   3501 	 * If the state only supports one attachment to be selected and multiple
   3502 	 * attachments are uploaded, the last attachment in the upload queue will
   3503 	 * be selected.
   3504 	 *
   3505 	 * @since 3.5.0
   3506 	 *
   3507 	 * @param {wp.media.model.Attachment} attachment
   3508 	 */
   3509 	uploading: function( attachment ) {
   3510 		var content = this.frame.content;
   3511 
   3512 		if ( 'upload' === content.mode() ) {
   3513 			this.frame.content.mode('browse');
   3514 		}
   3515 
   3516 		if ( this.get( 'autoSelect' ) ) {
   3517 			this.get('selection').add( attachment );
   3518 			this.frame.trigger( 'library:selection:add' );
   3519 		}
   3520 	},
   3521 
   3522 	/**
   3523 	 * Persist the mode of the content region as a user setting.
   3524 	 *
   3525 	 * @since 3.5.0
   3526 	 */
   3527 	saveContentMode: function() {
   3528 		if ( 'browse' !== this.get('router') ) {
   3529 			return;
   3530 		}
   3531 
   3532 		var mode = this.frame.content.mode(),
   3533 			view = this.frame.router.get();
   3534 
   3535 		if ( view && view.get( mode ) ) {
   3536 			setUserSetting( 'libraryContent', mode );
   3537 		}
   3538 	}
   3539 
   3540 });
   3541 
   3542 // Make selectionSync available on any Media Library state.
   3543 _.extend( Library.prototype, wp.media.selectionSync );
   3544 
   3545 module.exports = Library;
   3546 
   3547 
   3548 /***/ }),
   3549 
   3550 /***/ "GXJ6":
   3551 /***/ (function(module, exports) {
   3552 
   3553 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
   3554 	$ = jQuery,
   3555 	ImageDetails;
   3556 
   3557 /**
   3558  * wp.media.view.ImageDetails
   3559  *
   3560  * @memberOf wp.media.view
   3561  *
   3562  * @class
   3563  * @augments wp.media.view.Settings.AttachmentDisplay
   3564  * @augments wp.media.view.Settings
   3565  * @augments wp.media.View
   3566  * @augments wp.Backbone.View
   3567  * @augments Backbone.View
   3568  */
   3569 ImageDetails = AttachmentDisplay.extend(/** @lends wp.media.view.ImageDetails.prototype */{
   3570 	className: 'image-details',
   3571 	template:  wp.template('image-details'),
   3572 	events: _.defaults( AttachmentDisplay.prototype.events, {
   3573 		'click .edit-attachment': 'editAttachment',
   3574 		'click .replace-attachment': 'replaceAttachment',
   3575 		'click .advanced-toggle': 'onToggleAdvanced',
   3576 		'change [data-setting="customWidth"]': 'onCustomSize',
   3577 		'change [data-setting="customHeight"]': 'onCustomSize',
   3578 		'keyup [data-setting="customWidth"]': 'onCustomSize',
   3579 		'keyup [data-setting="customHeight"]': 'onCustomSize'
   3580 	} ),
   3581 	initialize: function() {
   3582 		// Used in AttachmentDisplay.prototype.updateLinkTo.
   3583 		this.options.attachment = this.model.attachment;
   3584 		this.listenTo( this.model, 'change:url', this.updateUrl );
   3585 		this.listenTo( this.model, 'change:link', this.toggleLinkSettings );
   3586 		this.listenTo( this.model, 'change:size', this.toggleCustomSize );
   3587 
   3588 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
   3589 	},
   3590 
   3591 	prepare: function() {
   3592 		var attachment = false;
   3593 
   3594 		if ( this.model.attachment ) {
   3595 			attachment = this.model.attachment.toJSON();
   3596 		}
   3597 		return _.defaults({
   3598 			model: this.model.toJSON(),
   3599 			attachment: attachment
   3600 		}, this.options );
   3601 	},
   3602 
   3603 	render: function() {
   3604 		var args = arguments;
   3605 
   3606 		if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
   3607 			this.model.dfd
   3608 				.done( _.bind( function() {
   3609 					AttachmentDisplay.prototype.render.apply( this, args );
   3610 					this.postRender();
   3611 				}, this ) )
   3612 				.fail( _.bind( function() {
   3613 					this.model.attachment = false;
   3614 					AttachmentDisplay.prototype.render.apply( this, args );
   3615 					this.postRender();
   3616 				}, this ) );
   3617 		} else {
   3618 			AttachmentDisplay.prototype.render.apply( this, arguments );
   3619 			this.postRender();
   3620 		}
   3621 
   3622 		return this;
   3623 	},
   3624 
   3625 	postRender: function() {
   3626 		setTimeout( _.bind( this.scrollToTop, this ), 10 );
   3627 		this.toggleLinkSettings();
   3628 		if ( window.getUserSetting( 'advImgDetails' ) === 'show' ) {
   3629 			this.toggleAdvanced( true );
   3630 		}
   3631 		this.trigger( 'post-render' );
   3632 	},
   3633 
   3634 	scrollToTop: function() {
   3635 		this.$( '.embed-media-settings' ).scrollTop( 0 );
   3636 	},
   3637 
   3638 	updateUrl: function() {
   3639 		this.$( '.image img' ).attr( 'src', this.model.get( 'url' ) );
   3640 		this.$( '.url' ).val( this.model.get( 'url' ) );
   3641 	},
   3642 
   3643 	toggleLinkSettings: function() {
   3644 		if ( this.model.get( 'link' ) === 'none' ) {
   3645 			this.$( '.link-settings' ).addClass('hidden');
   3646 		} else {
   3647 			this.$( '.link-settings' ).removeClass('hidden');
   3648 		}
   3649 	},
   3650 
   3651 	toggleCustomSize: function() {
   3652 		if ( this.model.get( 'size' ) !== 'custom' ) {
   3653 			this.$( '.custom-size' ).addClass('hidden');
   3654 		} else {
   3655 			this.$( '.custom-size' ).removeClass('hidden');
   3656 		}
   3657 	},
   3658 
   3659 	onCustomSize: function( event ) {
   3660 		var dimension = $( event.target ).data('setting'),
   3661 			num = $( event.target ).val(),
   3662 			value;
   3663 
   3664 		// Ignore bogus input.
   3665 		if ( ! /^\d+/.test( num ) || parseInt( num, 10 ) < 1 ) {
   3666 			event.preventDefault();
   3667 			return;
   3668 		}
   3669 
   3670 		if ( dimension === 'customWidth' ) {
   3671 			value = Math.round( 1 / this.model.get( 'aspectRatio' ) * num );
   3672 			this.model.set( 'customHeight', value, { silent: true } );
   3673 			this.$( '[data-setting="customHeight"]' ).val( value );
   3674 		} else {
   3675 			value = Math.round( this.model.get( 'aspectRatio' ) * num );
   3676 			this.model.set( 'customWidth', value, { silent: true  } );
   3677 			this.$( '[data-setting="customWidth"]' ).val( value );
   3678 		}
   3679 	},
   3680 
   3681 	onToggleAdvanced: function( event ) {
   3682 		event.preventDefault();
   3683 		this.toggleAdvanced();
   3684 	},
   3685 
   3686 	toggleAdvanced: function( show ) {
   3687 		var $advanced = this.$el.find( '.advanced-section' ),
   3688 			mode;
   3689 
   3690 		if ( $advanced.hasClass('advanced-visible') || show === false ) {
   3691 			$advanced.removeClass('advanced-visible');
   3692 			$advanced.find('.advanced-settings').addClass('hidden');
   3693 			mode = 'hide';
   3694 		} else {
   3695 			$advanced.addClass('advanced-visible');
   3696 			$advanced.find('.advanced-settings').removeClass('hidden');
   3697 			mode = 'show';
   3698 		}
   3699 
   3700 		window.setUserSetting( 'advImgDetails', mode );
   3701 	},
   3702 
   3703 	editAttachment: function( event ) {
   3704 		var editState = this.controller.states.get( 'edit-image' );
   3705 
   3706 		if ( window.imageEdit && editState ) {
   3707 			event.preventDefault();
   3708 			editState.set( 'image', this.model.attachment );
   3709 			this.controller.setState( 'edit-image' );
   3710 		}
   3711 	},
   3712 
   3713 	replaceAttachment: function( event ) {
   3714 		event.preventDefault();
   3715 		this.controller.setState( 'replace-image' );
   3716 	}
   3717 });
   3718 
   3719 module.exports = ImageDetails;
   3720 
   3721 
   3722 /***/ }),
   3723 
   3724 /***/ "GXkx":
   3725 /***/ (function(module, exports) {
   3726 
   3727 var View = wp.media.View,
   3728 	l10n = wp.media.view.l10n,
   3729 	$ = jQuery,
   3730 	EditorUploader;
   3731 
   3732 /**
   3733  * Creates a dropzone on WP editor instances (elements with .wp-editor-wrap)
   3734  * and relays drag'n'dropped files to a media workflow.
   3735  *
   3736  * wp.media.view.EditorUploader
   3737  *
   3738  * @memberOf wp.media.view
   3739  *
   3740  * @class
   3741  * @augments wp.media.View
   3742  * @augments wp.Backbone.View
   3743  * @augments Backbone.View
   3744  */
   3745 EditorUploader = View.extend(/** @lends wp.media.view.EditorUploader.prototype */{
   3746 	tagName:   'div',
   3747 	className: 'uploader-editor',
   3748 	template:  wp.template( 'uploader-editor' ),
   3749 
   3750 	localDrag: false,
   3751 	overContainer: false,
   3752 	overDropzone: false,
   3753 	draggingFile: null,
   3754 
   3755 	/**
   3756 	 * Bind drag'n'drop events to callbacks.
   3757 	 */
   3758 	initialize: function() {
   3759 		this.initialized = false;
   3760 
   3761 		// Bail if not enabled or UA does not support drag'n'drop or File API.
   3762 		if ( ! window.tinyMCEPreInit || ! window.tinyMCEPreInit.dragDropUpload || ! this.browserSupport() ) {
   3763 			return this;
   3764 		}
   3765 
   3766 		this.$document = $(document);
   3767 		this.dropzones = [];
   3768 		this.files = [];
   3769 
   3770 		this.$document.on( 'drop', '.uploader-editor', _.bind( this.drop, this ) );
   3771 		this.$document.on( 'dragover', '.uploader-editor', _.bind( this.dropzoneDragover, this ) );
   3772 		this.$document.on( 'dragleave', '.uploader-editor', _.bind( this.dropzoneDragleave, this ) );
   3773 		this.$document.on( 'click', '.uploader-editor', _.bind( this.click, this ) );
   3774 
   3775 		this.$document.on( 'dragover', _.bind( this.containerDragover, this ) );
   3776 		this.$document.on( 'dragleave', _.bind( this.containerDragleave, this ) );
   3777 
   3778 		this.$document.on( 'dragstart dragend drop', _.bind( function( event ) {
   3779 			this.localDrag = event.type === 'dragstart';
   3780 
   3781 			if ( event.type === 'drop' ) {
   3782 				this.containerDragleave();
   3783 			}
   3784 		}, this ) );
   3785 
   3786 		this.initialized = true;
   3787 		return this;
   3788 	},
   3789 
   3790 	/**
   3791 	 * Check browser support for drag'n'drop.
   3792 	 *
   3793 	 * @return {boolean}
   3794 	 */
   3795 	browserSupport: function() {
   3796 		var supports = false, div = document.createElement('div');
   3797 
   3798 		supports = ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div );
   3799 		supports = supports && !! ( window.File && window.FileList && window.FileReader );
   3800 		return supports;
   3801 	},
   3802 
   3803 	isDraggingFile: function( event ) {
   3804 		if ( this.draggingFile !== null ) {
   3805 			return this.draggingFile;
   3806 		}
   3807 
   3808 		if ( _.isUndefined( event.originalEvent ) || _.isUndefined( event.originalEvent.dataTransfer ) ) {
   3809 			return false;
   3810 		}
   3811 
   3812 		this.draggingFile = _.indexOf( event.originalEvent.dataTransfer.types, 'Files' ) > -1 &&
   3813 			_.indexOf( event.originalEvent.dataTransfer.types, 'text/plain' ) === -1;
   3814 
   3815 		return this.draggingFile;
   3816 	},
   3817 
   3818 	refresh: function( e ) {
   3819 		var dropzone_id;
   3820 		for ( dropzone_id in this.dropzones ) {
   3821 			// Hide the dropzones only if dragging has left the screen.
   3822 			this.dropzones[ dropzone_id ].toggle( this.overContainer || this.overDropzone );
   3823 		}
   3824 
   3825 		if ( ! _.isUndefined( e ) ) {
   3826 			$( e.target ).closest( '.uploader-editor' ).toggleClass( 'droppable', this.overDropzone );
   3827 		}
   3828 
   3829 		if ( ! this.overContainer && ! this.overDropzone ) {
   3830 			this.draggingFile = null;
   3831 		}
   3832 
   3833 		return this;
   3834 	},
   3835 
   3836 	render: function() {
   3837 		if ( ! this.initialized ) {
   3838 			return this;
   3839 		}
   3840 
   3841 		View.prototype.render.apply( this, arguments );
   3842 		$( '.wp-editor-wrap' ).each( _.bind( this.attach, this ) );
   3843 		return this;
   3844 	},
   3845 
   3846 	attach: function( index, editor ) {
   3847 		// Attach a dropzone to an editor.
   3848 		var dropzone = this.$el.clone();
   3849 		this.dropzones.push( dropzone );
   3850 		$( editor ).append( dropzone );
   3851 		return this;
   3852 	},
   3853 
   3854 	/**
   3855 	 * When a file is dropped on the editor uploader, open up an editor media workflow
   3856 	 * and upload the file immediately.
   3857 	 *
   3858 	 * @param {jQuery.Event} event The 'drop' event.
   3859 	 */
   3860 	drop: function( event ) {
   3861 		var $wrap, uploadView;
   3862 
   3863 		this.containerDragleave( event );
   3864 		this.dropzoneDragleave( event );
   3865 
   3866 		this.files = event.originalEvent.dataTransfer.files;
   3867 		if ( this.files.length < 1 ) {
   3868 			return;
   3869 		}
   3870 
   3871 		// Set the active editor to the drop target.
   3872 		$wrap = $( event.target ).parents( '.wp-editor-wrap' );
   3873 		if ( $wrap.length > 0 && $wrap[0].id ) {
   3874 			window.wpActiveEditor = $wrap[0].id.slice( 3, -5 );
   3875 		}
   3876 
   3877 		if ( ! this.workflow ) {
   3878 			this.workflow = wp.media.editor.open( window.wpActiveEditor, {
   3879 				frame:    'post',
   3880 				state:    'insert',
   3881 				title:    l10n.addMedia,
   3882 				multiple: true
   3883 			});
   3884 
   3885 			uploadView = this.workflow.uploader;
   3886 
   3887 			if ( uploadView.uploader && uploadView.uploader.ready ) {
   3888 				this.addFiles.apply( this );
   3889 			} else {
   3890 				this.workflow.on( 'uploader:ready', this.addFiles, this );
   3891 			}
   3892 		} else {
   3893 			this.workflow.state().reset();
   3894 			this.addFiles.apply( this );
   3895 			this.workflow.open();
   3896 		}
   3897 
   3898 		return false;
   3899 	},
   3900 
   3901 	/**
   3902 	 * Add the files to the uploader.
   3903 	 */
   3904 	addFiles: function() {
   3905 		if ( this.files.length ) {
   3906 			this.workflow.uploader.uploader.uploader.addFile( _.toArray( this.files ) );
   3907 			this.files = [];
   3908 		}
   3909 		return this;
   3910 	},
   3911 
   3912 	containerDragover: function( event ) {
   3913 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
   3914 			return;
   3915 		}
   3916 
   3917 		this.overContainer = true;
   3918 		this.refresh();
   3919 	},
   3920 
   3921 	containerDragleave: function() {
   3922 		this.overContainer = false;
   3923 
   3924 		// Throttle dragleave because it's called when bouncing from some elements to others.
   3925 		_.delay( _.bind( this.refresh, this ), 50 );
   3926 	},
   3927 
   3928 	dropzoneDragover: function( event ) {
   3929 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
   3930 			return;
   3931 		}
   3932 
   3933 		this.overDropzone = true;
   3934 		this.refresh( event );
   3935 		return false;
   3936 	},
   3937 
   3938 	dropzoneDragleave: function( e ) {
   3939 		this.overDropzone = false;
   3940 		_.delay( _.bind( this.refresh, this, e ), 50 );
   3941 	},
   3942 
   3943 	click: function( e ) {
   3944 		// In the rare case where the dropzone gets stuck, hide it on click.
   3945 		this.containerDragleave( e );
   3946 		this.dropzoneDragleave( e );
   3947 		this.localDrag = false;
   3948 	}
   3949 });
   3950 
   3951 module.exports = EditorUploader;
   3952 
   3953 
   3954 /***/ }),
   3955 
   3956 /***/ "I7TD":
   3957 /***/ (function(module, exports) {
   3958 
   3959 var Attachment = wp.media.model.Attachment,
   3960 	Library = wp.media.controller.Library,
   3961 	l10n = wp.media.view.l10n,
   3962 	FeaturedImage;
   3963 
   3964 /**
   3965  * wp.media.controller.FeaturedImage
   3966  *
   3967  * A state for selecting a featured image for a post.
   3968  *
   3969  * @memberOf wp.media.controller
   3970  *
   3971  * @class
   3972  * @augments wp.media.controller.Library
   3973  * @augments wp.media.controller.State
   3974  * @augments Backbone.Model
   3975  *
   3976  * @param {object}                     [attributes]                          The attributes hash passed to the state.
   3977  * @param {string}                     [attributes.id=featured-image]        Unique identifier.
   3978  * @param {string}                     [attributes.title=Set Featured Image] Title for the state. Displays in the media menu and the frame's title region.
   3979  * @param {wp.media.model.Attachments} [attributes.library]                  The attachments collection to browse.
   3980  *                                                                           If one is not supplied, a collection of all images will be created.
   3981  * @param {boolean}                    [attributes.multiple=false]           Whether multi-select is enabled.
   3982  * @param {string}                     [attributes.content=upload]           Initial mode for the content region.
   3983  *                                                                           Overridden by persistent user setting if 'contentUserSetting' is true.
   3984  * @param {string}                     [attributes.menu=default]             Initial mode for the menu region.
   3985  * @param {string}                     [attributes.router=browse]            Initial mode for the router region.
   3986  * @param {string}                     [attributes.toolbar=featured-image]   Initial mode for the toolbar region.
   3987  * @param {int}                        [attributes.priority=60]              The priority for the state link in the media menu.
   3988  * @param {boolean}                    [attributes.searchable=true]          Whether the library is searchable.
   3989  * @param {boolean|string}             [attributes.filterable=false]         Whether the library is filterable, and if so what filters should be shown.
   3990  *                                                                           Accepts 'all', 'uploaded', or 'unattached'.
   3991  * @param {boolean}                    [attributes.sortable=true]            Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
   3992  * @param {boolean}                    [attributes.autoSelect=true]          Whether an uploaded attachment should be automatically added to the selection.
   3993  * @param {boolean}                    [attributes.describe=false]           Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
   3994  * @param {boolean}                    [attributes.contentUserSetting=true]  Whether the content region's mode should be set and persisted per user.
   3995  * @param {boolean}                    [attributes.syncSelection=true]       Whether the Attachments selection should be persisted from the last state.
   3996  */
   3997 FeaturedImage = Library.extend(/** @lends wp.media.controller.FeaturedImage.prototype */{
   3998 	defaults: _.defaults({
   3999 		id:            'featured-image',
   4000 		title:         l10n.setFeaturedImageTitle,
   4001 		multiple:      false,
   4002 		filterable:    'uploaded',
   4003 		toolbar:       'featured-image',
   4004 		priority:      60,
   4005 		syncSelection: true
   4006 	}, Library.prototype.defaults ),
   4007 
   4008 	/**
   4009 	 * @since 3.5.0
   4010 	 */
   4011 	initialize: function() {
   4012 		var library, comparator;
   4013 
   4014 		// If we haven't been provided a `library`, create a `Selection`.
   4015 		if ( ! this.get('library') ) {
   4016 			this.set( 'library', wp.media.query({ type: 'image' }) );
   4017 		}
   4018 
   4019 		Library.prototype.initialize.apply( this, arguments );
   4020 
   4021 		library    = this.get('library');
   4022 		comparator = library.comparator;
   4023 
   4024 		// Overload the library's comparator to push items that are not in
   4025 		// the mirrored query to the front of the aggregate collection.
   4026 		library.comparator = function( a, b ) {
   4027 			var aInQuery = !! this.mirroring.get( a.cid ),
   4028 				bInQuery = !! this.mirroring.get( b.cid );
   4029 
   4030 			if ( ! aInQuery && bInQuery ) {
   4031 				return -1;
   4032 			} else if ( aInQuery && ! bInQuery ) {
   4033 				return 1;
   4034 			} else {
   4035 				return comparator.apply( this, arguments );
   4036 			}
   4037 		};
   4038 
   4039 		// Add all items in the selection to the library, so any featured
   4040 		// images that are not initially loaded still appear.
   4041 		library.observe( this.get('selection') );
   4042 	},
   4043 
   4044 	/**
   4045 	 * @since 3.5.0
   4046 	 */
   4047 	activate: function() {
   4048 		this.updateSelection();
   4049 		this.frame.on( 'open', this.updateSelection, this );
   4050 
   4051 		Library.prototype.activate.apply( this, arguments );
   4052 	},
   4053 
   4054 	/**
   4055 	 * @since 3.5.0
   4056 	 */
   4057 	deactivate: function() {
   4058 		this.frame.off( 'open', this.updateSelection, this );
   4059 
   4060 		Library.prototype.deactivate.apply( this, arguments );
   4061 	},
   4062 
   4063 	/**
   4064 	 * @since 3.5.0
   4065 	 */
   4066 	updateSelection: function() {
   4067 		var selection = this.get('selection'),
   4068 			id = wp.media.view.settings.post.featuredImageId,
   4069 			attachment;
   4070 
   4071 		if ( '' !== id && -1 !== id ) {
   4072 			attachment = Attachment.get( id );
   4073 			attachment.fetch();
   4074 		}
   4075 
   4076 		selection.reset( attachment ? [ attachment ] : [] );
   4077 	}
   4078 });
   4079 
   4080 module.exports = FeaturedImage;
   4081 
   4082 
   4083 /***/ }),
   4084 
   4085 /***/ "IgEq":
   4086 /***/ (function(module, exports) {
   4087 
   4088 var Toolbar = wp.media.view.Toolbar,
   4089 	l10n = wp.media.view.l10n,
   4090 	Select;
   4091 
   4092 /**
   4093  * wp.media.view.Toolbar.Select
   4094  *
   4095  * @memberOf wp.media.view.Toolbar
   4096  *
   4097  * @class
   4098  * @augments wp.media.view.Toolbar
   4099  * @augments wp.media.View
   4100  * @augments wp.Backbone.View
   4101  * @augments Backbone.View
   4102  */
   4103 Select = Toolbar.extend(/** @lends wp.media.view.Toolbar.Select.prototype */{
   4104 	initialize: function() {
   4105 		var options = this.options;
   4106 
   4107 		_.bindAll( this, 'clickSelect' );
   4108 
   4109 		_.defaults( options, {
   4110 			event: 'select',
   4111 			state: false,
   4112 			reset: true,
   4113 			close: true,
   4114 			text:  l10n.select,
   4115 
   4116 			// Does the button rely on the selection?
   4117 			requires: {
   4118 				selection: true
   4119 			}
   4120 		});
   4121 
   4122 		options.items = _.defaults( options.items || {}, {
   4123 			select: {
   4124 				style:    'primary',
   4125 				text:     options.text,
   4126 				priority: 80,
   4127 				click:    this.clickSelect,
   4128 				requires: options.requires
   4129 			}
   4130 		});
   4131 		// Call 'initialize' directly on the parent class.
   4132 		Toolbar.prototype.initialize.apply( this, arguments );
   4133 	},
   4134 
   4135 	clickSelect: function() {
   4136 		var options = this.options,
   4137 			controller = this.controller;
   4138 
   4139 		if ( options.close ) {
   4140 			controller.close();
   4141 		}
   4142 
   4143 		if ( options.event ) {
   4144 			controller.state().trigger( options.event );
   4145 		}
   4146 
   4147 		if ( options.state ) {
   4148 			controller.setState( options.state );
   4149 		}
   4150 
   4151 		if ( options.reset ) {
   4152 			controller.reset();
   4153 		}
   4154 	}
   4155 });
   4156 
   4157 module.exports = Select;
   4158 
   4159 
   4160 /***/ }),
   4161 
   4162 /***/ "IkWq":
   4163 /***/ (function(module, exports) {
   4164 
   4165 var State = wp.media.controller.State,
   4166 	Library = wp.media.controller.Library,
   4167 	l10n = wp.media.view.l10n,
   4168 	ImageDetails;
   4169 
   4170 /**
   4171  * wp.media.controller.ImageDetails
   4172  *
   4173  * A state for editing the attachment display settings of an image that's been
   4174  * inserted into the editor.
   4175  *
   4176  * @memberOf wp.media.controller
   4177  *
   4178  * @class
   4179  * @augments wp.media.controller.State
   4180  * @augments Backbone.Model
   4181  *
   4182  * @param {object}                    [attributes]                       The attributes hash passed to the state.
   4183  * @param {string}                    [attributes.id=image-details]      Unique identifier.
   4184  * @param {string}                    [attributes.title=Image Details]   Title for the state. Displays in the frame's title region.
   4185  * @param {wp.media.model.Attachment} attributes.image                   The image's model.
   4186  * @param {string|false}              [attributes.content=image-details] Initial mode for the content region.
   4187  * @param {string|false}              [attributes.menu=false]            Initial mode for the menu region.
   4188  * @param {string|false}              [attributes.router=false]          Initial mode for the router region.
   4189  * @param {string|false}              [attributes.toolbar=image-details] Initial mode for the toolbar region.
   4190  * @param {boolean}                   [attributes.editing=false]         Unused.
   4191  * @param {int}                       [attributes.priority=60]           Unused.
   4192  *
   4193  * @todo This state inherits some defaults from media.controller.Library.prototype.defaults,
   4194  *       however this may not do anything.
   4195  */
   4196 ImageDetails = State.extend(/** @lends wp.media.controller.ImageDetails.prototype */{
   4197 	defaults: _.defaults({
   4198 		id:       'image-details',
   4199 		title:    l10n.imageDetailsTitle,
   4200 		content:  'image-details',
   4201 		menu:     false,
   4202 		router:   false,
   4203 		toolbar:  'image-details',
   4204 		editing:  false,
   4205 		priority: 60
   4206 	}, Library.prototype.defaults ),
   4207 
   4208 	/**
   4209 	 * @since 3.9.0
   4210 	 *
   4211 	 * @param options Attributes
   4212 	 */
   4213 	initialize: function( options ) {
   4214 		this.image = options.image;
   4215 		State.prototype.initialize.apply( this, arguments );
   4216 	},
   4217 
   4218 	/**
   4219 	 * @since 3.9.0
   4220 	 */
   4221 	activate: function() {
   4222 		this.frame.modal.$el.addClass('image-details');
   4223 	}
   4224 });
   4225 
   4226 module.exports = ImageDetails;
   4227 
   4228 
   4229 /***/ }),
   4230 
   4231 /***/ "JecU":
   4232 /***/ (function(module, exports) {
   4233 
   4234 var $ = jQuery,
   4235 	EmbedLink;
   4236 
   4237 /**
   4238  * wp.media.view.EmbedLink
   4239  *
   4240  * @memberOf wp.media.view
   4241  *
   4242  * @class
   4243  * @augments wp.media.view.Settings
   4244  * @augments wp.media.View
   4245  * @augments wp.Backbone.View
   4246  * @augments Backbone.View
   4247  */
   4248 EmbedLink = wp.media.view.Settings.extend(/** @lends wp.media.view.EmbedLink.prototype */{
   4249 	className: 'embed-link-settings',
   4250 	template:  wp.template('embed-link-settings'),
   4251 
   4252 	initialize: function() {
   4253 		this.listenTo( this.model, 'change:url', this.updateoEmbed );
   4254 	},
   4255 
   4256 	updateoEmbed: _.debounce( function() {
   4257 		var url = this.model.get( 'url' );
   4258 
   4259 		// Clear out previous results.
   4260 		this.$('.embed-container').hide().find('.embed-preview').empty();
   4261 		this.$( '.setting' ).hide();
   4262 
   4263 		// Only proceed with embed if the field contains more than 11 characters.
   4264 		// Example: http://a.io is 11 chars
   4265 		if ( url && ( url.length < 11 || ! url.match(/^http(s)?:\/\//) ) ) {
   4266 			return;
   4267 		}
   4268 
   4269 		this.fetch();
   4270 	}, wp.media.controller.Embed.sensitivity ),
   4271 
   4272 	fetch: function() {
   4273 		var url = this.model.get( 'url' ), re, youTubeEmbedMatch;
   4274 
   4275 		// Check if they haven't typed in 500 ms.
   4276 		if ( $('#embed-url-field').val() !== url ) {
   4277 			return;
   4278 		}
   4279 
   4280 		if ( this.dfd && 'pending' === this.dfd.state() ) {
   4281 			this.dfd.abort();
   4282 		}
   4283 
   4284 		// Support YouTube embed urls, since they work once in the editor.
   4285 		re = /https?:\/\/www\.youtube\.com\/embed\/([^/]+)/;
   4286 		youTubeEmbedMatch = re.exec( url );
   4287 		if ( youTubeEmbedMatch ) {
   4288 			url = 'https://www.youtube.com/watch?v=' + youTubeEmbedMatch[ 1 ];
   4289 		}
   4290 
   4291 		this.dfd = wp.apiRequest({
   4292 			url: wp.media.view.settings.oEmbedProxyUrl,
   4293 			data: {
   4294 				url: url,
   4295 				maxwidth: this.model.get( 'width' ),
   4296 				maxheight: this.model.get( 'height' )
   4297 			},
   4298 			type: 'GET',
   4299 			dataType: 'json',
   4300 			context: this
   4301 		})
   4302 			.done( function( response ) {
   4303 				this.renderoEmbed( {
   4304 					data: {
   4305 						body: response.html || ''
   4306 					}
   4307 				} );
   4308 			} )
   4309 			.fail( this.renderFail );
   4310 	},
   4311 
   4312 	renderFail: function ( response, status ) {
   4313 		if ( 'abort' === status ) {
   4314 			return;
   4315 		}
   4316 		this.$( '.link-text' ).show();
   4317 	},
   4318 
   4319 	renderoEmbed: function( response ) {
   4320 		var html = ( response && response.data && response.data.body ) || '';
   4321 
   4322 		if ( html ) {
   4323 			this.$('.embed-container').show().find('.embed-preview').html( html );
   4324 		} else {
   4325 			this.renderFail();
   4326 		}
   4327 	}
   4328 });
   4329 
   4330 module.exports = EmbedLink;
   4331 
   4332 
   4333 /***/ }),
   4334 
   4335 /***/ "Ju2C":
   4336 /***/ (function(module, exports) {
   4337 
   4338 var MenuItem = wp.media.view.MenuItem,
   4339 	PriorityList = wp.media.view.PriorityList,
   4340 	Menu;
   4341 
   4342 /**
   4343  * wp.media.view.Menu
   4344  *
   4345  * @memberOf wp.media.view
   4346  *
   4347  * @class
   4348  * @augments wp.media.view.PriorityList
   4349  * @augments wp.media.View
   4350  * @augments wp.Backbone.View
   4351  * @augments Backbone.View
   4352  */
   4353 Menu = PriorityList.extend(/** @lends wp.media.view.Menu.prototype */{
   4354 	tagName:   'div',
   4355 	className: 'media-menu',
   4356 	property:  'state',
   4357 	ItemView:  MenuItem,
   4358 	region:    'menu',
   4359 
   4360 	attributes: {
   4361 		role:               'tablist',
   4362 		'aria-orientation': 'horizontal'
   4363 	},
   4364 
   4365 	initialize: function() {
   4366 		this._views = {};
   4367 
   4368 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
   4369 		delete this.options.views;
   4370 
   4371 		if ( ! this.options.silent ) {
   4372 			this.render();
   4373 		}
   4374 
   4375 		// Initialize the Focus Manager.
   4376 		this.focusManager = new wp.media.view.FocusManager( {
   4377 			el:   this.el,
   4378 			mode: 'tabsNavigation'
   4379 		} );
   4380 
   4381 		// The menu is always rendered and can be visible or hidden on some frames.
   4382 		this.isVisible = true;
   4383 	},
   4384 
   4385 	/**
   4386 	 * @param {Object} options
   4387 	 * @param {string} id
   4388 	 * @return {wp.media.View}
   4389 	 */
   4390 	toView: function( options, id ) {
   4391 		options = options || {};
   4392 		options[ this.property ] = options[ this.property ] || id;
   4393 		return new this.ItemView( options ).render();
   4394 	},
   4395 
   4396 	ready: function() {
   4397 		/**
   4398 		 * call 'ready' directly on the parent class
   4399 		 */
   4400 		PriorityList.prototype.ready.apply( this, arguments );
   4401 		this.visibility();
   4402 
   4403 		// Set up aria tabs initial attributes.
   4404 		this.focusManager.setupAriaTabs();
   4405 	},
   4406 
   4407 	set: function() {
   4408 		/**
   4409 		 * call 'set' directly on the parent class
   4410 		 */
   4411 		PriorityList.prototype.set.apply( this, arguments );
   4412 		this.visibility();
   4413 	},
   4414 
   4415 	unset: function() {
   4416 		/**
   4417 		 * call 'unset' directly on the parent class
   4418 		 */
   4419 		PriorityList.prototype.unset.apply( this, arguments );
   4420 		this.visibility();
   4421 	},
   4422 
   4423 	visibility: function() {
   4424 		var region = this.region,
   4425 			view = this.controller[ region ].get(),
   4426 			views = this.views.get(),
   4427 			hide = ! views || views.length < 2;
   4428 
   4429 		if ( this === view ) {
   4430 			// Flag this menu as hidden or visible.
   4431 			this.isVisible = ! hide;
   4432 			// Set or remove a CSS class to hide the menu.
   4433 			this.controller.$el.toggleClass( 'hide-' + region, hide );
   4434 		}
   4435 	},
   4436 	/**
   4437 	 * @param {string} id
   4438 	 */
   4439 	select: function( id ) {
   4440 		var view = this.get( id );
   4441 
   4442 		if ( ! view ) {
   4443 			return;
   4444 		}
   4445 
   4446 		this.deselect();
   4447 		view.$el.addClass('active');
   4448 
   4449 		// Set up again the aria tabs initial attributes after the menu updates.
   4450 		this.focusManager.setupAriaTabs();
   4451 	},
   4452 
   4453 	deselect: function() {
   4454 		this.$el.children().removeClass('active');
   4455 	},
   4456 
   4457 	hide: function( id ) {
   4458 		var view = this.get( id );
   4459 
   4460 		if ( ! view ) {
   4461 			return;
   4462 		}
   4463 
   4464 		view.$el.addClass('hidden');
   4465 	},
   4466 
   4467 	show: function( id ) {
   4468 		var view = this.get( id );
   4469 
   4470 		if ( ! view ) {
   4471 			return;
   4472 		}
   4473 
   4474 		view.$el.removeClass('hidden');
   4475 	}
   4476 });
   4477 
   4478 module.exports = Menu;
   4479 
   4480 
   4481 /***/ }),
   4482 
   4483 /***/ "KerO":
   4484 /***/ (function(module, exports) {
   4485 
   4486 var l10n = wp.media.view.l10n,
   4487 	All;
   4488 
   4489 /**
   4490  * wp.media.view.AttachmentFilters.All
   4491  *
   4492  * @memberOf wp.media.view.AttachmentFilters
   4493  *
   4494  * @class
   4495  * @augments wp.media.view.AttachmentFilters
   4496  * @augments wp.media.View
   4497  * @augments wp.Backbone.View
   4498  * @augments Backbone.View
   4499  */
   4500 All = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.All.prototype */{
   4501 	createFilters: function() {
   4502 		var filters = {},
   4503 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0;
   4504 
   4505 		_.each( wp.media.view.settings.mimeTypes || {}, function( text, key ) {
   4506 			filters[ key ] = {
   4507 				text: text,
   4508 				props: {
   4509 					status:  null,
   4510 					type:    key,
   4511 					uploadedTo: null,
   4512 					orderby: 'date',
   4513 					order:   'DESC',
   4514 					author:  null
   4515 				}
   4516 			};
   4517 		});
   4518 
   4519 		filters.all = {
   4520 			text:  l10n.allMediaItems,
   4521 			props: {
   4522 				status:  null,
   4523 				type:    null,
   4524 				uploadedTo: null,
   4525 				orderby: 'date',
   4526 				order:   'DESC',
   4527 				author:  null
   4528 			},
   4529 			priority: 10
   4530 		};
   4531 
   4532 		if ( wp.media.view.settings.post.id ) {
   4533 			filters.uploaded = {
   4534 				text:  l10n.uploadedToThisPost,
   4535 				props: {
   4536 					status:  null,
   4537 					type:    null,
   4538 					uploadedTo: wp.media.view.settings.post.id,
   4539 					orderby: 'menuOrder',
   4540 					order:   'ASC',
   4541 					author:  null
   4542 				},
   4543 				priority: 20
   4544 			};
   4545 		}
   4546 
   4547 		filters.unattached = {
   4548 			text:  l10n.unattached,
   4549 			props: {
   4550 				status:     null,
   4551 				uploadedTo: 0,
   4552 				type:       null,
   4553 				orderby:    'menuOrder',
   4554 				order:      'ASC',
   4555 				author:     null
   4556 			},
   4557 			priority: 50
   4558 		};
   4559 
   4560 		if ( uid ) {
   4561 			filters.mine = {
   4562 				text:  l10n.mine,
   4563 				props: {
   4564 					status:		null,
   4565 					type:		null,
   4566 					uploadedTo:	null,
   4567 					orderby:	'date',
   4568 					order:		'DESC',
   4569 					author:		uid
   4570 				},
   4571 				priority: 50
   4572 			};
   4573 		}
   4574 
   4575 		if ( wp.media.view.settings.mediaTrash &&
   4576 			this.controller.isModeActive( 'grid' ) ) {
   4577 
   4578 			filters.trash = {
   4579 				text:  l10n.trash,
   4580 				props: {
   4581 					uploadedTo: null,
   4582 					status:     'trash',
   4583 					type:       null,
   4584 					orderby:    'date',
   4585 					order:      'DESC',
   4586 					author:     null
   4587 				},
   4588 				priority: 50
   4589 			};
   4590 		}
   4591 
   4592 		this.filters = filters;
   4593 	}
   4594 });
   4595 
   4596 module.exports = All;
   4597 
   4598 
   4599 /***/ }),
   4600 
   4601 /***/ "LGdN":
   4602 /***/ (function(module, exports) {
   4603 
   4604 /**
   4605  * wp.media.view.Frame
   4606  *
   4607  * A frame is a composite view consisting of one or more regions and one or more
   4608  * states.
   4609  *
   4610  * @memberOf wp.media.view
   4611  *
   4612  * @see wp.media.controller.State
   4613  * @see wp.media.controller.Region
   4614  *
   4615  * @class
   4616  * @augments wp.media.View
   4617  * @augments wp.Backbone.View
   4618  * @augments Backbone.View
   4619  * @mixes wp.media.controller.StateMachine
   4620  */
   4621 var Frame = wp.media.View.extend(/** @lends wp.media.view.Frame.prototype */{
   4622 	initialize: function() {
   4623 		_.defaults( this.options, {
   4624 			mode: [ 'select' ]
   4625 		});
   4626 		this._createRegions();
   4627 		this._createStates();
   4628 		this._createModes();
   4629 	},
   4630 
   4631 	_createRegions: function() {
   4632 		// Clone the regions array.
   4633 		this.regions = this.regions ? this.regions.slice() : [];
   4634 
   4635 		// Initialize regions.
   4636 		_.each( this.regions, function( region ) {
   4637 			this[ region ] = new wp.media.controller.Region({
   4638 				view:     this,
   4639 				id:       region,
   4640 				selector: '.media-frame-' + region
   4641 			});
   4642 		}, this );
   4643 	},
   4644 	/**
   4645 	 * Create the frame's states.
   4646 	 *
   4647 	 * @see wp.media.controller.State
   4648 	 * @see wp.media.controller.StateMachine
   4649 	 *
   4650 	 * @fires wp.media.controller.State#ready
   4651 	 */
   4652 	_createStates: function() {
   4653 		// Create the default `states` collection.
   4654 		this.states = new Backbone.Collection( null, {
   4655 			model: wp.media.controller.State
   4656 		});
   4657 
   4658 		// Ensure states have a reference to the frame.
   4659 		this.states.on( 'add', function( model ) {
   4660 			model.frame = this;
   4661 			model.trigger('ready');
   4662 		}, this );
   4663 
   4664 		if ( this.options.states ) {
   4665 			this.states.add( this.options.states );
   4666 		}
   4667 	},
   4668 
   4669 	/**
   4670 	 * A frame can be in a mode or multiple modes at one time.
   4671 	 *
   4672 	 * For example, the manage media frame can be in the `Bulk Select` or `Edit` mode.
   4673 	 */
   4674 	_createModes: function() {
   4675 		// Store active "modes" that the frame is in. Unrelated to region modes.
   4676 		this.activeModes = new Backbone.Collection();
   4677 		this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
   4678 
   4679 		_.each( this.options.mode, function( mode ) {
   4680 			this.activateMode( mode );
   4681 		}, this );
   4682 	},
   4683 	/**
   4684 	 * Reset all states on the frame to their defaults.
   4685 	 *
   4686 	 * @return {wp.media.view.Frame} Returns itself to allow chaining.
   4687 	 */
   4688 	reset: function() {
   4689 		this.states.invoke( 'trigger', 'reset' );
   4690 		return this;
   4691 	},
   4692 	/**
   4693 	 * Map activeMode collection events to the frame.
   4694 	 */
   4695 	triggerModeEvents: function( model, collection, options ) {
   4696 		var collectionEvent,
   4697 			modeEventMap = {
   4698 				add: 'activate',
   4699 				remove: 'deactivate'
   4700 			},
   4701 			eventToTrigger;
   4702 		// Probably a better way to do this.
   4703 		_.each( options, function( value, key ) {
   4704 			if ( value ) {
   4705 				collectionEvent = key;
   4706 			}
   4707 		} );
   4708 
   4709 		if ( ! _.has( modeEventMap, collectionEvent ) ) {
   4710 			return;
   4711 		}
   4712 
   4713 		eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
   4714 		this.trigger( eventToTrigger );
   4715 	},
   4716 	/**
   4717 	 * Activate a mode on the frame.
   4718 	 *
   4719 	 * @param string mode Mode ID.
   4720 	 * @return {this} Returns itself to allow chaining.
   4721 	 */
   4722 	activateMode: function( mode ) {
   4723 		// Bail if the mode is already active.
   4724 		if ( this.isModeActive( mode ) ) {
   4725 			return;
   4726 		}
   4727 		this.activeModes.add( [ { id: mode } ] );
   4728 		// Add a CSS class to the frame so elements can be styled for the mode.
   4729 		this.$el.addClass( 'mode-' + mode );
   4730 
   4731 		return this;
   4732 	},
   4733 	/**
   4734 	 * Deactivate a mode on the frame.
   4735 	 *
   4736 	 * @param string mode Mode ID.
   4737 	 * @return {this} Returns itself to allow chaining.
   4738 	 */
   4739 	deactivateMode: function( mode ) {
   4740 		// Bail if the mode isn't active.
   4741 		if ( ! this.isModeActive( mode ) ) {
   4742 			return this;
   4743 		}
   4744 		this.activeModes.remove( this.activeModes.where( { id: mode } ) );
   4745 		this.$el.removeClass( 'mode-' + mode );
   4746 		/**
   4747 		 * Frame mode deactivation event.
   4748 		 *
   4749 		 * @event wp.media.view.Frame#{mode}:deactivate
   4750 		 */
   4751 		this.trigger( mode + ':deactivate' );
   4752 
   4753 		return this;
   4754 	},
   4755 	/**
   4756 	 * Check if a mode is enabled on the frame.
   4757 	 *
   4758 	 * @param string mode Mode ID.
   4759 	 * @return bool
   4760 	 */
   4761 	isModeActive: function( mode ) {
   4762 		return Boolean( this.activeModes.where( { id: mode } ).length );
   4763 	}
   4764 });
   4765 
   4766 // Make the `Frame` a `StateMachine`.
   4767 _.extend( Frame.prototype, wp.media.controller.StateMachine.prototype );
   4768 
   4769 module.exports = Frame;
   4770 
   4771 
   4772 /***/ }),
   4773 
   4774 /***/ "LND6":
   4775 /***/ (function(module, exports) {
   4776 
   4777 var View = wp.media.View,
   4778 	AttachmentCompat;
   4779 
   4780 /**
   4781  * wp.media.view.AttachmentCompat
   4782  *
   4783  * A view to display fields added via the `attachment_fields_to_edit` filter.
   4784  *
   4785  * @memberOf wp.media.view
   4786  *
   4787  * @class
   4788  * @augments wp.media.View
   4789  * @augments wp.Backbone.View
   4790  * @augments Backbone.View
   4791  */
   4792 AttachmentCompat = View.extend(/** @lends wp.media.view.AttachmentCompat.prototype */{
   4793 	tagName:   'form',
   4794 	className: 'compat-item',
   4795 
   4796 	events: {
   4797 		'submit':          'preventDefault',
   4798 		'change input':    'save',
   4799 		'change select':   'save',
   4800 		'change textarea': 'save'
   4801 	},
   4802 
   4803 	initialize: function() {
   4804 		this.listenTo( this.model, 'change:compat', this.render );
   4805 	},
   4806 	/**
   4807 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
   4808 	 */
   4809 	dispose: function() {
   4810 		if ( this.$(':focus').length ) {
   4811 			this.save();
   4812 		}
   4813 		/**
   4814 		 * call 'dispose' directly on the parent class
   4815 		 */
   4816 		return View.prototype.dispose.apply( this, arguments );
   4817 	},
   4818 	/**
   4819 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
   4820 	 */
   4821 	render: function() {
   4822 		var compat = this.model.get('compat');
   4823 		if ( ! compat || ! compat.item ) {
   4824 			return;
   4825 		}
   4826 
   4827 		this.views.detach();
   4828 		this.$el.html( compat.item );
   4829 		this.views.render();
   4830 		return this;
   4831 	},
   4832 	/**
   4833 	 * @param {Object} event
   4834 	 */
   4835 	preventDefault: function( event ) {
   4836 		event.preventDefault();
   4837 	},
   4838 	/**
   4839 	 * @param {Object} event
   4840 	 */
   4841 	save: function( event ) {
   4842 		var data = {};
   4843 
   4844 		if ( event ) {
   4845 			event.preventDefault();
   4846 		}
   4847 
   4848 		_.each( this.$el.serializeArray(), function( pair ) {
   4849 			data[ pair.name ] = pair.value;
   4850 		});
   4851 
   4852 		this.controller.trigger( 'attachment:compat:waiting', ['waiting'] );
   4853 		this.model.saveCompat( data ).always( _.bind( this.postSave, this ) );
   4854 	},
   4855 
   4856 	postSave: function() {
   4857 		this.controller.trigger( 'attachment:compat:ready', ['ready'] );
   4858 	}
   4859 });
   4860 
   4861 module.exports = AttachmentCompat;
   4862 
   4863 
   4864 /***/ }),
   4865 
   4866 /***/ "LZpE":
   4867 /***/ (function(module, exports) {
   4868 
   4869 /**
   4870  * wp.media.view.Button
   4871  *
   4872  * @memberOf wp.media.view
   4873  *
   4874  * @class
   4875  * @augments wp.media.View
   4876  * @augments wp.Backbone.View
   4877  * @augments Backbone.View
   4878  */
   4879 var Button = wp.media.View.extend(/** @lends wp.media.view.Button.prototype */{
   4880 	tagName:    'button',
   4881 	className:  'media-button',
   4882 	attributes: { type: 'button' },
   4883 
   4884 	events: {
   4885 		'click': 'click'
   4886 	},
   4887 
   4888 	defaults: {
   4889 		text:     '',
   4890 		style:    '',
   4891 		size:     'large',
   4892 		disabled: false
   4893 	},
   4894 
   4895 	initialize: function() {
   4896 		/**
   4897 		 * Create a model with the provided `defaults`.
   4898 		 *
   4899 		 * @member {Backbone.Model}
   4900 		 */
   4901 		this.model = new Backbone.Model( this.defaults );
   4902 
   4903 		// If any of the `options` have a key from `defaults`, apply its
   4904 		// value to the `model` and remove it from the `options object.
   4905 		_.each( this.defaults, function( def, key ) {
   4906 			var value = this.options[ key ];
   4907 			if ( _.isUndefined( value ) ) {
   4908 				return;
   4909 			}
   4910 
   4911 			this.model.set( key, value );
   4912 			delete this.options[ key ];
   4913 		}, this );
   4914 
   4915 		this.listenTo( this.model, 'change', this.render );
   4916 	},
   4917 	/**
   4918 	 * @return {wp.media.view.Button} Returns itself to allow chaining.
   4919 	 */
   4920 	render: function() {
   4921 		var classes = [ 'button', this.className ],
   4922 			model = this.model.toJSON();
   4923 
   4924 		if ( model.style ) {
   4925 			classes.push( 'button-' + model.style );
   4926 		}
   4927 
   4928 		if ( model.size ) {
   4929 			classes.push( 'button-' + model.size );
   4930 		}
   4931 
   4932 		classes = _.uniq( classes.concat( this.options.classes ) );
   4933 		this.el.className = classes.join(' ');
   4934 
   4935 		this.$el.attr( 'disabled', model.disabled );
   4936 		this.$el.text( this.model.get('text') );
   4937 
   4938 		return this;
   4939 	},
   4940 	/**
   4941 	 * @param {Object} event
   4942 	 */
   4943 	click: function( event ) {
   4944 		if ( '#' === this.attributes.href ) {
   4945 			event.preventDefault();
   4946 		}
   4947 
   4948 		if ( this.options.click && ! this.model.get('disabled') ) {
   4949 			this.options.click.apply( this, arguments );
   4950 		}
   4951 	}
   4952 });
   4953 
   4954 module.exports = Button;
   4955 
   4956 
   4957 /***/ }),
   4958 
   4959 /***/ "M+xU":
   4960 /***/ (function(module, exports) {
   4961 
   4962 var l10n = wp.media.view.l10n,
   4963 	Cropper;
   4964 
   4965 /**
   4966  * wp.media.controller.Cropper
   4967  *
   4968  * A class for cropping an image when called from the header media customization panel.
   4969  *
   4970  * @memberOf wp.media.controller
   4971  *
   4972  * @class
   4973  * @augments wp.media.controller.State
   4974  * @augments Backbone.Model
   4975  */
   4976 Cropper = wp.media.controller.State.extend(/** @lends wp.media.controller.Cropper.prototype */{
   4977 	defaults: {
   4978 		id:          'cropper',
   4979 		title:       l10n.cropImage,
   4980 		// Region mode defaults.
   4981 		toolbar:     'crop',
   4982 		content:     'crop',
   4983 		router:      false,
   4984 		canSkipCrop: false,
   4985 
   4986 		// Default doCrop Ajax arguments to allow the Customizer (for example) to inject state.
   4987 		doCropArgs: {}
   4988 	},
   4989 
   4990 	/**
   4991 	 * Shows the crop image window when called from the Add new image button.
   4992 	 *
   4993 	 * @since 4.2.0
   4994 	 *
   4995 	 * @return {void}
   4996 	 */
   4997 	activate: function() {
   4998 		this.frame.on( 'content:create:crop', this.createCropContent, this );
   4999 		this.frame.on( 'close', this.removeCropper, this );
   5000 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
   5001 	},
   5002 
   5003 	/**
   5004 	 * Changes the state of the toolbar window to browse mode.
   5005 	 *
   5006 	 * @since 4.2.0
   5007 	 *
   5008 	 * @return {void}
   5009 	 */
   5010 	deactivate: function() {
   5011 		this.frame.toolbar.mode('browse');
   5012 	},
   5013 
   5014 	/**
   5015 	 * Creates the crop image window.
   5016 	 *
   5017 	 * Initialized when clicking on the Select and Crop button.
   5018 	 *
   5019 	 * @since 4.2.0
   5020 	 *
   5021 	 * @fires crop window
   5022 	 *
   5023 	 * @return {void}
   5024 	 */
   5025 	createCropContent: function() {
   5026 		this.cropperView = new wp.media.view.Cropper({
   5027 			controller: this,
   5028 			attachment: this.get('selection').first()
   5029 		});
   5030 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
   5031 		this.frame.content.set(this.cropperView);
   5032 
   5033 	},
   5034 
   5035 	/**
   5036 	 * Removes the image selection and closes the cropping window.
   5037 	 *
   5038 	 * @since 4.2.0
   5039 	 *
   5040 	 * @return {void}
   5041 	 */
   5042 	removeCropper: function() {
   5043 		this.imgSelect.cancelSelection();
   5044 		this.imgSelect.setOptions({remove: true});
   5045 		this.imgSelect.update();
   5046 		this.cropperView.remove();
   5047 	},
   5048 
   5049 	/**
   5050 	 * Checks if cropping can be skipped and creates crop toolbar accordingly.
   5051 	 *
   5052 	 * @since 4.2.0
   5053 	 *
   5054 	 * @return {void}
   5055 	 */
   5056 	createCropToolbar: function() {
   5057 		var canSkipCrop, toolbarOptions;
   5058 
   5059 		canSkipCrop = this.get('canSkipCrop') || false;
   5060 
   5061 		toolbarOptions = {
   5062 			controller: this.frame,
   5063 			items: {
   5064 				insert: {
   5065 					style:    'primary',
   5066 					text:     l10n.cropImage,
   5067 					priority: 80,
   5068 					requires: { library: false, selection: false },
   5069 
   5070 					click: function() {
   5071 						var controller = this.controller,
   5072 							selection;
   5073 
   5074 						selection = controller.state().get('selection').first();
   5075 						selection.set({cropDetails: controller.state().imgSelect.getSelection()});
   5076 
   5077 						this.$el.text(l10n.cropping);
   5078 						this.$el.attr('disabled', true);
   5079 
   5080 						controller.state().doCrop( selection ).done( function( croppedImage ) {
   5081 							controller.trigger('cropped', croppedImage );
   5082 							controller.close();
   5083 						}).fail( function() {
   5084 							controller.trigger('content:error:crop');
   5085 						});
   5086 					}
   5087 				}
   5088 			}
   5089 		};
   5090 
   5091 		if ( canSkipCrop ) {
   5092 			_.extend( toolbarOptions.items, {
   5093 				skip: {
   5094 					style:      'secondary',
   5095 					text:       l10n.skipCropping,
   5096 					priority:   70,
   5097 					requires:   { library: false, selection: false },
   5098 					click:      function() {
   5099 						var selection = this.controller.state().get('selection').first();
   5100 						this.controller.state().cropperView.remove();
   5101 						this.controller.trigger('skippedcrop', selection);
   5102 						this.controller.close();
   5103 					}
   5104 				}
   5105 			});
   5106 		}
   5107 
   5108 		this.frame.toolbar.set( new wp.media.view.Toolbar(toolbarOptions) );
   5109 	},
   5110 
   5111 	/**
   5112 	 * Creates an object with the image attachment and crop properties.
   5113 	 *
   5114 	 * @since 4.2.0
   5115 	 *
   5116 	 * @return {$.promise} A jQuery promise with the custom header crop details.
   5117 	 */
   5118 	doCrop: function( attachment ) {
   5119 		return wp.ajax.post( 'custom-header-crop', _.extend(
   5120 			{},
   5121 			this.defaults.doCropArgs,
   5122 			{
   5123 				nonce: attachment.get( 'nonces' ).edit,
   5124 				id: attachment.get( 'id' ),
   5125 				cropDetails: attachment.get( 'cropDetails' )
   5126 			}
   5127 		) );
   5128 	}
   5129 });
   5130 
   5131 module.exports = Cropper;
   5132 
   5133 
   5134 /***/ }),
   5135 
   5136 /***/ "M5ZC":
   5137 /***/ (function(module, exports) {
   5138 
   5139 /**
   5140  * wp.media.controller.State
   5141  *
   5142  * A state is a step in a workflow that when set will trigger the controllers
   5143  * for the regions to be updated as specified in the frame.
   5144  *
   5145  * A state has an event-driven lifecycle:
   5146  *
   5147  *     'ready'      triggers when a state is added to a state machine's collection.
   5148  *     'activate'   triggers when a state is activated by a state machine.
   5149  *     'deactivate' triggers when a state is deactivated by a state machine.
   5150  *     'reset'      is not triggered automatically. It should be invoked by the
   5151  *                  proper controller to reset the state to its default.
   5152  *
   5153  * @memberOf wp.media.controller
   5154  *
   5155  * @class
   5156  * @augments Backbone.Model
   5157  */
   5158 var State = Backbone.Model.extend(/** @lends wp.media.controller.State.prototype */{
   5159 	/**
   5160 	 * Constructor.
   5161 	 *
   5162 	 * @since 3.5.0
   5163 	 */
   5164 	constructor: function() {
   5165 		this.on( 'activate', this._preActivate, this );
   5166 		this.on( 'activate', this.activate, this );
   5167 		this.on( 'activate', this._postActivate, this );
   5168 		this.on( 'deactivate', this._deactivate, this );
   5169 		this.on( 'deactivate', this.deactivate, this );
   5170 		this.on( 'reset', this.reset, this );
   5171 		this.on( 'ready', this._ready, this );
   5172 		this.on( 'ready', this.ready, this );
   5173 		/**
   5174 		 * Call parent constructor with passed arguments
   5175 		 */
   5176 		Backbone.Model.apply( this, arguments );
   5177 		this.on( 'change:menu', this._updateMenu, this );
   5178 	},
   5179 	/**
   5180 	 * Ready event callback.
   5181 	 *
   5182 	 * @abstract
   5183 	 * @since 3.5.0
   5184 	 */
   5185 	ready: function() {},
   5186 
   5187 	/**
   5188 	 * Activate event callback.
   5189 	 *
   5190 	 * @abstract
   5191 	 * @since 3.5.0
   5192 	 */
   5193 	activate: function() {},
   5194 
   5195 	/**
   5196 	 * Deactivate event callback.
   5197 	 *
   5198 	 * @abstract
   5199 	 * @since 3.5.0
   5200 	 */
   5201 	deactivate: function() {},
   5202 
   5203 	/**
   5204 	 * Reset event callback.
   5205 	 *
   5206 	 * @abstract
   5207 	 * @since 3.5.0
   5208 	 */
   5209 	reset: function() {},
   5210 
   5211 	/**
   5212 	 * @since 3.5.0
   5213 	 * @access private
   5214 	 */
   5215 	_ready: function() {
   5216 		this._updateMenu();
   5217 	},
   5218 
   5219 	/**
   5220 	 * @since 3.5.0
   5221 	 * @access private
   5222 	*/
   5223 	_preActivate: function() {
   5224 		this.active = true;
   5225 	},
   5226 
   5227 	/**
   5228 	 * @since 3.5.0
   5229 	 * @access private
   5230 	 */
   5231 	_postActivate: function() {
   5232 		this.on( 'change:menu', this._menu, this );
   5233 		this.on( 'change:titleMode', this._title, this );
   5234 		this.on( 'change:content', this._content, this );
   5235 		this.on( 'change:toolbar', this._toolbar, this );
   5236 
   5237 		this.frame.on( 'title:render:default', this._renderTitle, this );
   5238 
   5239 		this._title();
   5240 		this._menu();
   5241 		this._toolbar();
   5242 		this._content();
   5243 		this._router();
   5244 	},
   5245 
   5246 	/**
   5247 	 * @since 3.5.0
   5248 	 * @access private
   5249 	 */
   5250 	_deactivate: function() {
   5251 		this.active = false;
   5252 
   5253 		this.frame.off( 'title:render:default', this._renderTitle, this );
   5254 
   5255 		this.off( 'change:menu', this._menu, this );
   5256 		this.off( 'change:titleMode', this._title, this );
   5257 		this.off( 'change:content', this._content, this );
   5258 		this.off( 'change:toolbar', this._toolbar, this );
   5259 	},
   5260 
   5261 	/**
   5262 	 * @since 3.5.0
   5263 	 * @access private
   5264 	 */
   5265 	_title: function() {
   5266 		this.frame.title.render( this.get('titleMode') || 'default' );
   5267 	},
   5268 
   5269 	/**
   5270 	 * @since 3.5.0
   5271 	 * @access private
   5272 	 */
   5273 	_renderTitle: function( view ) {
   5274 		view.$el.text( this.get('title') || '' );
   5275 	},
   5276 
   5277 	/**
   5278 	 * @since 3.5.0
   5279 	 * @access private
   5280 	 */
   5281 	_router: function() {
   5282 		var router = this.frame.router,
   5283 			mode = this.get('router'),
   5284 			view;
   5285 
   5286 		this.frame.$el.toggleClass( 'hide-router', ! mode );
   5287 		if ( ! mode ) {
   5288 			return;
   5289 		}
   5290 
   5291 		this.frame.router.render( mode );
   5292 
   5293 		view = router.get();
   5294 		if ( view && view.select ) {
   5295 			view.select( this.frame.content.mode() );
   5296 		}
   5297 	},
   5298 
   5299 	/**
   5300 	 * @since 3.5.0
   5301 	 * @access private
   5302 	 */
   5303 	_menu: function() {
   5304 		var menu = this.frame.menu,
   5305 			mode = this.get('menu'),
   5306 			view;
   5307 
   5308 		this.frame.$el.toggleClass( 'hide-menu', ! mode );
   5309 		if ( ! mode ) {
   5310 			return;
   5311 		}
   5312 
   5313 		menu.mode( mode );
   5314 
   5315 		view = menu.get();
   5316 		if ( view && view.select ) {
   5317 			view.select( this.id );
   5318 		}
   5319 	},
   5320 
   5321 	/**
   5322 	 * @since 3.5.0
   5323 	 * @access private
   5324 	 */
   5325 	_updateMenu: function() {
   5326 		var previous = this.previous('menu'),
   5327 			menu = this.get('menu');
   5328 
   5329 		if ( previous ) {
   5330 			this.frame.off( 'menu:render:' + previous, this._renderMenu, this );
   5331 		}
   5332 
   5333 		if ( menu ) {
   5334 			this.frame.on( 'menu:render:' + menu, this._renderMenu, this );
   5335 		}
   5336 	},
   5337 
   5338 	/**
   5339 	 * Create a view in the media menu for the state.
   5340 	 *
   5341 	 * @since 3.5.0
   5342 	 * @access private
   5343 	 *
   5344 	 * @param {media.view.Menu} view The menu view.
   5345 	 */
   5346 	_renderMenu: function( view ) {
   5347 		var menuItem = this.get('menuItem'),
   5348 			title = this.get('title'),
   5349 			priority = this.get('priority');
   5350 
   5351 		if ( ! menuItem && title ) {
   5352 			menuItem = { text: title };
   5353 
   5354 			if ( priority ) {
   5355 				menuItem.priority = priority;
   5356 			}
   5357 		}
   5358 
   5359 		if ( ! menuItem ) {
   5360 			return;
   5361 		}
   5362 
   5363 		view.set( this.id, menuItem );
   5364 	}
   5365 });
   5366 
   5367 _.each(['toolbar','content'], function( region ) {
   5368 	/**
   5369 	 * @access private
   5370 	 */
   5371 	State.prototype[ '_' + region ] = function() {
   5372 		var mode = this.get( region );
   5373 		if ( mode ) {
   5374 			this.frame[ region ].render( mode );
   5375 		}
   5376 	};
   5377 });
   5378 
   5379 module.exports = State;
   5380 
   5381 
   5382 /***/ }),
   5383 
   5384 /***/ "Mt+m":
   5385 /***/ (function(module, exports) {
   5386 
   5387 var Library = wp.media.controller.Library,
   5388 	l10n = wp.media.view.l10n,
   5389 	$ = jQuery,
   5390 	CollectionEdit;
   5391 
   5392 /**
   5393  * wp.media.controller.CollectionEdit
   5394  *
   5395  * A state for editing a collection, which is used by audio and video playlists,
   5396  * and can be used for other collections.
   5397  *
   5398  * @memberOf wp.media.controller
   5399  *
   5400  * @class
   5401  * @augments wp.media.controller.Library
   5402  * @augments wp.media.controller.State
   5403  * @augments Backbone.Model
   5404  *
   5405  * @param {object}                     [attributes]                      The attributes hash passed to the state.
   5406  * @param {string}                     attributes.title                  Title for the state. Displays in the media menu and the frame's title region.
   5407  * @param {wp.media.model.Attachments} [attributes.library]              The attachments collection to edit.
   5408  *                                                                       If one is not supplied, an empty media.model.Selection collection is created.
   5409  * @param {boolean}                    [attributes.multiple=false]       Whether multi-select is enabled.
   5410  * @param {string}                     [attributes.content=browse]       Initial mode for the content region.
   5411  * @param {string}                     attributes.menu                   Initial mode for the menu region. @todo this needs a better explanation.
   5412  * @param {boolean}                    [attributes.searchable=false]     Whether the library is searchable.
   5413  * @param {boolean}                    [attributes.sortable=true]        Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
   5414  * @param {boolean}                    [attributes.date=true]            Whether to show the date filter in the browser's toolbar.
   5415  * @param {boolean}                    [attributes.describe=true]        Whether to offer UI to describe the attachments - e.g. captioning images in a gallery.
   5416  * @param {boolean}                    [attributes.dragInfo=true]        Whether to show instructional text about the attachments being sortable.
   5417  * @param {boolean}                    [attributes.dragInfoText]         Instructional text about the attachments being sortable.
   5418  * @param {int}                        [attributes.idealColumnWidth=170] The ideal column width in pixels for attachments.
   5419  * @param {boolean}                    [attributes.editing=false]        Whether the gallery is being created, or editing an existing instance.
   5420  * @param {int}                        [attributes.priority=60]          The priority for the state link in the media menu.
   5421  * @param {boolean}                    [attributes.syncSelection=false]  Whether the Attachments selection should be persisted from the last state.
   5422  *                                                                       Defaults to false for this state, because the library passed in  *is* the selection.
   5423  * @param {view}                       [attributes.SettingsView]         The view to edit the collection instance settings (e.g. Playlist settings with "Show tracklist" checkbox).
   5424  * @param {view}                       [attributes.AttachmentView]       The single `Attachment` view to be used in the `Attachments`.
   5425  *                                                                       If none supplied, defaults to wp.media.view.Attachment.EditLibrary.
   5426  * @param {string}                     attributes.type                   The collection's media type. (e.g. 'video').
   5427  * @param {string}                     attributes.collectionType         The collection type. (e.g. 'playlist').
   5428  */
   5429 CollectionEdit = Library.extend(/** @lends wp.media.controller.CollectionEdit.prototype */{
   5430 	defaults: {
   5431 		multiple:         false,
   5432 		sortable:         true,
   5433 		date:             false,
   5434 		searchable:       false,
   5435 		content:          'browse',
   5436 		describe:         true,
   5437 		dragInfo:         true,
   5438 		idealColumnWidth: 170,
   5439 		editing:          false,
   5440 		priority:         60,
   5441 		SettingsView:     false,
   5442 		syncSelection:    false
   5443 	},
   5444 
   5445 	/**
   5446 	 * @since 3.9.0
   5447 	 */
   5448 	initialize: function() {
   5449 		var collectionType = this.get('collectionType');
   5450 
   5451 		if ( 'video' === this.get( 'type' ) ) {
   5452 			collectionType = 'video-' + collectionType;
   5453 		}
   5454 
   5455 		this.set( 'id', collectionType + '-edit' );
   5456 		this.set( 'toolbar', collectionType + '-edit' );
   5457 
   5458 		// If we haven't been provided a `library`, create a `Selection`.
   5459 		if ( ! this.get('library') ) {
   5460 			this.set( 'library', new wp.media.model.Selection() );
   5461 		}
   5462 		// The single `Attachment` view to be used in the `Attachments` view.
   5463 		if ( ! this.get('AttachmentView') ) {
   5464 			this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );
   5465 		}
   5466 		Library.prototype.initialize.apply( this, arguments );
   5467 	},
   5468 
   5469 	/**
   5470 	 * @since 3.9.0
   5471 	 */
   5472 	activate: function() {
   5473 		var library = this.get('library');
   5474 
   5475 		// Limit the library to images only.
   5476 		library.props.set( 'type', this.get( 'type' ) );
   5477 
   5478 		// Watch for uploaded attachments.
   5479 		this.get('library').observe( wp.Uploader.queue );
   5480 
   5481 		this.frame.on( 'content:render:browse', this.renderSettings, this );
   5482 
   5483 		Library.prototype.activate.apply( this, arguments );
   5484 	},
   5485 
   5486 	/**
   5487 	 * @since 3.9.0
   5488 	 */
   5489 	deactivate: function() {
   5490 		// Stop watching for uploaded attachments.
   5491 		this.get('library').unobserve( wp.Uploader.queue );
   5492 
   5493 		this.frame.off( 'content:render:browse', this.renderSettings, this );
   5494 
   5495 		Library.prototype.deactivate.apply( this, arguments );
   5496 	},
   5497 
   5498 	/**
   5499 	 * Render the collection embed settings view in the browser sidebar.
   5500 	 *
   5501 	 * @todo This is against the pattern elsewhere in media. Typically the frame
   5502 	 *       is responsible for adding region mode callbacks. Explain.
   5503 	 *
   5504 	 * @since 3.9.0
   5505 	 *
   5506 	 * @param {wp.media.view.attachmentsBrowser} The attachments browser view.
   5507 	 */
   5508 	renderSettings: function( attachmentsBrowserView ) {
   5509 		var library = this.get('library'),
   5510 			collectionType = this.get('collectionType'),
   5511 			dragInfoText = this.get('dragInfoText'),
   5512 			SettingsView = this.get('SettingsView'),
   5513 			obj = {};
   5514 
   5515 		if ( ! library || ! attachmentsBrowserView ) {
   5516 			return;
   5517 		}
   5518 
   5519 		library[ collectionType ] = library[ collectionType ] || new Backbone.Model();
   5520 
   5521 		obj[ collectionType ] = new SettingsView({
   5522 			controller: this,
   5523 			model:      library[ collectionType ],
   5524 			priority:   40
   5525 		});
   5526 
   5527 		attachmentsBrowserView.sidebar.set( obj );
   5528 
   5529 		if ( dragInfoText ) {
   5530 			attachmentsBrowserView.toolbar.set( 'dragInfo', new wp.media.View({
   5531 				el: $( '<div class="instructions">' + dragInfoText + '</div>' )[0],
   5532 				priority: -40
   5533 			}) );
   5534 		}
   5535 
   5536 		// Add the 'Reverse order' button to the toolbar.
   5537 		attachmentsBrowserView.toolbar.set( 'reverse', {
   5538 			text:     l10n.reverseOrder,
   5539 			priority: 80,
   5540 
   5541 			click: function() {
   5542 				library.reset( library.toArray().reverse() );
   5543 			}
   5544 		});
   5545 	}
   5546 });
   5547 
   5548 module.exports = CollectionEdit;
   5549 
   5550 
   5551 /***/ }),
   5552 
   5553 /***/ "NguE":
   5554 /***/ (function(module, exports) {
   5555 
   5556 var View = wp.media.View,
   5557 	UploaderStatus;
   5558 
   5559 /**
   5560  * wp.media.view.UploaderStatus
   5561  *
   5562  * An uploader status for on-going uploads.
   5563  *
   5564  * @memberOf wp.media.view
   5565  *
   5566  * @class
   5567  * @augments wp.media.View
   5568  * @augments wp.Backbone.View
   5569  * @augments Backbone.View
   5570  */
   5571 UploaderStatus = View.extend(/** @lends wp.media.view.UploaderStatus.prototype */{
   5572 	className: 'media-uploader-status',
   5573 	template:  wp.template('uploader-status'),
   5574 
   5575 	events: {
   5576 		'click .upload-dismiss-errors': 'dismiss'
   5577 	},
   5578 
   5579 	initialize: function() {
   5580 		this.queue = wp.Uploader.queue;
   5581 		this.queue.on( 'add remove reset', this.visibility, this );
   5582 		this.queue.on( 'add remove reset change:percent', this.progress, this );
   5583 		this.queue.on( 'add remove reset change:uploading', this.info, this );
   5584 
   5585 		this.errors = wp.Uploader.errors;
   5586 		this.errors.reset();
   5587 		this.errors.on( 'add remove reset', this.visibility, this );
   5588 		this.errors.on( 'add', this.error, this );
   5589 	},
   5590 	/**
   5591 	 * @return {wp.media.view.UploaderStatus}
   5592 	 */
   5593 	dispose: function() {
   5594 		wp.Uploader.queue.off( null, null, this );
   5595 		/**
   5596 		 * call 'dispose' directly on the parent class
   5597 		 */
   5598 		View.prototype.dispose.apply( this, arguments );
   5599 		return this;
   5600 	},
   5601 
   5602 	visibility: function() {
   5603 		this.$el.toggleClass( 'uploading', !! this.queue.length );
   5604 		this.$el.toggleClass( 'errors', !! this.errors.length );
   5605 		this.$el.toggle( !! this.queue.length || !! this.errors.length );
   5606 	},
   5607 
   5608 	ready: function() {
   5609 		_.each({
   5610 			'$bar':      '.media-progress-bar div',
   5611 			'$index':    '.upload-index',
   5612 			'$total':    '.upload-total',
   5613 			'$filename': '.upload-filename'
   5614 		}, function( selector, key ) {
   5615 			this[ key ] = this.$( selector );
   5616 		}, this );
   5617 
   5618 		this.visibility();
   5619 		this.progress();
   5620 		this.info();
   5621 	},
   5622 
   5623 	progress: function() {
   5624 		var queue = this.queue,
   5625 			$bar = this.$bar;
   5626 
   5627 		if ( ! $bar || ! queue.length ) {
   5628 			return;
   5629 		}
   5630 
   5631 		$bar.width( ( queue.reduce( function( memo, attachment ) {
   5632 			if ( ! attachment.get('uploading') ) {
   5633 				return memo + 100;
   5634 			}
   5635 
   5636 			var percent = attachment.get('percent');
   5637 			return memo + ( _.isNumber( percent ) ? percent : 100 );
   5638 		}, 0 ) / queue.length ) + '%' );
   5639 	},
   5640 
   5641 	info: function() {
   5642 		var queue = this.queue,
   5643 			index = 0, active;
   5644 
   5645 		if ( ! queue.length ) {
   5646 			return;
   5647 		}
   5648 
   5649 		active = this.queue.find( function( attachment, i ) {
   5650 			index = i;
   5651 			return attachment.get('uploading');
   5652 		});
   5653 
   5654 		if ( this.$index && this.$total && this.$filename ) {
   5655 			this.$index.text( index + 1 );
   5656 			this.$total.text( queue.length );
   5657 			this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
   5658 		}
   5659 	},
   5660 	/**
   5661 	 * @param {string} filename
   5662 	 * @return {string}
   5663 	 */
   5664 	filename: function( filename ) {
   5665 		return _.escape( filename );
   5666 	},
   5667 	/**
   5668 	 * @param {Backbone.Model} error
   5669 	 */
   5670 	error: function( error ) {
   5671 		var statusError = new wp.media.view.UploaderStatusError( {
   5672 			filename: this.filename( error.get( 'file' ).name ),
   5673 			message:  error.get( 'message' )
   5674 		} );
   5675 
   5676 		var buttonClose = this.$el.find( 'button' );
   5677 
   5678 		// Can show additional info here while retrying to create image sub-sizes.
   5679 		this.views.add( '.upload-errors', statusError, { at: 0 } );
   5680 		_.delay( function() {
   5681 			buttonClose.trigger( 'focus' );
   5682 			wp.a11y.speak( error.get( 'message' ), 'assertive' );
   5683 		}, 1000 );
   5684 	},
   5685 
   5686 	dismiss: function() {
   5687 		var errors = this.views.get('.upload-errors');
   5688 
   5689 		if ( errors ) {
   5690 			_.invoke( errors, 'remove' );
   5691 		}
   5692 		wp.Uploader.errors.reset();
   5693 		// Move focus to the modal after the dismiss button gets removed from the DOM.
   5694 		if ( this.controller.modal ) {
   5695 			this.controller.modal.focusManager.focus();
   5696 		}
   5697 	}
   5698 });
   5699 
   5700 module.exports = UploaderStatus;
   5701 
   5702 
   5703 /***/ }),
   5704 
   5705 /***/ "NjyZ":
   5706 /***/ (function(module, exports) {
   5707 
   5708 /**
   5709  * wp.media.view.PriorityList
   5710  *
   5711  * @memberOf wp.media.view
   5712  *
   5713  * @class
   5714  * @augments wp.media.View
   5715  * @augments wp.Backbone.View
   5716  * @augments Backbone.View
   5717  */
   5718 var PriorityList = wp.media.View.extend(/** @lends wp.media.view.PriorityList.prototype */{
   5719 	tagName:   'div',
   5720 
   5721 	initialize: function() {
   5722 		this._views = {};
   5723 
   5724 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
   5725 		delete this.options.views;
   5726 
   5727 		if ( ! this.options.silent ) {
   5728 			this.render();
   5729 		}
   5730 	},
   5731 	/**
   5732 	 * @param {string} id
   5733 	 * @param {wp.media.View|Object} view
   5734 	 * @param {Object} options
   5735 	 * @return {wp.media.view.PriorityList} Returns itself to allow chaining.
   5736 	 */
   5737 	set: function( id, view, options ) {
   5738 		var priority, views, index;
   5739 
   5740 		options = options || {};
   5741 
   5742 		// Accept an object with an `id` : `view` mapping.
   5743 		if ( _.isObject( id ) ) {
   5744 			_.each( id, function( view, id ) {
   5745 				this.set( id, view );
   5746 			}, this );
   5747 			return this;
   5748 		}
   5749 
   5750 		if ( ! (view instanceof Backbone.View) ) {
   5751 			view = this.toView( view, id, options );
   5752 		}
   5753 		view.controller = view.controller || this.controller;
   5754 
   5755 		this.unset( id );
   5756 
   5757 		priority = view.options.priority || 10;
   5758 		views = this.views.get() || [];
   5759 
   5760 		_.find( views, function( existing, i ) {
   5761 			if ( existing.options.priority > priority ) {
   5762 				index = i;
   5763 				return true;
   5764 			}
   5765 		});
   5766 
   5767 		this._views[ id ] = view;
   5768 		this.views.add( view, {
   5769 			at: _.isNumber( index ) ? index : views.length || 0
   5770 		});
   5771 
   5772 		return this;
   5773 	},
   5774 	/**
   5775 	 * @param {string} id
   5776 	 * @return {wp.media.View}
   5777 	 */
   5778 	get: function( id ) {
   5779 		return this._views[ id ];
   5780 	},
   5781 	/**
   5782 	 * @param {string} id
   5783 	 * @return {wp.media.view.PriorityList}
   5784 	 */
   5785 	unset: function( id ) {
   5786 		var view = this.get( id );
   5787 
   5788 		if ( view ) {
   5789 			view.remove();
   5790 		}
   5791 
   5792 		delete this._views[ id ];
   5793 		return this;
   5794 	},
   5795 	/**
   5796 	 * @param {Object} options
   5797 	 * @return {wp.media.View}
   5798 	 */
   5799 	toView: function( options ) {
   5800 		return new wp.media.View( options );
   5801 	}
   5802 });
   5803 
   5804 module.exports = PriorityList;
   5805 
   5806 
   5807 /***/ }),
   5808 
   5809 /***/ "P6DV":
   5810 /***/ (function(module, exports) {
   5811 
   5812 /**
   5813  * wp.media.view.Attachment.EditSelection
   5814  *
   5815  * @memberOf wp.media.view.Attachment
   5816  *
   5817  * @class
   5818  * @augments wp.media.view.Attachment.Selection
   5819  * @augments wp.media.view.Attachment
   5820  * @augments wp.media.View
   5821  * @augments wp.Backbone.View
   5822  * @augments Backbone.View
   5823  */
   5824 var EditSelection = wp.media.view.Attachment.Selection.extend(/** @lends wp.media.view.Attachment.EditSelection.prototype */{
   5825 	buttons: {
   5826 		close: true
   5827 	}
   5828 });
   5829 
   5830 module.exports = EditSelection;
   5831 
   5832 
   5833 /***/ }),
   5834 
   5835 /***/ "PgTd":
   5836 /***/ (function(module, exports) {
   5837 
   5838 /**
   5839  * wp.media.selectionSync
   5840  *
   5841  * Sync an attachments selection in a state with another state.
   5842  *
   5843  * Allows for selecting multiple images in the Add Media workflow, and then
   5844  * switching to the Insert Gallery workflow while preserving the attachments selection.
   5845  *
   5846  * @memberOf wp.media
   5847  *
   5848  * @mixin
   5849  */
   5850 var selectionSync = {
   5851 	/**
   5852 	 * @since 3.5.0
   5853 	 */
   5854 	syncSelection: function() {
   5855 		var selection = this.get('selection'),
   5856 			manager = this.frame._selection;
   5857 
   5858 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
   5859 			return;
   5860 		}
   5861 
   5862 		/*
   5863 		 * If the selection supports multiple items, validate the stored
   5864 		 * attachments based on the new selection's conditions. Record
   5865 		 * the attachments that are not included; we'll maintain a
   5866 		 * reference to those. Other attachments are considered in flux.
   5867 		 */
   5868 		if ( selection.multiple ) {
   5869 			selection.reset( [], { silent: true });
   5870 			selection.validateAll( manager.attachments );
   5871 			manager.difference = _.difference( manager.attachments.models, selection.models );
   5872 		}
   5873 
   5874 		// Sync the selection's single item with the master.
   5875 		selection.single( manager.single );
   5876 	},
   5877 
   5878 	/**
   5879 	 * Record the currently active attachments, which is a combination
   5880 	 * of the selection's attachments and the set of selected
   5881 	 * attachments that this specific selection considered invalid.
   5882 	 * Reset the difference and record the single attachment.
   5883 	 *
   5884 	 * @since 3.5.0
   5885 	 */
   5886 	recordSelection: function() {
   5887 		var selection = this.get('selection'),
   5888 			manager = this.frame._selection;
   5889 
   5890 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
   5891 			return;
   5892 		}
   5893 
   5894 		if ( selection.multiple ) {
   5895 			manager.attachments.reset( selection.toArray().concat( manager.difference ) );
   5896 			manager.difference = [];
   5897 		} else {
   5898 			manager.attachments.add( selection.toArray() );
   5899 		}
   5900 
   5901 		manager.single = selection._single;
   5902 	}
   5903 };
   5904 
   5905 module.exports = selectionSync;
   5906 
   5907 
   5908 /***/ }),
   5909 
   5910 /***/ "Pt9x":
   5911 /***/ (function(module, exports) {
   5912 
   5913 var Frame = wp.media.view.Frame,
   5914 	l10n = wp.media.view.l10n,
   5915 	$ = jQuery,
   5916 	MediaFrame;
   5917 
   5918 /**
   5919  * wp.media.view.MediaFrame
   5920  *
   5921  * The frame used to create the media modal.
   5922  *
   5923  * @memberOf wp.media.view
   5924  *
   5925  * @class
   5926  * @augments wp.media.view.Frame
   5927  * @augments wp.media.View
   5928  * @augments wp.Backbone.View
   5929  * @augments Backbone.View
   5930  * @mixes wp.media.controller.StateMachine
   5931  */
   5932 MediaFrame = Frame.extend(/** @lends wp.media.view.MediaFrame.prototype */{
   5933 	className: 'media-frame',
   5934 	template:  wp.template('media-frame'),
   5935 	regions:   ['menu','title','content','toolbar','router'],
   5936 
   5937 	events: {
   5938 		'click .media-frame-menu-toggle': 'toggleMenu'
   5939 	},
   5940 
   5941 	/**
   5942 	 * @constructs
   5943 	 */
   5944 	initialize: function() {
   5945 		Frame.prototype.initialize.apply( this, arguments );
   5946 
   5947 		_.defaults( this.options, {
   5948 			title:    l10n.mediaFrameDefaultTitle,
   5949 			modal:    true,
   5950 			uploader: true
   5951 		});
   5952 
   5953 		// Ensure core UI is enabled.
   5954 		this.$el.addClass('wp-core-ui');
   5955 
   5956 		// Initialize modal container view.
   5957 		if ( this.options.modal ) {
   5958 			this.modal = new wp.media.view.Modal({
   5959 				controller: this,
   5960 				title:      this.options.title
   5961 			});
   5962 
   5963 			this.modal.content( this );
   5964 		}
   5965 
   5966 		// Force the uploader off if the upload limit has been exceeded or
   5967 		// if the browser isn't supported.
   5968 		if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
   5969 			this.options.uploader = false;
   5970 		}
   5971 
   5972 		// Initialize window-wide uploader.
   5973 		if ( this.options.uploader ) {
   5974 			this.uploader = new wp.media.view.UploaderWindow({
   5975 				controller: this,
   5976 				uploader: {
   5977 					dropzone:  this.modal ? this.modal.$el : this.$el,
   5978 					container: this.$el
   5979 				}
   5980 			});
   5981 			this.views.set( '.media-frame-uploader', this.uploader );
   5982 		}
   5983 
   5984 		this.on( 'attach', _.bind( this.views.ready, this.views ), this );
   5985 
   5986 		// Bind default title creation.
   5987 		this.on( 'title:create:default', this.createTitle, this );
   5988 		this.title.mode('default');
   5989 
   5990 		// Bind default menu.
   5991 		this.on( 'menu:create:default', this.createMenu, this );
   5992 
   5993 		// Set the menu ARIA tab panel attributes when the modal opens.
   5994 		this.on( 'open', this.setMenuTabPanelAriaAttributes, this );
   5995 		// Set the router ARIA tab panel attributes when the modal opens.
   5996 		this.on( 'open', this.setRouterTabPanelAriaAttributes, this );
   5997 
   5998 		// Update the menu ARIA tab panel attributes when the content updates.
   5999 		this.on( 'content:render', this.setMenuTabPanelAriaAttributes, this );
   6000 		// Update the router ARIA tab panel attributes when the content updates.
   6001 		this.on( 'content:render', this.setRouterTabPanelAriaAttributes, this );
   6002 	},
   6003 
   6004 	/**
   6005 	 * Sets the attributes to be used on the menu ARIA tab panel.
   6006 	 *
   6007 	 * @since 5.3.0
   6008 	 *
   6009 	 * @return {void}
   6010 	 */
   6011 	setMenuTabPanelAriaAttributes: function() {
   6012 		var stateId = this.state().get( 'id' ),
   6013 			tabPanelEl = this.$el.find( '.media-frame-tab-panel' ),
   6014 			ariaLabelledby;
   6015 
   6016 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
   6017 
   6018 		if ( this.state().get( 'menu' ) && this.menuView && this.menuView.isVisible ) {
   6019 			ariaLabelledby = 'menu-item-' + stateId;
   6020 
   6021 			// Set the tab panel attributes only if the tabs are visible.
   6022 			tabPanelEl
   6023 				.attr( {
   6024 					role: 'tabpanel',
   6025 					'aria-labelledby': ariaLabelledby,
   6026 					tabIndex: '0'
   6027 				} );
   6028 		}
   6029 	},
   6030 
   6031 	/**
   6032 	 * Sets the attributes to be used on the router ARIA tab panel.
   6033 	 *
   6034 	 * @since 5.3.0
   6035 	 *
   6036 	 * @return {void}
   6037 	 */
   6038 	setRouterTabPanelAriaAttributes: function() {
   6039 		var tabPanelEl = this.$el.find( '.media-frame-content' ),
   6040 			ariaLabelledby;
   6041 
   6042 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
   6043 
   6044 		// Set the tab panel attributes only if the tabs are visible.
   6045 		if ( this.state().get( 'router' ) && this.routerView && this.routerView.isVisible && this.content._mode ) {
   6046 			ariaLabelledby = 'menu-item-' + this.content._mode;
   6047 
   6048 			tabPanelEl
   6049 				.attr( {
   6050 					role: 'tabpanel',
   6051 					'aria-labelledby': ariaLabelledby,
   6052 					tabIndex: '0'
   6053 				} );
   6054 		}
   6055 	},
   6056 
   6057 	/**
   6058 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
   6059 	 */
   6060 	render: function() {
   6061 		// Activate the default state if no active state exists.
   6062 		if ( ! this.state() && this.options.state ) {
   6063 			this.setState( this.options.state );
   6064 		}
   6065 		/**
   6066 		 * call 'render' directly on the parent class
   6067 		 */
   6068 		return Frame.prototype.render.apply( this, arguments );
   6069 	},
   6070 	/**
   6071 	 * @param {Object} title
   6072 	 * @this wp.media.controller.Region
   6073 	 */
   6074 	createTitle: function( title ) {
   6075 		title.view = new wp.media.View({
   6076 			controller: this,
   6077 			tagName: 'h1'
   6078 		});
   6079 	},
   6080 	/**
   6081 	 * @param {Object} menu
   6082 	 * @this wp.media.controller.Region
   6083 	 */
   6084 	createMenu: function( menu ) {
   6085 		menu.view = new wp.media.view.Menu({
   6086 			controller: this,
   6087 
   6088 			attributes: {
   6089 				role:               'tablist',
   6090 				'aria-orientation': 'vertical'
   6091 			}
   6092 		});
   6093 
   6094 		this.menuView = menu.view;
   6095 	},
   6096 
   6097 	toggleMenu: function( event ) {
   6098 		var menu = this.$el.find( '.media-menu' );
   6099 
   6100 		menu.toggleClass( 'visible' );
   6101 		$( event.target ).attr( 'aria-expanded', menu.hasClass( 'visible' ) );
   6102 	},
   6103 
   6104 	/**
   6105 	 * @param {Object} toolbar
   6106 	 * @this wp.media.controller.Region
   6107 	 */
   6108 	createToolbar: function( toolbar ) {
   6109 		toolbar.view = new wp.media.view.Toolbar({
   6110 			controller: this
   6111 		});
   6112 	},
   6113 	/**
   6114 	 * @param {Object} router
   6115 	 * @this wp.media.controller.Region
   6116 	 */
   6117 	createRouter: function( router ) {
   6118 		router.view = new wp.media.view.Router({
   6119 			controller: this,
   6120 
   6121 			attributes: {
   6122 				role:               'tablist',
   6123 				'aria-orientation': 'horizontal'
   6124 			}
   6125 		});
   6126 
   6127 		this.routerView = router.view;
   6128 	},
   6129 	/**
   6130 	 * @param {Object} options
   6131 	 */
   6132 	createIframeStates: function( options ) {
   6133 		var settings = wp.media.view.settings,
   6134 			tabs = settings.tabs,
   6135 			tabUrl = settings.tabUrl,
   6136 			$postId;
   6137 
   6138 		if ( ! tabs || ! tabUrl ) {
   6139 			return;
   6140 		}
   6141 
   6142 		// Add the post ID to the tab URL if it exists.
   6143 		$postId = $('#post_ID');
   6144 		if ( $postId.length ) {
   6145 			tabUrl += '&post_id=' + $postId.val();
   6146 		}
   6147 
   6148 		// Generate the tab states.
   6149 		_.each( tabs, function( title, id ) {
   6150 			this.state( 'iframe:' + id ).set( _.defaults({
   6151 				tab:     id,
   6152 				src:     tabUrl + '&tab=' + id,
   6153 				title:   title,
   6154 				content: 'iframe',
   6155 				menu:    'default'
   6156 			}, options ) );
   6157 		}, this );
   6158 
   6159 		this.on( 'content:create:iframe', this.iframeContent, this );
   6160 		this.on( 'content:deactivate:iframe', this.iframeContentCleanup, this );
   6161 		this.on( 'menu:render:default', this.iframeMenu, this );
   6162 		this.on( 'open', this.hijackThickbox, this );
   6163 		this.on( 'close', this.restoreThickbox, this );
   6164 	},
   6165 
   6166 	/**
   6167 	 * @param {Object} content
   6168 	 * @this wp.media.controller.Region
   6169 	 */
   6170 	iframeContent: function( content ) {
   6171 		this.$el.addClass('hide-toolbar');
   6172 		content.view = new wp.media.view.Iframe({
   6173 			controller: this
   6174 		});
   6175 	},
   6176 
   6177 	iframeContentCleanup: function() {
   6178 		this.$el.removeClass('hide-toolbar');
   6179 	},
   6180 
   6181 	iframeMenu: function( view ) {
   6182 		var views = {};
   6183 
   6184 		if ( ! view ) {
   6185 			return;
   6186 		}
   6187 
   6188 		_.each( wp.media.view.settings.tabs, function( title, id ) {
   6189 			views[ 'iframe:' + id ] = {
   6190 				text: this.state( 'iframe:' + id ).get('title'),
   6191 				priority: 200
   6192 			};
   6193 		}, this );
   6194 
   6195 		view.set( views );
   6196 	},
   6197 
   6198 	hijackThickbox: function() {
   6199 		var frame = this;
   6200 
   6201 		if ( ! window.tb_remove || this._tb_remove ) {
   6202 			return;
   6203 		}
   6204 
   6205 		this._tb_remove = window.tb_remove;
   6206 		window.tb_remove = function() {
   6207 			frame.close();
   6208 			frame.reset();
   6209 			frame.setState( frame.options.state );
   6210 			frame._tb_remove.call( window );
   6211 		};
   6212 	},
   6213 
   6214 	restoreThickbox: function() {
   6215 		if ( ! this._tb_remove ) {
   6216 			return;
   6217 		}
   6218 
   6219 		window.tb_remove = this._tb_remove;
   6220 		delete this._tb_remove;
   6221 	}
   6222 });
   6223 
   6224 // Map some of the modal's methods to the frame.
   6225 _.each(['open','close','attach','detach','escape'], function( method ) {
   6226 	/**
   6227 	 * @function open
   6228 	 * @memberOf wp.media.view.MediaFrame
   6229 	 * @instance
   6230 	 *
   6231 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
   6232 	 */
   6233 	/**
   6234 	 * @function close
   6235 	 * @memberOf wp.media.view.MediaFrame
   6236 	 * @instance
   6237 	 *
   6238 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
   6239 	 */
   6240 	/**
   6241 	 * @function attach
   6242 	 * @memberOf wp.media.view.MediaFrame
   6243 	 * @instance
   6244 	 *
   6245 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
   6246 	 */
   6247 	/**
   6248 	 * @function detach
   6249 	 * @memberOf wp.media.view.MediaFrame
   6250 	 * @instance
   6251 	 *
   6252 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
   6253 	 */
   6254 	/**
   6255 	 * @function escape
   6256 	 * @memberOf wp.media.view.MediaFrame
   6257 	 * @instance
   6258 	 *
   6259 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
   6260 	 */
   6261 	MediaFrame.prototype[ method ] = function() {
   6262 		if ( this.modal ) {
   6263 			this.modal[ method ].apply( this.modal, arguments );
   6264 		}
   6265 		return this;
   6266 	};
   6267 });
   6268 
   6269 module.exports = MediaFrame;
   6270 
   6271 
   6272 /***/ }),
   6273 
   6274 /***/ "Q9T/":
   6275 /***/ (function(module, exports) {
   6276 
   6277 /**
   6278  * wp.media.view.RouterItem
   6279  *
   6280  * @memberOf wp.media.view
   6281  *
   6282  * @class
   6283  * @augments wp.media.view.MenuItem
   6284  * @augments wp.media.View
   6285  * @augments wp.Backbone.View
   6286  * @augments Backbone.View
   6287  */
   6288 var RouterItem = wp.media.view.MenuItem.extend(/** @lends wp.media.view.RouterItem.prototype */{
   6289 	/**
   6290 	 * On click handler to activate the content region's corresponding mode.
   6291 	 */
   6292 	click: function() {
   6293 		var contentMode = this.options.contentMode;
   6294 		if ( contentMode ) {
   6295 			this.controller.content.mode( contentMode );
   6296 		}
   6297 	}
   6298 });
   6299 
   6300 module.exports = RouterItem;
   6301 
   6302 
   6303 /***/ }),
   6304 
   6305 /***/ "S4jH":
   6306 /***/ (function(module, exports) {
   6307 
   6308 var $ = jQuery,
   6309 	UploaderWindow;
   6310 
   6311 /**
   6312  * wp.media.view.UploaderWindow
   6313  *
   6314  * An uploader window that allows for dragging and dropping media.
   6315  *
   6316  * @memberOf wp.media.view
   6317  *
   6318  * @class
   6319  * @augments wp.media.View
   6320  * @augments wp.Backbone.View
   6321  * @augments Backbone.View
   6322  *
   6323  * @param {object} [options]                   Options hash passed to the view.
   6324  * @param {object} [options.uploader]          Uploader properties.
   6325  * @param {jQuery} [options.uploader.browser]
   6326  * @param {jQuery} [options.uploader.dropzone] jQuery collection of the dropzone.
   6327  * @param {object} [options.uploader.params]
   6328  */
   6329 UploaderWindow = wp.media.View.extend(/** @lends wp.media.view.UploaderWindow.prototype */{
   6330 	tagName:   'div',
   6331 	className: 'uploader-window',
   6332 	template:  wp.template('uploader-window'),
   6333 
   6334 	initialize: function() {
   6335 		var uploader;
   6336 
   6337 		this.$browser = $( '<button type="button" class="browser" />' ).hide().appendTo( 'body' );
   6338 
   6339 		uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
   6340 			dropzone:  this.$el,
   6341 			browser:   this.$browser,
   6342 			params:    {}
   6343 		});
   6344 
   6345 		// Ensure the dropzone is a jQuery collection.
   6346 		if ( uploader.dropzone && ! (uploader.dropzone instanceof $) ) {
   6347 			uploader.dropzone = $( uploader.dropzone );
   6348 		}
   6349 
   6350 		this.controller.on( 'activate', this.refresh, this );
   6351 
   6352 		this.controller.on( 'detach', function() {
   6353 			this.$browser.remove();
   6354 		}, this );
   6355 	},
   6356 
   6357 	refresh: function() {
   6358 		if ( this.uploader ) {
   6359 			this.uploader.refresh();
   6360 		}
   6361 	},
   6362 
   6363 	ready: function() {
   6364 		var postId = wp.media.view.settings.post.id,
   6365 			dropzone;
   6366 
   6367 		// If the uploader already exists, bail.
   6368 		if ( this.uploader ) {
   6369 			return;
   6370 		}
   6371 
   6372 		if ( postId ) {
   6373 			this.options.uploader.params.post_id = postId;
   6374 		}
   6375 		this.uploader = new wp.Uploader( this.options.uploader );
   6376 
   6377 		dropzone = this.uploader.dropzone;
   6378 		dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
   6379 		dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
   6380 
   6381 		$( this.uploader ).on( 'uploader:ready', _.bind( this._ready, this ) );
   6382 	},
   6383 
   6384 	_ready: function() {
   6385 		this.controller.trigger( 'uploader:ready' );
   6386 	},
   6387 
   6388 	show: function() {
   6389 		var $el = this.$el.show();
   6390 
   6391 		// Ensure that the animation is triggered by waiting until
   6392 		// the transparent element is painted into the DOM.
   6393 		_.defer( function() {
   6394 			$el.css({ opacity: 1 });
   6395 		});
   6396 	},
   6397 
   6398 	hide: function() {
   6399 		var $el = this.$el.css({ opacity: 0 });
   6400 
   6401 		wp.media.transition( $el ).done( function() {
   6402 			// Transition end events are subject to race conditions.
   6403 			// Make sure that the value is set as intended.
   6404 			if ( '0' === $el.css('opacity') ) {
   6405 				$el.hide();
   6406 			}
   6407 		});
   6408 
   6409 		// https://core.trac.wordpress.org/ticket/27341
   6410 		_.delay( function() {
   6411 			if ( '0' === $el.css('opacity') && $el.is(':visible') ) {
   6412 				$el.hide();
   6413 			}
   6414 		}, 500 );
   6415 	}
   6416 });
   6417 
   6418 module.exports = UploaderWindow;
   6419 
   6420 
   6421 /***/ }),
   6422 
   6423 /***/ "U3Se":
   6424 /***/ (function(module, exports) {
   6425 
   6426 /**
   6427  * wp.media.controller.StateMachine
   6428  *
   6429  * A state machine keeps track of state. It is in one state at a time,
   6430  * and can change from one state to another.
   6431  *
   6432  * States are stored as models in a Backbone collection.
   6433  *
   6434  * @memberOf wp.media.controller
   6435  *
   6436  * @since 3.5.0
   6437  *
   6438  * @class
   6439  * @augments Backbone.Model
   6440  * @mixin
   6441  * @mixes Backbone.Events
   6442  */
   6443 var StateMachine = function() {
   6444 	return {
   6445 		// Use Backbone's self-propagating `extend` inheritance method.
   6446 		extend: Backbone.Model.extend
   6447 	};
   6448 };
   6449 
   6450 _.extend( StateMachine.prototype, Backbone.Events,/** @lends wp.media.controller.StateMachine.prototype */{
   6451 	/**
   6452 	 * Fetch a state.
   6453 	 *
   6454 	 * If no `id` is provided, returns the active state.
   6455 	 *
   6456 	 * Implicitly creates states.
   6457 	 *
   6458 	 * Ensure that the `states` collection exists so the `StateMachine`
   6459 	 * can be used as a mixin.
   6460 	 *
   6461 	 * @since 3.5.0
   6462 	 *
   6463 	 * @param {string} id
   6464 	 * @return {wp.media.controller.State} Returns a State model from
   6465 	 *                                     the StateMachine collection.
   6466 	 */
   6467 	state: function( id ) {
   6468 		this.states = this.states || new Backbone.Collection();
   6469 
   6470 		// Default to the active state.
   6471 		id = id || this._state;
   6472 
   6473 		if ( id && ! this.states.get( id ) ) {
   6474 			this.states.add({ id: id });
   6475 		}
   6476 		return this.states.get( id );
   6477 	},
   6478 
   6479 	/**
   6480 	 * Sets the active state.
   6481 	 *
   6482 	 * Bail if we're trying to select the current state, if we haven't
   6483 	 * created the `states` collection, or are trying to select a state
   6484 	 * that does not exist.
   6485 	 *
   6486 	 * @since 3.5.0
   6487 	 *
   6488 	 * @param {string} id
   6489 	 *
   6490 	 * @fires wp.media.controller.State#deactivate
   6491 	 * @fires wp.media.controller.State#activate
   6492 	 *
   6493 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
   6494 	 */
   6495 	setState: function( id ) {
   6496 		var previous = this.state();
   6497 
   6498 		if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) {
   6499 			return this;
   6500 		}
   6501 
   6502 		if ( previous ) {
   6503 			previous.trigger('deactivate');
   6504 			this._lastState = previous.id;
   6505 		}
   6506 
   6507 		this._state = id;
   6508 		this.state().trigger('activate');
   6509 
   6510 		return this;
   6511 	},
   6512 
   6513 	/**
   6514 	 * Returns the previous active state.
   6515 	 *
   6516 	 * Call the `state()` method with no parameters to retrieve the current
   6517 	 * active state.
   6518 	 *
   6519 	 * @since 3.5.0
   6520 	 *
   6521 	 * @return {wp.media.controller.State} Returns a State model from
   6522 	 *                                     the StateMachine collection.
   6523 	 */
   6524 	lastState: function() {
   6525 		if ( this._lastState ) {
   6526 			return this.state( this._lastState );
   6527 		}
   6528 	}
   6529 });
   6530 
   6531 // Map all event binding and triggering on a StateMachine to its `states` collection.
   6532 _.each([ 'on', 'off', 'trigger' ], function( method ) {
   6533 	/**
   6534 	 * @function on
   6535 	 * @memberOf wp.media.controller.StateMachine
   6536 	 * @instance
   6537 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
   6538 	 */
   6539 	/**
   6540 	 * @function off
   6541 	 * @memberOf wp.media.controller.StateMachine
   6542 	 * @instance
   6543 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
   6544 	 */
   6545 	/**
   6546 	 * @function trigger
   6547 	 * @memberOf wp.media.controller.StateMachine
   6548 	 * @instance
   6549 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
   6550 	 */
   6551 	StateMachine.prototype[ method ] = function() {
   6552 		// Ensure that the `states` collection exists so the `StateMachine`
   6553 		// can be used as a mixin.
   6554 		this.states = this.states || new Backbone.Collection();
   6555 		// Forward the method to the `states` collection.
   6556 		this.states[ method ].apply( this.states, arguments );
   6557 		return this;
   6558 	};
   6559 });
   6560 
   6561 module.exports = StateMachine;
   6562 
   6563 
   6564 /***/ }),
   6565 
   6566 /***/ "UmHM":
   6567 /***/ (function(module, exports) {
   6568 
   6569 var View = wp.media.view,
   6570 	SiteIconCropper;
   6571 
   6572 /**
   6573  * wp.media.view.SiteIconCropper
   6574  *
   6575  * Uses the imgAreaSelect plugin to allow a user to crop a Site Icon.
   6576  *
   6577  * Takes imgAreaSelect options from
   6578  * wp.customize.SiteIconControl.calculateImageSelectOptions.
   6579  *
   6580  * @memberOf wp.media.view
   6581  *
   6582  * @class
   6583  * @augments wp.media.view.Cropper
   6584  * @augments wp.media.View
   6585  * @augments wp.Backbone.View
   6586  * @augments Backbone.View
   6587  */
   6588 SiteIconCropper = View.Cropper.extend(/** @lends wp.media.view.SiteIconCropper.prototype */{
   6589 	className: 'crop-content site-icon',
   6590 
   6591 	ready: function () {
   6592 		View.Cropper.prototype.ready.apply( this, arguments );
   6593 
   6594 		this.$( '.crop-image' ).on( 'load', _.bind( this.addSidebar, this ) );
   6595 	},
   6596 
   6597 	addSidebar: function() {
   6598 		this.sidebar = new wp.media.view.Sidebar({
   6599 			controller: this.controller
   6600 		});
   6601 
   6602 		this.sidebar.set( 'preview', new wp.media.view.SiteIconPreview({
   6603 			controller: this.controller,
   6604 			attachment: this.options.attachment
   6605 		}) );
   6606 
   6607 		this.controller.cropperView.views.add( this.sidebar );
   6608 	}
   6609 });
   6610 
   6611 module.exports = SiteIconCropper;
   6612 
   6613 
   6614 /***/ }),
   6615 
   6616 /***/ "V6sy":
   6617 /***/ (function(module, exports) {
   6618 
   6619 /**
   6620  * wp.media.view.Label
   6621  *
   6622  * @memberOf wp.media.view
   6623  *
   6624  * @class
   6625  * @augments wp.media.View
   6626  * @augments wp.Backbone.View
   6627  * @augments Backbone.View
   6628  */
   6629 var Label = wp.media.View.extend(/** @lends wp.media.view.Label.prototype */{
   6630 	tagName: 'label',
   6631 	className: 'screen-reader-text',
   6632 
   6633 	initialize: function() {
   6634 		this.value = this.options.value;
   6635 	},
   6636 
   6637 	render: function() {
   6638 		this.$el.html( this.value );
   6639 
   6640 		return this;
   6641 	}
   6642 });
   6643 
   6644 module.exports = Label;
   6645 
   6646 
   6647 /***/ }),
   6648 
   6649 /***/ "VIJ9":
   6650 /***/ (function(module, exports) {
   6651 
   6652 var Select = wp.media.view.MediaFrame.Select,
   6653 	l10n = wp.media.view.l10n,
   6654 	ImageDetails;
   6655 
   6656 /**
   6657  * wp.media.view.MediaFrame.ImageDetails
   6658  *
   6659  * A media frame for manipulating an image that's already been inserted
   6660  * into a post.
   6661  *
   6662  * @memberOf wp.media.view.MediaFrame
   6663  *
   6664  * @class
   6665  * @augments wp.media.view.MediaFrame.Select
   6666  * @augments wp.media.view.MediaFrame
   6667  * @augments wp.media.view.Frame
   6668  * @augments wp.media.View
   6669  * @augments wp.Backbone.View
   6670  * @augments Backbone.View
   6671  * @mixes wp.media.controller.StateMachine
   6672  */
   6673 ImageDetails = Select.extend(/** @lends wp.media.view.MediaFrame.ImageDetails.prototype */{
   6674 	defaults: {
   6675 		id:      'image',
   6676 		url:     '',
   6677 		menu:    'image-details',
   6678 		content: 'image-details',
   6679 		toolbar: 'image-details',
   6680 		type:    'link',
   6681 		title:    l10n.imageDetailsTitle,
   6682 		priority: 120
   6683 	},
   6684 
   6685 	initialize: function( options ) {
   6686 		this.image = new wp.media.model.PostImage( options.metadata );
   6687 		this.options.selection = new wp.media.model.Selection( this.image.attachment, { multiple: false } );
   6688 		Select.prototype.initialize.apply( this, arguments );
   6689 	},
   6690 
   6691 	bindHandlers: function() {
   6692 		Select.prototype.bindHandlers.apply( this, arguments );
   6693 		this.on( 'menu:create:image-details', this.createMenu, this );
   6694 		this.on( 'content:create:image-details', this.imageDetailsContent, this );
   6695 		this.on( 'content:render:edit-image', this.editImageContent, this );
   6696 		this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
   6697 		// Override the select toolbar.
   6698 		this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
   6699 	},
   6700 
   6701 	createStates: function() {
   6702 		this.states.add([
   6703 			new wp.media.controller.ImageDetails({
   6704 				image: this.image,
   6705 				editable: false
   6706 			}),
   6707 			new wp.media.controller.ReplaceImage({
   6708 				id: 'replace-image',
   6709 				library: wp.media.query( { type: 'image' } ),
   6710 				image: this.image,
   6711 				multiple:  false,
   6712 				title:     l10n.imageReplaceTitle,
   6713 				toolbar: 'replace',
   6714 				priority:  80,
   6715 				displaySettings: true
   6716 			}),
   6717 			new wp.media.controller.EditImage( {
   6718 				image: this.image,
   6719 				selection: this.options.selection
   6720 			} )
   6721 		]);
   6722 	},
   6723 
   6724 	imageDetailsContent: function( options ) {
   6725 		options.view = new wp.media.view.ImageDetails({
   6726 			controller: this,
   6727 			model: this.state().image,
   6728 			attachment: this.state().image.attachment
   6729 		});
   6730 	},
   6731 
   6732 	editImageContent: function() {
   6733 		var state = this.state(),
   6734 			model = state.get('image'),
   6735 			view;
   6736 
   6737 		if ( ! model ) {
   6738 			return;
   6739 		}
   6740 
   6741 		view = new wp.media.view.EditImage( { model: model, controller: this } ).render();
   6742 
   6743 		this.content.set( view );
   6744 
   6745 		// After bringing in the frame, load the actual editor via an Ajax call.
   6746 		view.loadEditor();
   6747 
   6748 	},
   6749 
   6750 	renderImageDetailsToolbar: function() {
   6751 		this.toolbar.set( new wp.media.view.Toolbar({
   6752 			controller: this,
   6753 			items: {
   6754 				select: {
   6755 					style:    'primary',
   6756 					text:     l10n.update,
   6757 					priority: 80,
   6758 
   6759 					click: function() {
   6760 						var controller = this.controller,
   6761 							state = controller.state();
   6762 
   6763 						controller.close();
   6764 
   6765 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
   6766 						// perhaps wp.html.string to at least to build the <img />.
   6767 						state.trigger( 'update', controller.image.toJSON() );
   6768 
   6769 						// Restore and reset the default state.
   6770 						controller.setState( controller.options.state );
   6771 						controller.reset();
   6772 					}
   6773 				}
   6774 			}
   6775 		}) );
   6776 	},
   6777 
   6778 	renderReplaceImageToolbar: function() {
   6779 		var frame = this,
   6780 			lastState = frame.lastState(),
   6781 			previous = lastState && lastState.id;
   6782 
   6783 		this.toolbar.set( new wp.media.view.Toolbar({
   6784 			controller: this,
   6785 			items: {
   6786 				back: {
   6787 					text:     l10n.back,
   6788 					priority: 80,
   6789 					click:    function() {
   6790 						if ( previous ) {
   6791 							frame.setState( previous );
   6792 						} else {
   6793 							frame.close();
   6794 						}
   6795 					}
   6796 				},
   6797 
   6798 				replace: {
   6799 					style:    'primary',
   6800 					text:     l10n.replace,
   6801 					priority: 20,
   6802 					requires: { selection: true },
   6803 
   6804 					click: function() {
   6805 						var controller = this.controller,
   6806 							state = controller.state(),
   6807 							selection = state.get( 'selection' ),
   6808 							attachment = selection.single();
   6809 
   6810 						controller.close();
   6811 
   6812 						controller.image.changeAttachment( attachment, state.display( attachment ) );
   6813 
   6814 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
   6815 						// perhaps wp.html.string to at least to build the <img />.
   6816 						state.trigger( 'replace', controller.image.toJSON() );
   6817 
   6818 						// Restore and reset the default state.
   6819 						controller.setState( controller.options.state );
   6820 						controller.reset();
   6821 					}
   6822 				}
   6823 			}
   6824 		}) );
   6825 	}
   6826 
   6827 });
   6828 
   6829 module.exports = ImageDetails;
   6830 
   6831 
   6832 /***/ }),
   6833 
   6834 /***/ "VMHs":
   6835 /***/ (function(module, exports) {
   6836 
   6837 /**
   6838  * wp.media.view.Embed
   6839  *
   6840  * @memberOf wp.media.view
   6841  *
   6842  * @class
   6843  * @augments wp.media.View
   6844  * @augments wp.Backbone.View
   6845  * @augments Backbone.View
   6846  */
   6847 var Embed = wp.media.View.extend(/** @lends wp.media.view.Ember.prototype */{
   6848 	className: 'media-embed',
   6849 
   6850 	initialize: function() {
   6851 		/**
   6852 		 * @member {wp.media.view.EmbedUrl}
   6853 		 */
   6854 		this.url = new wp.media.view.EmbedUrl({
   6855 			controller: this.controller,
   6856 			model:      this.model.props
   6857 		}).render();
   6858 
   6859 		this.views.set([ this.url ]);
   6860 		this.refresh();
   6861 		this.listenTo( this.model, 'change:type', this.refresh );
   6862 		this.listenTo( this.model, 'change:loading', this.loading );
   6863 	},
   6864 
   6865 	/**
   6866 	 * @param {Object} view
   6867 	 */
   6868 	settings: function( view ) {
   6869 		if ( this._settings ) {
   6870 			this._settings.remove();
   6871 		}
   6872 		this._settings = view;
   6873 		this.views.add( view );
   6874 	},
   6875 
   6876 	refresh: function() {
   6877 		var type = this.model.get('type'),
   6878 			constructor;
   6879 
   6880 		if ( 'image' === type ) {
   6881 			constructor = wp.media.view.EmbedImage;
   6882 		} else if ( 'link' === type ) {
   6883 			constructor = wp.media.view.EmbedLink;
   6884 		} else {
   6885 			return;
   6886 		}
   6887 
   6888 		this.settings( new constructor({
   6889 			controller: this.controller,
   6890 			model:      this.model.props,
   6891 			priority:   40
   6892 		}) );
   6893 	},
   6894 
   6895 	loading: function() {
   6896 		this.$el.toggleClass( 'embed-loading', this.model.get('loading') );
   6897 	}
   6898 });
   6899 
   6900 module.exports = Embed;
   6901 
   6902 
   6903 /***/ }),
   6904 
   6905 /***/ "Vh02":
   6906 /***/ (function(module, exports) {
   6907 
   6908 var View = wp.media.View,
   6909 	UploaderStatus = wp.media.view.UploaderStatus,
   6910 	l10n = wp.media.view.l10n,
   6911 	$ = jQuery,
   6912 	Cropper;
   6913 
   6914 /**
   6915  * wp.media.view.Cropper
   6916  *
   6917  * Uses the imgAreaSelect plugin to allow a user to crop an image.
   6918  *
   6919  * Takes imgAreaSelect options from
   6920  * wp.customize.HeaderControl.calculateImageSelectOptions via
   6921  * wp.customize.HeaderControl.openMM.
   6922  *
   6923  * @memberOf wp.media.view
   6924  *
   6925  * @class
   6926  * @augments wp.media.View
   6927  * @augments wp.Backbone.View
   6928  * @augments Backbone.View
   6929  */
   6930 Cropper = View.extend(/** @lends wp.media.view.Cropper.prototype */{
   6931 	className: 'crop-content',
   6932 	template: wp.template('crop-content'),
   6933 	initialize: function() {
   6934 		_.bindAll(this, 'onImageLoad');
   6935 	},
   6936 	ready: function() {
   6937 		this.controller.frame.on('content:error:crop', this.onError, this);
   6938 		this.$image = this.$el.find('.crop-image');
   6939 		this.$image.on('load', this.onImageLoad);
   6940 		$(window).on('resize.cropper', _.debounce(this.onImageLoad, 250));
   6941 	},
   6942 	remove: function() {
   6943 		$(window).off('resize.cropper');
   6944 		this.$el.remove();
   6945 		this.$el.off();
   6946 		View.prototype.remove.apply(this, arguments);
   6947 	},
   6948 	prepare: function() {
   6949 		return {
   6950 			title: l10n.cropYourImage,
   6951 			url: this.options.attachment.get('url')
   6952 		};
   6953 	},
   6954 	onImageLoad: function() {
   6955 		var imgOptions = this.controller.get('imgSelectOptions'),
   6956 			imgSelect;
   6957 
   6958 		if (typeof imgOptions === 'function') {
   6959 			imgOptions = imgOptions(this.options.attachment, this.controller);
   6960 		}
   6961 
   6962 		imgOptions = _.extend(imgOptions, {
   6963 			parent: this.$el,
   6964 			onInit: function() {
   6965 
   6966 				// Store the set ratio.
   6967 				var setRatio = imgSelect.getOptions().aspectRatio;
   6968 
   6969 				// On mousedown, if no ratio is set and the Shift key is down, use a 1:1 ratio.
   6970 				this.parent.children().on( 'mousedown touchstart', function( e ) {
   6971 
   6972 					// If no ratio is set and the shift key is down, use a 1:1 ratio.
   6973 					if ( ! setRatio && e.shiftKey ) {
   6974 						imgSelect.setOptions( {
   6975 							aspectRatio: '1:1'
   6976 						} );
   6977 					}
   6978 				} );
   6979 
   6980 				this.parent.children().on( 'mouseup touchend', function() {
   6981 
   6982 					// Restore the set ratio.
   6983 					imgSelect.setOptions( {
   6984 						aspectRatio: setRatio ? setRatio : false
   6985 					} );
   6986 				} );
   6987 			}
   6988 		} );
   6989 		this.trigger('image-loaded');
   6990 		imgSelect = this.controller.imgSelect = this.$image.imgAreaSelect(imgOptions);
   6991 	},
   6992 	onError: function() {
   6993 		var filename = this.options.attachment.get('filename');
   6994 
   6995 		this.views.add( '.upload-errors', new wp.media.view.UploaderStatusError({
   6996 			filename: UploaderStatus.prototype.filename(filename),
   6997 			message: window._wpMediaViewsL10n.cropError
   6998 		}), { at: 0 });
   6999 	}
   7000 });
   7001 
   7002 module.exports = Cropper;
   7003 
   7004 
   7005 /***/ }),
   7006 
   7007 /***/ "VkcK":
   7008 /***/ (function(module, exports) {
   7009 
   7010 var l10n = wp.media.view.l10n,
   7011 	DateFilter;
   7012 
   7013 /**
   7014  * A filter dropdown for month/dates.
   7015  *
   7016  * @memberOf wp.media.view.AttachmentFilters
   7017  *
   7018  * @class
   7019  * @augments wp.media.view.AttachmentFilters
   7020  * @augments wp.media.View
   7021  * @augments wp.Backbone.View
   7022  * @augments Backbone.View
   7023  */
   7024 DateFilter = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Date.prototype */{
   7025 	id: 'media-attachment-date-filters',
   7026 
   7027 	createFilters: function() {
   7028 		var filters = {};
   7029 		_.each( wp.media.view.settings.months || {}, function( value, index ) {
   7030 			filters[ index ] = {
   7031 				text: value.text,
   7032 				props: {
   7033 					year: value.year,
   7034 					monthnum: value.month
   7035 				}
   7036 			};
   7037 		});
   7038 		filters.all = {
   7039 			text:  l10n.allDates,
   7040 			props: {
   7041 				monthnum: false,
   7042 				year:  false
   7043 			},
   7044 			priority: 10
   7045 		};
   7046 		this.filters = filters;
   7047 	}
   7048 });
   7049 
   7050 module.exports = DateFilter;
   7051 
   7052 
   7053 /***/ }),
   7054 
   7055 /***/ "W+32":
   7056 /***/ (function(module, exports) {
   7057 
   7058 var Controller = wp.media.controller,
   7059 	SiteIconCropper;
   7060 
   7061 /**
   7062  * wp.media.controller.SiteIconCropper
   7063  *
   7064  * A state for cropping a Site Icon.
   7065  *
   7066  * @memberOf wp.media.controller
   7067  *
   7068  * @class
   7069  * @augments wp.media.controller.Cropper
   7070  * @augments wp.media.controller.State
   7071  * @augments Backbone.Model
   7072  */
   7073 SiteIconCropper = Controller.Cropper.extend(/** @lends wp.media.controller.SiteIconCropper.prototype */{
   7074 	activate: function() {
   7075 		this.frame.on( 'content:create:crop', this.createCropContent, this );
   7076 		this.frame.on( 'close', this.removeCropper, this );
   7077 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
   7078 	},
   7079 
   7080 	createCropContent: function() {
   7081 		this.cropperView = new wp.media.view.SiteIconCropper({
   7082 			controller: this,
   7083 			attachment: this.get('selection').first()
   7084 		});
   7085 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
   7086 		this.frame.content.set(this.cropperView);
   7087 
   7088 	},
   7089 
   7090 	doCrop: function( attachment ) {
   7091 		var cropDetails = attachment.get( 'cropDetails' ),
   7092 			control = this.get( 'control' );
   7093 
   7094 		cropDetails.dst_width  = control.params.width;
   7095 		cropDetails.dst_height = control.params.height;
   7096 
   7097 		return wp.ajax.post( 'crop-image', {
   7098 			nonce: attachment.get( 'nonces' ).edit,
   7099 			id: attachment.get( 'id' ),
   7100 			context: 'site-icon',
   7101 			cropDetails: cropDetails
   7102 		} );
   7103 	}
   7104 });
   7105 
   7106 module.exports = SiteIconCropper;
   7107 
   7108 
   7109 /***/ }),
   7110 
   7111 /***/ "WiNq":
   7112 /***/ (function(module, exports) {
   7113 
   7114 /**
   7115  * wp.media.controller.Region
   7116  *
   7117  * A region is a persistent application layout area.
   7118  *
   7119  * A region assumes one mode at any time, and can be switched to another.
   7120  *
   7121  * When mode changes, events are triggered on the region's parent view.
   7122  * The parent view will listen to specific events and fill the region with an
   7123  * appropriate view depending on mode. For example, a frame listens for the
   7124  * 'browse' mode t be activated on the 'content' view and then fills the region
   7125  * with an AttachmentsBrowser view.
   7126  *
   7127  * @memberOf wp.media.controller
   7128  *
   7129  * @class
   7130  *
   7131  * @param {Object}        options          Options hash for the region.
   7132  * @param {string}        options.id       Unique identifier for the region.
   7133  * @param {Backbone.View} options.view     A parent view the region exists within.
   7134  * @param {string}        options.selector jQuery selector for the region within the parent view.
   7135  */
   7136 var Region = function( options ) {
   7137 	_.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
   7138 };
   7139 
   7140 // Use Backbone's self-propagating `extend` inheritance method.
   7141 Region.extend = Backbone.Model.extend;
   7142 
   7143 _.extend( Region.prototype,/** @lends wp.media.controller.Region.prototype */{
   7144 	/**
   7145 	 * Activate a mode.
   7146 	 *
   7147 	 * @since 3.5.0
   7148 	 *
   7149 	 * @param {string} mode
   7150 	 *
   7151 	 * @fires Region#activate
   7152 	 * @fires Region#deactivate
   7153 	 *
   7154 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
   7155 	 */
   7156 	mode: function( mode ) {
   7157 		if ( ! mode ) {
   7158 			return this._mode;
   7159 		}
   7160 		// Bail if we're trying to change to the current mode.
   7161 		if ( mode === this._mode ) {
   7162 			return this;
   7163 		}
   7164 
   7165 		/**
   7166 		 * Region mode deactivation event.
   7167 		 *
   7168 		 * @event wp.media.controller.Region#deactivate
   7169 		 */
   7170 		this.trigger('deactivate');
   7171 
   7172 		this._mode = mode;
   7173 		this.render( mode );
   7174 
   7175 		/**
   7176 		 * Region mode activation event.
   7177 		 *
   7178 		 * @event wp.media.controller.Region#activate
   7179 		 */
   7180 		this.trigger('activate');
   7181 		return this;
   7182 	},
   7183 	/**
   7184 	 * Render a mode.
   7185 	 *
   7186 	 * @since 3.5.0
   7187 	 *
   7188 	 * @param {string} mode
   7189 	 *
   7190 	 * @fires Region#create
   7191 	 * @fires Region#render
   7192 	 *
   7193 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
   7194 	 */
   7195 	render: function( mode ) {
   7196 		// If the mode isn't active, activate it.
   7197 		if ( mode && mode !== this._mode ) {
   7198 			return this.mode( mode );
   7199 		}
   7200 
   7201 		var set = { view: null },
   7202 			view;
   7203 
   7204 		/**
   7205 		 * Create region view event.
   7206 		 *
   7207 		 * Region view creation takes place in an event callback on the frame.
   7208 		 *
   7209 		 * @event wp.media.controller.Region#create
   7210 		 * @type {object}
   7211 		 * @property {object} view
   7212 		 */
   7213 		this.trigger( 'create', set );
   7214 		view = set.view;
   7215 
   7216 		/**
   7217 		 * Render region view event.
   7218 		 *
   7219 		 * Region view creation takes place in an event callback on the frame.
   7220 		 *
   7221 		 * @event wp.media.controller.Region#render
   7222 		 * @type {object}
   7223 		 */
   7224 		this.trigger( 'render', view );
   7225 		if ( view ) {
   7226 			this.set( view );
   7227 		}
   7228 		return this;
   7229 	},
   7230 
   7231 	/**
   7232 	 * Get the region's view.
   7233 	 *
   7234 	 * @since 3.5.0
   7235 	 *
   7236 	 * @return {wp.media.View}
   7237 	 */
   7238 	get: function() {
   7239 		return this.view.views.first( this.selector );
   7240 	},
   7241 
   7242 	/**
   7243 	 * Set the region's view as a subview of the frame.
   7244 	 *
   7245 	 * @since 3.5.0
   7246 	 *
   7247 	 * @param {Array|Object} views
   7248 	 * @param {Object} [options={}]
   7249 	 * @return {wp.Backbone.Subviews} Subviews is returned to allow chaining.
   7250 	 */
   7251 	set: function( views, options ) {
   7252 		if ( options ) {
   7253 			options.add = false;
   7254 		}
   7255 		return this.view.views.set( this.selector, views, options );
   7256 	},
   7257 
   7258 	/**
   7259 	 * Trigger regional view events on the frame.
   7260 	 *
   7261 	 * @since 3.5.0
   7262 	 *
   7263 	 * @param {string} event
   7264 	 * @return {undefined|wp.media.controller.Region} Returns itself to allow chaining.
   7265 	 */
   7266 	trigger: function( event ) {
   7267 		var base, args;
   7268 
   7269 		if ( ! this._mode ) {
   7270 			return;
   7271 		}
   7272 
   7273 		args = _.toArray( arguments );
   7274 		base = this.id + ':' + event;
   7275 
   7276 		// Trigger `{this.id}:{event}:{this._mode}` event on the frame.
   7277 		args[0] = base + ':' + this._mode;
   7278 		this.view.trigger.apply( this.view, args );
   7279 
   7280 		// Trigger `{this.id}:{event}` event on the frame.
   7281 		args[0] = base;
   7282 		this.view.trigger.apply( this.view, args );
   7283 		return this;
   7284 	}
   7285 });
   7286 
   7287 module.exports = Region;
   7288 
   7289 
   7290 /***/ }),
   7291 
   7292 /***/ "ZeG4":
   7293 /***/ (function(module, exports) {
   7294 
   7295 /**
   7296  * wp.media.view.UploaderStatusError
   7297  *
   7298  * @memberOf wp.media.view
   7299  *
   7300  * @class
   7301  * @augments wp.media.View
   7302  * @augments wp.Backbone.View
   7303  * @augments Backbone.View
   7304  */
   7305 var UploaderStatusError = wp.media.View.extend(/** @lends wp.media.view.UploaderStatusError.prototype */{
   7306 	className: 'upload-error',
   7307 	template:  wp.template('uploader-status-error')
   7308 });
   7309 
   7310 module.exports = UploaderStatusError;
   7311 
   7312 
   7313 /***/ }),
   7314 
   7315 /***/ "ZgZ7":
   7316 /***/ (function(module, exports) {
   7317 
   7318 var Search;
   7319 
   7320 /**
   7321  * wp.media.view.Search
   7322  *
   7323  * @memberOf wp.media.view
   7324  *
   7325  * @class
   7326  * @augments wp.media.View
   7327  * @augments wp.Backbone.View
   7328  * @augments Backbone.View
   7329  */
   7330 Search = wp.media.View.extend(/** @lends wp.media.view.Search.prototype */{
   7331 	tagName:   'input',
   7332 	className: 'search',
   7333 	id:        'media-search-input',
   7334 
   7335 	attributes: {
   7336 		type: 'search'
   7337 	},
   7338 
   7339 	events: {
   7340 		'input': 'search'
   7341 	},
   7342 
   7343 	/**
   7344 	 * @return {wp.media.view.Search} Returns itself to allow chaining.
   7345 	 */
   7346 	render: function() {
   7347 		this.el.value = this.model.escape('search');
   7348 		return this;
   7349 	},
   7350 
   7351 	search: _.debounce( function( event ) {
   7352 		var searchTerm = event.target.value.trim();
   7353 
   7354 		// Trigger the search only after 2 ASCII characters.
   7355 		if ( searchTerm && searchTerm.length > 1 ) {
   7356 			this.model.set( 'search', searchTerm );
   7357 		} else {
   7358 			this.model.unset( 'search' );
   7359 		}
   7360 	}, 500 )
   7361 });
   7362 
   7363 module.exports = Search;
   7364 
   7365 
   7366 /***/ }),
   7367 
   7368 /***/ "aBqq":
   7369 /***/ (function(module, exports) {
   7370 
   7371 var Library = wp.media.controller.Library,
   7372 	l10n = wp.media.view.l10n,
   7373 	ReplaceImage;
   7374 
   7375 /**
   7376  * wp.media.controller.ReplaceImage
   7377  *
   7378  * A state for replacing an image.
   7379  *
   7380  * @memberOf wp.media.controller
   7381  *
   7382  * @class
   7383  * @augments wp.media.controller.Library
   7384  * @augments wp.media.controller.State
   7385  * @augments Backbone.Model
   7386  *
   7387  * @param {object}                     [attributes]                         The attributes hash passed to the state.
   7388  * @param {string}                     [attributes.id=replace-image]        Unique identifier.
   7389  * @param {string}                     [attributes.title=Replace Image]     Title for the state. Displays in the media menu and the frame's title region.
   7390  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
   7391  *                                                                          If one is not supplied, a collection of all images will be created.
   7392  * @param {boolean}                    [attributes.multiple=false]          Whether multi-select is enabled.
   7393  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
   7394  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
   7395  * @param {string}                     [attributes.menu=default]            Initial mode for the menu region.
   7396  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
   7397  * @param {string}                     [attributes.toolbar=replace]         Initial mode for the toolbar region.
   7398  * @param {int}                        [attributes.priority=60]             The priority for the state link in the media menu.
   7399  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
   7400  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
   7401  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
   7402  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
   7403  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
   7404  * @param {boolean}                    [attributes.describe=false]          Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
   7405  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
   7406  * @param {boolean}                    [attributes.syncSelection=true]      Whether the Attachments selection should be persisted from the last state.
   7407  */
   7408 ReplaceImage = Library.extend(/** @lends wp.media.controller.ReplaceImage.prototype */{
   7409 	defaults: _.defaults({
   7410 		id:            'replace-image',
   7411 		title:         l10n.replaceImageTitle,
   7412 		multiple:      false,
   7413 		filterable:    'uploaded',
   7414 		toolbar:       'replace',
   7415 		menu:          false,
   7416 		priority:      60,
   7417 		syncSelection: true
   7418 	}, Library.prototype.defaults ),
   7419 
   7420 	/**
   7421 	 * @since 3.9.0
   7422 	 *
   7423 	 * @param options
   7424 	 */
   7425 	initialize: function( options ) {
   7426 		var library, comparator;
   7427 
   7428 		this.image = options.image;
   7429 		// If we haven't been provided a `library`, create a `Selection`.
   7430 		if ( ! this.get('library') ) {
   7431 			this.set( 'library', wp.media.query({ type: 'image' }) );
   7432 		}
   7433 
   7434 		Library.prototype.initialize.apply( this, arguments );
   7435 
   7436 		library    = this.get('library');
   7437 		comparator = library.comparator;
   7438 
   7439 		// Overload the library's comparator to push items that are not in
   7440 		// the mirrored query to the front of the aggregate collection.
   7441 		library.comparator = function( a, b ) {
   7442 			var aInQuery = !! this.mirroring.get( a.cid ),
   7443 				bInQuery = !! this.mirroring.get( b.cid );
   7444 
   7445 			if ( ! aInQuery && bInQuery ) {
   7446 				return -1;
   7447 			} else if ( aInQuery && ! bInQuery ) {
   7448 				return 1;
   7449 			} else {
   7450 				return comparator.apply( this, arguments );
   7451 			}
   7452 		};
   7453 
   7454 		// Add all items in the selection to the library, so any featured
   7455 		// images that are not initially loaded still appear.
   7456 		library.observe( this.get('selection') );
   7457 	},
   7458 
   7459 	/**
   7460 	 * @since 3.9.0
   7461 	 */
   7462 	activate: function() {
   7463 		this.updateSelection();
   7464 		Library.prototype.activate.apply( this, arguments );
   7465 	},
   7466 
   7467 	/**
   7468 	 * @since 3.9.0
   7469 	 */
   7470 	updateSelection: function() {
   7471 		var selection = this.get('selection'),
   7472 			attachment = this.image.attachment;
   7473 
   7474 		selection.reset( attachment ? [ attachment ] : [] );
   7475 	}
   7476 });
   7477 
   7478 module.exports = ReplaceImage;
   7479 
   7480 
   7481 /***/ }),
   7482 
   7483 /***/ "cH3P":
   7484 /***/ (function(module, exports) {
   7485 
   7486 /**
   7487  * wp.media.view.Spinner
   7488  *
   7489  * Represents a spinner in the Media Library.
   7490  *
   7491  * @since 3.9.0
   7492  *
   7493  * @memberOf wp.media.view
   7494  *
   7495  * @class
   7496  * @augments wp.media.View
   7497  * @augments wp.Backbone.View
   7498  * @augments Backbone.View
   7499  */
   7500 var Spinner = wp.media.View.extend(/** @lends wp.media.view.Spinner.prototype */{
   7501 	tagName:   'span',
   7502 	className: 'spinner',
   7503 	spinnerTimeout: false,
   7504 	delay: 400,
   7505 
   7506 	/**
   7507 	 * Shows the spinner. Delays the visibility by the configured amount.
   7508 	 *
   7509 	 * @since 3.9.0
   7510 	 *
   7511 	 * @return {wp.media.view.Spinner} The spinner.
   7512 	 */
   7513 	show: function() {
   7514 		if ( ! this.spinnerTimeout ) {
   7515 			this.spinnerTimeout = _.delay(function( $el ) {
   7516 				$el.addClass( 'is-active' );
   7517 			}, this.delay, this.$el );
   7518 		}
   7519 
   7520 		return this;
   7521 	},
   7522 
   7523 	/**
   7524 	 * Hides the spinner.
   7525 	 *
   7526 	 * @since 3.9.0
   7527 	 *
   7528 	 * @return {wp.media.view.Spinner} The spinner.
   7529 	 */
   7530 	hide: function() {
   7531 		this.$el.removeClass( 'is-active' );
   7532 		this.spinnerTimeout = clearTimeout( this.spinnerTimeout );
   7533 
   7534 		return this;
   7535 	}
   7536 });
   7537 
   7538 module.exports = Spinner;
   7539 
   7540 
   7541 /***/ }),
   7542 
   7543 /***/ "d3xu":
   7544 /***/ (function(module, exports) {
   7545 
   7546 var View = wp.media.View,
   7547 	$ = jQuery,
   7548 	SiteIconPreview;
   7549 
   7550 /**
   7551  * wp.media.view.SiteIconPreview
   7552  *
   7553  * Shows a preview of the Site Icon as a favicon and app icon while cropping.
   7554  *
   7555  * @memberOf wp.media.view
   7556  *
   7557  * @class
   7558  * @augments wp.media.View
   7559  * @augments wp.Backbone.View
   7560  * @augments Backbone.View
   7561  */
   7562 SiteIconPreview = View.extend(/** @lends wp.media.view.SiteIconPreview.prototype */{
   7563 	className: 'site-icon-preview',
   7564 	template: wp.template( 'site-icon-preview' ),
   7565 
   7566 	ready: function() {
   7567 		this.controller.imgSelect.setOptions({
   7568 			onInit: this.updatePreview,
   7569 			onSelectChange: this.updatePreview
   7570 		});
   7571 	},
   7572 
   7573 	prepare: function() {
   7574 		return {
   7575 			url: this.options.attachment.get( 'url' )
   7576 		};
   7577 	},
   7578 
   7579 	updatePreview: function( img, coords ) {
   7580 		var rx = 64 / coords.width,
   7581 			ry = 64 / coords.height,
   7582 			preview_rx = 16 / coords.width,
   7583 			preview_ry = 16 / coords.height;
   7584 
   7585 		$( '#preview-app-icon' ).css({
   7586 			width: Math.round(rx * this.imageWidth ) + 'px',
   7587 			height: Math.round(ry * this.imageHeight ) + 'px',
   7588 			marginLeft: '-' + Math.round(rx * coords.x1) + 'px',
   7589 			marginTop: '-' + Math.round(ry * coords.y1) + 'px'
   7590 		});
   7591 
   7592 		$( '#preview-favicon' ).css({
   7593 			width: Math.round( preview_rx * this.imageWidth ) + 'px',
   7594 			height: Math.round( preview_ry * this.imageHeight ) + 'px',
   7595 			marginLeft: '-' + Math.round( preview_rx * coords.x1 ) + 'px',
   7596 			marginTop: '-' + Math.floor( preview_ry* coords.y1 ) + 'px'
   7597 		});
   7598 	}
   7599 });
   7600 
   7601 module.exports = SiteIconPreview;
   7602 
   7603 
   7604 /***/ }),
   7605 
   7606 /***/ "dpRc":
   7607 /***/ (function(module, exports) {
   7608 
   7609 var MenuItem;
   7610 
   7611 /**
   7612  * wp.media.view.MenuItem
   7613  *
   7614  * @memberOf wp.media.view
   7615  *
   7616  * @class
   7617  * @augments wp.media.View
   7618  * @augments wp.Backbone.View
   7619  * @augments Backbone.View
   7620  */
   7621 MenuItem = wp.media.View.extend(/** @lends wp.media.view.MenuItem.prototype */{
   7622 	tagName:   'button',
   7623 	className: 'media-menu-item',
   7624 
   7625 	attributes: {
   7626 		type: 'button',
   7627 		role: 'tab'
   7628 	},
   7629 
   7630 	events: {
   7631 		'click': '_click'
   7632 	},
   7633 
   7634 	/**
   7635 	 * Allows to override the click event.
   7636 	 */
   7637 	_click: function() {
   7638 		var clickOverride = this.options.click;
   7639 
   7640 		if ( clickOverride ) {
   7641 			clickOverride.call( this );
   7642 		} else {
   7643 			this.click();
   7644 		}
   7645 	},
   7646 
   7647 	click: function() {
   7648 		var state = this.options.state;
   7649 
   7650 		if ( state ) {
   7651 			this.controller.setState( state );
   7652 			// Toggle the menu visibility in the responsive view.
   7653 			this.views.parent.$el.removeClass( 'visible' ); // @todo Or hide on any click, see below.
   7654 		}
   7655 	},
   7656 
   7657 	/**
   7658 	 * @return {wp.media.view.MenuItem} returns itself to allow chaining.
   7659 	 */
   7660 	render: function() {
   7661 		var options = this.options,
   7662 			menuProperty = options.state || options.contentMode;
   7663 
   7664 		if ( options.text ) {
   7665 			this.$el.text( options.text );
   7666 		} else if ( options.html ) {
   7667 			this.$el.html( options.html );
   7668 		}
   7669 
   7670 		// Set the menu item ID based on the frame state associated to the menu item.
   7671 		this.$el.attr( 'id', 'menu-item-' + menuProperty );
   7672 
   7673 		return this;
   7674 	}
   7675 });
   7676 
   7677 module.exports = MenuItem;
   7678 
   7679 
   7680 /***/ }),
   7681 
   7682 /***/ "eqTc":
   7683 /***/ (function(module, exports) {
   7684 
   7685 var Controller = wp.media.controller,
   7686 	CustomizeImageCropper;
   7687 
   7688 /**
   7689  * A state for cropping an image in the customizer.
   7690  *
   7691  * @since 4.3.0
   7692  *
   7693  * @constructs wp.media.controller.CustomizeImageCropper
   7694  * @memberOf wp.media.controller
   7695  * @augments wp.media.controller.CustomizeImageCropper.Cropper
   7696  * @inheritDoc
   7697  */
   7698 CustomizeImageCropper = Controller.Cropper.extend(/** @lends wp.media.controller.CustomizeImageCropper.prototype */{
   7699 	/**
   7700 	 * Posts the crop details to the admin.
   7701 	 *
   7702 	 * Uses crop measurements when flexible in both directions.
   7703 	 * Constrains flexible side based on image ratio and size of the fixed side.
   7704 	 *
   7705 	 * @since 4.3.0
   7706 	 *
   7707 	 * @param {Object} attachment The attachment to crop.
   7708 	 *
   7709 	 * @return {$.promise} A jQuery promise that represents the crop image request.
   7710 	 */
   7711 	doCrop: function( attachment ) {
   7712 		var cropDetails = attachment.get( 'cropDetails' ),
   7713 			control = this.get( 'control' ),
   7714 			ratio = cropDetails.width / cropDetails.height;
   7715 
   7716 		// Use crop measurements when flexible in both directions.
   7717 		if ( control.params.flex_width && control.params.flex_height ) {
   7718 			cropDetails.dst_width  = cropDetails.width;
   7719 			cropDetails.dst_height = cropDetails.height;
   7720 
   7721 		// Constrain flexible side based on image ratio and size of the fixed side.
   7722 		} else {
   7723 			cropDetails.dst_width  = control.params.flex_width  ? control.params.height * ratio : control.params.width;
   7724 			cropDetails.dst_height = control.params.flex_height ? control.params.width  / ratio : control.params.height;
   7725 		}
   7726 
   7727 		return wp.ajax.post( 'crop-image', {
   7728 			wp_customize: 'on',
   7729 			nonce: attachment.get( 'nonces' ).edit,
   7730 			id: attachment.get( 'id' ),
   7731 			context: control.id,
   7732 			cropDetails: cropDetails
   7733 		} );
   7734 	}
   7735 });
   7736 
   7737 module.exports = CustomizeImageCropper;
   7738 
   7739 
   7740 /***/ }),
   7741 
   7742 /***/ "fYN4":
   7743 /***/ (function(module, exports) {
   7744 
   7745 var MediaFrame = wp.media.view.MediaFrame,
   7746 	l10n = wp.media.view.l10n,
   7747 	Select;
   7748 
   7749 /**
   7750  * wp.media.view.MediaFrame.Select
   7751  *
   7752  * A frame for selecting an item or items from the media library.
   7753  *
   7754  * @memberOf wp.media.view.MediaFrame
   7755  *
   7756  * @class
   7757  * @augments wp.media.view.MediaFrame
   7758  * @augments wp.media.view.Frame
   7759  * @augments wp.media.View
   7760  * @augments wp.Backbone.View
   7761  * @augments Backbone.View
   7762  * @mixes wp.media.controller.StateMachine
   7763  */
   7764 Select = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Select.prototype */{
   7765 	initialize: function() {
   7766 		// Call 'initialize' directly on the parent class.
   7767 		MediaFrame.prototype.initialize.apply( this, arguments );
   7768 
   7769 		_.defaults( this.options, {
   7770 			selection: [],
   7771 			library:   {},
   7772 			multiple:  false,
   7773 			state:    'library'
   7774 		});
   7775 
   7776 		this.createSelection();
   7777 		this.createStates();
   7778 		this.bindHandlers();
   7779 	},
   7780 
   7781 	/**
   7782 	 * Attach a selection collection to the frame.
   7783 	 *
   7784 	 * A selection is a collection of attachments used for a specific purpose
   7785 	 * by a media frame. e.g. Selecting an attachment (or many) to insert into
   7786 	 * post content.
   7787 	 *
   7788 	 * @see media.model.Selection
   7789 	 */
   7790 	createSelection: function() {
   7791 		var selection = this.options.selection;
   7792 
   7793 		if ( ! (selection instanceof wp.media.model.Selection) ) {
   7794 			this.options.selection = new wp.media.model.Selection( selection, {
   7795 				multiple: this.options.multiple
   7796 			});
   7797 		}
   7798 
   7799 		this._selection = {
   7800 			attachments: new wp.media.model.Attachments(),
   7801 			difference: []
   7802 		};
   7803 	},
   7804 
   7805 	editImageContent: function() {
   7806 		var image = this.state().get('image'),
   7807 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
   7808 
   7809 		this.content.set( view );
   7810 
   7811 		// After creating the wrapper view, load the actual editor via an Ajax call.
   7812 		view.loadEditor();
   7813 	},
   7814 
   7815 	/**
   7816 	 * Create the default states on the frame.
   7817 	 */
   7818 	createStates: function() {
   7819 		var options = this.options;
   7820 
   7821 		if ( this.options.states ) {
   7822 			return;
   7823 		}
   7824 
   7825 		// Add the default states.
   7826 		this.states.add([
   7827 			// Main states.
   7828 			new wp.media.controller.Library({
   7829 				library:   wp.media.query( options.library ),
   7830 				multiple:  options.multiple,
   7831 				title:     options.title,
   7832 				priority:  20
   7833 			}),
   7834 			new wp.media.controller.EditImage( { model: options.editImage } )
   7835 		]);
   7836 	},
   7837 
   7838 	/**
   7839 	 * Bind region mode event callbacks.
   7840 	 *
   7841 	 * @see media.controller.Region.render
   7842 	 */
   7843 	bindHandlers: function() {
   7844 		this.on( 'router:create:browse', this.createRouter, this );
   7845 		this.on( 'router:render:browse', this.browseRouter, this );
   7846 		this.on( 'content:create:browse', this.browseContent, this );
   7847 		this.on( 'content:render:upload', this.uploadContent, this );
   7848 		this.on( 'toolbar:create:select', this.createSelectToolbar, this );
   7849 		this.on( 'content:render:edit-image', this.editImageContent, this );
   7850 	},
   7851 
   7852 	/**
   7853 	 * Render callback for the router region in the `browse` mode.
   7854 	 *
   7855 	 * @param {wp.media.view.Router} routerView
   7856 	 */
   7857 	browseRouter: function( routerView ) {
   7858 		routerView.set({
   7859 			upload: {
   7860 				text:     l10n.uploadFilesTitle,
   7861 				priority: 20
   7862 			},
   7863 			browse: {
   7864 				text:     l10n.mediaLibraryTitle,
   7865 				priority: 40
   7866 			}
   7867 		});
   7868 	},
   7869 
   7870 	/**
   7871 	 * Render callback for the content region in the `browse` mode.
   7872 	 *
   7873 	 * @param {wp.media.controller.Region} contentRegion
   7874 	 */
   7875 	browseContent: function( contentRegion ) {
   7876 		var state = this.state();
   7877 
   7878 		this.$el.removeClass('hide-toolbar');
   7879 
   7880 		// Browse our library of attachments.
   7881 		contentRegion.view = new wp.media.view.AttachmentsBrowser({
   7882 			controller: this,
   7883 			collection: state.get('library'),
   7884 			selection:  state.get('selection'),
   7885 			model:      state,
   7886 			sortable:   state.get('sortable'),
   7887 			search:     state.get('searchable'),
   7888 			filters:    state.get('filterable'),
   7889 			date:       state.get('date'),
   7890 			display:    state.has('display') ? state.get('display') : state.get('displaySettings'),
   7891 			dragInfo:   state.get('dragInfo'),
   7892 
   7893 			idealColumnWidth: state.get('idealColumnWidth'),
   7894 			suggestedWidth:   state.get('suggestedWidth'),
   7895 			suggestedHeight:  state.get('suggestedHeight'),
   7896 
   7897 			AttachmentView: state.get('AttachmentView')
   7898 		});
   7899 	},
   7900 
   7901 	/**
   7902 	 * Render callback for the content region in the `upload` mode.
   7903 	 */
   7904 	uploadContent: function() {
   7905 		this.$el.removeClass( 'hide-toolbar' );
   7906 		this.content.set( new wp.media.view.UploaderInline({
   7907 			controller: this
   7908 		}) );
   7909 	},
   7910 
   7911 	/**
   7912 	 * Toolbars
   7913 	 *
   7914 	 * @param {Object} toolbar
   7915 	 * @param {Object} [options={}]
   7916 	 * @this wp.media.controller.Region
   7917 	 */
   7918 	createSelectToolbar: function( toolbar, options ) {
   7919 		options = options || this.options.button || {};
   7920 		options.controller = this;
   7921 
   7922 		toolbar.view = new wp.media.view.Toolbar.Select( options );
   7923 	}
   7924 });
   7925 
   7926 module.exports = Select;
   7927 
   7928 
   7929 /***/ }),
   7930 
   7931 /***/ "gOpb":
   7932 /***/ (function(module, exports) {
   7933 
   7934 var $ = jQuery,
   7935 	Modal;
   7936 
   7937 /**
   7938  * wp.media.view.Modal
   7939  *
   7940  * A modal view, which the media modal uses as its default container.
   7941  *
   7942  * @memberOf wp.media.view
   7943  *
   7944  * @class
   7945  * @augments wp.media.View
   7946  * @augments wp.Backbone.View
   7947  * @augments Backbone.View
   7948  */
   7949 Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
   7950 	tagName:  'div',
   7951 	template: wp.template('media-modal'),
   7952 
   7953 	events: {
   7954 		'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
   7955 		'keydown': 'keydown'
   7956 	},
   7957 
   7958 	clickedOpenerEl: null,
   7959 
   7960 	initialize: function() {
   7961 		_.defaults( this.options, {
   7962 			container:      document.body,
   7963 			title:          '',
   7964 			propagate:      true,
   7965 			hasCloseButton: true
   7966 		});
   7967 
   7968 		this.focusManager = new wp.media.view.FocusManager({
   7969 			el: this.el
   7970 		});
   7971 	},
   7972 	/**
   7973 	 * @return {Object}
   7974 	 */
   7975 	prepare: function() {
   7976 		return {
   7977 			title:          this.options.title,
   7978 			hasCloseButton: this.options.hasCloseButton
   7979 		};
   7980 	},
   7981 
   7982 	/**
   7983 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
   7984 	 */
   7985 	attach: function() {
   7986 		if ( this.views.attached ) {
   7987 			return this;
   7988 		}
   7989 
   7990 		if ( ! this.views.rendered ) {
   7991 			this.render();
   7992 		}
   7993 
   7994 		this.$el.appendTo( this.options.container );
   7995 
   7996 		// Manually mark the view as attached and trigger ready.
   7997 		this.views.attached = true;
   7998 		this.views.ready();
   7999 
   8000 		return this.propagate('attach');
   8001 	},
   8002 
   8003 	/**
   8004 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
   8005 	 */
   8006 	detach: function() {
   8007 		if ( this.$el.is(':visible') ) {
   8008 			this.close();
   8009 		}
   8010 
   8011 		this.$el.detach();
   8012 		this.views.attached = false;
   8013 		return this.propagate('detach');
   8014 	},
   8015 
   8016 	/**
   8017 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
   8018 	 */
   8019 	open: function() {
   8020 		var $el = this.$el,
   8021 			mceEditor;
   8022 
   8023 		if ( $el.is(':visible') ) {
   8024 			return this;
   8025 		}
   8026 
   8027 		this.clickedOpenerEl = document.activeElement;
   8028 
   8029 		if ( ! this.views.attached ) {
   8030 			this.attach();
   8031 		}
   8032 
   8033 		// Disable page scrolling.
   8034 		$( 'body' ).addClass( 'modal-open' );
   8035 
   8036 		$el.show();
   8037 
   8038 		// Try to close the onscreen keyboard.
   8039 		if ( 'ontouchend' in document ) {
   8040 			if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor ) && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
   8041 				mceEditor.iframeElement.focus();
   8042 				mceEditor.iframeElement.blur();
   8043 
   8044 				setTimeout( function() {
   8045 					mceEditor.iframeElement.blur();
   8046 				}, 100 );
   8047 			}
   8048 		}
   8049 
   8050 		// Set initial focus on the content instead of this view element, to avoid page scrolling.
   8051 		this.$( '.media-modal' ).trigger( 'focus' );
   8052 
   8053 		// Hide the page content from assistive technologies.
   8054 		this.focusManager.setAriaHiddenOnBodyChildren( $el );
   8055 
   8056 		return this.propagate('open');
   8057 	},
   8058 
   8059 	/**
   8060 	 * @param {Object} options
   8061 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
   8062 	 */
   8063 	close: function( options ) {
   8064 		if ( ! this.views.attached || ! this.$el.is(':visible') ) {
   8065 			return this;
   8066 		}
   8067 
   8068 		// Pause current audio/video even after closing the modal.
   8069 		$( '.mejs-pause button' ).trigger( 'click' );
   8070 
   8071 		// Enable page scrolling.
   8072 		$( 'body' ).removeClass( 'modal-open' );
   8073 
   8074 		// Hide modal and remove restricted media modal tab focus once it's closed.
   8075 		this.$el.hide().off( 'keydown' );
   8076 
   8077 		/*
   8078 		 * Make visible again to assistive technologies all body children that
   8079 		 * have been made hidden when the modal opened.
   8080 		 */
   8081 		this.focusManager.removeAriaHiddenFromBodyChildren();
   8082 
   8083 		// Move focus back in useful location once modal is closed.
   8084 		if ( null !== this.clickedOpenerEl ) {
   8085 			// Move focus back to the element that opened the modal.
   8086 			this.clickedOpenerEl.focus();
   8087 		} else {
   8088 			// Fallback to the admin page main element.
   8089 			$( '#wpbody-content' )
   8090 				.attr( 'tabindex', '-1' )
   8091 				.trigger( 'focus' );
   8092 		}
   8093 
   8094 		this.propagate('close');
   8095 
   8096 		if ( options && options.escape ) {
   8097 			this.propagate('escape');
   8098 		}
   8099 
   8100 		return this;
   8101 	},
   8102 	/**
   8103 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
   8104 	 */
   8105 	escape: function() {
   8106 		return this.close({ escape: true });
   8107 	},
   8108 	/**
   8109 	 * @param {Object} event
   8110 	 */
   8111 	escapeHandler: function( event ) {
   8112 		event.preventDefault();
   8113 		this.escape();
   8114 	},
   8115 
   8116 	/**
   8117 	 * @param {Array|Object} content Views to register to '.media-modal-content'
   8118 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
   8119 	 */
   8120 	content: function( content ) {
   8121 		this.views.set( '.media-modal-content', content );
   8122 		return this;
   8123 	},
   8124 
   8125 	/**
   8126 	 * Triggers a modal event and if the `propagate` option is set,
   8127 	 * forwards events to the modal's controller.
   8128 	 *
   8129 	 * @param {string} id
   8130 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
   8131 	 */
   8132 	propagate: function( id ) {
   8133 		this.trigger( id );
   8134 
   8135 		if ( this.options.propagate ) {
   8136 			this.controller.trigger( id );
   8137 		}
   8138 
   8139 		return this;
   8140 	},
   8141 	/**
   8142 	 * @param {Object} event
   8143 	 */
   8144 	keydown: function( event ) {
   8145 		// Close the modal when escape is pressed.
   8146 		if ( 27 === event.which && this.$el.is(':visible') ) {
   8147 			this.escape();
   8148 			event.stopImmediatePropagation();
   8149 		}
   8150 	}
   8151 });
   8152 
   8153 module.exports = Modal;
   8154 
   8155 
   8156 /***/ }),
   8157 
   8158 /***/ "ibOK":
   8159 /***/ (function(module, exports) {
   8160 
   8161 var View = wp.media.View,
   8162 	EditImage;
   8163 
   8164 /**
   8165  * wp.media.view.EditImage
   8166  *
   8167  * @memberOf wp.media.view
   8168  *
   8169  * @class
   8170  * @augments wp.media.View
   8171  * @augments wp.Backbone.View
   8172  * @augments Backbone.View
   8173  */
   8174 EditImage = View.extend(/** @lends wp.media.view.EditImage.prototype */{
   8175 	className: 'image-editor',
   8176 	template: wp.template('image-editor'),
   8177 
   8178 	initialize: function( options ) {
   8179 		this.editor = window.imageEdit;
   8180 		this.controller = options.controller;
   8181 		View.prototype.initialize.apply( this, arguments );
   8182 	},
   8183 
   8184 	prepare: function() {
   8185 		return this.model.toJSON();
   8186 	},
   8187 
   8188 	loadEditor: function() {
   8189 		this.editor.open( this.model.get( 'id' ), this.model.get( 'nonces' ).edit, this );
   8190 	},
   8191 
   8192 	back: function() {
   8193 		var lastState = this.controller.lastState();
   8194 		this.controller.setState( lastState );
   8195 	},
   8196 
   8197 	refresh: function() {
   8198 		this.model.fetch();
   8199 	},
   8200 
   8201 	save: function() {
   8202 		var lastState = this.controller.lastState();
   8203 
   8204 		this.model.fetch().done( _.bind( function() {
   8205 			this.controller.setState( lastState );
   8206 		}, this ) );
   8207 	}
   8208 
   8209 });
   8210 
   8211 module.exports = EditImage;
   8212 
   8213 
   8214 /***/ }),
   8215 
   8216 /***/ "iipZ":
   8217 /***/ (function(module, exports) {
   8218 
   8219 var Selection = wp.media.model.Selection,
   8220 	Library = wp.media.controller.Library,
   8221 	CollectionAdd;
   8222 
   8223 /**
   8224  * wp.media.controller.CollectionAdd
   8225  *
   8226  * A state for adding attachments to a collection (e.g. video playlist).
   8227  *
   8228  * @memberOf wp.media.controller
   8229  *
   8230  * @class
   8231  * @augments wp.media.controller.Library
   8232  * @augments wp.media.controller.State
   8233  * @augments Backbone.Model
   8234  *
   8235  * @param {object}                     [attributes]                         The attributes hash passed to the state.
   8236  * @param {string}                     [attributes.id=library]              Unique identifier.
   8237  * @param {string}                     attributes.title                     Title for the state. Displays in the frame's title region.
   8238  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
   8239  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
   8240  *                                                                          If one is not supplied, a collection of attachments of the specified type will be created.
   8241  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
   8242  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
   8243  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
   8244  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
   8245  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
   8246  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
   8247  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
   8248  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
   8249  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
   8250  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
   8251  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
   8252  * @param {int}                        [attributes.priority=100]            The priority for the state link in the media menu.
   8253  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
   8254  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
   8255  * @param {string}                     attributes.type                      The collection's media type. (e.g. 'video').
   8256  * @param {string}                     attributes.collectionType            The collection type. (e.g. 'playlist').
   8257  */
   8258 CollectionAdd = Library.extend(/** @lends wp.media.controller.CollectionAdd.prototype */{
   8259 	defaults: _.defaults( {
   8260 		// Selection defaults. @see media.model.Selection
   8261 		multiple:      'add',
   8262 		// Attachments browser defaults. @see media.view.AttachmentsBrowser
   8263 		filterable:    'uploaded',
   8264 
   8265 		priority:      100,
   8266 		syncSelection: false
   8267 	}, Library.prototype.defaults ),
   8268 
   8269 	/**
   8270 	 * @since 3.9.0
   8271 	 */
   8272 	initialize: function() {
   8273 		var collectionType = this.get('collectionType');
   8274 
   8275 		if ( 'video' === this.get( 'type' ) ) {
   8276 			collectionType = 'video-' + collectionType;
   8277 		}
   8278 
   8279 		this.set( 'id', collectionType + '-library' );
   8280 		this.set( 'toolbar', collectionType + '-add' );
   8281 		this.set( 'menu', collectionType );
   8282 
   8283 		// If we haven't been provided a `library`, create a `Selection`.
   8284 		if ( ! this.get('library') ) {
   8285 			this.set( 'library', wp.media.query({ type: this.get('type') }) );
   8286 		}
   8287 		Library.prototype.initialize.apply( this, arguments );
   8288 	},
   8289 
   8290 	/**
   8291 	 * @since 3.9.0
   8292 	 */
   8293 	activate: function() {
   8294 		var library = this.get('library'),
   8295 			editLibrary = this.get('editLibrary'),
   8296 			edit = this.frame.state( this.get('collectionType') + '-edit' ).get('library');
   8297 
   8298 		if ( editLibrary && editLibrary !== edit ) {
   8299 			library.unobserve( editLibrary );
   8300 		}
   8301 
   8302 		// Accepts attachments that exist in the original library and
   8303 		// that do not exist in gallery's library.
   8304 		library.validator = function( attachment ) {
   8305 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
   8306 		};
   8307 
   8308 		/*
   8309 		 * Reset the library to ensure that all attachments are re-added
   8310 		 * to the collection. Do so silently, as calling `observe` will
   8311 		 * trigger the `reset` event.
   8312 		 */
   8313 		library.reset( library.mirroring.models, { silent: true });
   8314 		library.observe( edit );
   8315 		this.set('editLibrary', edit);
   8316 
   8317 		Library.prototype.activate.apply( this, arguments );
   8318 	}
   8319 });
   8320 
   8321 module.exports = CollectionAdd;
   8322 
   8323 
   8324 /***/ }),
   8325 
   8326 /***/ "iupV":
   8327 /***/ (function(module, exports) {
   8328 
   8329 /* global ClipboardJS */
   8330 var Attachment = wp.media.view.Attachment,
   8331 	l10n = wp.media.view.l10n,
   8332 	$ = jQuery,
   8333 	Details,
   8334 	__ = wp.i18n.__;
   8335 
   8336 Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototype */{
   8337 	tagName:   'div',
   8338 	className: 'attachment-details',
   8339 	template:  wp.template('attachment-details'),
   8340 
   8341 	/*
   8342 	 * Reset all the attributes inherited from Attachment including role=checkbox,
   8343 	 * tabindex, etc., as they are inappropriate for this view. See #47458 and [30483] / #30390.
   8344 	 */
   8345 	attributes: {},
   8346 
   8347 	events: {
   8348 		'change [data-setting]':          'updateSetting',
   8349 		'change [data-setting] input':    'updateSetting',
   8350 		'change [data-setting] select':   'updateSetting',
   8351 		'change [data-setting] textarea': 'updateSetting',
   8352 		'click .delete-attachment':       'deleteAttachment',
   8353 		'click .trash-attachment':        'trashAttachment',
   8354 		'click .untrash-attachment':      'untrashAttachment',
   8355 		'click .edit-attachment':         'editAttachment',
   8356 		'keydown':                        'toggleSelectionHandler'
   8357 	},
   8358 
   8359 	/**
   8360 	 * Copies the attachment URL to the clipboard.
   8361 	 *
   8362 	 * @since 5.5.0
   8363 	 *
   8364 	 * @param {MouseEvent} event A click event.
   8365 	 *
   8366 	 * @return {void}
   8367 	 */
   8368 	 copyAttachmentDetailsURLClipboard: function() {
   8369 		var clipboard = new ClipboardJS( '.copy-attachment-url' ),
   8370 			successTimeout;
   8371 
   8372 		clipboard.on( 'success', function( event ) {
   8373 			var triggerElement = $( event.trigger ),
   8374 				successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
   8375 
   8376 			// Clear the selection and move focus back to the trigger.
   8377 			event.clearSelection();
   8378 			// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
   8379 			triggerElement.trigger( 'focus' );
   8380 
   8381 			// Show success visual feedback.
   8382 			clearTimeout( successTimeout );
   8383 			successElement.removeClass( 'hidden' );
   8384 
   8385 			// Hide success visual feedback after 3 seconds since last success.
   8386 			successTimeout = setTimeout( function() {
   8387 				successElement.addClass( 'hidden' );
   8388 			}, 3000 );
   8389 
   8390 			// Handle success audible feedback.
   8391 			wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
   8392 		} );
   8393 	 },
   8394 
   8395 	/**
   8396 	 * Shows the details of an attachment.
   8397 	 *
   8398 	 * @since 3.5.0
   8399 	 *
   8400 	 * @constructs wp.media.view.Attachment.Details
   8401 	 * @augments wp.media.view.Attachment
   8402 	 *
   8403 	 * @return {void}
   8404 	 */
   8405 	initialize: function() {
   8406 		this.options = _.defaults( this.options, {
   8407 			rerenderOnModelChange: false
   8408 		});
   8409 
   8410 		// Call 'initialize' directly on the parent class.
   8411 		Attachment.prototype.initialize.apply( this, arguments );
   8412 
   8413 		this.copyAttachmentDetailsURLClipboard();
   8414 	},
   8415 
   8416 	/**
   8417 	 * Gets the focusable elements to move focus to.
   8418 	 *
   8419 	 * @since 5.3.0
   8420 	 */
   8421 	getFocusableElements: function() {
   8422 		var editedAttachment = $( 'li[data-id="' + this.model.id + '"]' );
   8423 
   8424 		this.previousAttachment = editedAttachment.prev();
   8425 		this.nextAttachment = editedAttachment.next();
   8426 	},
   8427 
   8428 	/**
   8429 	 * Moves focus to the previous or next attachment in the grid.
   8430 	 * Fallbacks to the upload button or media frame when there are no attachments.
   8431 	 *
   8432 	 * @since 5.3.0
   8433 	 */
   8434 	moveFocus: function() {
   8435 		if ( this.previousAttachment.length ) {
   8436 			this.previousAttachment.trigger( 'focus' );
   8437 			return;
   8438 		}
   8439 
   8440 		if ( this.nextAttachment.length ) {
   8441 			this.nextAttachment.trigger( 'focus' );
   8442 			return;
   8443 		}
   8444 
   8445 		// Fallback: move focus to the "Select Files" button in the media modal.
   8446 		if ( this.controller.uploader && this.controller.uploader.$browser ) {
   8447 			this.controller.uploader.$browser.trigger( 'focus' );
   8448 			return;
   8449 		}
   8450 
   8451 		// Last fallback.
   8452 		this.moveFocusToLastFallback();
   8453 	},
   8454 
   8455 	/**
   8456 	 * Moves focus to the media frame as last fallback.
   8457 	 *
   8458 	 * @since 5.3.0
   8459 	 */
   8460 	moveFocusToLastFallback: function() {
   8461 		// Last fallback: make the frame focusable and move focus to it.
   8462 		$( '.media-frame' )
   8463 			.attr( 'tabindex', '-1' )
   8464 			.trigger( 'focus' );
   8465 	},
   8466 
   8467 	/**
   8468 	 * Deletes an attachment.
   8469 	 *
   8470 	 * Deletes an attachment after asking for confirmation. After deletion,
   8471 	 * keeps focus in the modal.
   8472 	 *
   8473 	 * @since 3.5.0
   8474 	 *
   8475 	 * @param {MouseEvent} event A click event.
   8476 	 *
   8477 	 * @return {void}
   8478 	 */
   8479 	deleteAttachment: function( event ) {
   8480 		event.preventDefault();
   8481 
   8482 		this.getFocusableElements();
   8483 
   8484 		if ( window.confirm( l10n.warnDelete ) ) {
   8485 			this.model.destroy();
   8486 			this.moveFocus();
   8487 		}
   8488 	},
   8489 
   8490 	/**
   8491 	 * Sets the Trash state on an attachment, or destroys the model itself.
   8492 	 *
   8493 	 * If the mediaTrash setting is set to true, trashes the attachment.
   8494 	 * Otherwise, the model itself is destroyed.
   8495 	 *
   8496 	 * @since 3.9.0
   8497 	 *
   8498 	 * @param {MouseEvent} event A click event.
   8499 	 *
   8500 	 * @return {void}
   8501 	 */
   8502 	trashAttachment: function( event ) {
   8503 		var library = this.controller.library,
   8504 			self = this;
   8505 		event.preventDefault();
   8506 
   8507 		this.getFocusableElements();
   8508 
   8509 		// When in the Media Library and the Media Trash is enabled.
   8510 		if ( wp.media.view.settings.mediaTrash &&
   8511 			'edit-metadata' === this.controller.content.mode() ) {
   8512 
   8513 			this.model.set( 'status', 'trash' );
   8514 			this.model.save().done( function() {
   8515 				library._requery( true );
   8516 				/*
   8517 				 * @todo We need to move focus back to the previous, next, or first
   8518 				 * attachment but the library gets re-queried and refreshed.
   8519 				 * Thus, the references to the previous attachments are lost.
   8520 				 * We need an alternate method.
   8521 				 */
   8522 				self.moveFocusToLastFallback();
   8523 			} );
   8524 		} else {
   8525 			this.model.destroy();
   8526 			this.moveFocus();
   8527 		}
   8528 	},
   8529 
   8530 	/**
   8531 	 * Untrashes an attachment.
   8532 	 *
   8533 	 * @since 4.0.0
   8534 	 *
   8535 	 * @param {MouseEvent} event A click event.
   8536 	 *
   8537 	 * @return {void}
   8538 	 */
   8539 	untrashAttachment: function( event ) {
   8540 		var library = this.controller.library;
   8541 		event.preventDefault();
   8542 
   8543 		this.model.set( 'status', 'inherit' );
   8544 		this.model.save().done( function() {
   8545 			library._requery( true );
   8546 		} );
   8547 	},
   8548 
   8549 	/**
   8550 	 * Opens the edit page for a specific attachment.
   8551 	 *
   8552 	 * @since 3.5.0
   8553 	 *
   8554 	 * @param {MouseEvent} event A click event.
   8555 	 *
   8556 	 * @return {void}
   8557 	 */
   8558 	editAttachment: function( event ) {
   8559 		var editState = this.controller.states.get( 'edit-image' );
   8560 		if ( window.imageEdit && editState ) {
   8561 			event.preventDefault();
   8562 
   8563 			editState.set( 'image', this.model );
   8564 			this.controller.setState( 'edit-image' );
   8565 		} else {
   8566 			this.$el.addClass('needs-refresh');
   8567 		}
   8568 	},
   8569 
   8570 	/**
   8571 	 * Triggers an event on the controller when reverse tabbing (shift+tab).
   8572 	 *
   8573 	 * This event can be used to make sure to move the focus correctly.
   8574 	 *
   8575 	 * @since 4.0.0
   8576 	 *
   8577 	 * @fires wp.media.controller.MediaLibrary#attachment:details:shift-tab
   8578 	 * @fires wp.media.controller.MediaLibrary#attachment:keydown:arrow
   8579 	 *
   8580 	 * @param {KeyboardEvent} event A keyboard event.
   8581 	 *
   8582 	 * @return {boolean|void} Returns false or undefined.
   8583 	 */
   8584 	toggleSelectionHandler: function( event ) {
   8585 		if ( 'keydown' === event.type && 9 === event.keyCode && event.shiftKey && event.target === this.$( ':tabbable' ).get( 0 ) ) {
   8586 			this.controller.trigger( 'attachment:details:shift-tab', event );
   8587 			return false;
   8588 		}
   8589 	},
   8590 
   8591 	render: function() {
   8592 		Attachment.prototype.render.apply( this, arguments );
   8593 
   8594 		wp.media.mixin.removeAllPlayers();
   8595 		this.$( 'audio, video' ).each( function (i, elem) {
   8596 			var el = wp.media.view.MediaDetails.prepareSrc( elem );
   8597 			new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings );
   8598 		} );
   8599 	}
   8600 });
   8601 
   8602 module.exports = Details;
   8603 
   8604 
   8605 /***/ }),
   8606 
   8607 /***/ "l2j4":
   8608 /***/ (function(module, exports) {
   8609 
   8610 /**
   8611  * wp.media.view.Heading
   8612  *
   8613  * A reusable heading component for the media library
   8614  *
   8615  * Used to add accessibility friendly headers in the media library/modal.
   8616  *
   8617  * @class
   8618  * @augments wp.media.View
   8619  * @augments wp.Backbone.View
   8620  * @augments Backbone.View
   8621  */
   8622 var Heading = wp.media.View.extend( {
   8623 	tagName: function() {
   8624 		return this.options.level || 'h1';
   8625 	},
   8626 	className: 'media-views-heading',
   8627 
   8628 	initialize: function() {
   8629 
   8630 		if ( this.options.className ) {
   8631 			this.$el.addClass( this.options.className );
   8632 		}
   8633 
   8634 		this.text = this.options.text;
   8635 	},
   8636 
   8637 	render: function() {
   8638 		this.$el.html( this.text );
   8639 		return this;
   8640 	}
   8641 } );
   8642 
   8643 module.exports = Heading;
   8644 
   8645 
   8646 /***/ }),
   8647 
   8648 /***/ "mVaH":
   8649 /***/ (function(module, exports) {
   8650 
   8651 /**
   8652  * wp.media.controller.MediaLibrary
   8653  *
   8654  * @memberOf wp.media.controller
   8655  *
   8656  * @class
   8657  * @augments wp.media.controller.Library
   8658  * @augments wp.media.controller.State
   8659  * @augments Backbone.Model
   8660  */
   8661 var Library = wp.media.controller.Library,
   8662 	MediaLibrary;
   8663 
   8664 MediaLibrary = Library.extend(/** @lends wp.media.controller.MediaLibrary.prototype */{
   8665 	defaults: _.defaults({
   8666 		// Attachments browser defaults. @see media.view.AttachmentsBrowser
   8667 		filterable:      'uploaded',
   8668 
   8669 		displaySettings: false,
   8670 		priority:        80,
   8671 		syncSelection:   false
   8672 	}, Library.prototype.defaults ),
   8673 
   8674 	/**
   8675 	 * @since 3.9.0
   8676 	 *
   8677 	 * @param options
   8678 	 */
   8679 	initialize: function( options ) {
   8680 		this.media = options.media;
   8681 		this.type = options.type;
   8682 		this.set( 'library', wp.media.query({ type: this.type }) );
   8683 
   8684 		Library.prototype.initialize.apply( this, arguments );
   8685 	},
   8686 
   8687 	/**
   8688 	 * @since 3.9.0
   8689 	 */
   8690 	activate: function() {
   8691 		// @todo this should use this.frame.
   8692 		if ( wp.media.frame.lastMime ) {
   8693 			this.set( 'library', wp.media.query({ type: wp.media.frame.lastMime }) );
   8694 			delete wp.media.frame.lastMime;
   8695 		}
   8696 		Library.prototype.activate.apply( this, arguments );
   8697 	}
   8698 });
   8699 
   8700 module.exports = MediaLibrary;
   8701 
   8702 
   8703 /***/ }),
   8704 
   8705 /***/ "ng6N":
   8706 /***/ (function(module, exports) {
   8707 
   8708 var Selection = wp.media.model.Selection,
   8709 	Library = wp.media.controller.Library,
   8710 	l10n = wp.media.view.l10n,
   8711 	GalleryAdd;
   8712 
   8713 /**
   8714  * wp.media.controller.GalleryAdd
   8715  *
   8716  * A state for selecting more images to add to a gallery.
   8717  *
   8718  * @since 3.5.0
   8719  *
   8720  * @class
   8721  * @augments wp.media.controller.Library
   8722  * @augments wp.media.controller.State
   8723  * @augments Backbone.Model
   8724  *
   8725  * @memberof wp.media.controller
   8726  *
   8727  * @param {Object}                     [attributes]                         The attributes hash passed to the state.
   8728  * @param {string}                     [attributes.id=gallery-library]      Unique identifier.
   8729  * @param {string}                     [attributes.title=Add to Gallery]    Title for the state. Displays in the frame's title region.
   8730  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
   8731  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
   8732  *                                                                          If one is not supplied, a collection of all images will be created.
   8733  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
   8734  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
   8735  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
   8736  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
   8737  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
   8738  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
   8739  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
   8740  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
   8741  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
   8742  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
   8743  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
   8744  * @param {number}                     [attributes.priority=100]            The priority for the state link in the media menu.
   8745  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
   8746  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
   8747  */
   8748 GalleryAdd = Library.extend(/** @lends wp.media.controller.GalleryAdd.prototype */{
   8749 	defaults: _.defaults({
   8750 		id:            'gallery-library',
   8751 		title:         l10n.addToGalleryTitle,
   8752 		multiple:      'add',
   8753 		filterable:    'uploaded',
   8754 		menu:          'gallery',
   8755 		toolbar:       'gallery-add',
   8756 		priority:      100,
   8757 		syncSelection: false
   8758 	}, Library.prototype.defaults ),
   8759 
   8760 	/**
   8761 	 * Initializes the library. Creates a library of images if a library isn't supplied.
   8762 	 *
   8763 	 * @since 3.5.0
   8764 	 *
   8765 	 * @return {void}
   8766 	 */
   8767 	initialize: function() {
   8768 		if ( ! this.get('library') ) {
   8769 			this.set( 'library', wp.media.query({ type: 'image' }) );
   8770 		}
   8771 
   8772 		Library.prototype.initialize.apply( this, arguments );
   8773 	},
   8774 
   8775 	/**
   8776 	 * Activates the library.
   8777 	 *
   8778 	 * Removes all event listeners if in edit mode. Creates a validator to check an attachment.
   8779 	 * Resets library and re-enables event listeners. Activates edit mode. Calls the parent's activate method.
   8780 	 *
   8781 	 * @since 3.5.0
   8782 	 *
   8783 	 * @return {void}
   8784 	 */
   8785 	activate: function() {
   8786 		var library = this.get('library'),
   8787 			edit    = this.frame.state('gallery-edit').get('library');
   8788 
   8789 		if ( this.editLibrary && this.editLibrary !== edit ) {
   8790 			library.unobserve( this.editLibrary );
   8791 		}
   8792 
   8793 		/*
   8794 		 * Accept attachments that exist in the original library but
   8795 		 * that do not exist in gallery's library yet.
   8796 		 */
   8797 		library.validator = function( attachment ) {
   8798 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
   8799 		};
   8800 
   8801 		/*
   8802 		 * Reset the library to ensure that all attachments are re-added
   8803 		 * to the collection. Do so silently, as calling `observe` will
   8804 		 * trigger the `reset` event.
   8805 		 */
   8806 		library.reset( library.mirroring.models, { silent: true });
   8807 		library.observe( edit );
   8808 		this.editLibrary = edit;
   8809 
   8810 		Library.prototype.activate.apply( this, arguments );
   8811 	}
   8812 });
   8813 
   8814 module.exports = GalleryAdd;
   8815 
   8816 
   8817 /***/ }),
   8818 
   8819 /***/ "nwwF":
   8820 /***/ (function(module, exports) {
   8821 
   8822 var View = wp.media.View,
   8823 	$ = Backbone.$,
   8824 	Settings;
   8825 
   8826 /**
   8827  * wp.media.view.Settings
   8828  *
   8829  * @memberOf wp.media.view
   8830  *
   8831  * @class
   8832  * @augments wp.media.View
   8833  * @augments wp.Backbone.View
   8834  * @augments Backbone.View
   8835  */
   8836 Settings = View.extend(/** @lends wp.media.view.Settings.prototype */{
   8837 	events: {
   8838 		'click button':    'updateHandler',
   8839 		'change input':    'updateHandler',
   8840 		'change select':   'updateHandler',
   8841 		'change textarea': 'updateHandler'
   8842 	},
   8843 
   8844 	initialize: function() {
   8845 		this.model = this.model || new Backbone.Model();
   8846 		this.listenTo( this.model, 'change', this.updateChanges );
   8847 	},
   8848 
   8849 	prepare: function() {
   8850 		return _.defaults({
   8851 			model: this.model.toJSON()
   8852 		}, this.options );
   8853 	},
   8854 	/**
   8855 	 * @return {wp.media.view.Settings} Returns itself to allow chaining.
   8856 	 */
   8857 	render: function() {
   8858 		View.prototype.render.apply( this, arguments );
   8859 		// Select the correct values.
   8860 		_( this.model.attributes ).chain().keys().each( this.update, this );
   8861 		return this;
   8862 	},
   8863 	/**
   8864 	 * @param {string} key
   8865 	 */
   8866 	update: function( key ) {
   8867 		var value = this.model.get( key ),
   8868 			$setting = this.$('[data-setting="' + key + '"]'),
   8869 			$buttons, $value;
   8870 
   8871 		// Bail if we didn't find a matching setting.
   8872 		if ( ! $setting.length ) {
   8873 			return;
   8874 		}
   8875 
   8876 		// Attempt to determine how the setting is rendered and update
   8877 		// the selected value.
   8878 
   8879 		// Handle dropdowns.
   8880 		if ( $setting.is('select') ) {
   8881 			$value = $setting.find('[value="' + value + '"]');
   8882 
   8883 			if ( $value.length ) {
   8884 				$setting.find('option').prop( 'selected', false );
   8885 				$value.prop( 'selected', true );
   8886 			} else {
   8887 				// If we can't find the desired value, record what *is* selected.
   8888 				this.model.set( key, $setting.find(':selected').val() );
   8889 			}
   8890 
   8891 		// Handle button groups.
   8892 		} else if ( $setting.hasClass('button-group') ) {
   8893 			$buttons = $setting.find( 'button' )
   8894 				.removeClass( 'active' )
   8895 				.attr( 'aria-pressed', 'false' );
   8896 			$buttons.filter( '[value="' + value + '"]' )
   8897 				.addClass( 'active' )
   8898 				.attr( 'aria-pressed', 'true' );
   8899 
   8900 		// Handle text inputs and textareas.
   8901 		} else if ( $setting.is('input[type="text"], textarea') ) {
   8902 			if ( ! $setting.is(':focus') ) {
   8903 				$setting.val( value );
   8904 			}
   8905 		// Handle checkboxes.
   8906 		} else if ( $setting.is('input[type="checkbox"]') ) {
   8907 			$setting.prop( 'checked', !! value && 'false' !== value );
   8908 		}
   8909 	},
   8910 	/**
   8911 	 * @param {Object} event
   8912 	 */
   8913 	updateHandler: function( event ) {
   8914 		var $setting = $( event.target ).closest('[data-setting]'),
   8915 			value = event.target.value,
   8916 			userSetting;
   8917 
   8918 		event.preventDefault();
   8919 
   8920 		if ( ! $setting.length ) {
   8921 			return;
   8922 		}
   8923 
   8924 		// Use the correct value for checkboxes.
   8925 		if ( $setting.is('input[type="checkbox"]') ) {
   8926 			value = $setting[0].checked;
   8927 		}
   8928 
   8929 		// Update the corresponding setting.
   8930 		this.model.set( $setting.data('setting'), value );
   8931 
   8932 		// If the setting has a corresponding user setting,
   8933 		// update that as well.
   8934 		userSetting = $setting.data('userSetting');
   8935 		if ( userSetting ) {
   8936 			window.setUserSetting( userSetting, value );
   8937 		}
   8938 	},
   8939 
   8940 	updateChanges: function( model ) {
   8941 		if ( model.hasChanged() ) {
   8942 			_( model.changed ).chain().keys().each( this.update, this );
   8943 		}
   8944 	}
   8945 });
   8946 
   8947 module.exports = Settings;
   8948 
   8949 
   8950 /***/ }),
   8951 
   8952 /***/ "ojD6":
   8953 /***/ (function(module, exports) {
   8954 
   8955 var View = wp.media.View,
   8956 	$ = jQuery,
   8957 	Attachments,
   8958 	infiniteScrolling = wp.media.view.settings.infiniteScrolling;
   8959 
   8960 Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{
   8961 	tagName:   'ul',
   8962 	className: 'attachments',
   8963 
   8964 	attributes: {
   8965 		tabIndex: -1
   8966 	},
   8967 
   8968 	/**
   8969 	 * Represents the overview of attachments in the Media Library.
   8970 	 *
   8971 	 * The constructor binds events to the collection this view represents when
   8972 	 * adding or removing attachments or resetting the entire collection.
   8973 	 *
   8974 	 * @since 3.5.0
   8975 	 *
   8976 	 * @constructs
   8977 	 * @memberof wp.media.view
   8978 	 *
   8979 	 * @augments wp.media.View
   8980 	 *
   8981 	 * @listens collection:add
   8982 	 * @listens collection:remove
   8983 	 * @listens collection:reset
   8984 	 * @listens controller:library:selection:add
   8985 	 * @listens scrollElement:scroll
   8986 	 * @listens this:ready
   8987 	 * @listens controller:open
   8988 	 */
   8989 	initialize: function() {
   8990 		this.el.id = _.uniqueId('__attachments-view-');
   8991 
   8992 		/**
   8993 		 * @since 5.8.0 Added the `infiniteScrolling` parameter.
   8994 		 *
   8995 		 * @param infiniteScrolling  Whether to enable infinite scrolling or use
   8996 		 *                           the default "load more" button.
   8997 		 * @param refreshSensitivity The time in milliseconds to throttle the scroll
   8998 		 *                           handler.
   8999 		 * @param refreshThreshold   The amount of pixels that should be scrolled before
   9000 		 *                           loading more attachments from the server.
   9001 		 * @param AttachmentView     The view class to be used for models in the
   9002 		 *                           collection.
   9003 		 * @param sortable           A jQuery sortable options object
   9004 		 *                           ( http://api.jqueryui.com/sortable/ ).
   9005 		 * @param resize             A boolean indicating whether or not to listen to
   9006 		 *                           resize events.
   9007 		 * @param idealColumnWidth   The width in pixels which a column should have when
   9008 		 *                           calculating the total number of columns.
   9009 		 */
   9010 		_.defaults( this.options, {
   9011 			infiniteScrolling:  infiniteScrolling || false,
   9012 			refreshSensitivity: wp.media.isTouchDevice ? 300 : 200,
   9013 			refreshThreshold:   3,
   9014 			AttachmentView:     wp.media.view.Attachment,
   9015 			sortable:           false,
   9016 			resize:             true,
   9017 			idealColumnWidth:   $( window ).width() < 640 ? 135 : 150
   9018 		});
   9019 
   9020 		this._viewsByCid = {};
   9021 		this.$window = $( window );
   9022 		this.resizeEvent = 'resize.media-modal-columns';
   9023 
   9024 		this.collection.on( 'add', function( attachment ) {
   9025 			this.views.add( this.createAttachmentView( attachment ), {
   9026 				at: this.collection.indexOf( attachment )
   9027 			});
   9028 		}, this );
   9029 
   9030 		/*
   9031 		 * Find the view to be removed, delete it and call the remove function to clear
   9032 		 * any set event handlers.
   9033 		 */
   9034 		this.collection.on( 'remove', function( attachment ) {
   9035 			var view = this._viewsByCid[ attachment.cid ];
   9036 			delete this._viewsByCid[ attachment.cid ];
   9037 
   9038 			if ( view ) {
   9039 				view.remove();
   9040 			}
   9041 		}, this );
   9042 
   9043 		this.collection.on( 'reset', this.render, this );
   9044 
   9045 		this.controller.on( 'library:selection:add', this.attachmentFocus, this );
   9046 
   9047 		if ( this.options.infiniteScrolling ) {
   9048 			// Throttle the scroll handler and bind this.
   9049 			this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
   9050 
   9051 			this.options.scrollElement = this.options.scrollElement || this.el;
   9052 			$( this.options.scrollElement ).on( 'scroll', this.scroll );
   9053 		}
   9054 
   9055 		this.initSortable();
   9056 
   9057 		_.bindAll( this, 'setColumns' );
   9058 
   9059 		if ( this.options.resize ) {
   9060 			this.on( 'ready', this.bindEvents );
   9061 			this.controller.on( 'open', this.setColumns );
   9062 
   9063 			/*
   9064 			 * Call this.setColumns() after this view has been rendered in the
   9065 			 * DOM so attachments get proper width applied.
   9066 			 */
   9067 			_.defer( this.setColumns, this );
   9068 		}
   9069 	},
   9070 
   9071 	/**
   9072 	 * Listens to the resizeEvent on the window.
   9073 	 *
   9074 	 * Adjusts the amount of columns accordingly. First removes any existing event
   9075 	 * handlers to prevent duplicate listeners.
   9076 	 *
   9077 	 * @since 4.0.0
   9078 	 *
   9079 	 * @listens window:resize
   9080 	 *
   9081 	 * @return {void}
   9082 	 */
   9083 	bindEvents: function() {
   9084 		this.$window.off( this.resizeEvent ).on( this.resizeEvent, _.debounce( this.setColumns, 50 ) );
   9085 	},
   9086 
   9087 	/**
   9088 	 * Focuses the first item in the collection.
   9089 	 *
   9090 	 * @since 4.0.0
   9091 	 *
   9092 	 * @return {void}
   9093 	 */
   9094 	attachmentFocus: function() {
   9095 		/*
   9096 		 * @todo When uploading new attachments, this tries to move focus to
   9097 		 * the attachments grid. Actually, a progress bar gets initially displayed
   9098 		 * and then updated when uploading completes, so focus is lost.
   9099 		 * Additionally: this view is used for both the attachments list and
   9100 		 * the list of selected attachments in the bottom media toolbar. Thus, when
   9101 		 * uploading attachments, it is called twice and returns two different `this`.
   9102 		 * `this.columns` is truthy within the modal.
   9103 		 */
   9104 		if ( this.columns ) {
   9105 			// Move focus to the grid list within the modal.
   9106 			this.$el.focus();
   9107 		}
   9108 	},
   9109 
   9110 	/**
   9111 	 * Restores focus to the selected item in the collection.
   9112 	 *
   9113 	 * Moves focus back to the first selected attachment in the grid. Used when
   9114 	 * tabbing backwards from the attachment details sidebar.
   9115 	 * See media.view.AttachmentsBrowser.
   9116 	 *
   9117 	 * @since 4.0.0
   9118 	 *
   9119 	 * @return {void}
   9120 	 */
   9121 	restoreFocus: function() {
   9122 		this.$( 'li.selected:first' ).focus();
   9123 	},
   9124 
   9125 	/**
   9126 	 * Handles events for arrow key presses.
   9127 	 *
   9128 	 * Focuses the attachment in the direction of the used arrow key if it exists.
   9129 	 *
   9130 	 * @since 4.0.0
   9131 	 *
   9132 	 * @param {KeyboardEvent} event The keyboard event that triggered this function.
   9133 	 *
   9134 	 * @return {void}
   9135 	 */
   9136 	arrowEvent: function( event ) {
   9137 		var attachments = this.$el.children( 'li' ),
   9138 			perRow = this.columns,
   9139 			index = attachments.filter( ':focus' ).index(),
   9140 			row = ( index + 1 ) <= perRow ? 1 : Math.ceil( ( index + 1 ) / perRow );
   9141 
   9142 		if ( index === -1 ) {
   9143 			return;
   9144 		}
   9145 
   9146 		// Left arrow = 37.
   9147 		if ( 37 === event.keyCode ) {
   9148 			if ( 0 === index ) {
   9149 				return;
   9150 			}
   9151 			attachments.eq( index - 1 ).focus();
   9152 		}
   9153 
   9154 		// Up arrow = 38.
   9155 		if ( 38 === event.keyCode ) {
   9156 			if ( 1 === row ) {
   9157 				return;
   9158 			}
   9159 			attachments.eq( index - perRow ).focus();
   9160 		}
   9161 
   9162 		// Right arrow = 39.
   9163 		if ( 39 === event.keyCode ) {
   9164 			if ( attachments.length === index ) {
   9165 				return;
   9166 			}
   9167 			attachments.eq( index + 1 ).focus();
   9168 		}
   9169 
   9170 		// Down arrow = 40.
   9171 		if ( 40 === event.keyCode ) {
   9172 			if ( Math.ceil( attachments.length / perRow ) === row ) {
   9173 				return;
   9174 			}
   9175 			attachments.eq( index + perRow ).focus();
   9176 		}
   9177 	},
   9178 
   9179 	/**
   9180 	 * Clears any set event handlers.
   9181 	 *
   9182 	 * @since 3.5.0
   9183 	 *
   9184 	 * @return {void}
   9185 	 */
   9186 	dispose: function() {
   9187 		this.collection.props.off( null, null, this );
   9188 		if ( this.options.resize ) {
   9189 			this.$window.off( this.resizeEvent );
   9190 		}
   9191 
   9192 		// Call 'dispose' directly on the parent class.
   9193 		View.prototype.dispose.apply( this, arguments );
   9194 	},
   9195 
   9196 	/**
   9197 	 * Calculates the amount of columns.
   9198 	 *
   9199 	 * Calculates the amount of columns and sets it on the data-columns attribute
   9200 	 * of .media-frame-content.
   9201 	 *
   9202 	 * @since 4.0.0
   9203 	 *
   9204 	 * @return {void}
   9205 	 */
   9206 	setColumns: function() {
   9207 		var prev = this.columns,
   9208 			width = this.$el.width();
   9209 
   9210 		if ( width ) {
   9211 			this.columns = Math.min( Math.round( width / this.options.idealColumnWidth ), 12 ) || 1;
   9212 
   9213 			if ( ! prev || prev !== this.columns ) {
   9214 				this.$el.closest( '.media-frame-content' ).attr( 'data-columns', this.columns );
   9215 			}
   9216 		}
   9217 	},
   9218 
   9219 	/**
   9220 	 * Initializes jQuery sortable on the attachment list.
   9221 	 *
   9222 	 * Fails gracefully if jQuery sortable doesn't exist or isn't passed
   9223 	 * in the options.
   9224 	 *
   9225 	 * @since 3.5.0
   9226 	 *
   9227 	 * @fires collection:reset
   9228 	 *
   9229 	 * @return {void}
   9230 	 */
   9231 	initSortable: function() {
   9232 		var collection = this.collection;
   9233 
   9234 		if ( ! this.options.sortable || ! $.fn.sortable ) {
   9235 			return;
   9236 		}
   9237 
   9238 		this.$el.sortable( _.extend({
   9239 			// If the `collection` has a `comparator`, disable sorting.
   9240 			disabled: !! collection.comparator,
   9241 
   9242 			/*
   9243 			 * Change the position of the attachment as soon as the mouse pointer
   9244 			 * overlaps a thumbnail.
   9245 			 */
   9246 			tolerance: 'pointer',
   9247 
   9248 			// Record the initial `index` of the dragged model.
   9249 			start: function( event, ui ) {
   9250 				ui.item.data('sortableIndexStart', ui.item.index());
   9251 			},
   9252 
   9253 			/*
   9254 			 * Update the model's index in the collection. Do so silently, as the view
   9255 			 * is already accurate.
   9256 			 */
   9257 			update: function( event, ui ) {
   9258 				var model = collection.at( ui.item.data('sortableIndexStart') ),
   9259 					comparator = collection.comparator;
   9260 
   9261 				// Temporarily disable the comparator to prevent `add`
   9262 				// from re-sorting.
   9263 				delete collection.comparator;
   9264 
   9265 				// Silently shift the model to its new index.
   9266 				collection.remove( model, {
   9267 					silent: true
   9268 				});
   9269 				collection.add( model, {
   9270 					silent: true,
   9271 					at:     ui.item.index()
   9272 				});
   9273 
   9274 				// Restore the comparator.
   9275 				collection.comparator = comparator;
   9276 
   9277 				// Fire the `reset` event to ensure other collections sync.
   9278 				collection.trigger( 'reset', collection );
   9279 
   9280 				// If the collection is sorted by menu order, update the menu order.
   9281 				collection.saveMenuOrder();
   9282 			}
   9283 		}, this.options.sortable ) );
   9284 
   9285 		/*
   9286 		 * If the `orderby` property is changed on the `collection`,
   9287 		 * check to see if we have a `comparator`. If so, disable sorting.
   9288 		 */
   9289 		collection.props.on( 'change:orderby', function() {
   9290 			this.$el.sortable( 'option', 'disabled', !! collection.comparator );
   9291 		}, this );
   9292 
   9293 		this.collection.props.on( 'change:orderby', this.refreshSortable, this );
   9294 		this.refreshSortable();
   9295 	},
   9296 
   9297 	/**
   9298 	 * Disables jQuery sortable if collection has a comparator or collection.orderby
   9299 	 * equals menuOrder.
   9300 	 *
   9301 	 * @since 3.5.0
   9302 	 *
   9303 	 * @return {void}
   9304 	 */
   9305 	refreshSortable: function() {
   9306 		if ( ! this.options.sortable || ! $.fn.sortable ) {
   9307 			return;
   9308 		}
   9309 
   9310 		var collection = this.collection,
   9311 			orderby = collection.props.get('orderby'),
   9312 			enabled = 'menuOrder' === orderby || ! collection.comparator;
   9313 
   9314 		this.$el.sortable( 'option', 'disabled', ! enabled );
   9315 	},
   9316 
   9317 	/**
   9318 	 * Creates a new view for an attachment and adds it to _viewsByCid.
   9319 	 *
   9320 	 * @since 3.5.0
   9321 	 *
   9322 	 * @param {wp.media.model.Attachment} attachment
   9323 	 *
   9324 	 * @return {wp.media.View} The created view.
   9325 	 */
   9326 	createAttachmentView: function( attachment ) {
   9327 		var view = new this.options.AttachmentView({
   9328 			controller:           this.controller,
   9329 			model:                attachment,
   9330 			collection:           this.collection,
   9331 			selection:            this.options.selection
   9332 		});
   9333 
   9334 		return this._viewsByCid[ attachment.cid ] = view;
   9335 	},
   9336 
   9337 	/**
   9338 	 * Prepares view for display.
   9339 	 *
   9340 	 * Creates views for every attachment in collection if the collection is not
   9341 	 * empty, otherwise clears all views and loads more attachments.
   9342 	 *
   9343 	 * @since 3.5.0
   9344 	 *
   9345 	 * @return {void}
   9346 	 */
   9347 	prepare: function() {
   9348 		if ( this.collection.length ) {
   9349 			this.views.set( this.collection.map( this.createAttachmentView, this ) );
   9350 		} else {
   9351 			this.views.unset();
   9352 			if ( this.options.infiniteScrolling ) {
   9353 				this.collection.more().done( this.scroll );
   9354 			}
   9355 		}
   9356 	},
   9357 
   9358 	/**
   9359 	 * Triggers the scroll function to check if we should query for additional
   9360 	 * attachments right away.
   9361 	 *
   9362 	 * @since 3.5.0
   9363 	 *
   9364 	 * @return {void}
   9365 	 */
   9366 	ready: function() {
   9367 		if ( this.options.infiniteScrolling ) {
   9368 			this.scroll();
   9369 		}
   9370 	},
   9371 
   9372 	/**
   9373 	 * Handles scroll events.
   9374 	 *
   9375 	 * Shows the spinner if we're close to the bottom. Loads more attachments from
   9376 	 * server if we're {refreshThreshold} times away from the bottom.
   9377 	 *
   9378 	 * @since 3.5.0
   9379 	 *
   9380 	 * @return {void}
   9381 	 */
   9382 	scroll: function() {
   9383 		var view = this,
   9384 			el = this.options.scrollElement,
   9385 			scrollTop = el.scrollTop,
   9386 			toolbar;
   9387 
   9388 		/*
   9389 		 * The scroll event occurs on the document, but the element that should be
   9390 		 * checked is the document body.
   9391 		 */
   9392 		if ( el === document ) {
   9393 			el = document.body;
   9394 			scrollTop = $(document).scrollTop();
   9395 		}
   9396 
   9397 		if ( ! $(el).is(':visible') || ! this.collection.hasMore() ) {
   9398 			return;
   9399 		}
   9400 
   9401 		toolbar = this.views.parent.toolbar;
   9402 
   9403 		// Show the spinner only if we are close to the bottom.
   9404 		if ( el.scrollHeight - ( scrollTop + el.clientHeight ) < el.clientHeight / 3 ) {
   9405 			toolbar.get('spinner').show();
   9406 		}
   9407 
   9408 		if ( el.scrollHeight < scrollTop + ( el.clientHeight * this.options.refreshThreshold ) ) {
   9409 			this.collection.more().done(function() {
   9410 				view.scroll();
   9411 				toolbar.get('spinner').hide();
   9412 			});
   9413 		}
   9414 	}
   9415 });
   9416 
   9417 module.exports = Attachments;
   9418 
   9419 
   9420 /***/ }),
   9421 
   9422 /***/ "qe5n":
   9423 /***/ (function(module, exports) {
   9424 
   9425 var l10n = wp.media.view.l10n,
   9426 	$ = Backbone.$,
   9427 	Embed;
   9428 
   9429 /**
   9430  * wp.media.controller.Embed
   9431  *
   9432  * A state for embedding media from a URL.
   9433  *
   9434  * @memberOf wp.media.controller
   9435  *
   9436  * @class
   9437  * @augments wp.media.controller.State
   9438  * @augments Backbone.Model
   9439  *
   9440  * @param {object} attributes                         The attributes hash passed to the state.
   9441  * @param {string} [attributes.id=embed]              Unique identifier.
   9442  * @param {string} [attributes.title=Insert From URL] Title for the state. Displays in the media menu and the frame's title region.
   9443  * @param {string} [attributes.content=embed]         Initial mode for the content region.
   9444  * @param {string} [attributes.menu=default]          Initial mode for the menu region.
   9445  * @param {string} [attributes.toolbar=main-embed]    Initial mode for the toolbar region.
   9446  * @param {string} [attributes.menu=false]            Initial mode for the menu region.
   9447  * @param {int}    [attributes.priority=120]          The priority for the state link in the media menu.
   9448  * @param {string} [attributes.type=link]             The type of embed. Currently only link is supported.
   9449  * @param {string} [attributes.url]                   The embed URL.
   9450  * @param {object} [attributes.metadata={}]           Properties of the embed, which will override attributes.url if set.
   9451  */
   9452 Embed = wp.media.controller.State.extend(/** @lends wp.media.controller.Embed.prototype */{
   9453 	defaults: {
   9454 		id:       'embed',
   9455 		title:    l10n.insertFromUrlTitle,
   9456 		content:  'embed',
   9457 		menu:     'default',
   9458 		toolbar:  'main-embed',
   9459 		priority: 120,
   9460 		type:     'link',
   9461 		url:      '',
   9462 		metadata: {}
   9463 	},
   9464 
   9465 	// The amount of time used when debouncing the scan.
   9466 	sensitivity: 400,
   9467 
   9468 	initialize: function(options) {
   9469 		this.metadata = options.metadata;
   9470 		this.debouncedScan = _.debounce( _.bind( this.scan, this ), this.sensitivity );
   9471 		this.props = new Backbone.Model( this.metadata || { url: '' });
   9472 		this.props.on( 'change:url', this.debouncedScan, this );
   9473 		this.props.on( 'change:url', this.refresh, this );
   9474 		this.on( 'scan', this.scanImage, this );
   9475 	},
   9476 
   9477 	/**
   9478 	 * Trigger a scan of the embedded URL's content for metadata required to embed.
   9479 	 *
   9480 	 * @fires wp.media.controller.Embed#scan
   9481 	 */
   9482 	scan: function() {
   9483 		var scanners,
   9484 			embed = this,
   9485 			attributes = {
   9486 				type: 'link',
   9487 				scanners: []
   9488 			};
   9489 
   9490 		/*
   9491 		 * Scan is triggered with the list of `attributes` to set on the
   9492 		 * state, useful for the 'type' attribute and 'scanners' attribute,
   9493 		 * an array of promise objects for asynchronous scan operations.
   9494 		 */
   9495 		if ( this.props.get('url') ) {
   9496 			this.trigger( 'scan', attributes );
   9497 		}
   9498 
   9499 		if ( attributes.scanners.length ) {
   9500 			scanners = attributes.scanners = $.when.apply( $, attributes.scanners );
   9501 			scanners.always( function() {
   9502 				if ( embed.get('scanners') === scanners ) {
   9503 					embed.set( 'loading', false );
   9504 				}
   9505 			});
   9506 		} else {
   9507 			attributes.scanners = null;
   9508 		}
   9509 
   9510 		attributes.loading = !! attributes.scanners;
   9511 		this.set( attributes );
   9512 	},
   9513 	/**
   9514 	 * Try scanning the embed as an image to discover its dimensions.
   9515 	 *
   9516 	 * @param {Object} attributes
   9517 	 */
   9518 	scanImage: function( attributes ) {
   9519 		var frame = this.frame,
   9520 			state = this,
   9521 			url = this.props.get('url'),
   9522 			image = new Image(),
   9523 			deferred = $.Deferred();
   9524 
   9525 		attributes.scanners.push( deferred.promise() );
   9526 
   9527 		// Try to load the image and find its width/height.
   9528 		image.onload = function() {
   9529 			deferred.resolve();
   9530 
   9531 			if ( state !== frame.state() || url !== state.props.get('url') ) {
   9532 				return;
   9533 			}
   9534 
   9535 			state.set({
   9536 				type: 'image'
   9537 			});
   9538 
   9539 			state.props.set({
   9540 				width:  image.width,
   9541 				height: image.height
   9542 			});
   9543 		};
   9544 
   9545 		image.onerror = deferred.reject;
   9546 		image.src = url;
   9547 	},
   9548 
   9549 	refresh: function() {
   9550 		this.frame.toolbar.get().refresh();
   9551 	},
   9552 
   9553 	reset: function() {
   9554 		this.props.clear().set({ url: '' });
   9555 
   9556 		if ( this.active ) {
   9557 			this.refresh();
   9558 		}
   9559 	}
   9560 });
   9561 
   9562 module.exports = Embed;
   9563 
   9564 
   9565 /***/ }),
   9566 
   9567 /***/ "sULL":
   9568 /***/ (function(module, exports) {
   9569 
   9570 var View = wp.media.View,
   9571 	$ = jQuery,
   9572 	Attachment;
   9573 
   9574 /**
   9575  * wp.media.view.Attachment
   9576  *
   9577  * @memberOf wp.media.view
   9578  *
   9579  * @class
   9580  * @augments wp.media.View
   9581  * @augments wp.Backbone.View
   9582  * @augments Backbone.View
   9583  */
   9584 Attachment = View.extend(/** @lends wp.media.view.Attachment.prototype */{
   9585 	tagName:   'li',
   9586 	className: 'attachment',
   9587 	template:  wp.template('attachment'),
   9588 
   9589 	attributes: function() {
   9590 		return {
   9591 			'tabIndex':     0,
   9592 			'role':         'checkbox',
   9593 			'aria-label':   this.model.get( 'title' ),
   9594 			'aria-checked': false,
   9595 			'data-id':      this.model.get( 'id' )
   9596 		};
   9597 	},
   9598 
   9599 	events: {
   9600 		'click':                          'toggleSelectionHandler',
   9601 		'change [data-setting]':          'updateSetting',
   9602 		'change [data-setting] input':    'updateSetting',
   9603 		'change [data-setting] select':   'updateSetting',
   9604 		'change [data-setting] textarea': 'updateSetting',
   9605 		'click .attachment-close':        'removeFromLibrary',
   9606 		'click .check':                   'checkClickHandler',
   9607 		'keydown':                        'toggleSelectionHandler'
   9608 	},
   9609 
   9610 	buttons: {},
   9611 
   9612 	initialize: function() {
   9613 		var selection = this.options.selection,
   9614 			options = _.defaults( this.options, {
   9615 				rerenderOnModelChange: true
   9616 			} );
   9617 
   9618 		if ( options.rerenderOnModelChange ) {
   9619 			this.listenTo( this.model, 'change', this.render );
   9620 		} else {
   9621 			this.listenTo( this.model, 'change:percent', this.progress );
   9622 		}
   9623 		this.listenTo( this.model, 'change:title', this._syncTitle );
   9624 		this.listenTo( this.model, 'change:caption', this._syncCaption );
   9625 		this.listenTo( this.model, 'change:artist', this._syncArtist );
   9626 		this.listenTo( this.model, 'change:album', this._syncAlbum );
   9627 
   9628 		// Update the selection.
   9629 		this.listenTo( this.model, 'add', this.select );
   9630 		this.listenTo( this.model, 'remove', this.deselect );
   9631 		if ( selection ) {
   9632 			selection.on( 'reset', this.updateSelect, this );
   9633 			// Update the model's details view.
   9634 			this.listenTo( this.model, 'selection:single selection:unsingle', this.details );
   9635 			this.details( this.model, this.controller.state().get('selection') );
   9636 		}
   9637 
   9638 		this.listenTo( this.controller.states, 'attachment:compat:waiting attachment:compat:ready', this.updateSave );
   9639 	},
   9640 	/**
   9641 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
   9642 	 */
   9643 	dispose: function() {
   9644 		var selection = this.options.selection;
   9645 
   9646 		// Make sure all settings are saved before removing the view.
   9647 		this.updateAll();
   9648 
   9649 		if ( selection ) {
   9650 			selection.off( null, null, this );
   9651 		}
   9652 		/**
   9653 		 * call 'dispose' directly on the parent class
   9654 		 */
   9655 		View.prototype.dispose.apply( this, arguments );
   9656 		return this;
   9657 	},
   9658 	/**
   9659 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
   9660 	 */
   9661 	render: function() {
   9662 		var options = _.defaults( this.model.toJSON(), {
   9663 				orientation:   'landscape',
   9664 				uploading:     false,
   9665 				type:          '',
   9666 				subtype:       '',
   9667 				icon:          '',
   9668 				filename:      '',
   9669 				caption:       '',
   9670 				title:         '',
   9671 				dateFormatted: '',
   9672 				width:         '',
   9673 				height:        '',
   9674 				compat:        false,
   9675 				alt:           '',
   9676 				description:   ''
   9677 			}, this.options );
   9678 
   9679 		options.buttons  = this.buttons;
   9680 		options.describe = this.controller.state().get('describe');
   9681 
   9682 		if ( 'image' === options.type ) {
   9683 			options.size = this.imageSize();
   9684 		}
   9685 
   9686 		options.can = {};
   9687 		if ( options.nonces ) {
   9688 			options.can.remove = !! options.nonces['delete'];
   9689 			options.can.save = !! options.nonces.update;
   9690 		}
   9691 
   9692 		if ( this.controller.state().get('allowLocalEdits') ) {
   9693 			options.allowLocalEdits = true;
   9694 		}
   9695 
   9696 		if ( options.uploading && ! options.percent ) {
   9697 			options.percent = 0;
   9698 		}
   9699 
   9700 		this.views.detach();
   9701 		this.$el.html( this.template( options ) );
   9702 
   9703 		this.$el.toggleClass( 'uploading', options.uploading );
   9704 
   9705 		if ( options.uploading ) {
   9706 			this.$bar = this.$('.media-progress-bar div');
   9707 		} else {
   9708 			delete this.$bar;
   9709 		}
   9710 
   9711 		// Check if the model is selected.
   9712 		this.updateSelect();
   9713 
   9714 		// Update the save status.
   9715 		this.updateSave();
   9716 
   9717 		this.views.render();
   9718 
   9719 		return this;
   9720 	},
   9721 
   9722 	progress: function() {
   9723 		if ( this.$bar && this.$bar.length ) {
   9724 			this.$bar.width( this.model.get('percent') + '%' );
   9725 		}
   9726 	},
   9727 
   9728 	/**
   9729 	 * @param {Object} event
   9730 	 */
   9731 	toggleSelectionHandler: function( event ) {
   9732 		var method;
   9733 
   9734 		// Don't do anything inside inputs and on the attachment check and remove buttons.
   9735 		if ( 'INPUT' === event.target.nodeName || 'BUTTON' === event.target.nodeName ) {
   9736 			return;
   9737 		}
   9738 
   9739 		// Catch arrow events.
   9740 		if ( 37 === event.keyCode || 38 === event.keyCode || 39 === event.keyCode || 40 === event.keyCode ) {
   9741 			this.controller.trigger( 'attachment:keydown:arrow', event );
   9742 			return;
   9743 		}
   9744 
   9745 		// Catch enter and space events.
   9746 		if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
   9747 			return;
   9748 		}
   9749 
   9750 		event.preventDefault();
   9751 
   9752 		// In the grid view, bubble up an edit:attachment event to the controller.
   9753 		if ( this.controller.isModeActive( 'grid' ) ) {
   9754 			if ( this.controller.isModeActive( 'edit' ) ) {
   9755 				// Pass the current target to restore focus when closing.
   9756 				this.controller.trigger( 'edit:attachment', this.model, event.currentTarget );
   9757 				return;
   9758 			}
   9759 
   9760 			if ( this.controller.isModeActive( 'select' ) ) {
   9761 				method = 'toggle';
   9762 			}
   9763 		}
   9764 
   9765 		if ( event.shiftKey ) {
   9766 			method = 'between';
   9767 		} else if ( event.ctrlKey || event.metaKey ) {
   9768 			method = 'toggle';
   9769 		}
   9770 
   9771 		this.toggleSelection({
   9772 			method: method
   9773 		});
   9774 
   9775 		this.controller.trigger( 'selection:toggle' );
   9776 	},
   9777 	/**
   9778 	 * @param {Object} options
   9779 	 */
   9780 	toggleSelection: function( options ) {
   9781 		var collection = this.collection,
   9782 			selection = this.options.selection,
   9783 			model = this.model,
   9784 			method = options && options.method,
   9785 			single, models, singleIndex, modelIndex;
   9786 
   9787 		if ( ! selection ) {
   9788 			return;
   9789 		}
   9790 
   9791 		single = selection.single();
   9792 		method = _.isUndefined( method ) ? selection.multiple : method;
   9793 
   9794 		// If the `method` is set to `between`, select all models that
   9795 		// exist between the current and the selected model.
   9796 		if ( 'between' === method && single && selection.multiple ) {
   9797 			// If the models are the same, short-circuit.
   9798 			if ( single === model ) {
   9799 				return;
   9800 			}
   9801 
   9802 			singleIndex = collection.indexOf( single );
   9803 			modelIndex  = collection.indexOf( this.model );
   9804 
   9805 			if ( singleIndex < modelIndex ) {
   9806 				models = collection.models.slice( singleIndex, modelIndex + 1 );
   9807 			} else {
   9808 				models = collection.models.slice( modelIndex, singleIndex + 1 );
   9809 			}
   9810 
   9811 			selection.add( models );
   9812 			selection.single( model );
   9813 			return;
   9814 
   9815 		// If the `method` is set to `toggle`, just flip the selection
   9816 		// status, regardless of whether the model is the single model.
   9817 		} else if ( 'toggle' === method ) {
   9818 			selection[ this.selected() ? 'remove' : 'add' ]( model );
   9819 			selection.single( model );
   9820 			return;
   9821 		} else if ( 'add' === method ) {
   9822 			selection.add( model );
   9823 			selection.single( model );
   9824 			return;
   9825 		}
   9826 
   9827 		// Fixes bug that loses focus when selecting a featured image.
   9828 		if ( ! method ) {
   9829 			method = 'add';
   9830 		}
   9831 
   9832 		if ( method !== 'add' ) {
   9833 			method = 'reset';
   9834 		}
   9835 
   9836 		if ( this.selected() ) {
   9837 			/*
   9838 			 * If the model is the single model, remove it.
   9839 			 * If it is not the same as the single model,
   9840 			 * it now becomes the single model.
   9841 			 */
   9842 			selection[ single === model ? 'remove' : 'single' ]( model );
   9843 		} else {
   9844 			/*
   9845 			 * If the model is not selected, run the `method` on the
   9846 			 * selection. By default, we `reset` the selection, but the
   9847 			 * `method` can be set to `add` the model to the selection.
   9848 			 */
   9849 			selection[ method ]( model );
   9850 			selection.single( model );
   9851 		}
   9852 	},
   9853 
   9854 	updateSelect: function() {
   9855 		this[ this.selected() ? 'select' : 'deselect' ]();
   9856 	},
   9857 	/**
   9858 	 * @return {unresolved|boolean}
   9859 	 */
   9860 	selected: function() {
   9861 		var selection = this.options.selection;
   9862 		if ( selection ) {
   9863 			return !! selection.get( this.model.cid );
   9864 		}
   9865 	},
   9866 	/**
   9867 	 * @param {Backbone.Model} model
   9868 	 * @param {Backbone.Collection} collection
   9869 	 */
   9870 	select: function( model, collection ) {
   9871 		var selection = this.options.selection,
   9872 			controller = this.controller;
   9873 
   9874 		/*
   9875 		 * Check if a selection exists and if it's the collection provided.
   9876 		 * If they're not the same collection, bail; we're in another
   9877 		 * selection's event loop.
   9878 		 */
   9879 		if ( ! selection || ( collection && collection !== selection ) ) {
   9880 			return;
   9881 		}
   9882 
   9883 		// Bail if the model is already selected.
   9884 		if ( this.$el.hasClass( 'selected' ) ) {
   9885 			return;
   9886 		}
   9887 
   9888 		// Add 'selected' class to model, set aria-checked to true.
   9889 		this.$el.addClass( 'selected' ).attr( 'aria-checked', true );
   9890 		//  Make the checkbox tabable, except in media grid (bulk select mode).
   9891 		if ( ! ( controller.isModeActive( 'grid' ) && controller.isModeActive( 'select' ) ) ) {
   9892 			this.$( '.check' ).attr( 'tabindex', '0' );
   9893 		}
   9894 	},
   9895 	/**
   9896 	 * @param {Backbone.Model} model
   9897 	 * @param {Backbone.Collection} collection
   9898 	 */
   9899 	deselect: function( model, collection ) {
   9900 		var selection = this.options.selection;
   9901 
   9902 		/*
   9903 		 * Check if a selection exists and if it's the collection provided.
   9904 		 * If they're not the same collection, bail; we're in another
   9905 		 * selection's event loop.
   9906 		 */
   9907 		if ( ! selection || ( collection && collection !== selection ) ) {
   9908 			return;
   9909 		}
   9910 		this.$el.removeClass( 'selected' ).attr( 'aria-checked', false )
   9911 			.find( '.check' ).attr( 'tabindex', '-1' );
   9912 	},
   9913 	/**
   9914 	 * @param {Backbone.Model} model
   9915 	 * @param {Backbone.Collection} collection
   9916 	 */
   9917 	details: function( model, collection ) {
   9918 		var selection = this.options.selection,
   9919 			details;
   9920 
   9921 		if ( selection !== collection ) {
   9922 			return;
   9923 		}
   9924 
   9925 		details = selection.single();
   9926 		this.$el.toggleClass( 'details', details === this.model );
   9927 	},
   9928 	/**
   9929 	 * @param {string} size
   9930 	 * @return {Object}
   9931 	 */
   9932 	imageSize: function( size ) {
   9933 		var sizes = this.model.get('sizes'), matched = false;
   9934 
   9935 		size = size || 'medium';
   9936 
   9937 		// Use the provided image size if possible.
   9938 		if ( sizes ) {
   9939 			if ( sizes[ size ] ) {
   9940 				matched = sizes[ size ];
   9941 			} else if ( sizes.large ) {
   9942 				matched = sizes.large;
   9943 			} else if ( sizes.thumbnail ) {
   9944 				matched = sizes.thumbnail;
   9945 			} else if ( sizes.full ) {
   9946 				matched = sizes.full;
   9947 			}
   9948 
   9949 			if ( matched ) {
   9950 				return _.clone( matched );
   9951 			}
   9952 		}
   9953 
   9954 		return {
   9955 			url:         this.model.get('url'),
   9956 			width:       this.model.get('width'),
   9957 			height:      this.model.get('height'),
   9958 			orientation: this.model.get('orientation')
   9959 		};
   9960 	},
   9961 	/**
   9962 	 * @param {Object} event
   9963 	 */
   9964 	updateSetting: function( event ) {
   9965 		var $setting = $( event.target ).closest('[data-setting]'),
   9966 			setting, value;
   9967 
   9968 		if ( ! $setting.length ) {
   9969 			return;
   9970 		}
   9971 
   9972 		setting = $setting.data('setting');
   9973 		value   = event.target.value;
   9974 
   9975 		if ( this.model.get( setting ) !== value ) {
   9976 			this.save( setting, value );
   9977 		}
   9978 	},
   9979 
   9980 	/**
   9981 	 * Pass all the arguments to the model's save method.
   9982 	 *
   9983 	 * Records the aggregate status of all save requests and updates the
   9984 	 * view's classes accordingly.
   9985 	 */
   9986 	save: function() {
   9987 		var view = this,
   9988 			save = this._save = this._save || { status: 'ready' },
   9989 			request = this.model.save.apply( this.model, arguments ),
   9990 			requests = save.requests ? $.when( request, save.requests ) : request;
   9991 
   9992 		// If we're waiting to remove 'Saved.', stop.
   9993 		if ( save.savedTimer ) {
   9994 			clearTimeout( save.savedTimer );
   9995 		}
   9996 
   9997 		this.updateSave('waiting');
   9998 		save.requests = requests;
   9999 		requests.always( function() {
  10000 			// If we've performed another request since this one, bail.
  10001 			if ( save.requests !== requests ) {
  10002 				return;
  10003 			}
  10004 
  10005 			view.updateSave( requests.state() === 'resolved' ? 'complete' : 'error' );
  10006 			save.savedTimer = setTimeout( function() {
  10007 				view.updateSave('ready');
  10008 				delete save.savedTimer;
  10009 			}, 2000 );
  10010 		});
  10011 	},
  10012 	/**
  10013 	 * @param {string} status
  10014 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  10015 	 */
  10016 	updateSave: function( status ) {
  10017 		var save = this._save = this._save || { status: 'ready' };
  10018 
  10019 		if ( status && status !== save.status ) {
  10020 			this.$el.removeClass( 'save-' + save.status );
  10021 			save.status = status;
  10022 		}
  10023 
  10024 		this.$el.addClass( 'save-' + save.status );
  10025 		return this;
  10026 	},
  10027 
  10028 	updateAll: function() {
  10029 		var $settings = this.$('[data-setting]'),
  10030 			model = this.model,
  10031 			changed;
  10032 
  10033 		changed = _.chain( $settings ).map( function( el ) {
  10034 			var $input = $('input, textarea, select, [value]', el ),
  10035 				setting, value;
  10036 
  10037 			if ( ! $input.length ) {
  10038 				return;
  10039 			}
  10040 
  10041 			setting = $(el).data('setting');
  10042 			value = $input.val();
  10043 
  10044 			// Record the value if it changed.
  10045 			if ( model.get( setting ) !== value ) {
  10046 				return [ setting, value ];
  10047 			}
  10048 		}).compact().object().value();
  10049 
  10050 		if ( ! _.isEmpty( changed ) ) {
  10051 			model.save( changed );
  10052 		}
  10053 	},
  10054 	/**
  10055 	 * @param {Object} event
  10056 	 */
  10057 	removeFromLibrary: function( event ) {
  10058 		// Catch enter and space events.
  10059 		if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
  10060 			return;
  10061 		}
  10062 
  10063 		// Stop propagation so the model isn't selected.
  10064 		event.stopPropagation();
  10065 
  10066 		this.collection.remove( this.model );
  10067 	},
  10068 
  10069 	/**
  10070 	 * Add the model if it isn't in the selection, if it is in the selection,
  10071 	 * remove it.
  10072 	 *
  10073 	 * @param {[type]} event [description]
  10074 	 * @return {[type]} [description]
  10075 	 */
  10076 	checkClickHandler: function ( event ) {
  10077 		var selection = this.options.selection;
  10078 		if ( ! selection ) {
  10079 			return;
  10080 		}
  10081 		event.stopPropagation();
  10082 		if ( selection.where( { id: this.model.get( 'id' ) } ).length ) {
  10083 			selection.remove( this.model );
  10084 			// Move focus back to the attachment tile (from the check).
  10085 			this.$el.focus();
  10086 		} else {
  10087 			selection.add( this.model );
  10088 		}
  10089 
  10090 		// Trigger an action button update.
  10091 		this.controller.trigger( 'selection:toggle' );
  10092 	}
  10093 });
  10094 
  10095 // Ensure settings remain in sync between attachment views.
  10096 _.each({
  10097 	caption: '_syncCaption',
  10098 	title:   '_syncTitle',
  10099 	artist:  '_syncArtist',
  10100 	album:   '_syncAlbum'
  10101 }, function( method, setting ) {
  10102 	/**
  10103 	 * @function _syncCaption
  10104 	 * @memberOf wp.media.view.Attachment
  10105 	 * @instance
  10106 	 *
  10107 	 * @param {Backbone.Model} model
  10108 	 * @param {string} value
  10109 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  10110 	 */
  10111 	/**
  10112 	 * @function _syncTitle
  10113 	 * @memberOf wp.media.view.Attachment
  10114 	 * @instance
  10115 	 *
  10116 	 * @param {Backbone.Model} model
  10117 	 * @param {string} value
  10118 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  10119 	 */
  10120 	/**
  10121 	 * @function _syncArtist
  10122 	 * @memberOf wp.media.view.Attachment
  10123 	 * @instance
  10124 	 *
  10125 	 * @param {Backbone.Model} model
  10126 	 * @param {string} value
  10127 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  10128 	 */
  10129 	/**
  10130 	 * @function _syncAlbum
  10131 	 * @memberOf wp.media.view.Attachment
  10132 	 * @instance
  10133 	 *
  10134 	 * @param {Backbone.Model} model
  10135 	 * @param {string} value
  10136 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
  10137 	 */
  10138 	Attachment.prototype[ method ] = function( model, value ) {
  10139 		var $setting = this.$('[data-setting="' + setting + '"]');
  10140 
  10141 		if ( ! $setting.length ) {
  10142 			return this;
  10143 		}
  10144 
  10145 		/*
  10146 		 * If the updated value is in sync with the value in the DOM, there
  10147 		 * is no need to re-render. If we're currently editing the value,
  10148 		 * it will automatically be in sync, suppressing the re-render for
  10149 		 * the view we're editing, while updating any others.
  10150 		 */
  10151 		if ( value === $setting.find('input, textarea, select, [value]').val() ) {
  10152 			return this;
  10153 		}
  10154 
  10155 		return this.render();
  10156 	};
  10157 });
  10158 
  10159 module.exports = Attachment;
  10160 
  10161 
  10162 /***/ }),
  10163 
  10164 /***/ "t3nl":
  10165 /***/ (function(module, exports) {
  10166 
  10167 /**
  10168  * wp.media.view.Iframe
  10169  *
  10170  * @memberOf wp.media.view
  10171  *
  10172  * @class
  10173  * @augments wp.media.View
  10174  * @augments wp.Backbone.View
  10175  * @augments Backbone.View
  10176  */
  10177 var Iframe = wp.media.View.extend(/** @lends wp.media.view.Iframe.prototype */{
  10178 	className: 'media-iframe',
  10179 	/**
  10180 	 * @return {wp.media.view.Iframe} Returns itself to allow chaining.
  10181 	 */
  10182 	render: function() {
  10183 		this.views.detach();
  10184 		this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
  10185 		this.views.render();
  10186 		return this;
  10187 	}
  10188 });
  10189 
  10190 module.exports = Iframe;
  10191 
  10192 
  10193 /***/ }),
  10194 
  10195 /***/ "tg/Y":
  10196 /***/ (function(module, exports, __webpack_require__) {
  10197 
  10198 /**
  10199  * @output wp-includes/js/media-views.js
  10200  */
  10201 
  10202 var media = wp.media,
  10203 	$ = jQuery,
  10204 	l10n;
  10205 
  10206 media.isTouchDevice = ( 'ontouchend' in document );
  10207 
  10208 // Link any localized strings.
  10209 l10n = media.view.l10n = window._wpMediaViewsL10n || {};
  10210 
  10211 // Link any settings.
  10212 media.view.settings = l10n.settings || {};
  10213 delete l10n.settings;
  10214 
  10215 // Copy the `post` setting over to the model settings.
  10216 media.model.settings.post = media.view.settings.post;
  10217 
  10218 // Check if the browser supports CSS 3.0 transitions.
  10219 $.support.transition = (function(){
  10220 	var style = document.documentElement.style,
  10221 		transitions = {
  10222 			WebkitTransition: 'webkitTransitionEnd',
  10223 			MozTransition:    'transitionend',
  10224 			OTransition:      'oTransitionEnd otransitionend',
  10225 			transition:       'transitionend'
  10226 		}, transition;
  10227 
  10228 	transition = _.find( _.keys( transitions ), function( transition ) {
  10229 		return ! _.isUndefined( style[ transition ] );
  10230 	});
  10231 
  10232 	return transition && {
  10233 		end: transitions[ transition ]
  10234 	};
  10235 }());
  10236 
  10237 /**
  10238  * A shared event bus used to provide events into
  10239  * the media workflows that 3rd-party devs can use to hook
  10240  * in.
  10241  */
  10242 media.events = _.extend( {}, Backbone.Events );
  10243 
  10244 /**
  10245  * Makes it easier to bind events using transitions.
  10246  *
  10247  * @param {string} selector
  10248  * @param {number} sensitivity
  10249  * @return {Promise}
  10250  */
  10251 media.transition = function( selector, sensitivity ) {
  10252 	var deferred = $.Deferred();
  10253 
  10254 	sensitivity = sensitivity || 2000;
  10255 
  10256 	if ( $.support.transition ) {
  10257 		if ( ! (selector instanceof $) ) {
  10258 			selector = $( selector );
  10259 		}
  10260 
  10261 		// Resolve the deferred when the first element finishes animating.
  10262 		selector.first().one( $.support.transition.end, deferred.resolve );
  10263 
  10264 		// Just in case the event doesn't trigger, fire a callback.
  10265 		_.delay( deferred.resolve, sensitivity );
  10266 
  10267 	// Otherwise, execute on the spot.
  10268 	} else {
  10269 		deferred.resolve();
  10270 	}
  10271 
  10272 	return deferred.promise();
  10273 };
  10274 
  10275 media.controller.Region = __webpack_require__( "WiNq" );
  10276 media.controller.StateMachine = __webpack_require__( "U3Se" );
  10277 media.controller.State = __webpack_require__( "M5ZC" );
  10278 
  10279 media.selectionSync = __webpack_require__( "PgTd" );
  10280 media.controller.Library = __webpack_require__( "F/kE" );
  10281 media.controller.ImageDetails = __webpack_require__( "IkWq" );
  10282 media.controller.GalleryEdit = __webpack_require__( "99yY" );
  10283 media.controller.GalleryAdd = __webpack_require__( "ng6N" );
  10284 media.controller.CollectionEdit = __webpack_require__( "Mt+m" );
  10285 media.controller.CollectionAdd = __webpack_require__( "iipZ" );
  10286 media.controller.FeaturedImage = __webpack_require__( "I7TD" );
  10287 media.controller.ReplaceImage = __webpack_require__( "aBqq" );
  10288 media.controller.EditImage = __webpack_require__( "4tHu" );
  10289 media.controller.MediaLibrary = __webpack_require__( "mVaH" );
  10290 media.controller.Embed = __webpack_require__( "qe5n" );
  10291 media.controller.Cropper = __webpack_require__( "M+xU" );
  10292 media.controller.CustomizeImageCropper = __webpack_require__( "eqTc" );
  10293 media.controller.SiteIconCropper = __webpack_require__( "W+32" );
  10294 
  10295 media.View = __webpack_require__( "Bbnu" );
  10296 media.view.Frame = __webpack_require__( "LGdN" );
  10297 media.view.MediaFrame = __webpack_require__( "Pt9x" );
  10298 media.view.MediaFrame.Select = __webpack_require__( "fYN4" );
  10299 media.view.MediaFrame.Post = __webpack_require__( "6B7g" );
  10300 media.view.MediaFrame.ImageDetails = __webpack_require__( "VIJ9" );
  10301 media.view.Modal = __webpack_require__( "gOpb" );
  10302 media.view.FocusManager = __webpack_require__( "3nJM" );
  10303 media.view.UploaderWindow = __webpack_require__( "S4jH" );
  10304 media.view.EditorUploader = __webpack_require__( "GXkx" );
  10305 media.view.UploaderInline = __webpack_require__( "7Bpz" );
  10306 media.view.UploaderStatus = __webpack_require__( "NguE" );
  10307 media.view.UploaderStatusError = __webpack_require__( "ZeG4" );
  10308 media.view.Toolbar = __webpack_require__( "2NU8" );
  10309 media.view.Toolbar.Select = __webpack_require__( "IgEq" );
  10310 media.view.Toolbar.Embed = __webpack_require__( "xQvM" );
  10311 media.view.Button = __webpack_require__( "LZpE" );
  10312 media.view.ButtonGroup = __webpack_require__( "z/+l" );
  10313 media.view.PriorityList = __webpack_require__( "NjyZ" );
  10314 media.view.MenuItem = __webpack_require__( "dpRc" );
  10315 media.view.Menu = __webpack_require__( "Ju2C" );
  10316 media.view.RouterItem = __webpack_require__( "Q9T/" );
  10317 media.view.Router = __webpack_require__( "EVvK" );
  10318 media.view.Sidebar = __webpack_require__( "9ARG" );
  10319 media.view.Attachment = __webpack_require__( "sULL" );
  10320 media.view.Attachment.Library = __webpack_require__( "2jku" );
  10321 media.view.Attachment.EditLibrary = __webpack_require__( "EvXF" );
  10322 media.view.Attachments = __webpack_require__( "ojD6" );
  10323 media.view.Search = __webpack_require__( "ZgZ7" );
  10324 media.view.AttachmentFilters = __webpack_require__( "1S4+" );
  10325 media.view.DateFilter = __webpack_require__( "VkcK" );
  10326 media.view.AttachmentFilters.Uploaded = __webpack_require__( "4jjk" );
  10327 media.view.AttachmentFilters.All = __webpack_require__( "KerO" );
  10328 media.view.AttachmentsBrowser = __webpack_require__( "72mI" );
  10329 media.view.Selection = __webpack_require__( "04Ix" );
  10330 media.view.Attachment.Selection = __webpack_require__( "yGM1" );
  10331 media.view.Attachments.Selection = __webpack_require__( "wfCN" );
  10332 media.view.Attachment.EditSelection = __webpack_require__( "P6DV" );
  10333 media.view.Settings = __webpack_require__( "nwwF" );
  10334 media.view.Settings.AttachmentDisplay = __webpack_require__( "2AvB" );
  10335 media.view.Settings.Gallery = __webpack_require__( "umxe" );
  10336 media.view.Settings.Playlist = __webpack_require__( "76BF" );
  10337 media.view.Attachment.Details = __webpack_require__( "iupV" );
  10338 media.view.AttachmentCompat = __webpack_require__( "LND6" );
  10339 media.view.Iframe = __webpack_require__( "t3nl" );
  10340 media.view.Embed = __webpack_require__( "VMHs" );
  10341 media.view.Label = __webpack_require__( "V6sy" );
  10342 media.view.EmbedUrl = __webpack_require__( "+mQJ" );
  10343 media.view.EmbedLink = __webpack_require__( "JecU" );
  10344 media.view.EmbedImage = __webpack_require__( "+B8m" );
  10345 media.view.ImageDetails = __webpack_require__( "GXJ6" );
  10346 media.view.Cropper = __webpack_require__( "Vh02" );
  10347 media.view.SiteIconCropper = __webpack_require__( "UmHM" );
  10348 media.view.SiteIconPreview = __webpack_require__( "d3xu" );
  10349 media.view.EditImage = __webpack_require__( "ibOK" );
  10350 media.view.Spinner = __webpack_require__( "cH3P" );
  10351 media.view.Heading = __webpack_require__( "l2j4" );
  10352 
  10353 
  10354 /***/ }),
  10355 
  10356 /***/ "umxe":
  10357 /***/ (function(module, exports) {
  10358 
  10359 /**
  10360  * wp.media.view.Settings.Gallery
  10361  *
  10362  * @memberOf wp.media.view.Settings
  10363  *
  10364  * @class
  10365  * @augments wp.media.view.Settings
  10366  * @augments wp.media.View
  10367  * @augments wp.Backbone.View
  10368  * @augments Backbone.View
  10369  */
  10370 var Gallery = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Gallery.prototype */{
  10371 	className: 'collection-settings gallery-settings',
  10372 	template:  wp.template('gallery-settings')
  10373 });
  10374 
  10375 module.exports = Gallery;
  10376 
  10377 
  10378 /***/ }),
  10379 
  10380 /***/ "wfCN":
  10381 /***/ (function(module, exports) {
  10382 
  10383 var Attachments = wp.media.view.Attachments,
  10384 	Selection;
  10385 
  10386 /**
  10387  * wp.media.view.Attachments.Selection
  10388  *
  10389  * @memberOf wp.media.view.Attachments
  10390  *
  10391  * @class
  10392  * @augments wp.media.view.Attachments
  10393  * @augments wp.media.View
  10394  * @augments wp.Backbone.View
  10395  * @augments Backbone.View
  10396  */
  10397 Selection = Attachments.extend(/** @lends wp.media.view.Attachments.Selection.prototype */{
  10398 	events: {},
  10399 	initialize: function() {
  10400 		_.defaults( this.options, {
  10401 			sortable:   false,
  10402 			resize:     false,
  10403 
  10404 			// The single `Attachment` view to be used in the `Attachments` view.
  10405 			AttachmentView: wp.media.view.Attachment.Selection
  10406 		});
  10407 		// Call 'initialize' directly on the parent class.
  10408 		return Attachments.prototype.initialize.apply( this, arguments );
  10409 	}
  10410 });
  10411 
  10412 module.exports = Selection;
  10413 
  10414 
  10415 /***/ }),
  10416 
  10417 /***/ "xQvM":
  10418 /***/ (function(module, exports) {
  10419 
  10420 var Select = wp.media.view.Toolbar.Select,
  10421 	l10n = wp.media.view.l10n,
  10422 	Embed;
  10423 
  10424 /**
  10425  * wp.media.view.Toolbar.Embed
  10426  *
  10427  * @memberOf wp.media.view.Toolbar
  10428  *
  10429  * @class
  10430  * @augments wp.media.view.Toolbar.Select
  10431  * @augments wp.media.view.Toolbar
  10432  * @augments wp.media.View
  10433  * @augments wp.Backbone.View
  10434  * @augments Backbone.View
  10435  */
  10436 Embed = Select.extend(/** @lends wp.media.view.Toolbar.Embed.prototype */{
  10437 	initialize: function() {
  10438 		_.defaults( this.options, {
  10439 			text: l10n.insertIntoPost,
  10440 			requires: false
  10441 		});
  10442 		// Call 'initialize' directly on the parent class.
  10443 		Select.prototype.initialize.apply( this, arguments );
  10444 	},
  10445 
  10446 	refresh: function() {
  10447 		var url = this.controller.state().props.get('url');
  10448 		this.get('select').model.set( 'disabled', ! url || url === 'http://' );
  10449 		/**
  10450 		 * call 'refresh' directly on the parent class
  10451 		 */
  10452 		Select.prototype.refresh.apply( this, arguments );
  10453 	}
  10454 });
  10455 
  10456 module.exports = Embed;
  10457 
  10458 
  10459 /***/ }),
  10460 
  10461 /***/ "yGM1":
  10462 /***/ (function(module, exports) {
  10463 
  10464 /**
  10465  * wp.media.view.Attachment.Selection
  10466  *
  10467  * @memberOf wp.media.view.Attachment
  10468  *
  10469  * @class
  10470  * @augments wp.media.view.Attachment
  10471  * @augments wp.media.View
  10472  * @augments wp.Backbone.View
  10473  * @augments Backbone.View
  10474  */
  10475 var Selection = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Selection.prototype */{
  10476 	className: 'attachment selection',
  10477 
  10478 	// On click, just select the model, instead of removing the model from
  10479 	// the selection.
  10480 	toggleSelection: function() {
  10481 		this.options.selection.single( this.model );
  10482 	}
  10483 });
  10484 
  10485 module.exports = Selection;
  10486 
  10487 
  10488 /***/ }),
  10489 
  10490 /***/ "z/+l":
  10491 /***/ (function(module, exports) {
  10492 
  10493 var $ = Backbone.$,
  10494 	ButtonGroup;
  10495 
  10496 /**
  10497  * wp.media.view.ButtonGroup
  10498  *
  10499  * @memberOf wp.media.view
  10500  *
  10501  * @class
  10502  * @augments wp.media.View
  10503  * @augments wp.Backbone.View
  10504  * @augments Backbone.View
  10505  */
  10506 ButtonGroup = wp.media.View.extend(/** @lends wp.media.view.ButtonGroup.prototype */{
  10507 	tagName:   'div',
  10508 	className: 'button-group button-large media-button-group',
  10509 
  10510 	initialize: function() {
  10511 		/**
  10512 		 * @member {wp.media.view.Button[]}
  10513 		 */
  10514 		this.buttons = _.map( this.options.buttons || [], function( button ) {
  10515 			if ( button instanceof Backbone.View ) {
  10516 				return button;
  10517 			} else {
  10518 				return new wp.media.view.Button( button ).render();
  10519 			}
  10520 		});
  10521 
  10522 		delete this.options.buttons;
  10523 
  10524 		if ( this.options.classes ) {
  10525 			this.$el.addClass( this.options.classes );
  10526 		}
  10527 	},
  10528 
  10529 	/**
  10530 	 * @return {wp.media.view.ButtonGroup}
  10531 	 */
  10532 	render: function() {
  10533 		this.$el.html( $( _.pluck( this.buttons, 'el' ) ).detach() );
  10534 		return this;
  10535 	}
  10536 });
  10537 
  10538 module.exports = ButtonGroup;
  10539 
  10540 
  10541 /***/ })
  10542 
  10543 /******/ });