wp/wp-includes/js/media-views.js
changeset 22 8c2e4d02f4ef
parent 21 48c4eec2b7e6
equal deleted inserted replaced
21:48c4eec2b7e6 22:8c2e4d02f4ef
     1 /******/ (() => { // webpackBootstrap
     1 /******/ (() => { // webpackBootstrap
     2 /******/ 	var __webpack_modules__ = ({
     2 /******/ 	var __webpack_modules__ = ({
     3 
     3 
     4 /***/ 7145:
     4 /***/ 1:
     5 /***/ ((module) => {
     5 /***/ ((module) => {
     6 
     6 
     7 var Selection = wp.media.model.Selection,
     7 var MenuItem = wp.media.view.MenuItem,
     8 	Library = wp.media.controller.Library,
     8 	PriorityList = wp.media.view.PriorityList,
     9 	CollectionAdd;
     9 	Menu;
    10 
    10 
    11 /**
    11 /**
    12  * wp.media.controller.CollectionAdd
    12  * wp.media.view.Menu
    13  *
    13  *
    14  * A state for adding attachments to a collection (e.g. video playlist).
    14  * @memberOf wp.media.view
    15  *
       
    16  * @memberOf wp.media.controller
       
    17  *
    15  *
    18  * @class
    16  * @class
    19  * @augments wp.media.controller.Library
    17  * @augments wp.media.view.PriorityList
    20  * @augments wp.media.controller.State
    18  * @augments wp.media.View
    21  * @augments Backbone.Model
    19  * @augments wp.Backbone.View
    22  *
    20  * @augments Backbone.View
    23  * @param {object}                     [attributes]                         The attributes hash passed to the state.
       
    24  * @param {string}                     [attributes.id=library]              Unique identifier.
       
    25  * @param {string}                     attributes.title                     Title for the state. Displays in the frame's title region.
       
    26  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
       
    27  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
       
    28  *                                                                          If one is not supplied, a collection of attachments of the specified type will be created.
       
    29  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
       
    30  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
       
    31  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
       
    32  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
       
    33  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
       
    34  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
       
    35  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
       
    36  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
       
    37  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
    38  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
    39  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
    40  * @param {int}                        [attributes.priority=100]            The priority for the state link in the media menu.
       
    41  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
       
    42  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
       
    43  * @param {string}                     attributes.type                      The collection's media type. (e.g. 'video').
       
    44  * @param {string}                     attributes.collectionType            The collection type. (e.g. 'playlist').
       
    45  */
    21  */
    46 CollectionAdd = Library.extend(/** @lends wp.media.controller.CollectionAdd.prototype */{
    22 Menu = PriorityList.extend(/** @lends wp.media.view.Menu.prototype */{
    47 	defaults: _.defaults( {
    23 	tagName:   'div',
    48 		// Selection defaults. @see media.model.Selection
    24 	className: 'media-menu',
    49 		multiple:      'add',
    25 	property:  'state',
    50 		// Attachments browser defaults. @see media.view.AttachmentsBrowser
    26 	ItemView:  MenuItem,
    51 		filterable:    'uploaded',
    27 	region:    'menu',
    52 
    28 
    53 		priority:      100,
    29 	attributes: {
    54 		syncSelection: false
    30 		role:               'tablist',
    55 	}, Library.prototype.defaults ),
    31 		'aria-orientation': 'horizontal'
    56 
    32 	},
    57 	/**
    33 
    58 	 * @since 3.9.0
       
    59 	 */
       
    60 	initialize: function() {
    34 	initialize: function() {
    61 		var collectionType = this.get('collectionType');
    35 		this._views = {};
    62 
    36 
    63 		if ( 'video' === this.get( 'type' ) ) {
    37 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
    64 			collectionType = 'video-' + collectionType;
    38 		delete this.options.views;
    65 		}
    39 
    66 
    40 		if ( ! this.options.silent ) {
    67 		this.set( 'id', collectionType + '-library' );
    41 			this.render();
    68 		this.set( 'toolbar', collectionType + '-add' );
    42 		}
    69 		this.set( 'menu', collectionType );
    43 
    70 
    44 		// Initialize the Focus Manager.
    71 		// If we haven't been provided a `library`, create a `Selection`.
    45 		this.focusManager = new wp.media.view.FocusManager( {
    72 		if ( ! this.get('library') ) {
    46 			el:   this.el,
    73 			this.set( 'library', wp.media.query({ type: this.get('type') }) );
    47 			mode: 'tabsNavigation'
    74 		}
    48 		} );
    75 		Library.prototype.initialize.apply( this, arguments );
    49 
    76 	},
    50 		// The menu is always rendered and can be visible or hidden on some frames.
    77 
    51 		this.isVisible = true;
    78 	/**
    52 	},
    79 	 * @since 3.9.0
    53 
    80 	 */
    54 	/**
    81 	activate: function() {
    55 	 * @param {Object} options
    82 		var library = this.get('library'),
    56 	 * @param {string} id
    83 			editLibrary = this.get('editLibrary'),
    57 	 * @return {wp.media.View}
    84 			edit = this.frame.state( this.get('collectionType') + '-edit' ).get('library');
    58 	 */
    85 
    59 	toView: function( options, id ) {
    86 		if ( editLibrary && editLibrary !== edit ) {
    60 		options = options || {};
    87 			library.unobserve( editLibrary );
    61 		options[ this.property ] = options[ this.property ] || id;
    88 		}
    62 		return new this.ItemView( options ).render();
    89 
    63 	},
    90 		// Accepts attachments that exist in the original library and
    64 
    91 		// that do not exist in gallery's library.
    65 	ready: function() {
    92 		library.validator = function( attachment ) {
    66 		/**
    93 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
    67 		 * call 'ready' directly on the parent class
    94 		};
       
    95 
       
    96 		/*
       
    97 		 * Reset the library to ensure that all attachments are re-added
       
    98 		 * to the collection. Do so silently, as calling `observe` will
       
    99 		 * trigger the `reset` event.
       
   100 		 */
    68 		 */
   101 		library.reset( library.mirroring.models, { silent: true });
    69 		PriorityList.prototype.ready.apply( this, arguments );
   102 		library.observe( edit );
    70 		this.visibility();
   103 		this.set('editLibrary', edit);
    71 
   104 
    72 		// Set up aria tabs initial attributes.
   105 		Library.prototype.activate.apply( this, arguments );
    73 		this.focusManager.setupAriaTabs();
       
    74 	},
       
    75 
       
    76 	set: function() {
       
    77 		/**
       
    78 		 * call 'set' directly on the parent class
       
    79 		 */
       
    80 		PriorityList.prototype.set.apply( this, arguments );
       
    81 		this.visibility();
       
    82 	},
       
    83 
       
    84 	unset: function() {
       
    85 		/**
       
    86 		 * call 'unset' directly on the parent class
       
    87 		 */
       
    88 		PriorityList.prototype.unset.apply( this, arguments );
       
    89 		this.visibility();
       
    90 	},
       
    91 
       
    92 	visibility: function() {
       
    93 		var region = this.region,
       
    94 			view = this.controller[ region ].get(),
       
    95 			views = this.views.get(),
       
    96 			hide = ! views || views.length < 2;
       
    97 
       
    98 		if ( this === view ) {
       
    99 			// Flag this menu as hidden or visible.
       
   100 			this.isVisible = ! hide;
       
   101 			// Set or remove a CSS class to hide the menu.
       
   102 			this.controller.$el.toggleClass( 'hide-' + region, hide );
       
   103 		}
       
   104 	},
       
   105 	/**
       
   106 	 * @param {string} id
       
   107 	 */
       
   108 	select: function( id ) {
       
   109 		var view = this.get( id );
       
   110 
       
   111 		if ( ! view ) {
       
   112 			return;
       
   113 		}
       
   114 
       
   115 		this.deselect();
       
   116 		view.$el.addClass('active');
       
   117 
       
   118 		// Set up again the aria tabs initial attributes after the menu updates.
       
   119 		this.focusManager.setupAriaTabs();
       
   120 	},
       
   121 
       
   122 	deselect: function() {
       
   123 		this.$el.children().removeClass('active');
       
   124 	},
       
   125 
       
   126 	hide: function( id ) {
       
   127 		var view = this.get( id );
       
   128 
       
   129 		if ( ! view ) {
       
   130 			return;
       
   131 		}
       
   132 
       
   133 		view.$el.addClass('hidden');
       
   134 	},
       
   135 
       
   136 	show: function( id ) {
       
   137 		var view = this.get( id );
       
   138 
       
   139 		if ( ! view ) {
       
   140 			return;
       
   141 		}
       
   142 
       
   143 		view.$el.removeClass('hidden');
   106 	}
   144 	}
   107 });
   145 });
   108 
   146 
   109 module.exports = CollectionAdd;
   147 module.exports = Menu;
   110 
   148 
   111 
   149 
   112 /***/ }),
   150 /***/ }),
   113 
   151 
   114 /***/ 8612:
   152 /***/ 168:
   115 /***/ ((module) => {
   153 /***/ ((module) => {
   116 
   154 
   117 var Library = wp.media.controller.Library,
   155 var $ = Backbone.$,
   118 	l10n = wp.media.view.l10n,
   156 	ButtonGroup;
   119 	$ = jQuery,
       
   120 	CollectionEdit;
       
   121 
   157 
   122 /**
   158 /**
   123  * wp.media.controller.CollectionEdit
   159  * wp.media.view.ButtonGroup
   124  *
   160  *
   125  * A state for editing a collection, which is used by audio and video playlists,
   161  * @memberOf wp.media.view
   126  * and can be used for other collections.
       
   127  *
       
   128  * @memberOf wp.media.controller
       
   129  *
   162  *
   130  * @class
   163  * @class
   131  * @augments wp.media.controller.Library
   164  * @augments wp.media.View
   132  * @augments wp.media.controller.State
   165  * @augments wp.Backbone.View
   133  * @augments Backbone.Model
   166  * @augments Backbone.View
   134  *
       
   135  * @param {object}                     [attributes]                      The attributes hash passed to the state.
       
   136  * @param {string}                     attributes.title                  Title for the state. Displays in the media menu and the frame's title region.
       
   137  * @param {wp.media.model.Attachments} [attributes.library]              The attachments collection to edit.
       
   138  *                                                                       If one is not supplied, an empty media.model.Selection collection is created.
       
   139  * @param {boolean}                    [attributes.multiple=false]       Whether multi-select is enabled.
       
   140  * @param {string}                     [attributes.content=browse]       Initial mode for the content region.
       
   141  * @param {string}                     attributes.menu                   Initial mode for the menu region. @todo this needs a better explanation.
       
   142  * @param {boolean}                    [attributes.searchable=false]     Whether the library is searchable.
       
   143  * @param {boolean}                    [attributes.sortable=true]        Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
   144  * @param {boolean}                    [attributes.date=true]            Whether to show the date filter in the browser's toolbar.
       
   145  * @param {boolean}                    [attributes.describe=true]        Whether to offer UI to describe the attachments - e.g. captioning images in a gallery.
       
   146  * @param {boolean}                    [attributes.dragInfo=true]        Whether to show instructional text about the attachments being sortable.
       
   147  * @param {boolean}                    [attributes.dragInfoText]         Instructional text about the attachments being sortable.
       
   148  * @param {int}                        [attributes.idealColumnWidth=170] The ideal column width in pixels for attachments.
       
   149  * @param {boolean}                    [attributes.editing=false]        Whether the gallery is being created, or editing an existing instance.
       
   150  * @param {int}                        [attributes.priority=60]          The priority for the state link in the media menu.
       
   151  * @param {boolean}                    [attributes.syncSelection=false]  Whether the Attachments selection should be persisted from the last state.
       
   152  *                                                                       Defaults to false for this state, because the library passed in  *is* the selection.
       
   153  * @param {view}                       [attributes.SettingsView]         The view to edit the collection instance settings (e.g. Playlist settings with "Show tracklist" checkbox).
       
   154  * @param {view}                       [attributes.AttachmentView]       The single `Attachment` view to be used in the `Attachments`.
       
   155  *                                                                       If none supplied, defaults to wp.media.view.Attachment.EditLibrary.
       
   156  * @param {string}                     attributes.type                   The collection's media type. (e.g. 'video').
       
   157  * @param {string}                     attributes.collectionType         The collection type. (e.g. 'playlist').
       
   158  */
   167  */
   159 CollectionEdit = Library.extend(/** @lends wp.media.controller.CollectionEdit.prototype */{
   168 ButtonGroup = wp.media.View.extend(/** @lends wp.media.view.ButtonGroup.prototype */{
   160 	defaults: {
   169 	tagName:   'div',
   161 		multiple:         false,
   170 	className: 'button-group button-large media-button-group',
   162 		sortable:         true,
   171 
   163 		date:             false,
       
   164 		searchable:       false,
       
   165 		content:          'browse',
       
   166 		describe:         true,
       
   167 		dragInfo:         true,
       
   168 		idealColumnWidth: 170,
       
   169 		editing:          false,
       
   170 		priority:         60,
       
   171 		SettingsView:     false,
       
   172 		syncSelection:    false
       
   173 	},
       
   174 
       
   175 	/**
       
   176 	 * @since 3.9.0
       
   177 	 */
       
   178 	initialize: function() {
   172 	initialize: function() {
   179 		var collectionType = this.get('collectionType');
   173 		/**
   180 
   174 		 * @member {wp.media.view.Button[]}
   181 		if ( 'video' === this.get( 'type' ) ) {
   175 		 */
   182 			collectionType = 'video-' + collectionType;
   176 		this.buttons = _.map( this.options.buttons || [], function( button ) {
   183 		}
   177 			if ( button instanceof Backbone.View ) {
   184 
   178 				return button;
   185 		this.set( 'id', collectionType + '-edit' );
   179 			} else {
   186 		this.set( 'toolbar', collectionType + '-edit' );
   180 				return new wp.media.view.Button( button ).render();
   187 
       
   188 		// If we haven't been provided a `library`, create a `Selection`.
       
   189 		if ( ! this.get('library') ) {
       
   190 			this.set( 'library', new wp.media.model.Selection() );
       
   191 		}
       
   192 		// The single `Attachment` view to be used in the `Attachments` view.
       
   193 		if ( ! this.get('AttachmentView') ) {
       
   194 			this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );
       
   195 		}
       
   196 		Library.prototype.initialize.apply( this, arguments );
       
   197 	},
       
   198 
       
   199 	/**
       
   200 	 * @since 3.9.0
       
   201 	 */
       
   202 	activate: function() {
       
   203 		var library = this.get('library');
       
   204 
       
   205 		// Limit the library to images only.
       
   206 		library.props.set( 'type', this.get( 'type' ) );
       
   207 
       
   208 		// Watch for uploaded attachments.
       
   209 		this.get('library').observe( wp.Uploader.queue );
       
   210 
       
   211 		this.frame.on( 'content:render:browse', this.renderSettings, this );
       
   212 
       
   213 		Library.prototype.activate.apply( this, arguments );
       
   214 	},
       
   215 
       
   216 	/**
       
   217 	 * @since 3.9.0
       
   218 	 */
       
   219 	deactivate: function() {
       
   220 		// Stop watching for uploaded attachments.
       
   221 		this.get('library').unobserve( wp.Uploader.queue );
       
   222 
       
   223 		this.frame.off( 'content:render:browse', this.renderSettings, this );
       
   224 
       
   225 		Library.prototype.deactivate.apply( this, arguments );
       
   226 	},
       
   227 
       
   228 	/**
       
   229 	 * Render the collection embed settings view in the browser sidebar.
       
   230 	 *
       
   231 	 * @todo This is against the pattern elsewhere in media. Typically the frame
       
   232 	 *       is responsible for adding region mode callbacks. Explain.
       
   233 	 *
       
   234 	 * @since 3.9.0
       
   235 	 *
       
   236 	 * @param {wp.media.view.attachmentsBrowser} The attachments browser view.
       
   237 	 */
       
   238 	renderSettings: function( attachmentsBrowserView ) {
       
   239 		var library = this.get('library'),
       
   240 			collectionType = this.get('collectionType'),
       
   241 			dragInfoText = this.get('dragInfoText'),
       
   242 			SettingsView = this.get('SettingsView'),
       
   243 			obj = {};
       
   244 
       
   245 		if ( ! library || ! attachmentsBrowserView ) {
       
   246 			return;
       
   247 		}
       
   248 
       
   249 		library[ collectionType ] = library[ collectionType ] || new Backbone.Model();
       
   250 
       
   251 		obj[ collectionType ] = new SettingsView({
       
   252 			controller: this,
       
   253 			model:      library[ collectionType ],
       
   254 			priority:   40
       
   255 		});
       
   256 
       
   257 		attachmentsBrowserView.sidebar.set( obj );
       
   258 
       
   259 		if ( dragInfoText ) {
       
   260 			attachmentsBrowserView.toolbar.set( 'dragInfo', new wp.media.View({
       
   261 				el: $( '<div class="instructions">' + dragInfoText + '</div>' )[0],
       
   262 				priority: -40
       
   263 			}) );
       
   264 		}
       
   265 
       
   266 		// Add the 'Reverse order' button to the toolbar.
       
   267 		attachmentsBrowserView.toolbar.set( 'reverse', {
       
   268 			text:     l10n.reverseOrder,
       
   269 			priority: 80,
       
   270 
       
   271 			click: function() {
       
   272 				library.reset( library.toArray().reverse() );
       
   273 			}
   181 			}
   274 		});
   182 		});
       
   183 
       
   184 		delete this.options.buttons;
       
   185 
       
   186 		if ( this.options.classes ) {
       
   187 			this.$el.addClass( this.options.classes );
       
   188 		}
       
   189 	},
       
   190 
       
   191 	/**
       
   192 	 * @return {wp.media.view.ButtonGroup}
       
   193 	 */
       
   194 	render: function() {
       
   195 		this.$el.html( $( _.pluck( this.buttons, 'el' ) ).detach() );
       
   196 		return this;
   275 	}
   197 	}
   276 });
   198 });
   277 
   199 
   278 module.exports = CollectionEdit;
   200 module.exports = ButtonGroup;
   279 
   201 
   280 
   202 
   281 /***/ }),
   203 /***/ }),
   282 
   204 
   283 /***/ 5422:
   205 /***/ 170:
   284 /***/ ((module) => {
   206 /***/ ((module) => {
   285 
   207 
       
   208 /**
       
   209  * wp.media.view.Heading
       
   210  *
       
   211  * A reusable heading component for the media library
       
   212  *
       
   213  * Used to add accessibility friendly headers in the media library/modal.
       
   214  *
       
   215  * @class
       
   216  * @augments wp.media.View
       
   217  * @augments wp.Backbone.View
       
   218  * @augments Backbone.View
       
   219  */
       
   220 var Heading = wp.media.View.extend( {
       
   221 	tagName: function() {
       
   222 		return this.options.level || 'h1';
       
   223 	},
       
   224 	className: 'media-views-heading',
       
   225 
       
   226 	initialize: function() {
       
   227 
       
   228 		if ( this.options.className ) {
       
   229 			this.$el.addClass( this.options.className );
       
   230 		}
       
   231 
       
   232 		this.text = this.options.text;
       
   233 	},
       
   234 
       
   235 	render: function() {
       
   236 		this.$el.html( this.text );
       
   237 		return this;
       
   238 	}
       
   239 } );
       
   240 
       
   241 module.exports = Heading;
       
   242 
       
   243 
       
   244 /***/ }),
       
   245 
       
   246 /***/ 397:
       
   247 /***/ ((module) => {
       
   248 
       
   249 var Select = wp.media.view.Toolbar.Select,
       
   250 	l10n = wp.media.view.l10n,
       
   251 	Embed;
       
   252 
       
   253 /**
       
   254  * wp.media.view.Toolbar.Embed
       
   255  *
       
   256  * @memberOf wp.media.view.Toolbar
       
   257  *
       
   258  * @class
       
   259  * @augments wp.media.view.Toolbar.Select
       
   260  * @augments wp.media.view.Toolbar
       
   261  * @augments wp.media.View
       
   262  * @augments wp.Backbone.View
       
   263  * @augments Backbone.View
       
   264  */
       
   265 Embed = Select.extend(/** @lends wp.media.view.Toolbar.Embed.prototype */{
       
   266 	initialize: function() {
       
   267 		_.defaults( this.options, {
       
   268 			text: l10n.insertIntoPost,
       
   269 			requires: false
       
   270 		});
       
   271 		// Call 'initialize' directly on the parent class.
       
   272 		Select.prototype.initialize.apply( this, arguments );
       
   273 	},
       
   274 
       
   275 	refresh: function() {
       
   276 		var url = this.controller.state().props.get('url');
       
   277 		this.get('select').model.set( 'disabled', ! url || url === 'http://' );
       
   278 		/**
       
   279 		 * call 'refresh' directly on the parent class
       
   280 		 */
       
   281 		Select.prototype.refresh.apply( this, arguments );
       
   282 	}
       
   283 });
       
   284 
       
   285 module.exports = Embed;
       
   286 
       
   287 
       
   288 /***/ }),
       
   289 
       
   290 /***/ 443:
       
   291 /***/ ((module) => {
       
   292 
       
   293 var View = wp.media.view,
       
   294 	SiteIconCropper;
       
   295 
       
   296 /**
       
   297  * wp.media.view.SiteIconCropper
       
   298  *
       
   299  * Uses the imgAreaSelect plugin to allow a user to crop a Site Icon.
       
   300  *
       
   301  * Takes imgAreaSelect options from
       
   302  * wp.customize.SiteIconControl.calculateImageSelectOptions.
       
   303  *
       
   304  * @memberOf wp.media.view
       
   305  *
       
   306  * @class
       
   307  * @augments wp.media.view.Cropper
       
   308  * @augments wp.media.View
       
   309  * @augments wp.Backbone.View
       
   310  * @augments Backbone.View
       
   311  */
       
   312 SiteIconCropper = View.Cropper.extend(/** @lends wp.media.view.SiteIconCropper.prototype */{
       
   313 	className: 'crop-content site-icon',
       
   314 
       
   315 	ready: function () {
       
   316 		View.Cropper.prototype.ready.apply( this, arguments );
       
   317 
       
   318 		this.$( '.crop-image' ).on( 'load', _.bind( this.addSidebar, this ) );
       
   319 	},
       
   320 
       
   321 	addSidebar: function() {
       
   322 		this.sidebar = new wp.media.view.Sidebar({
       
   323 			controller: this.controller
       
   324 		});
       
   325 
       
   326 		this.sidebar.set( 'preview', new wp.media.view.SiteIconPreview({
       
   327 			controller: this.controller,
       
   328 			attachment: this.options.attachment
       
   329 		}) );
       
   330 
       
   331 		this.controller.cropperView.views.add( this.sidebar );
       
   332 	}
       
   333 });
       
   334 
       
   335 module.exports = SiteIconCropper;
       
   336 
       
   337 
       
   338 /***/ }),
       
   339 
       
   340 /***/ 455:
       
   341 /***/ ((module) => {
       
   342 
       
   343 var MediaFrame = wp.media.view.MediaFrame,
       
   344 	l10n = wp.media.view.l10n,
       
   345 	Select;
       
   346 
       
   347 /**
       
   348  * wp.media.view.MediaFrame.Select
       
   349  *
       
   350  * A frame for selecting an item or items from the media library.
       
   351  *
       
   352  * @memberOf wp.media.view.MediaFrame
       
   353  *
       
   354  * @class
       
   355  * @augments wp.media.view.MediaFrame
       
   356  * @augments wp.media.view.Frame
       
   357  * @augments wp.media.View
       
   358  * @augments wp.Backbone.View
       
   359  * @augments Backbone.View
       
   360  * @mixes wp.media.controller.StateMachine
       
   361  */
       
   362 Select = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Select.prototype */{
       
   363 	initialize: function() {
       
   364 		// Call 'initialize' directly on the parent class.
       
   365 		MediaFrame.prototype.initialize.apply( this, arguments );
       
   366 
       
   367 		_.defaults( this.options, {
       
   368 			selection: [],
       
   369 			library:   {},
       
   370 			multiple:  false,
       
   371 			state:    'library'
       
   372 		});
       
   373 
       
   374 		this.createSelection();
       
   375 		this.createStates();
       
   376 		this.bindHandlers();
       
   377 	},
       
   378 
       
   379 	/**
       
   380 	 * Attach a selection collection to the frame.
       
   381 	 *
       
   382 	 * A selection is a collection of attachments used for a specific purpose
       
   383 	 * by a media frame. e.g. Selecting an attachment (or many) to insert into
       
   384 	 * post content.
       
   385 	 *
       
   386 	 * @see media.model.Selection
       
   387 	 */
       
   388 	createSelection: function() {
       
   389 		var selection = this.options.selection;
       
   390 
       
   391 		if ( ! (selection instanceof wp.media.model.Selection) ) {
       
   392 			this.options.selection = new wp.media.model.Selection( selection, {
       
   393 				multiple: this.options.multiple
       
   394 			});
       
   395 		}
       
   396 
       
   397 		this._selection = {
       
   398 			attachments: new wp.media.model.Attachments(),
       
   399 			difference: []
       
   400 		};
       
   401 	},
       
   402 
       
   403 	editImageContent: function() {
       
   404 		var image = this.state().get('image'),
       
   405 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
       
   406 
       
   407 		this.content.set( view );
       
   408 
       
   409 		// After creating the wrapper view, load the actual editor via an Ajax call.
       
   410 		view.loadEditor();
       
   411 	},
       
   412 
       
   413 	/**
       
   414 	 * Create the default states on the frame.
       
   415 	 */
       
   416 	createStates: function() {
       
   417 		var options = this.options;
       
   418 
       
   419 		if ( this.options.states ) {
       
   420 			return;
       
   421 		}
       
   422 
       
   423 		// Add the default states.
       
   424 		this.states.add([
       
   425 			// Main states.
       
   426 			new wp.media.controller.Library({
       
   427 				library:   wp.media.query( options.library ),
       
   428 				multiple:  options.multiple,
       
   429 				title:     options.title,
       
   430 				priority:  20
       
   431 			}),
       
   432 			new wp.media.controller.EditImage( { model: options.editImage } )
       
   433 		]);
       
   434 	},
       
   435 
       
   436 	/**
       
   437 	 * Bind region mode event callbacks.
       
   438 	 *
       
   439 	 * @see media.controller.Region.render
       
   440 	 */
       
   441 	bindHandlers: function() {
       
   442 		this.on( 'router:create:browse', this.createRouter, this );
       
   443 		this.on( 'router:render:browse', this.browseRouter, this );
       
   444 		this.on( 'content:create:browse', this.browseContent, this );
       
   445 		this.on( 'content:render:upload', this.uploadContent, this );
       
   446 		this.on( 'toolbar:create:select', this.createSelectToolbar, this );
       
   447 		this.on( 'content:render:edit-image', this.editImageContent, this );
       
   448 	},
       
   449 
       
   450 	/**
       
   451 	 * Render callback for the router region in the `browse` mode.
       
   452 	 *
       
   453 	 * @param {wp.media.view.Router} routerView
       
   454 	 */
       
   455 	browseRouter: function( routerView ) {
       
   456 		routerView.set({
       
   457 			upload: {
       
   458 				text:     l10n.uploadFilesTitle,
       
   459 				priority: 20
       
   460 			},
       
   461 			browse: {
       
   462 				text:     l10n.mediaLibraryTitle,
       
   463 				priority: 40
       
   464 			}
       
   465 		});
       
   466 	},
       
   467 
       
   468 	/**
       
   469 	 * Render callback for the content region in the `browse` mode.
       
   470 	 *
       
   471 	 * @param {wp.media.controller.Region} contentRegion
       
   472 	 */
       
   473 	browseContent: function( contentRegion ) {
       
   474 		var state = this.state();
       
   475 
       
   476 		this.$el.removeClass('hide-toolbar');
       
   477 
       
   478 		// Browse our library of attachments.
       
   479 		contentRegion.view = new wp.media.view.AttachmentsBrowser({
       
   480 			controller: this,
       
   481 			collection: state.get('library'),
       
   482 			selection:  state.get('selection'),
       
   483 			model:      state,
       
   484 			sortable:   state.get('sortable'),
       
   485 			search:     state.get('searchable'),
       
   486 			filters:    state.get('filterable'),
       
   487 			date:       state.get('date'),
       
   488 			display:    state.has('display') ? state.get('display') : state.get('displaySettings'),
       
   489 			dragInfo:   state.get('dragInfo'),
       
   490 
       
   491 			idealColumnWidth: state.get('idealColumnWidth'),
       
   492 			suggestedWidth:   state.get('suggestedWidth'),
       
   493 			suggestedHeight:  state.get('suggestedHeight'),
       
   494 
       
   495 			AttachmentView: state.get('AttachmentView')
       
   496 		});
       
   497 	},
       
   498 
       
   499 	/**
       
   500 	 * Render callback for the content region in the `upload` mode.
       
   501 	 */
       
   502 	uploadContent: function() {
       
   503 		this.$el.removeClass( 'hide-toolbar' );
       
   504 		this.content.set( new wp.media.view.UploaderInline({
       
   505 			controller: this
       
   506 		}) );
       
   507 	},
       
   508 
       
   509 	/**
       
   510 	 * Toolbars
       
   511 	 *
       
   512 	 * @param {Object} toolbar
       
   513 	 * @param {Object} [options={}]
       
   514 	 * @this wp.media.controller.Region
       
   515 	 */
       
   516 	createSelectToolbar: function( toolbar, options ) {
       
   517 		options = options || this.options.button || {};
       
   518 		options.controller = this;
       
   519 
       
   520 		toolbar.view = new wp.media.view.Toolbar.Select( options );
       
   521 	}
       
   522 });
       
   523 
       
   524 module.exports = Select;
       
   525 
       
   526 
       
   527 /***/ }),
       
   528 
       
   529 /***/ 472:
       
   530 /***/ ((module) => {
       
   531 
   286 var l10n = wp.media.view.l10n,
   532 var l10n = wp.media.view.l10n,
   287 	Cropper;
   533 	getUserSetting = window.getUserSetting,
       
   534 	setUserSetting = window.setUserSetting,
       
   535 	Library;
   288 
   536 
   289 /**
   537 /**
   290  * wp.media.controller.Cropper
   538  * wp.media.controller.Library
   291  *
   539  *
   292  * A class for cropping an image when called from the header media customization panel.
   540  * A state for choosing an attachment or group of attachments from the media library.
   293  *
   541  *
   294  * @memberOf wp.media.controller
   542  * @memberOf wp.media.controller
   295  *
   543  *
   296  * @class
   544  * @class
   297  * @augments wp.media.controller.State
   545  * @augments wp.media.controller.State
   298  * @augments Backbone.Model
   546  * @augments Backbone.Model
       
   547  * @mixes media.selectionSync
       
   548  *
       
   549  * @param {object}                          [attributes]                         The attributes hash passed to the state.
       
   550  * @param {string}                          [attributes.id=library]              Unique identifier.
       
   551  * @param {string}                          [attributes.title=Media library]     Title for the state. Displays in the media menu and the frame's title region.
       
   552  * @param {wp.media.model.Attachments}      [attributes.library]                 The attachments collection to browse.
       
   553  *                                                                               If one is not supplied, a collection of all attachments will be created.
       
   554  * @param {wp.media.model.Selection|object} [attributes.selection]               A collection to contain attachment selections within the state.
       
   555  *                                                                               If the 'selection' attribute is a plain JS object,
       
   556  *                                                                               a Selection will be created using its values as the selection instance's `props` model.
       
   557  *                                                                               Otherwise, it will copy the library's `props` model.
       
   558  * @param {boolean}                         [attributes.multiple=false]          Whether multi-select is enabled.
       
   559  * @param {string}                          [attributes.content=upload]          Initial mode for the content region.
       
   560  *                                                                               Overridden by persistent user setting if 'contentUserSetting' is true.
       
   561  * @param {string}                          [attributes.menu=default]            Initial mode for the menu region.
       
   562  * @param {string}                          [attributes.router=browse]           Initial mode for the router region.
       
   563  * @param {string}                          [attributes.toolbar=select]          Initial mode for the toolbar region.
       
   564  * @param {boolean}                         [attributes.searchable=true]         Whether the library is searchable.
       
   565  * @param {boolean|string}                  [attributes.filterable=false]        Whether the library is filterable, and if so what filters should be shown.
       
   566  *                                                                               Accepts 'all', 'uploaded', or 'unattached'.
       
   567  * @param {boolean}                         [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
   568  * @param {boolean}                         [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
   569  * @param {boolean}                         [attributes.describe=false]          Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
       
   570  * @param {boolean}                         [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
   571  * @param {boolean}                         [attributes.syncSelection=true]      Whether the Attachments selection should be persisted from the last state.
   299  */
   572  */
   300 Cropper = wp.media.controller.State.extend(/** @lends wp.media.controller.Cropper.prototype */{
   573 Library = wp.media.controller.State.extend(/** @lends wp.media.controller.Library.prototype */{
   301 	defaults: {
   574 	defaults: {
   302 		id:          'cropper',
   575 		id:                 'library',
   303 		title:       l10n.cropImage,
   576 		title:              l10n.mediaLibraryTitle,
   304 		// Region mode defaults.
   577 		multiple:           false,
   305 		toolbar:     'crop',
   578 		content:            'upload',
   306 		content:     'crop',
   579 		menu:               'default',
   307 		router:      false,
   580 		router:             'browse',
   308 		canSkipCrop: false,
   581 		toolbar:            'select',
   309 
   582 		searchable:         true,
   310 		// Default doCrop Ajax arguments to allow the Customizer (for example) to inject state.
   583 		filterable:         false,
   311 		doCropArgs: {}
   584 		sortable:           true,
   312 	},
   585 		autoSelect:         true,
   313 
   586 		describe:           false,
   314 	/**
   587 		contentUserSetting: true,
   315 	 * Shows the crop image window when called from the Add new image button.
   588 		syncSelection:      true
   316 	 *
   589 	},
   317 	 * @since 4.2.0
   590 
   318 	 *
   591 	/**
   319 	 * @return {void}
   592 	 * If a library isn't provided, query all media items.
       
   593 	 * If a selection instance isn't provided, create one.
       
   594 	 *
       
   595 	 * @since 3.5.0
       
   596 	 */
       
   597 	initialize: function() {
       
   598 		var selection = this.get('selection'),
       
   599 			props;
       
   600 
       
   601 		if ( ! this.get('library') ) {
       
   602 			this.set( 'library', wp.media.query() );
       
   603 		}
       
   604 
       
   605 		if ( ! ( selection instanceof wp.media.model.Selection ) ) {
       
   606 			props = selection;
       
   607 
       
   608 			if ( ! props ) {
       
   609 				props = this.get('library').props.toJSON();
       
   610 				props = _.omit( props, 'orderby', 'query' );
       
   611 			}
       
   612 
       
   613 			this.set( 'selection', new wp.media.model.Selection( null, {
       
   614 				multiple: this.get('multiple'),
       
   615 				props: props
       
   616 			}) );
       
   617 		}
       
   618 
       
   619 		this.resetDisplays();
       
   620 	},
       
   621 
       
   622 	/**
       
   623 	 * @since 3.5.0
   320 	 */
   624 	 */
   321 	activate: function() {
   625 	activate: function() {
   322 		this.frame.on( 'content:create:crop', this.createCropContent, this );
   626 		this.syncSelection();
   323 		this.frame.on( 'close', this.removeCropper, this );
   627 
   324 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
   628 		wp.Uploader.queue.on( 'add', this.uploading, this );
   325 	},
   629 
   326 
   630 		this.get('selection').on( 'add remove reset', this.refreshContent, this );
   327 	/**
   631 
   328 	 * Changes the state of the toolbar window to browse mode.
   632 		if ( this.get( 'router' ) && this.get('contentUserSetting') ) {
   329 	 *
   633 			this.frame.on( 'content:activate', this.saveContentMode, this );
   330 	 * @since 4.2.0
   634 			this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
   331 	 *
   635 		}
   332 	 * @return {void}
   636 	},
       
   637 
       
   638 	/**
       
   639 	 * @since 3.5.0
   333 	 */
   640 	 */
   334 	deactivate: function() {
   641 	deactivate: function() {
   335 		this.frame.toolbar.mode('browse');
   642 		this.recordSelection();
   336 	},
   643 
   337 
   644 		this.frame.off( 'content:activate', this.saveContentMode, this );
   338 	/**
   645 
   339 	 * Creates the crop image window.
   646 		// Unbind all event handlers that use this state as the context
   340 	 *
   647 		// from the selection.
   341 	 * Initialized when clicking on the Select and Crop button.
   648 		this.get('selection').off( null, null, this );
   342 	 *
   649 
   343 	 * @since 4.2.0
   650 		wp.Uploader.queue.off( null, null, this );
   344 	 *
   651 	},
   345 	 * @fires crop window
   652 
   346 	 *
   653 	/**
   347 	 * @return {void}
   654 	 * Reset the library to its initial state.
   348 	 */
   655 	 *
   349 	createCropContent: function() {
   656 	 * @since 3.5.0
   350 		this.cropperView = new wp.media.view.Cropper({
   657 	 */
   351 			controller: this,
   658 	reset: function() {
   352 			attachment: this.get('selection').first()
   659 		this.get('selection').reset();
   353 		});
   660 		this.resetDisplays();
   354 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
   661 		this.refreshContent();
   355 		this.frame.content.set(this.cropperView);
   662 	},
   356 
   663 
   357 	},
   664 	/**
   358 
   665 	 * Reset the attachment display settings defaults to the site options.
   359 	/**
   666 	 *
   360 	 * Removes the image selection and closes the cropping window.
   667 	 * If site options don't define them, fall back to a persistent user setting.
   361 	 *
   668 	 *
   362 	 * @since 4.2.0
   669 	 * @since 3.5.0
   363 	 *
   670 	 */
   364 	 * @return {void}
   671 	resetDisplays: function() {
   365 	 */
   672 		var defaultProps = wp.media.view.settings.defaultProps;
   366 	removeCropper: function() {
   673 		this._displays = [];
   367 		this.imgSelect.cancelSelection();
   674 		this._defaultDisplaySettings = {
   368 		this.imgSelect.setOptions({remove: true});
   675 			align: getUserSetting( 'align', defaultProps.align ) || 'none',
   369 		this.imgSelect.update();
   676 			size:  getUserSetting( 'imgsize', defaultProps.size ) || 'medium',
   370 		this.cropperView.remove();
   677 			link:  getUserSetting( 'urlbutton', defaultProps.link ) || 'none'
   371 	},
   678 		};
   372 
   679 	},
   373 	/**
   680 
   374 	 * Checks if cropping can be skipped and creates crop toolbar accordingly.
   681 	/**
   375 	 *
   682 	 * Create a model to represent display settings (alignment, etc.) for an attachment.
   376 	 * @since 4.2.0
   683 	 *
   377 	 *
   684 	 * @since 3.5.0
   378 	 * @return {void}
   685 	 *
   379 	 */
   686 	 * @param {wp.media.model.Attachment} attachment
   380 	createCropToolbar: function() {
   687 	 * @return {Backbone.Model}
   381 		var canSkipCrop, toolbarOptions;
   688 	 */
   382 
   689 	display: function( attachment ) {
   383 		canSkipCrop = this.get('canSkipCrop') || false;
   690 		var displays = this._displays;
   384 
   691 
   385 		toolbarOptions = {
   692 		if ( ! displays[ attachment.cid ] ) {
   386 			controller: this.frame,
   693 			displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) );
   387 			items: {
   694 		}
   388 				insert: {
   695 		return displays[ attachment.cid ];
   389 					style:    'primary',
   696 	},
   390 					text:     l10n.cropImage,
   697 
   391 					priority: 80,
   698 	/**
   392 					requires: { library: false, selection: false },
   699 	 * Given an attachment, create attachment display settings properties.
   393 
   700 	 *
   394 					click: function() {
   701 	 * @since 3.6.0
   395 						var controller = this.controller,
   702 	 *
   396 							selection;
   703 	 * @param {wp.media.model.Attachment} attachment
   397 
   704 	 * @return {Object}
   398 						selection = controller.state().get('selection').first();
   705 	 */
   399 						selection.set({cropDetails: controller.state().imgSelect.getSelection()});
   706 	defaultDisplaySettings: function( attachment ) {
   400 
   707 		var settings = _.clone( this._defaultDisplaySettings );
   401 						this.$el.text(l10n.cropping);
   708 
   402 						this.$el.attr('disabled', true);
   709 		settings.canEmbed = this.canEmbed( attachment );
   403 
   710 		if ( settings.canEmbed ) {
   404 						controller.state().doCrop( selection ).done( function( croppedImage ) {
   711 			settings.link = 'embed';
   405 							controller.trigger('cropped', croppedImage );
   712 		} else if ( ! this.isImageAttachment( attachment ) && settings.link === 'none' ) {
   406 							controller.close();
   713 			settings.link = 'file';
   407 						}).fail( function() {
   714 		}
   408 							controller.trigger('content:error:crop');
   715 
   409 						});
   716 		return settings;
   410 					}
   717 	},
   411 				}
   718 
       
   719 	/**
       
   720 	 * Whether an attachment is image.
       
   721 	 *
       
   722 	 * @since 4.4.1
       
   723 	 *
       
   724 	 * @param {wp.media.model.Attachment} attachment
       
   725 	 * @return {boolean}
       
   726 	 */
       
   727 	isImageAttachment: function( attachment ) {
       
   728 		// If uploading, we know the filename but not the mime type.
       
   729 		if ( attachment.get('uploading') ) {
       
   730 			return /\.(jpe?g|png|gif|webp|avif|heic|heif)$/i.test( attachment.get('filename') );
       
   731 		}
       
   732 
       
   733 		return attachment.get('type') === 'image';
       
   734 	},
       
   735 
       
   736 	/**
       
   737 	 * Whether an attachment can be embedded (audio or video).
       
   738 	 *
       
   739 	 * @since 3.6.0
       
   740 	 *
       
   741 	 * @param {wp.media.model.Attachment} attachment
       
   742 	 * @return {boolean}
       
   743 	 */
       
   744 	canEmbed: function( attachment ) {
       
   745 		// If uploading, we know the filename but not the mime type.
       
   746 		if ( ! attachment.get('uploading') ) {
       
   747 			var type = attachment.get('type');
       
   748 			if ( type !== 'audio' && type !== 'video' ) {
       
   749 				return false;
   412 			}
   750 			}
   413 		};
   751 		}
   414 
   752 
   415 		if ( canSkipCrop ) {
   753 		return _.contains( wp.media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
   416 			_.extend( toolbarOptions.items, {
   754 	},
   417 				skip: {
   755 
   418 					style:      'secondary',
   756 
   419 					text:       l10n.skipCropping,
   757 	/**
   420 					priority:   70,
   758 	 * If the state is active, no items are selected, and the current
   421 					requires:   { library: false, selection: false },
   759 	 * content mode is not an option in the state's router (provided
   422 					click:      function() {
   760 	 * the state has a router), reset the content mode to the default.
   423 						var selection = this.controller.state().get('selection').first();
   761 	 *
   424 						this.controller.state().cropperView.remove();
   762 	 * @since 3.5.0
   425 						this.controller.trigger('skippedcrop', selection);
   763 	 */
   426 						this.controller.close();
   764 	refreshContent: function() {
   427 					}
   765 		var selection = this.get('selection'),
   428 				}
   766 			frame = this.frame,
   429 			});
   767 			router = frame.router.get(),
   430 		}
   768 			mode = frame.content.mode();
   431 
   769 
   432 		this.frame.toolbar.set( new wp.media.view.Toolbar(toolbarOptions) );
   770 		if ( this.active && ! selection.length && router && ! router.get( mode ) ) {
   433 	},
   771 			this.frame.content.render( this.get('content') );
   434 
   772 		}
   435 	/**
   773 	},
   436 	 * Creates an object with the image attachment and crop properties.
   774 
   437 	 *
   775 	/**
   438 	 * @since 4.2.0
   776 	 * Callback handler when an attachment is uploaded.
   439 	 *
   777 	 *
   440 	 * @return {$.promise} A jQuery promise with the custom header crop details.
   778 	 * Switch to the Media Library if uploaded from the 'Upload Files' tab.
   441 	 */
   779 	 *
   442 	doCrop: function( attachment ) {
   780 	 * Adds any uploading attachments to the selection.
   443 		return wp.ajax.post( 'custom-header-crop', _.extend(
   781 	 *
   444 			{},
   782 	 * If the state only supports one attachment to be selected and multiple
   445 			this.defaults.doCropArgs,
   783 	 * attachments are uploaded, the last attachment in the upload queue will
   446 			{
   784 	 * be selected.
   447 				nonce: attachment.get( 'nonces' ).edit,
   785 	 *
   448 				id: attachment.get( 'id' ),
   786 	 * @since 3.5.0
   449 				cropDetails: attachment.get( 'cropDetails' )
   787 	 *
   450 			}
   788 	 * @param {wp.media.model.Attachment} attachment
   451 		) );
   789 	 */
       
   790 	uploading: function( attachment ) {
       
   791 		var content = this.frame.content;
       
   792 
       
   793 		if ( 'upload' === content.mode() ) {
       
   794 			this.frame.content.mode('browse');
       
   795 		}
       
   796 
       
   797 		if ( this.get( 'autoSelect' ) ) {
       
   798 			this.get('selection').add( attachment );
       
   799 			this.frame.trigger( 'library:selection:add' );
       
   800 		}
       
   801 	},
       
   802 
       
   803 	/**
       
   804 	 * Persist the mode of the content region as a user setting.
       
   805 	 *
       
   806 	 * @since 3.5.0
       
   807 	 */
       
   808 	saveContentMode: function() {
       
   809 		if ( 'browse' !== this.get('router') ) {
       
   810 			return;
       
   811 		}
       
   812 
       
   813 		var mode = this.frame.content.mode(),
       
   814 			view = this.frame.router.get();
       
   815 
       
   816 		if ( view && view.get( mode ) ) {
       
   817 			setUserSetting( 'libraryContent', mode );
       
   818 		}
   452 	}
   819 	}
       
   820 
   453 });
   821 });
   454 
   822 
   455 module.exports = Cropper;
   823 // Make selectionSync available on any Media Library state.
       
   824 _.extend( Library.prototype, wp.media.selectionSync );
       
   825 
       
   826 module.exports = Library;
   456 
   827 
   457 
   828 
   458 /***/ }),
   829 /***/ }),
   459 
   830 
   460 /***/ 9660:
   831 /***/ 705:
   461 /***/ ((module) => {
   832 /***/ ((module) => {
   462 
   833 
   463 var Controller = wp.media.controller,
   834 var State = wp.media.controller.State,
   464 	CustomizeImageCropper;
   835 	Library = wp.media.controller.Library,
       
   836 	l10n = wp.media.view.l10n,
       
   837 	ImageDetails;
   465 
   838 
   466 /**
   839 /**
   467  * A state for cropping an image in the customizer.
   840  * wp.media.controller.ImageDetails
   468  *
   841  *
   469  * @since 4.3.0
   842  * A state for editing the attachment display settings of an image that's been
   470  *
   843  * inserted into the editor.
   471  * @constructs wp.media.controller.CustomizeImageCropper
       
   472  * @memberOf wp.media.controller
       
   473  * @augments wp.media.controller.CustomizeImageCropper.Cropper
       
   474  * @inheritDoc
       
   475  */
       
   476 CustomizeImageCropper = Controller.Cropper.extend(/** @lends wp.media.controller.CustomizeImageCropper.prototype */{
       
   477 	/**
       
   478 	 * Posts the crop details to the admin.
       
   479 	 *
       
   480 	 * Uses crop measurements when flexible in both directions.
       
   481 	 * Constrains flexible side based on image ratio and size of the fixed side.
       
   482 	 *
       
   483 	 * @since 4.3.0
       
   484 	 *
       
   485 	 * @param {Object} attachment The attachment to crop.
       
   486 	 *
       
   487 	 * @return {$.promise} A jQuery promise that represents the crop image request.
       
   488 	 */
       
   489 	doCrop: function( attachment ) {
       
   490 		var cropDetails = attachment.get( 'cropDetails' ),
       
   491 			control = this.get( 'control' ),
       
   492 			ratio = cropDetails.width / cropDetails.height;
       
   493 
       
   494 		// Use crop measurements when flexible in both directions.
       
   495 		if ( control.params.flex_width && control.params.flex_height ) {
       
   496 			cropDetails.dst_width  = cropDetails.width;
       
   497 			cropDetails.dst_height = cropDetails.height;
       
   498 
       
   499 		// Constrain flexible side based on image ratio and size of the fixed side.
       
   500 		} else {
       
   501 			cropDetails.dst_width  = control.params.flex_width  ? control.params.height * ratio : control.params.width;
       
   502 			cropDetails.dst_height = control.params.flex_height ? control.params.width  / ratio : control.params.height;
       
   503 		}
       
   504 
       
   505 		return wp.ajax.post( 'crop-image', {
       
   506 			wp_customize: 'on',
       
   507 			nonce: attachment.get( 'nonces' ).edit,
       
   508 			id: attachment.get( 'id' ),
       
   509 			context: control.id,
       
   510 			cropDetails: cropDetails
       
   511 		} );
       
   512 	}
       
   513 });
       
   514 
       
   515 module.exports = CustomizeImageCropper;
       
   516 
       
   517 
       
   518 /***/ }),
       
   519 
       
   520 /***/ 5663:
       
   521 /***/ ((module) => {
       
   522 
       
   523 var l10n = wp.media.view.l10n,
       
   524 	EditImage;
       
   525 
       
   526 /**
       
   527  * wp.media.controller.EditImage
       
   528  *
       
   529  * A state for editing (cropping, etc.) an image.
       
   530  *
   844  *
   531  * @memberOf wp.media.controller
   845  * @memberOf wp.media.controller
   532  *
   846  *
   533  * @class
   847  * @class
   534  * @augments wp.media.controller.State
   848  * @augments wp.media.controller.State
   535  * @augments Backbone.Model
   849  * @augments Backbone.Model
   536  *
   850  *
   537  * @param {object}                    attributes                      The attributes hash passed to the state.
   851  * @param {object}                    [attributes]                       The attributes hash passed to the state.
   538  * @param {wp.media.model.Attachment} attributes.model                The attachment.
   852  * @param {string}                    [attributes.id=image-details]      Unique identifier.
   539  * @param {string}                    [attributes.id=edit-image]      Unique identifier.
   853  * @param {string}                    [attributes.title=Image Details]   Title for the state. Displays in the frame's title region.
   540  * @param {string}                    [attributes.title=Edit Image]   Title for the state. Displays in the media menu and the frame's title region.
   854  * @param {wp.media.model.Attachment} attributes.image                   The image's model.
   541  * @param {string}                    [attributes.content=edit-image] Initial mode for the content region.
   855  * @param {string|false}              [attributes.content=image-details] Initial mode for the content region.
   542  * @param {string}                    [attributes.toolbar=edit-image] Initial mode for the toolbar region.
   856  * @param {string|false}              [attributes.menu=false]            Initial mode for the menu region.
   543  * @param {string}                    [attributes.menu=false]         Initial mode for the menu region.
   857  * @param {string|false}              [attributes.router=false]          Initial mode for the router region.
   544  * @param {string}                    [attributes.url]                Unused. @todo Consider removal.
   858  * @param {string|false}              [attributes.toolbar=image-details] Initial mode for the toolbar region.
       
   859  * @param {boolean}                   [attributes.editing=false]         Unused.
       
   860  * @param {int}                       [attributes.priority=60]           Unused.
       
   861  *
       
   862  * @todo This state inherits some defaults from media.controller.Library.prototype.defaults,
       
   863  *       however this may not do anything.
   545  */
   864  */
   546 EditImage = wp.media.controller.State.extend(/** @lends wp.media.controller.EditImage.prototype */{
   865 ImageDetails = State.extend(/** @lends wp.media.controller.ImageDetails.prototype */{
   547 	defaults: {
   866 	defaults: _.defaults({
   548 		id:      'edit-image',
   867 		id:       'image-details',
   549 		title:   l10n.editImage,
   868 		title:    l10n.imageDetailsTitle,
   550 		menu:    false,
   869 		content:  'image-details',
   551 		toolbar: 'edit-image',
   870 		menu:     false,
   552 		content: 'edit-image',
   871 		router:   false,
   553 		url:     ''
   872 		toolbar:  'image-details',
   554 	},
   873 		editing:  false,
   555 
   874 		priority: 60
   556 	/**
   875 	}, Library.prototype.defaults ),
   557 	 * Activates a frame for editing a featured image.
   876 
   558 	 *
   877 	/**
   559 	 * @since 3.9.0
   878 	 * @since 3.9.0
   560 	 *
   879 	 *
   561 	 * @return {void}
   880 	 * @param options Attributes
       
   881 	 */
       
   882 	initialize: function( options ) {
       
   883 		this.image = options.image;
       
   884 		State.prototype.initialize.apply( this, arguments );
       
   885 	},
       
   886 
       
   887 	/**
       
   888 	 * @since 3.9.0
   562 	 */
   889 	 */
   563 	activate: function() {
   890 	activate: function() {
   564 		this.frame.on( 'toolbar:render:edit-image', _.bind( this.toolbar, this ) );
   891 		this.frame.modal.$el.addClass('image-details');
   565 	},
       
   566 
       
   567 	/**
       
   568 	 * Deactivates a frame for editing a featured image.
       
   569 	 *
       
   570 	 * @since 3.9.0
       
   571 	 *
       
   572 	 * @return {void}
       
   573 	 */
       
   574 	deactivate: function() {
       
   575 		this.frame.off( 'toolbar:render:edit-image' );
       
   576 	},
       
   577 
       
   578 	/**
       
   579 	 * Adds a toolbar with a back button.
       
   580 	 *
       
   581 	 * When the back button is pressed it checks whether there is a previous state.
       
   582 	 * In case there is a previous state it sets that previous state otherwise it
       
   583 	 * closes the frame.
       
   584 	 *
       
   585 	 * @since 3.9.0
       
   586 	 *
       
   587 	 * @return {void}
       
   588 	 */
       
   589 	toolbar: function() {
       
   590 		var frame = this.frame,
       
   591 			lastState = frame.lastState(),
       
   592 			previous = lastState && lastState.id;
       
   593 
       
   594 		frame.toolbar.set( new wp.media.view.Toolbar({
       
   595 			controller: frame,
       
   596 			items: {
       
   597 				back: {
       
   598 					style: 'primary',
       
   599 					text:     l10n.back,
       
   600 					priority: 20,
       
   601 					click:    function() {
       
   602 						if ( previous ) {
       
   603 							frame.setState( previous );
       
   604 						} else {
       
   605 							frame.close();
       
   606 						}
       
   607 					}
       
   608 				}
       
   609 			}
       
   610 		}) );
       
   611 	}
   892 	}
   612 });
   893 });
   613 
   894 
   614 module.exports = EditImage;
   895 module.exports = ImageDetails;
   615 
   896 
   616 
   897 
   617 /***/ }),
   898 /***/ }),
   618 
   899 
   619 /***/ 4910:
   900 /***/ 718:
   620 /***/ ((module) => {
   901 /***/ ((module) => {
   621 
   902 
   622 var l10n = wp.media.view.l10n,
   903 var $ = jQuery;
   623 	$ = Backbone.$,
       
   624 	Embed;
       
   625 
   904 
   626 /**
   905 /**
   627  * wp.media.controller.Embed
   906  * wp.media.view.FocusManager
   628  *
   907  *
   629  * A state for embedding media from a URL.
   908  * @memberOf wp.media.view
   630  *
       
   631  * @memberOf wp.media.controller
       
   632  *
   909  *
   633  * @class
   910  * @class
   634  * @augments wp.media.controller.State
   911  * @augments wp.media.View
   635  * @augments Backbone.Model
   912  * @augments wp.Backbone.View
   636  *
   913  * @augments Backbone.View
   637  * @param {object} attributes                         The attributes hash passed to the state.
       
   638  * @param {string} [attributes.id=embed]              Unique identifier.
       
   639  * @param {string} [attributes.title=Insert From URL] Title for the state. Displays in the media menu and the frame's title region.
       
   640  * @param {string} [attributes.content=embed]         Initial mode for the content region.
       
   641  * @param {string} [attributes.menu=default]          Initial mode for the menu region.
       
   642  * @param {string} [attributes.toolbar=main-embed]    Initial mode for the toolbar region.
       
   643  * @param {string} [attributes.menu=false]            Initial mode for the menu region.
       
   644  * @param {int}    [attributes.priority=120]          The priority for the state link in the media menu.
       
   645  * @param {string} [attributes.type=link]             The type of embed. Currently only link is supported.
       
   646  * @param {string} [attributes.url]                   The embed URL.
       
   647  * @param {object} [attributes.metadata={}]           Properties of the embed, which will override attributes.url if set.
       
   648  */
   914  */
   649 Embed = wp.media.controller.State.extend(/** @lends wp.media.controller.Embed.prototype */{
   915 var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.prototype */{
   650 	defaults: {
   916 
   651 		id:       'embed',
   917 	events: {
   652 		title:    l10n.insertFromUrlTitle,
   918 		'keydown': 'focusManagementMode'
   653 		content:  'embed',
   919 	},
   654 		menu:     'default',
   920 
   655 		toolbar:  'main-embed',
   921 	/**
   656 		priority: 120,
   922 	 * Initializes the Focus Manager.
   657 		type:     'link',
   923 	 *
   658 		url:      '',
   924 	 * @param {Object} options The Focus Manager options.
   659 		metadata: {}
   925 	 *
   660 	},
   926 	 * @since 5.3.0
   661 
   927 	 *
   662 	// The amount of time used when debouncing the scan.
   928 	 * @return {void}
   663 	sensitivity: 400,
   929 	 */
   664 
   930 	initialize: function( options ) {
   665 	initialize: function(options) {
   931 		this.mode                    = options.mode || 'constrainTabbing';
   666 		this.metadata = options.metadata;
   932 		this.tabsAutomaticActivation = options.tabsAutomaticActivation || false;
   667 		this.debouncedScan = _.debounce( _.bind( this.scan, this ), this.sensitivity );
   933 	},
   668 		this.props = new Backbone.Model( this.metadata || { url: '' });
   934 
   669 		this.props.on( 'change:url', this.debouncedScan, this );
   935  	/**
   670 		this.props.on( 'change:url', this.refresh, this );
   936 	 * Determines which focus management mode to use.
   671 		this.on( 'scan', this.scanImage, this );
   937 	 *
   672 	},
   938 	 * @since 5.3.0
   673 
   939 	 *
   674 	/**
   940 	 * @param {Object} event jQuery event object.
   675 	 * Trigger a scan of the embedded URL's content for metadata required to embed.
   941 	 *
   676 	 *
   942 	 * @return {void}
   677 	 * @fires wp.media.controller.Embed#scan
   943 	 */
   678 	 */
   944 	focusManagementMode: function( event ) {
   679 	scan: function() {
   945 		if ( this.mode === 'constrainTabbing' ) {
   680 		var scanners,
   946 			this.constrainTabbing( event );
   681 			embed = this,
   947 		}
   682 			attributes = {
   948 
   683 				type: 'link',
   949 		if ( this.mode === 'tabsNavigation' ) {
   684 				scanners: []
   950 			this.tabsNavigation( event );
   685 			};
   951 		}
   686 
   952 	},
   687 		/*
   953 
   688 		 * Scan is triggered with the list of `attributes` to set on the
   954 	/**
   689 		 * state, useful for the 'type' attribute and 'scanners' attribute,
   955 	 * Gets all the tabbable elements.
   690 		 * an array of promise objects for asynchronous scan operations.
   956 	 *
   691 		 */
   957 	 * @since 5.3.0
   692 		if ( this.props.get('url') ) {
   958 	 *
   693 			this.trigger( 'scan', attributes );
   959 	 * @return {Object} A jQuery collection of tabbable elements.
   694 		}
   960 	 */
   695 
   961 	getTabbables: function() {
   696 		if ( attributes.scanners.length ) {
   962 		// Skip the file input added by Plupload.
   697 			scanners = attributes.scanners = $.when.apply( $, attributes.scanners );
   963 		return this.$( ':tabbable' ).not( '.moxie-shim input[type="file"]' );
   698 			scanners.always( function() {
   964 	},
   699 				if ( embed.get('scanners') === scanners ) {
   965 
   700 					embed.set( 'loading', false );
   966 	/**
   701 				}
   967 	 * Moves focus to the modal dialog.
   702 			});
   968 	 *
   703 		} else {
   969 	 * @since 3.5.0
   704 			attributes.scanners = null;
   970 	 *
   705 		}
   971 	 * @return {void}
   706 
   972 	 */
   707 		attributes.loading = !! attributes.scanners;
   973 	focus: function() {
   708 		this.set( attributes );
   974 		this.$( '.media-modal' ).trigger( 'focus' );
   709 	},
   975 	},
   710 	/**
   976 
   711 	 * Try scanning the embed as an image to discover its dimensions.
   977 	/**
   712 	 *
   978 	 * Constrains navigation with the Tab key within the media view element.
   713 	 * @param {Object} attributes
   979 	 *
   714 	 */
   980 	 * @since 4.0.0
   715 	scanImage: function( attributes ) {
   981 	 *
   716 		var frame = this.frame,
   982 	 * @param {Object} event A keydown jQuery event.
   717 			state = this,
   983 	 *
   718 			url = this.props.get('url'),
   984 	 * @return {void}
   719 			image = new Image(),
   985 	 */
   720 			deferred = $.Deferred();
   986 	constrainTabbing: function( event ) {
   721 
   987 		var tabbables;
   722 		attributes.scanners.push( deferred.promise() );
   988 
   723 
   989 		// Look for the tab key.
   724 		// Try to load the image and find its width/height.
   990 		if ( 9 !== event.keyCode ) {
   725 		image.onload = function() {
   991 			return;
   726 			deferred.resolve();
   992 		}
   727 
   993 
   728 			if ( state !== frame.state() || url !== state.props.get('url') ) {
   994 		tabbables = this.getTabbables();
       
   995 
       
   996 		// Keep tab focus within media modal while it's open.
       
   997 		if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
       
   998 			tabbables.first().focus();
       
   999 			return false;
       
  1000 		} else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
       
  1001 			tabbables.last().focus();
       
  1002 			return false;
       
  1003 		}
       
  1004 	},
       
  1005 
       
  1006 	/**
       
  1007 	 * Hides from assistive technologies all the body children.
       
  1008 	 *
       
  1009 	 * Sets an `aria-hidden="true"` attribute on all the body children except
       
  1010 	 * the provided element and other elements that should not be hidden.
       
  1011 	 *
       
  1012 	 * The reason why we use `aria-hidden` is that `aria-modal="true"` is buggy
       
  1013 	 * in Safari 11.1 and support is spotty in other browsers. Also, `aria-modal="true"`
       
  1014 	 * prevents the `wp.a11y.speak()` ARIA live regions to work as they're outside
       
  1015 	 * of the modal dialog and get hidden from assistive technologies.
       
  1016 	 *
       
  1017 	 * @since 5.2.3
       
  1018 	 *
       
  1019 	 * @param {Object} visibleElement The jQuery object representing the element that should not be hidden.
       
  1020 	 *
       
  1021 	 * @return {void}
       
  1022 	 */
       
  1023 	setAriaHiddenOnBodyChildren: function( visibleElement ) {
       
  1024 		var bodyChildren,
       
  1025 			self = this;
       
  1026 
       
  1027 		if ( this.isBodyAriaHidden ) {
       
  1028 			return;
       
  1029 		}
       
  1030 
       
  1031 		// Get all the body children.
       
  1032 		bodyChildren = document.body.children;
       
  1033 
       
  1034 		// Loop through the body children and hide the ones that should be hidden.
       
  1035 		_.each( bodyChildren, function( element ) {
       
  1036 			// Don't hide the modal element.
       
  1037 			if ( element === visibleElement[0] ) {
   729 				return;
  1038 				return;
   730 			}
  1039 			}
   731 
  1040 
   732 			state.set({
  1041 			// Determine the body children to hide.
   733 				type: 'image'
  1042 			if ( self.elementShouldBeHidden( element ) ) {
   734 			});
  1043 				element.setAttribute( 'aria-hidden', 'true' );
   735 
  1044 				// Store the hidden elements.
   736 			state.props.set({
  1045 				self.ariaHiddenElements.push( element );
   737 				width:  image.width,
  1046 			}
   738 				height: image.height
  1047 		} );
   739 			});
  1048 
   740 		};
  1049 		this.isBodyAriaHidden = true;
   741 
  1050 	},
   742 		image.onerror = deferred.reject;
  1051 
   743 		image.src = url;
  1052 	/**
   744 	},
  1053 	 * Unhides from assistive technologies all the body children.
   745 
  1054 	 *
   746 	refresh: function() {
  1055 	 * Makes visible again to assistive technologies all the body children
   747 		this.frame.toolbar.get().refresh();
  1056 	 * previously hidden and stored in this.ariaHiddenElements.
   748 	},
  1057 	 *
   749 
  1058 	 * @since 5.2.3
   750 	reset: function() {
  1059 	 *
   751 		this.props.clear().set({ url: '' });
  1060 	 * @return {void}
   752 
  1061 	 */
   753 		if ( this.active ) {
  1062 	removeAriaHiddenFromBodyChildren: function() {
   754 			this.refresh();
  1063 		_.each( this.ariaHiddenElements, function( element ) {
       
  1064 			element.removeAttribute( 'aria-hidden' );
       
  1065 		} );
       
  1066 
       
  1067 		this.ariaHiddenElements = [];
       
  1068 		this.isBodyAriaHidden   = false;
       
  1069 	},
       
  1070 
       
  1071 	/**
       
  1072 	 * Determines if the passed element should not be hidden from assistive technologies.
       
  1073 	 *
       
  1074 	 * @since 5.2.3
       
  1075 	 *
       
  1076 	 * @param {Object} element The DOM element that should be checked.
       
  1077 	 *
       
  1078 	 * @return {boolean} Whether the element should not be hidden from assistive technologies.
       
  1079 	 */
       
  1080 	elementShouldBeHidden: function( element ) {
       
  1081 		var role = element.getAttribute( 'role' ),
       
  1082 			liveRegionsRoles = [ 'alert', 'status', 'log', 'marquee', 'timer' ];
       
  1083 
       
  1084 		/*
       
  1085 		 * Don't hide scripts, elements that already have `aria-hidden`, and
       
  1086 		 * ARIA live regions.
       
  1087 		 */
       
  1088 		return ! (
       
  1089 			element.tagName === 'SCRIPT' ||
       
  1090 			element.hasAttribute( 'aria-hidden' ) ||
       
  1091 			element.hasAttribute( 'aria-live' ) ||
       
  1092 			liveRegionsRoles.indexOf( role ) !== -1
       
  1093 		);
       
  1094 	},
       
  1095 
       
  1096 	/**
       
  1097 	 * Whether the body children are hidden from assistive technologies.
       
  1098 	 *
       
  1099 	 * @since 5.2.3
       
  1100 	 */
       
  1101 	isBodyAriaHidden: false,
       
  1102 
       
  1103 	/**
       
  1104 	 * Stores an array of DOM elements that should be hidden from assistive
       
  1105 	 * technologies, for example when the media modal dialog opens.
       
  1106 	 *
       
  1107 	 * @since 5.2.3
       
  1108 	 */
       
  1109 	ariaHiddenElements: [],
       
  1110 
       
  1111 	/**
       
  1112 	 * Holds the jQuery collection of ARIA tabs.
       
  1113 	 *
       
  1114 	 * @since 5.3.0
       
  1115 	 */
       
  1116 	tabs: $(),
       
  1117 
       
  1118 	/**
       
  1119 	 * Sets up tabs in an ARIA tabbed interface.
       
  1120 	 *
       
  1121 	 * @since 5.3.0
       
  1122 	 *
       
  1123 	 * @param {Object} event jQuery event object.
       
  1124 	 *
       
  1125 	 * @return {void}
       
  1126 	 */
       
  1127 	setupAriaTabs: function() {
       
  1128 		this.tabs = this.$( '[role="tab"]' );
       
  1129 
       
  1130 		// Set up initial attributes.
       
  1131 		this.tabs.attr( {
       
  1132 			'aria-selected': 'false',
       
  1133 			tabIndex: '-1'
       
  1134 		} );
       
  1135 
       
  1136 		// Set up attributes on the initially active tab.
       
  1137 		this.tabs.filter( '.active' )
       
  1138 			.removeAttr( 'tabindex' )
       
  1139 			.attr( 'aria-selected', 'true' );
       
  1140 	},
       
  1141 
       
  1142 	/**
       
  1143 	 * Enables arrows navigation within the ARIA tabbed interface.
       
  1144 	 *
       
  1145 	 * @since 5.3.0
       
  1146 	 *
       
  1147 	 * @param {Object} event jQuery event object.
       
  1148 	 *
       
  1149 	 * @return {void}
       
  1150 	 */
       
  1151 	tabsNavigation: function( event ) {
       
  1152 		var orientation = 'horizontal',
       
  1153 			keys = [ 32, 35, 36, 37, 38, 39, 40 ];
       
  1154 
       
  1155 		// Return if not Spacebar, End, Home, or Arrow keys.
       
  1156 		if ( keys.indexOf( event.which ) === -1 ) {
       
  1157 			return;
       
  1158 		}
       
  1159 
       
  1160 		// Determine navigation direction.
       
  1161 		if ( this.$el.attr( 'aria-orientation' ) === 'vertical' ) {
       
  1162 			orientation = 'vertical';
       
  1163 		}
       
  1164 
       
  1165 		// Make Up and Down arrow keys do nothing with horizontal tabs.
       
  1166 		if ( orientation === 'horizontal' && [ 38, 40 ].indexOf( event.which ) !== -1 ) {
       
  1167 			return;
       
  1168 		}
       
  1169 
       
  1170 		// Make Left and Right arrow keys do nothing with vertical tabs.
       
  1171 		if ( orientation === 'vertical' && [ 37, 39 ].indexOf( event.which ) !== -1 ) {
       
  1172 			return;
       
  1173 		}
       
  1174 
       
  1175 		this.switchTabs( event, this.tabs );
       
  1176 	},
       
  1177 
       
  1178 	/**
       
  1179 	 * Switches tabs in the ARIA tabbed interface.
       
  1180 	 *
       
  1181 	 * @since 5.3.0
       
  1182 	 *
       
  1183 	 * @param {Object} event jQuery event object.
       
  1184 	 *
       
  1185 	 * @return {void}
       
  1186 	 */
       
  1187 	switchTabs: function( event ) {
       
  1188 		var key   = event.which,
       
  1189 			index = this.tabs.index( $( event.target ) ),
       
  1190 			newIndex;
       
  1191 
       
  1192 		switch ( key ) {
       
  1193 			// Space bar: Activate current targeted tab.
       
  1194 			case 32: {
       
  1195 				this.activateTab( this.tabs[ index ] );
       
  1196 				break;
       
  1197 			}
       
  1198 			// End key: Activate last tab.
       
  1199 			case 35: {
       
  1200 				event.preventDefault();
       
  1201 				this.activateTab( this.tabs[ this.tabs.length - 1 ] );
       
  1202 				break;
       
  1203 			}
       
  1204 			// Home key: Activate first tab.
       
  1205 			case 36: {
       
  1206 				event.preventDefault();
       
  1207 				this.activateTab( this.tabs[ 0 ] );
       
  1208 				break;
       
  1209 			}
       
  1210 			// Left and up keys: Activate previous tab.
       
  1211 			case 37:
       
  1212 			case 38: {
       
  1213 				event.preventDefault();
       
  1214 				newIndex = ( index - 1 ) < 0 ? this.tabs.length - 1 : index - 1;
       
  1215 				this.activateTab( this.tabs[ newIndex ] );
       
  1216 				break;
       
  1217 			}
       
  1218 			// Right and down keys: Activate next tab.
       
  1219 			case 39:
       
  1220 			case 40: {
       
  1221 				event.preventDefault();
       
  1222 				newIndex = ( index + 1 ) === this.tabs.length ? 0 : index + 1;
       
  1223 				this.activateTab( this.tabs[ newIndex ] );
       
  1224 				break;
       
  1225 			}
       
  1226 		}
       
  1227 	},
       
  1228 
       
  1229 	/**
       
  1230 	 * Sets a single tab to be focusable and semantically selected.
       
  1231 	 *
       
  1232 	 * @since 5.3.0
       
  1233 	 *
       
  1234 	 * @param {Object} tab The tab DOM element.
       
  1235 	 *
       
  1236 	 * @return {void}
       
  1237 	 */
       
  1238 	activateTab: function( tab ) {
       
  1239 		if ( ! tab ) {
       
  1240 			return;
       
  1241 		}
       
  1242 
       
  1243 		// The tab is a DOM element: no need for jQuery methods.
       
  1244 		tab.focus();
       
  1245 
       
  1246 		// Handle automatic activation.
       
  1247 		if ( this.tabsAutomaticActivation ) {
       
  1248 			tab.removeAttribute( 'tabindex' );
       
  1249 			tab.setAttribute( 'aria-selected', 'true' );
       
  1250 			tab.click();
       
  1251 
       
  1252 			return;
       
  1253 		}
       
  1254 
       
  1255 		// Handle manual activation.
       
  1256 		$( tab ).on( 'click', function() {
       
  1257 			tab.removeAttribute( 'tabindex' );
       
  1258 			tab.setAttribute( 'aria-selected', 'true' );
       
  1259 		} );
       
  1260  	}
       
  1261 });
       
  1262 
       
  1263 module.exports = FocusManager;
       
  1264 
       
  1265 
       
  1266 /***/ }),
       
  1267 
       
  1268 /***/ 846:
       
  1269 /***/ ((module) => {
       
  1270 
       
  1271 /**
       
  1272  * wp.media.view.Button
       
  1273  *
       
  1274  * @memberOf wp.media.view
       
  1275  *
       
  1276  * @class
       
  1277  * @augments wp.media.View
       
  1278  * @augments wp.Backbone.View
       
  1279  * @augments Backbone.View
       
  1280  */
       
  1281 var Button = wp.media.View.extend(/** @lends wp.media.view.Button.prototype */{
       
  1282 	tagName:    'button',
       
  1283 	className:  'media-button',
       
  1284 	attributes: { type: 'button' },
       
  1285 
       
  1286 	events: {
       
  1287 		'click': 'click'
       
  1288 	},
       
  1289 
       
  1290 	defaults: {
       
  1291 		text:     '',
       
  1292 		style:    '',
       
  1293 		size:     'large',
       
  1294 		disabled: false
       
  1295 	},
       
  1296 
       
  1297 	initialize: function() {
       
  1298 		/**
       
  1299 		 * Create a model with the provided `defaults`.
       
  1300 		 *
       
  1301 		 * @member {Backbone.Model}
       
  1302 		 */
       
  1303 		this.model = new Backbone.Model( this.defaults );
       
  1304 
       
  1305 		// If any of the `options` have a key from `defaults`, apply its
       
  1306 		// value to the `model` and remove it from the `options object.
       
  1307 		_.each( this.defaults, function( def, key ) {
       
  1308 			var value = this.options[ key ];
       
  1309 			if ( _.isUndefined( value ) ) {
       
  1310 				return;
       
  1311 			}
       
  1312 
       
  1313 			this.model.set( key, value );
       
  1314 			delete this.options[ key ];
       
  1315 		}, this );
       
  1316 
       
  1317 		this.listenTo( this.model, 'change', this.render );
       
  1318 	},
       
  1319 	/**
       
  1320 	 * @return {wp.media.view.Button} Returns itself to allow chaining.
       
  1321 	 */
       
  1322 	render: function() {
       
  1323 		var classes = [ 'button', this.className ],
       
  1324 			model = this.model.toJSON();
       
  1325 
       
  1326 		if ( model.style ) {
       
  1327 			classes.push( 'button-' + model.style );
       
  1328 		}
       
  1329 
       
  1330 		if ( model.size ) {
       
  1331 			classes.push( 'button-' + model.size );
       
  1332 		}
       
  1333 
       
  1334 		classes = _.uniq( classes.concat( this.options.classes ) );
       
  1335 		this.el.className = classes.join(' ');
       
  1336 
       
  1337 		this.$el.attr( 'disabled', model.disabled );
       
  1338 		this.$el.text( this.model.get('text') );
       
  1339 
       
  1340 		return this;
       
  1341 	},
       
  1342 	/**
       
  1343 	 * @param {Object} event
       
  1344 	 */
       
  1345 	click: function( event ) {
       
  1346 		if ( '#' === this.attributes.href ) {
       
  1347 			event.preventDefault();
       
  1348 		}
       
  1349 
       
  1350 		if ( this.options.click && ! this.model.get('disabled') ) {
       
  1351 			this.options.click.apply( this, arguments );
   755 		}
  1352 		}
   756 	}
  1353 	}
   757 });
  1354 });
   758 
  1355 
   759 module.exports = Embed;
  1356 module.exports = Button;
       
  1357 
       
  1358 
       
  1359 /***/ }),
       
  1360 
       
  1361 /***/ 1061:
       
  1362 /***/ ((module) => {
       
  1363 
       
  1364 /**
       
  1365  * wp.media.view.Frame
       
  1366  *
       
  1367  * A frame is a composite view consisting of one or more regions and one or more
       
  1368  * states.
       
  1369  *
       
  1370  * @memberOf wp.media.view
       
  1371  *
       
  1372  * @see wp.media.controller.State
       
  1373  * @see wp.media.controller.Region
       
  1374  *
       
  1375  * @class
       
  1376  * @augments wp.media.View
       
  1377  * @augments wp.Backbone.View
       
  1378  * @augments Backbone.View
       
  1379  * @mixes wp.media.controller.StateMachine
       
  1380  */
       
  1381 var Frame = wp.media.View.extend(/** @lends wp.media.view.Frame.prototype */{
       
  1382 	initialize: function() {
       
  1383 		_.defaults( this.options, {
       
  1384 			mode: [ 'select' ]
       
  1385 		});
       
  1386 		this._createRegions();
       
  1387 		this._createStates();
       
  1388 		this._createModes();
       
  1389 	},
       
  1390 
       
  1391 	_createRegions: function() {
       
  1392 		// Clone the regions array.
       
  1393 		this.regions = this.regions ? this.regions.slice() : [];
       
  1394 
       
  1395 		// Initialize regions.
       
  1396 		_.each( this.regions, function( region ) {
       
  1397 			this[ region ] = new wp.media.controller.Region({
       
  1398 				view:     this,
       
  1399 				id:       region,
       
  1400 				selector: '.media-frame-' + region
       
  1401 			});
       
  1402 		}, this );
       
  1403 	},
       
  1404 	/**
       
  1405 	 * Create the frame's states.
       
  1406 	 *
       
  1407 	 * @see wp.media.controller.State
       
  1408 	 * @see wp.media.controller.StateMachine
       
  1409 	 *
       
  1410 	 * @fires wp.media.controller.State#ready
       
  1411 	 */
       
  1412 	_createStates: function() {
       
  1413 		// Create the default `states` collection.
       
  1414 		this.states = new Backbone.Collection( null, {
       
  1415 			model: wp.media.controller.State
       
  1416 		});
       
  1417 
       
  1418 		// Ensure states have a reference to the frame.
       
  1419 		this.states.on( 'add', function( model ) {
       
  1420 			model.frame = this;
       
  1421 			model.trigger('ready');
       
  1422 		}, this );
       
  1423 
       
  1424 		if ( this.options.states ) {
       
  1425 			this.states.add( this.options.states );
       
  1426 		}
       
  1427 	},
       
  1428 
       
  1429 	/**
       
  1430 	 * A frame can be in a mode or multiple modes at one time.
       
  1431 	 *
       
  1432 	 * For example, the manage media frame can be in the `Bulk Select` or `Edit` mode.
       
  1433 	 */
       
  1434 	_createModes: function() {
       
  1435 		// Store active "modes" that the frame is in. Unrelated to region modes.
       
  1436 		this.activeModes = new Backbone.Collection();
       
  1437 		this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
       
  1438 
       
  1439 		_.each( this.options.mode, function( mode ) {
       
  1440 			this.activateMode( mode );
       
  1441 		}, this );
       
  1442 	},
       
  1443 	/**
       
  1444 	 * Reset all states on the frame to their defaults.
       
  1445 	 *
       
  1446 	 * @return {wp.media.view.Frame} Returns itself to allow chaining.
       
  1447 	 */
       
  1448 	reset: function() {
       
  1449 		this.states.invoke( 'trigger', 'reset' );
       
  1450 		return this;
       
  1451 	},
       
  1452 	/**
       
  1453 	 * Map activeMode collection events to the frame.
       
  1454 	 */
       
  1455 	triggerModeEvents: function( model, collection, options ) {
       
  1456 		var collectionEvent,
       
  1457 			modeEventMap = {
       
  1458 				add: 'activate',
       
  1459 				remove: 'deactivate'
       
  1460 			},
       
  1461 			eventToTrigger;
       
  1462 		// Probably a better way to do this.
       
  1463 		_.each( options, function( value, key ) {
       
  1464 			if ( value ) {
       
  1465 				collectionEvent = key;
       
  1466 			}
       
  1467 		} );
       
  1468 
       
  1469 		if ( ! _.has( modeEventMap, collectionEvent ) ) {
       
  1470 			return;
       
  1471 		}
       
  1472 
       
  1473 		eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
       
  1474 		this.trigger( eventToTrigger );
       
  1475 	},
       
  1476 	/**
       
  1477 	 * Activate a mode on the frame.
       
  1478 	 *
       
  1479 	 * @param string mode Mode ID.
       
  1480 	 * @return {this} Returns itself to allow chaining.
       
  1481 	 */
       
  1482 	activateMode: function( mode ) {
       
  1483 		// Bail if the mode is already active.
       
  1484 		if ( this.isModeActive( mode ) ) {
       
  1485 			return;
       
  1486 		}
       
  1487 		this.activeModes.add( [ { id: mode } ] );
       
  1488 		// Add a CSS class to the frame so elements can be styled for the mode.
       
  1489 		this.$el.addClass( 'mode-' + mode );
       
  1490 
       
  1491 		return this;
       
  1492 	},
       
  1493 	/**
       
  1494 	 * Deactivate a mode on the frame.
       
  1495 	 *
       
  1496 	 * @param string mode Mode ID.
       
  1497 	 * @return {this} Returns itself to allow chaining.
       
  1498 	 */
       
  1499 	deactivateMode: function( mode ) {
       
  1500 		// Bail if the mode isn't active.
       
  1501 		if ( ! this.isModeActive( mode ) ) {
       
  1502 			return this;
       
  1503 		}
       
  1504 		this.activeModes.remove( this.activeModes.where( { id: mode } ) );
       
  1505 		this.$el.removeClass( 'mode-' + mode );
       
  1506 		/**
       
  1507 		 * Frame mode deactivation event.
       
  1508 		 *
       
  1509 		 * @event wp.media.view.Frame#{mode}:deactivate
       
  1510 		 */
       
  1511 		this.trigger( mode + ':deactivate' );
       
  1512 
       
  1513 		return this;
       
  1514 	},
       
  1515 	/**
       
  1516 	 * Check if a mode is enabled on the frame.
       
  1517 	 *
       
  1518 	 * @param string mode Mode ID.
       
  1519 	 * @return bool
       
  1520 	 */
       
  1521 	isModeActive: function( mode ) {
       
  1522 		return Boolean( this.activeModes.where( { id: mode } ).length );
       
  1523 	}
       
  1524 });
       
  1525 
       
  1526 // Make the `Frame` a `StateMachine`.
       
  1527 _.extend( Frame.prototype, wp.media.controller.StateMachine.prototype );
       
  1528 
       
  1529 module.exports = Frame;
   760 
  1530 
   761 
  1531 
   762 /***/ }),
  1532 /***/ }),
   763 
  1533 
   764 /***/ 1169:
  1534 /***/ 1169:
   887 module.exports = FeaturedImage;
  1657 module.exports = FeaturedImage;
   888 
  1658 
   889 
  1659 
   890 /***/ }),
  1660 /***/ }),
   891 
  1661 
   892 /***/ 7127:
  1662 /***/ 1368:
   893 /***/ ((module) => {
  1663 /***/ ((module) => {
   894 
  1664 
   895 var Selection = wp.media.model.Selection,
  1665 var l10n = wp.media.view.l10n,
   896 	Library = wp.media.controller.Library,
  1666 	Uploaded;
   897 	l10n = wp.media.view.l10n,
       
   898 	GalleryAdd;
       
   899 
  1667 
   900 /**
  1668 /**
   901  * wp.media.controller.GalleryAdd
  1669  * wp.media.view.AttachmentFilters.Uploaded
   902  *
  1670  *
   903  * A state for selecting more images to add to a gallery.
  1671  * @memberOf wp.media.view.AttachmentFilters
   904  *
       
   905  * @since 3.5.0
       
   906  *
  1672  *
   907  * @class
  1673  * @class
   908  * @augments wp.media.controller.Library
  1674  * @augments wp.media.view.AttachmentFilters
   909  * @augments wp.media.controller.State
  1675  * @augments wp.media.View
   910  * @augments Backbone.Model
  1676  * @augments wp.Backbone.View
   911  *
  1677  * @augments Backbone.View
   912  * @memberof wp.media.controller
       
   913  *
       
   914  * @param {Object}                     [attributes]                         The attributes hash passed to the state.
       
   915  * @param {string}                     [attributes.id=gallery-library]      Unique identifier.
       
   916  * @param {string}                     [attributes.title=Add to Gallery]    Title for the state. Displays in the frame's title region.
       
   917  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
       
   918  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
       
   919  *                                                                          If one is not supplied, a collection of all images will be created.
       
   920  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
       
   921  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
       
   922  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
       
   923  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
       
   924  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
       
   925  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
       
   926  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
       
   927  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
       
   928  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
   929  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
   930  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
   931  * @param {number}                     [attributes.priority=100]            The priority for the state link in the media menu.
       
   932  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
       
   933  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
       
   934  */
  1678  */
   935 GalleryAdd = Library.extend(/** @lends wp.media.controller.GalleryAdd.prototype */{
  1679 Uploaded = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Uploaded.prototype */{
   936 	defaults: _.defaults({
  1680 	createFilters: function() {
   937 		id:            'gallery-library',
  1681 		var type = this.model.get('type'),
   938 		title:         l10n.addToGalleryTitle,
  1682 			types = wp.media.view.settings.mimeTypes,
   939 		multiple:      'add',
  1683 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0,
   940 		filterable:    'uploaded',
  1684 			text;
   941 		menu:          'gallery',
  1685 
   942 		toolbar:       'gallery-add',
  1686 		if ( types && type ) {
   943 		priority:      100,
  1687 			text = types[ type ];
   944 		syncSelection: false
  1688 		}
   945 	}, Library.prototype.defaults ),
  1689 
   946 
  1690 		this.filters = {
   947 	/**
  1691 			all: {
   948 	 * Initializes the library. Creates a library of images if a library isn't supplied.
  1692 				text:  text || l10n.allMediaItems,
   949 	 *
  1693 				props: {
   950 	 * @since 3.5.0
  1694 					uploadedTo: null,
   951 	 *
  1695 					orderby: 'date',
   952 	 * @return {void}
  1696 					order:   'DESC',
   953 	 */
  1697 					author:	 null
   954 	initialize: function() {
  1698 				},
   955 		if ( ! this.get('library') ) {
  1699 				priority: 10
   956 			this.set( 'library', wp.media.query({ type: 'image' }) );
  1700 			},
   957 		}
  1701 
   958 
  1702 			uploaded: {
   959 		Library.prototype.initialize.apply( this, arguments );
  1703 				text:  l10n.uploadedToThisPost,
   960 	},
  1704 				props: {
   961 
  1705 					uploadedTo: wp.media.view.settings.post.id,
   962 	/**
  1706 					orderby: 'menuOrder',
   963 	 * Activates the library.
  1707 					order:   'ASC',
   964 	 *
  1708 					author:	 null
   965 	 * Removes all event listeners if in edit mode. Creates a validator to check an attachment.
  1709 				},
   966 	 * Resets library and re-enables event listeners. Activates edit mode. Calls the parent's activate method.
  1710 				priority: 20
   967 	 *
  1711 			},
   968 	 * @since 3.5.0
  1712 
   969 	 *
  1713 			unattached: {
   970 	 * @return {void}
  1714 				text:  l10n.unattached,
   971 	 */
  1715 				props: {
   972 	activate: function() {
  1716 					uploadedTo: 0,
   973 		var library = this.get('library'),
  1717 					orderby: 'menuOrder',
   974 			edit    = this.frame.state('gallery-edit').get('library');
  1718 					order:   'ASC',
   975 
  1719 					author:	 null
   976 		if ( this.editLibrary && this.editLibrary !== edit ) {
  1720 				},
   977 			library.unobserve( this.editLibrary );
  1721 				priority: 50
   978 		}
  1722 			}
   979 
       
   980 		/*
       
   981 		 * Accept attachments that exist in the original library but
       
   982 		 * that do not exist in gallery's library yet.
       
   983 		 */
       
   984 		library.validator = function( attachment ) {
       
   985 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
       
   986 		};
  1723 		};
   987 
  1724 
   988 		/*
  1725 		if ( uid ) {
   989 		 * Reset the library to ensure that all attachments are re-added
  1726 			this.filters.mine = {
   990 		 * to the collection. Do so silently, as calling `observe` will
  1727 				text:  l10n.mine,
   991 		 * trigger the `reset` event.
  1728 				props: {
   992 		 */
  1729 					orderby: 'date',
   993 		library.reset( library.mirroring.models, { silent: true });
  1730 					order:   'DESC',
   994 		library.observe( edit );
  1731 					author:  uid
   995 		this.editLibrary = edit;
  1732 				},
   996 
  1733 				priority: 50
   997 		Library.prototype.activate.apply( this, arguments );
  1734 			};
       
  1735 		}
   998 	}
  1736 	}
   999 });
  1737 });
  1000 
  1738 
  1001 module.exports = GalleryAdd;
  1739 module.exports = Uploaded;
       
  1740 
       
  1741 
       
  1742 /***/ }),
       
  1743 
       
  1744 /***/ 1753:
       
  1745 /***/ ((module) => {
       
  1746 
       
  1747 var View = wp.media.View,
       
  1748 	UploaderInline;
       
  1749 
       
  1750 /**
       
  1751  * wp.media.view.UploaderInline
       
  1752  *
       
  1753  * The inline uploader that shows up in the 'Upload Files' tab.
       
  1754  *
       
  1755  * @memberOf wp.media.view
       
  1756  *
       
  1757  * @class
       
  1758  * @augments wp.media.View
       
  1759  * @augments wp.Backbone.View
       
  1760  * @augments Backbone.View
       
  1761  */
       
  1762 UploaderInline = View.extend(/** @lends wp.media.view.UploaderInline.prototype */{
       
  1763 	tagName:   'div',
       
  1764 	className: 'uploader-inline',
       
  1765 	template:  wp.template('uploader-inline'),
       
  1766 
       
  1767 	events: {
       
  1768 		'click .close': 'hide'
       
  1769 	},
       
  1770 
       
  1771 	initialize: function() {
       
  1772 		_.defaults( this.options, {
       
  1773 			message: '',
       
  1774 			status:  true,
       
  1775 			canClose: false
       
  1776 		});
       
  1777 
       
  1778 		if ( ! this.options.$browser && this.controller.uploader ) {
       
  1779 			this.options.$browser = this.controller.uploader.$browser;
       
  1780 		}
       
  1781 
       
  1782 		if ( _.isUndefined( this.options.postId ) ) {
       
  1783 			this.options.postId = wp.media.view.settings.post.id;
       
  1784 		}
       
  1785 
       
  1786 		if ( this.options.status ) {
       
  1787 			this.views.set( '.upload-inline-status', new wp.media.view.UploaderStatus({
       
  1788 				controller: this.controller
       
  1789 			}) );
       
  1790 		}
       
  1791 	},
       
  1792 
       
  1793 	prepare: function() {
       
  1794 		var suggestedWidth = this.controller.state().get('suggestedWidth'),
       
  1795 			suggestedHeight = this.controller.state().get('suggestedHeight'),
       
  1796 			data = {};
       
  1797 
       
  1798 		data.message = this.options.message;
       
  1799 		data.canClose = this.options.canClose;
       
  1800 
       
  1801 		if ( suggestedWidth && suggestedHeight ) {
       
  1802 			data.suggestedWidth = suggestedWidth;
       
  1803 			data.suggestedHeight = suggestedHeight;
       
  1804 		}
       
  1805 
       
  1806 		return data;
       
  1807 	},
       
  1808 	/**
       
  1809 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
       
  1810 	 */
       
  1811 	dispose: function() {
       
  1812 		if ( this.disposing ) {
       
  1813 			/**
       
  1814 			 * call 'dispose' directly on the parent class
       
  1815 			 */
       
  1816 			return View.prototype.dispose.apply( this, arguments );
       
  1817 		}
       
  1818 
       
  1819 		/*
       
  1820 		 * Run remove on `dispose`, so we can be sure to refresh the
       
  1821 		 * uploader with a view-less DOM. Track whether we're disposing
       
  1822 		 * so we don't trigger an infinite loop.
       
  1823 		 */
       
  1824 		this.disposing = true;
       
  1825 		return this.remove();
       
  1826 	},
       
  1827 	/**
       
  1828 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
       
  1829 	 */
       
  1830 	remove: function() {
       
  1831 		/**
       
  1832 		 * call 'remove' directly on the parent class
       
  1833 		 */
       
  1834 		var result = View.prototype.remove.apply( this, arguments );
       
  1835 
       
  1836 		_.defer( _.bind( this.refresh, this ) );
       
  1837 		return result;
       
  1838 	},
       
  1839 
       
  1840 	refresh: function() {
       
  1841 		var uploader = this.controller.uploader;
       
  1842 
       
  1843 		if ( uploader ) {
       
  1844 			uploader.refresh();
       
  1845 		}
       
  1846 	},
       
  1847 	/**
       
  1848 	 * @return {wp.media.view.UploaderInline}
       
  1849 	 */
       
  1850 	ready: function() {
       
  1851 		var $browser = this.options.$browser,
       
  1852 			$placeholder;
       
  1853 
       
  1854 		if ( this.controller.uploader ) {
       
  1855 			$placeholder = this.$('.browser');
       
  1856 
       
  1857 			// Check if we've already replaced the placeholder.
       
  1858 			if ( $placeholder[0] === $browser[0] ) {
       
  1859 				return;
       
  1860 			}
       
  1861 
       
  1862 			$browser.detach().text( $placeholder.text() );
       
  1863 			$browser[0].className = $placeholder[0].className;
       
  1864 			$browser[0].setAttribute( 'aria-labelledby', $browser[0].id + ' ' + $placeholder[0].getAttribute('aria-labelledby') );
       
  1865 			$placeholder.replaceWith( $browser.show() );
       
  1866 		}
       
  1867 
       
  1868 		this.refresh();
       
  1869 		return this;
       
  1870 	},
       
  1871 	show: function() {
       
  1872 		this.$el.removeClass( 'hidden' );
       
  1873 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
       
  1874 			this.controller.$uploaderToggler.attr( 'aria-expanded', 'true' );
       
  1875 		}
       
  1876 	},
       
  1877 	hide: function() {
       
  1878 		this.$el.addClass( 'hidden' );
       
  1879 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
       
  1880 			this.controller.$uploaderToggler
       
  1881 				.attr( 'aria-expanded', 'false' )
       
  1882 				// Move focus back to the toggle button when closing the uploader.
       
  1883 				.trigger( 'focus' );
       
  1884 		}
       
  1885 	}
       
  1886 
       
  1887 });
       
  1888 
       
  1889 module.exports = UploaderInline;
       
  1890 
       
  1891 
       
  1892 /***/ }),
       
  1893 
       
  1894 /***/ 1915:
       
  1895 /***/ ((module) => {
       
  1896 
       
  1897 var View = wp.media.View,
       
  1898 	$ = Backbone.$,
       
  1899 	Settings;
       
  1900 
       
  1901 /**
       
  1902  * wp.media.view.Settings
       
  1903  *
       
  1904  * @memberOf wp.media.view
       
  1905  *
       
  1906  * @class
       
  1907  * @augments wp.media.View
       
  1908  * @augments wp.Backbone.View
       
  1909  * @augments Backbone.View
       
  1910  */
       
  1911 Settings = View.extend(/** @lends wp.media.view.Settings.prototype */{
       
  1912 	events: {
       
  1913 		'click button':    'updateHandler',
       
  1914 		'change input':    'updateHandler',
       
  1915 		'change select':   'updateHandler',
       
  1916 		'change textarea': 'updateHandler'
       
  1917 	},
       
  1918 
       
  1919 	initialize: function() {
       
  1920 		this.model = this.model || new Backbone.Model();
       
  1921 		this.listenTo( this.model, 'change', this.updateChanges );
       
  1922 	},
       
  1923 
       
  1924 	prepare: function() {
       
  1925 		return _.defaults({
       
  1926 			model: this.model.toJSON()
       
  1927 		}, this.options );
       
  1928 	},
       
  1929 	/**
       
  1930 	 * @return {wp.media.view.Settings} Returns itself to allow chaining.
       
  1931 	 */
       
  1932 	render: function() {
       
  1933 		View.prototype.render.apply( this, arguments );
       
  1934 		// Select the correct values.
       
  1935 		_( this.model.attributes ).chain().keys().each( this.update, this );
       
  1936 		return this;
       
  1937 	},
       
  1938 	/**
       
  1939 	 * @param {string} key
       
  1940 	 */
       
  1941 	update: function( key ) {
       
  1942 		var value = this.model.get( key ),
       
  1943 			$setting = this.$('[data-setting="' + key + '"]'),
       
  1944 			$buttons, $value;
       
  1945 
       
  1946 		// Bail if we didn't find a matching setting.
       
  1947 		if ( ! $setting.length ) {
       
  1948 			return;
       
  1949 		}
       
  1950 
       
  1951 		// Attempt to determine how the setting is rendered and update
       
  1952 		// the selected value.
       
  1953 
       
  1954 		// Handle dropdowns.
       
  1955 		if ( $setting.is('select') ) {
       
  1956 			$value = $setting.find('[value="' + value + '"]');
       
  1957 
       
  1958 			if ( $value.length ) {
       
  1959 				$setting.find('option').prop( 'selected', false );
       
  1960 				$value.prop( 'selected', true );
       
  1961 			} else {
       
  1962 				// If we can't find the desired value, record what *is* selected.
       
  1963 				this.model.set( key, $setting.find(':selected').val() );
       
  1964 			}
       
  1965 
       
  1966 		// Handle button groups.
       
  1967 		} else if ( $setting.hasClass('button-group') ) {
       
  1968 			$buttons = $setting.find( 'button' )
       
  1969 				.removeClass( 'active' )
       
  1970 				.attr( 'aria-pressed', 'false' );
       
  1971 			$buttons.filter( '[value="' + value + '"]' )
       
  1972 				.addClass( 'active' )
       
  1973 				.attr( 'aria-pressed', 'true' );
       
  1974 
       
  1975 		// Handle text inputs and textareas.
       
  1976 		} else if ( $setting.is('input[type="text"], textarea') ) {
       
  1977 			if ( ! $setting.is(':focus') ) {
       
  1978 				$setting.val( value );
       
  1979 			}
       
  1980 		// Handle checkboxes.
       
  1981 		} else if ( $setting.is('input[type="checkbox"]') ) {
       
  1982 			$setting.prop( 'checked', !! value && 'false' !== value );
       
  1983 		}
       
  1984 	},
       
  1985 	/**
       
  1986 	 * @param {Object} event
       
  1987 	 */
       
  1988 	updateHandler: function( event ) {
       
  1989 		var $setting = $( event.target ).closest('[data-setting]'),
       
  1990 			value = event.target.value,
       
  1991 			userSetting;
       
  1992 
       
  1993 		event.preventDefault();
       
  1994 
       
  1995 		if ( ! $setting.length ) {
       
  1996 			return;
       
  1997 		}
       
  1998 
       
  1999 		// Use the correct value for checkboxes.
       
  2000 		if ( $setting.is('input[type="checkbox"]') ) {
       
  2001 			value = $setting[0].checked;
       
  2002 		}
       
  2003 
       
  2004 		// Update the corresponding setting.
       
  2005 		this.model.set( $setting.data('setting'), value );
       
  2006 
       
  2007 		// If the setting has a corresponding user setting,
       
  2008 		// update that as well.
       
  2009 		userSetting = $setting.data('userSetting');
       
  2010 		if ( userSetting ) {
       
  2011 			window.setUserSetting( userSetting, value );
       
  2012 		}
       
  2013 	},
       
  2014 
       
  2015 	updateChanges: function( model ) {
       
  2016 		if ( model.hasChanged() ) {
       
  2017 			_( model.changed ).chain().keys().each( this.update, this );
       
  2018 		}
       
  2019 	}
       
  2020 });
       
  2021 
       
  2022 module.exports = Settings;
       
  2023 
       
  2024 
       
  2025 /***/ }),
       
  2026 
       
  2027 /***/ 1982:
       
  2028 /***/ ((module) => {
       
  2029 
       
  2030 /**
       
  2031  * wp.media.view.Iframe
       
  2032  *
       
  2033  * @memberOf wp.media.view
       
  2034  *
       
  2035  * @class
       
  2036  * @augments wp.media.View
       
  2037  * @augments wp.Backbone.View
       
  2038  * @augments Backbone.View
       
  2039  */
       
  2040 var Iframe = wp.media.View.extend(/** @lends wp.media.view.Iframe.prototype */{
       
  2041 	className: 'media-iframe',
       
  2042 	/**
       
  2043 	 * @return {wp.media.view.Iframe} Returns itself to allow chaining.
       
  2044 	 */
       
  2045 	render: function() {
       
  2046 		this.views.detach();
       
  2047 		this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
       
  2048 		this.views.render();
       
  2049 		return this;
       
  2050 	}
       
  2051 });
       
  2052 
       
  2053 module.exports = Iframe;
       
  2054 
       
  2055 
       
  2056 /***/ }),
       
  2057 
       
  2058 /***/ 1992:
       
  2059 /***/ ((module) => {
       
  2060 
       
  2061 /**
       
  2062  * wp.media.view.Sidebar
       
  2063  *
       
  2064  * @memberOf wp.media.view
       
  2065  *
       
  2066  * @class
       
  2067  * @augments wp.media.view.PriorityList
       
  2068  * @augments wp.media.View
       
  2069  * @augments wp.Backbone.View
       
  2070  * @augments Backbone.View
       
  2071  */
       
  2072 var Sidebar = wp.media.view.PriorityList.extend(/** @lends wp.media.view.Sidebar.prototype */{
       
  2073 	className: 'media-sidebar'
       
  2074 });
       
  2075 
       
  2076 module.exports = Sidebar;
  1002 
  2077 
  1003 
  2078 
  1004 /***/ }),
  2079 /***/ }),
  1005 
  2080 
  1006 /***/ 2038:
  2081 /***/ 2038:
  1177 module.exports = GalleryEdit;
  2252 module.exports = GalleryEdit;
  1178 
  2253 
  1179 
  2254 
  1180 /***/ }),
  2255 /***/ }),
  1181 
  2256 
  1182 /***/ 705:
  2257 /***/ 2102:
  1183 /***/ ((module) => {
  2258 /***/ ((module) => {
  1184 
  2259 
  1185 var State = wp.media.controller.State,
  2260 var Search;
  1186 	Library = wp.media.controller.Library,
       
  1187 	l10n = wp.media.view.l10n,
       
  1188 	ImageDetails;
       
  1189 
  2261 
  1190 /**
  2262 /**
  1191  * wp.media.controller.ImageDetails
  2263  * wp.media.view.Search
  1192  *
  2264  *
  1193  * A state for editing the attachment display settings of an image that's been
  2265  * @memberOf wp.media.view
  1194  * inserted into the editor.
       
  1195  *
       
  1196  * @memberOf wp.media.controller
       
  1197  *
  2266  *
  1198  * @class
  2267  * @class
  1199  * @augments wp.media.controller.State
  2268  * @augments wp.media.View
  1200  * @augments Backbone.Model
  2269  * @augments wp.Backbone.View
  1201  *
  2270  * @augments Backbone.View
  1202  * @param {object}                    [attributes]                       The attributes hash passed to the state.
       
  1203  * @param {string}                    [attributes.id=image-details]      Unique identifier.
       
  1204  * @param {string}                    [attributes.title=Image Details]   Title for the state. Displays in the frame's title region.
       
  1205  * @param {wp.media.model.Attachment} attributes.image                   The image's model.
       
  1206  * @param {string|false}              [attributes.content=image-details] Initial mode for the content region.
       
  1207  * @param {string|false}              [attributes.menu=false]            Initial mode for the menu region.
       
  1208  * @param {string|false}              [attributes.router=false]          Initial mode for the router region.
       
  1209  * @param {string|false}              [attributes.toolbar=image-details] Initial mode for the toolbar region.
       
  1210  * @param {boolean}                   [attributes.editing=false]         Unused.
       
  1211  * @param {int}                       [attributes.priority=60]           Unused.
       
  1212  *
       
  1213  * @todo This state inherits some defaults from media.controller.Library.prototype.defaults,
       
  1214  *       however this may not do anything.
       
  1215  */
  2271  */
  1216 ImageDetails = State.extend(/** @lends wp.media.controller.ImageDetails.prototype */{
  2272 Search = wp.media.View.extend(/** @lends wp.media.view.Search.prototype */{
  1217 	defaults: _.defaults({
  2273 	tagName:   'input',
  1218 		id:       'image-details',
  2274 	className: 'search',
  1219 		title:    l10n.imageDetailsTitle,
  2275 	id:        'media-search-input',
  1220 		content:  'image-details',
  2276 
  1221 		menu:     false,
  2277 	attributes: {
  1222 		router:   false,
  2278 		type: 'search'
  1223 		toolbar:  'image-details',
  2279 	},
  1224 		editing:  false,
  2280 
  1225 		priority: 60
  2281 	events: {
  1226 	}, Library.prototype.defaults ),
  2282 		'input': 'search'
  1227 
  2283 	},
  1228 	/**
  2284 
  1229 	 * @since 3.9.0
  2285 	/**
  1230 	 *
  2286 	 * @return {wp.media.view.Search} Returns itself to allow chaining.
  1231 	 * @param options Attributes
  2287 	 */
  1232 	 */
  2288 	render: function() {
  1233 	initialize: function( options ) {
  2289 		this.el.value = this.model.escape('search');
  1234 		this.image = options.image;
  2290 		return this;
  1235 		State.prototype.initialize.apply( this, arguments );
  2291 	},
  1236 	},
  2292 
  1237 
  2293 	search: _.debounce( function( event ) {
  1238 	/**
  2294 		var searchTerm = event.target.value.trim();
  1239 	 * @since 3.9.0
  2295 
  1240 	 */
  2296 		// Trigger the search only after 2 ASCII characters.
  1241 	activate: function() {
  2297 		if ( searchTerm && searchTerm.length > 1 ) {
  1242 		this.frame.modal.$el.addClass('image-details');
  2298 			this.model.set( 'search', searchTerm );
  1243 	}
  2299 		} else {
       
  2300 			this.model.unset( 'search' );
       
  2301 		}
       
  2302 	}, 500 )
  1244 });
  2303 });
  1245 
  2304 
  1246 module.exports = ImageDetails;
  2305 module.exports = Search;
  1247 
       
  1248 
       
  1249 /***/ }),
       
  1250 
       
  1251 /***/ 472:
       
  1252 /***/ ((module) => {
       
  1253 
       
  1254 var l10n = wp.media.view.l10n,
       
  1255 	getUserSetting = window.getUserSetting,
       
  1256 	setUserSetting = window.setUserSetting,
       
  1257 	Library;
       
  1258 
       
  1259 /**
       
  1260  * wp.media.controller.Library
       
  1261  *
       
  1262  * A state for choosing an attachment or group of attachments from the media library.
       
  1263  *
       
  1264  * @memberOf wp.media.controller
       
  1265  *
       
  1266  * @class
       
  1267  * @augments wp.media.controller.State
       
  1268  * @augments Backbone.Model
       
  1269  * @mixes media.selectionSync
       
  1270  *
       
  1271  * @param {object}                          [attributes]                         The attributes hash passed to the state.
       
  1272  * @param {string}                          [attributes.id=library]              Unique identifier.
       
  1273  * @param {string}                          [attributes.title=Media library]     Title for the state. Displays in the media menu and the frame's title region.
       
  1274  * @param {wp.media.model.Attachments}      [attributes.library]                 The attachments collection to browse.
       
  1275  *                                                                               If one is not supplied, a collection of all attachments will be created.
       
  1276  * @param {wp.media.model.Selection|object} [attributes.selection]               A collection to contain attachment selections within the state.
       
  1277  *                                                                               If the 'selection' attribute is a plain JS object,
       
  1278  *                                                                               a Selection will be created using its values as the selection instance's `props` model.
       
  1279  *                                                                               Otherwise, it will copy the library's `props` model.
       
  1280  * @param {boolean}                         [attributes.multiple=false]          Whether multi-select is enabled.
       
  1281  * @param {string}                          [attributes.content=upload]          Initial mode for the content region.
       
  1282  *                                                                               Overridden by persistent user setting if 'contentUserSetting' is true.
       
  1283  * @param {string}                          [attributes.menu=default]            Initial mode for the menu region.
       
  1284  * @param {string}                          [attributes.router=browse]           Initial mode for the router region.
       
  1285  * @param {string}                          [attributes.toolbar=select]          Initial mode for the toolbar region.
       
  1286  * @param {boolean}                         [attributes.searchable=true]         Whether the library is searchable.
       
  1287  * @param {boolean|string}                  [attributes.filterable=false]        Whether the library is filterable, and if so what filters should be shown.
       
  1288  *                                                                               Accepts 'all', 'uploaded', or 'unattached'.
       
  1289  * @param {boolean}                         [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  1290  * @param {boolean}                         [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
  1291  * @param {boolean}                         [attributes.describe=false]          Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
       
  1292  * @param {boolean}                         [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
  1293  * @param {boolean}                         [attributes.syncSelection=true]      Whether the Attachments selection should be persisted from the last state.
       
  1294  */
       
  1295 Library = wp.media.controller.State.extend(/** @lends wp.media.controller.Library.prototype */{
       
  1296 	defaults: {
       
  1297 		id:                 'library',
       
  1298 		title:              l10n.mediaLibraryTitle,
       
  1299 		multiple:           false,
       
  1300 		content:            'upload',
       
  1301 		menu:               'default',
       
  1302 		router:             'browse',
       
  1303 		toolbar:            'select',
       
  1304 		searchable:         true,
       
  1305 		filterable:         false,
       
  1306 		sortable:           true,
       
  1307 		autoSelect:         true,
       
  1308 		describe:           false,
       
  1309 		contentUserSetting: true,
       
  1310 		syncSelection:      true
       
  1311 	},
       
  1312 
       
  1313 	/**
       
  1314 	 * If a library isn't provided, query all media items.
       
  1315 	 * If a selection instance isn't provided, create one.
       
  1316 	 *
       
  1317 	 * @since 3.5.0
       
  1318 	 */
       
  1319 	initialize: function() {
       
  1320 		var selection = this.get('selection'),
       
  1321 			props;
       
  1322 
       
  1323 		if ( ! this.get('library') ) {
       
  1324 			this.set( 'library', wp.media.query() );
       
  1325 		}
       
  1326 
       
  1327 		if ( ! ( selection instanceof wp.media.model.Selection ) ) {
       
  1328 			props = selection;
       
  1329 
       
  1330 			if ( ! props ) {
       
  1331 				props = this.get('library').props.toJSON();
       
  1332 				props = _.omit( props, 'orderby', 'query' );
       
  1333 			}
       
  1334 
       
  1335 			this.set( 'selection', new wp.media.model.Selection( null, {
       
  1336 				multiple: this.get('multiple'),
       
  1337 				props: props
       
  1338 			}) );
       
  1339 		}
       
  1340 
       
  1341 		this.resetDisplays();
       
  1342 	},
       
  1343 
       
  1344 	/**
       
  1345 	 * @since 3.5.0
       
  1346 	 */
       
  1347 	activate: function() {
       
  1348 		this.syncSelection();
       
  1349 
       
  1350 		wp.Uploader.queue.on( 'add', this.uploading, this );
       
  1351 
       
  1352 		this.get('selection').on( 'add remove reset', this.refreshContent, this );
       
  1353 
       
  1354 		if ( this.get( 'router' ) && this.get('contentUserSetting') ) {
       
  1355 			this.frame.on( 'content:activate', this.saveContentMode, this );
       
  1356 			this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
       
  1357 		}
       
  1358 	},
       
  1359 
       
  1360 	/**
       
  1361 	 * @since 3.5.0
       
  1362 	 */
       
  1363 	deactivate: function() {
       
  1364 		this.recordSelection();
       
  1365 
       
  1366 		this.frame.off( 'content:activate', this.saveContentMode, this );
       
  1367 
       
  1368 		// Unbind all event handlers that use this state as the context
       
  1369 		// from the selection.
       
  1370 		this.get('selection').off( null, null, this );
       
  1371 
       
  1372 		wp.Uploader.queue.off( null, null, this );
       
  1373 	},
       
  1374 
       
  1375 	/**
       
  1376 	 * Reset the library to its initial state.
       
  1377 	 *
       
  1378 	 * @since 3.5.0
       
  1379 	 */
       
  1380 	reset: function() {
       
  1381 		this.get('selection').reset();
       
  1382 		this.resetDisplays();
       
  1383 		this.refreshContent();
       
  1384 	},
       
  1385 
       
  1386 	/**
       
  1387 	 * Reset the attachment display settings defaults to the site options.
       
  1388 	 *
       
  1389 	 * If site options don't define them, fall back to a persistent user setting.
       
  1390 	 *
       
  1391 	 * @since 3.5.0
       
  1392 	 */
       
  1393 	resetDisplays: function() {
       
  1394 		var defaultProps = wp.media.view.settings.defaultProps;
       
  1395 		this._displays = [];
       
  1396 		this._defaultDisplaySettings = {
       
  1397 			align: getUserSetting( 'align', defaultProps.align ) || 'none',
       
  1398 			size:  getUserSetting( 'imgsize', defaultProps.size ) || 'medium',
       
  1399 			link:  getUserSetting( 'urlbutton', defaultProps.link ) || 'none'
       
  1400 		};
       
  1401 	},
       
  1402 
       
  1403 	/**
       
  1404 	 * Create a model to represent display settings (alignment, etc.) for an attachment.
       
  1405 	 *
       
  1406 	 * @since 3.5.0
       
  1407 	 *
       
  1408 	 * @param {wp.media.model.Attachment} attachment
       
  1409 	 * @return {Backbone.Model}
       
  1410 	 */
       
  1411 	display: function( attachment ) {
       
  1412 		var displays = this._displays;
       
  1413 
       
  1414 		if ( ! displays[ attachment.cid ] ) {
       
  1415 			displays[ attachment.cid ] = new Backbone.Model( this.defaultDisplaySettings( attachment ) );
       
  1416 		}
       
  1417 		return displays[ attachment.cid ];
       
  1418 	},
       
  1419 
       
  1420 	/**
       
  1421 	 * Given an attachment, create attachment display settings properties.
       
  1422 	 *
       
  1423 	 * @since 3.6.0
       
  1424 	 *
       
  1425 	 * @param {wp.media.model.Attachment} attachment
       
  1426 	 * @return {Object}
       
  1427 	 */
       
  1428 	defaultDisplaySettings: function( attachment ) {
       
  1429 		var settings = _.clone( this._defaultDisplaySettings );
       
  1430 
       
  1431 		settings.canEmbed = this.canEmbed( attachment );
       
  1432 		if ( settings.canEmbed ) {
       
  1433 			settings.link = 'embed';
       
  1434 		} else if ( ! this.isImageAttachment( attachment ) && settings.link === 'none' ) {
       
  1435 			settings.link = 'file';
       
  1436 		}
       
  1437 
       
  1438 		return settings;
       
  1439 	},
       
  1440 
       
  1441 	/**
       
  1442 	 * Whether an attachment is image.
       
  1443 	 *
       
  1444 	 * @since 4.4.1
       
  1445 	 *
       
  1446 	 * @param {wp.media.model.Attachment} attachment
       
  1447 	 * @return {boolean}
       
  1448 	 */
       
  1449 	isImageAttachment: function( attachment ) {
       
  1450 		// If uploading, we know the filename but not the mime type.
       
  1451 		if ( attachment.get('uploading') ) {
       
  1452 			return /\.(jpe?g|png|gif|webp|avif)$/i.test( attachment.get('filename') );
       
  1453 		}
       
  1454 
       
  1455 		return attachment.get('type') === 'image';
       
  1456 	},
       
  1457 
       
  1458 	/**
       
  1459 	 * Whether an attachment can be embedded (audio or video).
       
  1460 	 *
       
  1461 	 * @since 3.6.0
       
  1462 	 *
       
  1463 	 * @param {wp.media.model.Attachment} attachment
       
  1464 	 * @return {boolean}
       
  1465 	 */
       
  1466 	canEmbed: function( attachment ) {
       
  1467 		// If uploading, we know the filename but not the mime type.
       
  1468 		if ( ! attachment.get('uploading') ) {
       
  1469 			var type = attachment.get('type');
       
  1470 			if ( type !== 'audio' && type !== 'video' ) {
       
  1471 				return false;
       
  1472 			}
       
  1473 		}
       
  1474 
       
  1475 		return _.contains( wp.media.view.settings.embedExts, attachment.get('filename').split('.').pop() );
       
  1476 	},
       
  1477 
       
  1478 
       
  1479 	/**
       
  1480 	 * If the state is active, no items are selected, and the current
       
  1481 	 * content mode is not an option in the state's router (provided
       
  1482 	 * the state has a router), reset the content mode to the default.
       
  1483 	 *
       
  1484 	 * @since 3.5.0
       
  1485 	 */
       
  1486 	refreshContent: function() {
       
  1487 		var selection = this.get('selection'),
       
  1488 			frame = this.frame,
       
  1489 			router = frame.router.get(),
       
  1490 			mode = frame.content.mode();
       
  1491 
       
  1492 		if ( this.active && ! selection.length && router && ! router.get( mode ) ) {
       
  1493 			this.frame.content.render( this.get('content') );
       
  1494 		}
       
  1495 	},
       
  1496 
       
  1497 	/**
       
  1498 	 * Callback handler when an attachment is uploaded.
       
  1499 	 *
       
  1500 	 * Switch to the Media Library if uploaded from the 'Upload Files' tab.
       
  1501 	 *
       
  1502 	 * Adds any uploading attachments to the selection.
       
  1503 	 *
       
  1504 	 * If the state only supports one attachment to be selected and multiple
       
  1505 	 * attachments are uploaded, the last attachment in the upload queue will
       
  1506 	 * be selected.
       
  1507 	 *
       
  1508 	 * @since 3.5.0
       
  1509 	 *
       
  1510 	 * @param {wp.media.model.Attachment} attachment
       
  1511 	 */
       
  1512 	uploading: function( attachment ) {
       
  1513 		var content = this.frame.content;
       
  1514 
       
  1515 		if ( 'upload' === content.mode() ) {
       
  1516 			this.frame.content.mode('browse');
       
  1517 		}
       
  1518 
       
  1519 		if ( this.get( 'autoSelect' ) ) {
       
  1520 			this.get('selection').add( attachment );
       
  1521 			this.frame.trigger( 'library:selection:add' );
       
  1522 		}
       
  1523 	},
       
  1524 
       
  1525 	/**
       
  1526 	 * Persist the mode of the content region as a user setting.
       
  1527 	 *
       
  1528 	 * @since 3.5.0
       
  1529 	 */
       
  1530 	saveContentMode: function() {
       
  1531 		if ( 'browse' !== this.get('router') ) {
       
  1532 			return;
       
  1533 		}
       
  1534 
       
  1535 		var mode = this.frame.content.mode(),
       
  1536 			view = this.frame.router.get();
       
  1537 
       
  1538 		if ( view && view.get( mode ) ) {
       
  1539 			setUserSetting( 'libraryContent', mode );
       
  1540 		}
       
  1541 	}
       
  1542 
       
  1543 });
       
  1544 
       
  1545 // Make selectionSync available on any Media Library state.
       
  1546 _.extend( Library.prototype, wp.media.selectionSync );
       
  1547 
       
  1548 module.exports = Library;
       
  1549 
       
  1550 
       
  1551 /***/ }),
       
  1552 
       
  1553 /***/ 8065:
       
  1554 /***/ ((module) => {
       
  1555 
       
  1556 /**
       
  1557  * wp.media.controller.MediaLibrary
       
  1558  *
       
  1559  * @memberOf wp.media.controller
       
  1560  *
       
  1561  * @class
       
  1562  * @augments wp.media.controller.Library
       
  1563  * @augments wp.media.controller.State
       
  1564  * @augments Backbone.Model
       
  1565  */
       
  1566 var Library = wp.media.controller.Library,
       
  1567 	MediaLibrary;
       
  1568 
       
  1569 MediaLibrary = Library.extend(/** @lends wp.media.controller.MediaLibrary.prototype */{
       
  1570 	defaults: _.defaults({
       
  1571 		// Attachments browser defaults. @see media.view.AttachmentsBrowser
       
  1572 		filterable:      'uploaded',
       
  1573 
       
  1574 		displaySettings: false,
       
  1575 		priority:        80,
       
  1576 		syncSelection:   false
       
  1577 	}, Library.prototype.defaults ),
       
  1578 
       
  1579 	/**
       
  1580 	 * @since 3.9.0
       
  1581 	 *
       
  1582 	 * @param options
       
  1583 	 */
       
  1584 	initialize: function( options ) {
       
  1585 		this.media = options.media;
       
  1586 		this.type = options.type;
       
  1587 		this.set( 'library', wp.media.query({ type: this.type }) );
       
  1588 
       
  1589 		Library.prototype.initialize.apply( this, arguments );
       
  1590 	},
       
  1591 
       
  1592 	/**
       
  1593 	 * @since 3.9.0
       
  1594 	 */
       
  1595 	activate: function() {
       
  1596 		// @todo this should use this.frame.
       
  1597 		if ( wp.media.frame.lastMime ) {
       
  1598 			this.set( 'library', wp.media.query({ type: wp.media.frame.lastMime }) );
       
  1599 			delete wp.media.frame.lastMime;
       
  1600 		}
       
  1601 		Library.prototype.activate.apply( this, arguments );
       
  1602 	}
       
  1603 });
       
  1604 
       
  1605 module.exports = MediaLibrary;
       
  1606 
       
  1607 
       
  1608 /***/ }),
       
  1609 
       
  1610 /***/ 9875:
       
  1611 /***/ ((module) => {
       
  1612 
       
  1613 /**
       
  1614  * wp.media.controller.Region
       
  1615  *
       
  1616  * A region is a persistent application layout area.
       
  1617  *
       
  1618  * A region assumes one mode at any time, and can be switched to another.
       
  1619  *
       
  1620  * When mode changes, events are triggered on the region's parent view.
       
  1621  * The parent view will listen to specific events and fill the region with an
       
  1622  * appropriate view depending on mode. For example, a frame listens for the
       
  1623  * 'browse' mode t be activated on the 'content' view and then fills the region
       
  1624  * with an AttachmentsBrowser view.
       
  1625  *
       
  1626  * @memberOf wp.media.controller
       
  1627  *
       
  1628  * @class
       
  1629  *
       
  1630  * @param {Object}        options          Options hash for the region.
       
  1631  * @param {string}        options.id       Unique identifier for the region.
       
  1632  * @param {Backbone.View} options.view     A parent view the region exists within.
       
  1633  * @param {string}        options.selector jQuery selector for the region within the parent view.
       
  1634  */
       
  1635 var Region = function( options ) {
       
  1636 	_.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
       
  1637 };
       
  1638 
       
  1639 // Use Backbone's self-propagating `extend` inheritance method.
       
  1640 Region.extend = Backbone.Model.extend;
       
  1641 
       
  1642 _.extend( Region.prototype,/** @lends wp.media.controller.Region.prototype */{
       
  1643 	/**
       
  1644 	 * Activate a mode.
       
  1645 	 *
       
  1646 	 * @since 3.5.0
       
  1647 	 *
       
  1648 	 * @param {string} mode
       
  1649 	 *
       
  1650 	 * @fires Region#activate
       
  1651 	 * @fires Region#deactivate
       
  1652 	 *
       
  1653 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
       
  1654 	 */
       
  1655 	mode: function( mode ) {
       
  1656 		if ( ! mode ) {
       
  1657 			return this._mode;
       
  1658 		}
       
  1659 		// Bail if we're trying to change to the current mode.
       
  1660 		if ( mode === this._mode ) {
       
  1661 			return this;
       
  1662 		}
       
  1663 
       
  1664 		/**
       
  1665 		 * Region mode deactivation event.
       
  1666 		 *
       
  1667 		 * @event wp.media.controller.Region#deactivate
       
  1668 		 */
       
  1669 		this.trigger('deactivate');
       
  1670 
       
  1671 		this._mode = mode;
       
  1672 		this.render( mode );
       
  1673 
       
  1674 		/**
       
  1675 		 * Region mode activation event.
       
  1676 		 *
       
  1677 		 * @event wp.media.controller.Region#activate
       
  1678 		 */
       
  1679 		this.trigger('activate');
       
  1680 		return this;
       
  1681 	},
       
  1682 	/**
       
  1683 	 * Render a mode.
       
  1684 	 *
       
  1685 	 * @since 3.5.0
       
  1686 	 *
       
  1687 	 * @param {string} mode
       
  1688 	 *
       
  1689 	 * @fires Region#create
       
  1690 	 * @fires Region#render
       
  1691 	 *
       
  1692 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
       
  1693 	 */
       
  1694 	render: function( mode ) {
       
  1695 		// If the mode isn't active, activate it.
       
  1696 		if ( mode && mode !== this._mode ) {
       
  1697 			return this.mode( mode );
       
  1698 		}
       
  1699 
       
  1700 		var set = { view: null },
       
  1701 			view;
       
  1702 
       
  1703 		/**
       
  1704 		 * Create region view event.
       
  1705 		 *
       
  1706 		 * Region view creation takes place in an event callback on the frame.
       
  1707 		 *
       
  1708 		 * @event wp.media.controller.Region#create
       
  1709 		 * @type {object}
       
  1710 		 * @property {object} view
       
  1711 		 */
       
  1712 		this.trigger( 'create', set );
       
  1713 		view = set.view;
       
  1714 
       
  1715 		/**
       
  1716 		 * Render region view event.
       
  1717 		 *
       
  1718 		 * Region view creation takes place in an event callback on the frame.
       
  1719 		 *
       
  1720 		 * @event wp.media.controller.Region#render
       
  1721 		 * @type {object}
       
  1722 		 */
       
  1723 		this.trigger( 'render', view );
       
  1724 		if ( view ) {
       
  1725 			this.set( view );
       
  1726 		}
       
  1727 		return this;
       
  1728 	},
       
  1729 
       
  1730 	/**
       
  1731 	 * Get the region's view.
       
  1732 	 *
       
  1733 	 * @since 3.5.0
       
  1734 	 *
       
  1735 	 * @return {wp.media.View}
       
  1736 	 */
       
  1737 	get: function() {
       
  1738 		return this.view.views.first( this.selector );
       
  1739 	},
       
  1740 
       
  1741 	/**
       
  1742 	 * Set the region's view as a subview of the frame.
       
  1743 	 *
       
  1744 	 * @since 3.5.0
       
  1745 	 *
       
  1746 	 * @param {Array|Object} views
       
  1747 	 * @param {Object} [options={}]
       
  1748 	 * @return {wp.Backbone.Subviews} Subviews is returned to allow chaining.
       
  1749 	 */
       
  1750 	set: function( views, options ) {
       
  1751 		if ( options ) {
       
  1752 			options.add = false;
       
  1753 		}
       
  1754 		return this.view.views.set( this.selector, views, options );
       
  1755 	},
       
  1756 
       
  1757 	/**
       
  1758 	 * Trigger regional view events on the frame.
       
  1759 	 *
       
  1760 	 * @since 3.5.0
       
  1761 	 *
       
  1762 	 * @param {string} event
       
  1763 	 * @return {undefined|wp.media.controller.Region} Returns itself to allow chaining.
       
  1764 	 */
       
  1765 	trigger: function( event ) {
       
  1766 		var base, args;
       
  1767 
       
  1768 		if ( ! this._mode ) {
       
  1769 			return;
       
  1770 		}
       
  1771 
       
  1772 		args = _.toArray( arguments );
       
  1773 		base = this.id + ':' + event;
       
  1774 
       
  1775 		// Trigger `{this.id}:{event}:{this._mode}` event on the frame.
       
  1776 		args[0] = base + ':' + this._mode;
       
  1777 		this.view.trigger.apply( this.view, args );
       
  1778 
       
  1779 		// Trigger `{this.id}:{event}` event on the frame.
       
  1780 		args[0] = base;
       
  1781 		this.view.trigger.apply( this.view, args );
       
  1782 		return this;
       
  1783 	}
       
  1784 });
       
  1785 
       
  1786 module.exports = Region;
       
  1787 
  2306 
  1788 
  2307 
  1789 /***/ }),
  2308 /***/ }),
  1790 
  2309 
  1791 /***/ 2275:
  2310 /***/ 2275:
  1911 module.exports = ReplaceImage;
  2430 module.exports = ReplaceImage;
  1912 
  2431 
  1913 
  2432 
  1914 /***/ }),
  2433 /***/ }),
  1915 
  2434 
  1916 /***/ 6172:
  2435 /***/ 2356:
  1917 /***/ ((module) => {
  2436 /***/ ((module) => {
  1918 
  2437 
  1919 var Controller = wp.media.controller,
       
  1920 	SiteIconCropper;
       
  1921 
       
  1922 /**
  2438 /**
  1923  * wp.media.controller.SiteIconCropper
  2439  * wp.media.view.Settings.Playlist
  1924  *
  2440  *
  1925  * A state for cropping a Site Icon.
  2441  * @memberOf wp.media.view.Settings
       
  2442  *
       
  2443  * @class
       
  2444  * @augments wp.media.view.Settings
       
  2445  * @augments wp.media.View
       
  2446  * @augments wp.Backbone.View
       
  2447  * @augments Backbone.View
       
  2448  */
       
  2449 var Playlist = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Playlist.prototype */{
       
  2450 	className: 'collection-settings playlist-settings',
       
  2451 	template:  wp.template('playlist-settings')
       
  2452 });
       
  2453 
       
  2454 module.exports = Playlist;
       
  2455 
       
  2456 
       
  2457 /***/ }),
       
  2458 
       
  2459 /***/ 2395:
       
  2460 /***/ ((module) => {
       
  2461 
       
  2462 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
       
  2463 	EmbedImage;
       
  2464 
       
  2465 /**
       
  2466  * wp.media.view.EmbedImage
       
  2467  *
       
  2468  * @memberOf wp.media.view
       
  2469  *
       
  2470  * @class
       
  2471  * @augments wp.media.view.Settings.AttachmentDisplay
       
  2472  * @augments wp.media.view.Settings
       
  2473  * @augments wp.media.View
       
  2474  * @augments wp.Backbone.View
       
  2475  * @augments Backbone.View
       
  2476  */
       
  2477 EmbedImage = AttachmentDisplay.extend(/** @lends wp.media.view.EmbedImage.prototype */{
       
  2478 	className: 'embed-media-settings',
       
  2479 	template:  wp.template('embed-image-settings'),
       
  2480 
       
  2481 	initialize: function() {
       
  2482 		/**
       
  2483 		 * Call `initialize` directly on parent class with passed arguments
       
  2484 		 */
       
  2485 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
       
  2486 		this.listenTo( this.model, 'change:url', this.updateImage );
       
  2487 	},
       
  2488 
       
  2489 	updateImage: function() {
       
  2490 		this.$('img').attr( 'src', this.model.get('url') );
       
  2491 	}
       
  2492 });
       
  2493 
       
  2494 module.exports = EmbedImage;
       
  2495 
       
  2496 
       
  2497 /***/ }),
       
  2498 
       
  2499 /***/ 2621:
       
  2500 /***/ ((module) => {
       
  2501 
       
  2502 var $ = jQuery,
       
  2503 	Modal;
       
  2504 
       
  2505 /**
       
  2506  * wp.media.view.Modal
       
  2507  *
       
  2508  * A modal view, which the media modal uses as its default container.
       
  2509  *
       
  2510  * @memberOf wp.media.view
       
  2511  *
       
  2512  * @class
       
  2513  * @augments wp.media.View
       
  2514  * @augments wp.Backbone.View
       
  2515  * @augments Backbone.View
       
  2516  */
       
  2517 Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
       
  2518 	tagName:  'div',
       
  2519 	template: wp.template('media-modal'),
       
  2520 
       
  2521 	events: {
       
  2522 		'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
       
  2523 		'keydown': 'keydown'
       
  2524 	},
       
  2525 
       
  2526 	clickedOpenerEl: null,
       
  2527 
       
  2528 	initialize: function() {
       
  2529 		_.defaults( this.options, {
       
  2530 			container:      document.body,
       
  2531 			title:          '',
       
  2532 			propagate:      true,
       
  2533 			hasCloseButton: true
       
  2534 		});
       
  2535 
       
  2536 		this.focusManager = new wp.media.view.FocusManager({
       
  2537 			el: this.el
       
  2538 		});
       
  2539 	},
       
  2540 	/**
       
  2541 	 * @return {Object}
       
  2542 	 */
       
  2543 	prepare: function() {
       
  2544 		return {
       
  2545 			title:          this.options.title,
       
  2546 			hasCloseButton: this.options.hasCloseButton
       
  2547 		};
       
  2548 	},
       
  2549 
       
  2550 	/**
       
  2551 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  2552 	 */
       
  2553 	attach: function() {
       
  2554 		if ( this.views.attached ) {
       
  2555 			return this;
       
  2556 		}
       
  2557 
       
  2558 		if ( ! this.views.rendered ) {
       
  2559 			this.render();
       
  2560 		}
       
  2561 
       
  2562 		this.$el.appendTo( this.options.container );
       
  2563 
       
  2564 		// Manually mark the view as attached and trigger ready.
       
  2565 		this.views.attached = true;
       
  2566 		this.views.ready();
       
  2567 
       
  2568 		return this.propagate('attach');
       
  2569 	},
       
  2570 
       
  2571 	/**
       
  2572 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  2573 	 */
       
  2574 	detach: function() {
       
  2575 		if ( this.$el.is(':visible') ) {
       
  2576 			this.close();
       
  2577 		}
       
  2578 
       
  2579 		this.$el.detach();
       
  2580 		this.views.attached = false;
       
  2581 		return this.propagate('detach');
       
  2582 	},
       
  2583 
       
  2584 	/**
       
  2585 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  2586 	 */
       
  2587 	open: function() {
       
  2588 		var $el = this.$el,
       
  2589 			mceEditor;
       
  2590 
       
  2591 		if ( $el.is(':visible') ) {
       
  2592 			return this;
       
  2593 		}
       
  2594 
       
  2595 		this.clickedOpenerEl = document.activeElement;
       
  2596 
       
  2597 		if ( ! this.views.attached ) {
       
  2598 			this.attach();
       
  2599 		}
       
  2600 
       
  2601 		// Disable page scrolling.
       
  2602 		$( 'body' ).addClass( 'modal-open' );
       
  2603 
       
  2604 		$el.show();
       
  2605 
       
  2606 		// Try to close the onscreen keyboard.
       
  2607 		if ( 'ontouchend' in document ) {
       
  2608 			if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor ) && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
       
  2609 				mceEditor.iframeElement.focus();
       
  2610 				mceEditor.iframeElement.blur();
       
  2611 
       
  2612 				setTimeout( function() {
       
  2613 					mceEditor.iframeElement.blur();
       
  2614 				}, 100 );
       
  2615 			}
       
  2616 		}
       
  2617 
       
  2618 		// Set initial focus on the content instead of this view element, to avoid page scrolling.
       
  2619 		this.$( '.media-modal' ).trigger( 'focus' );
       
  2620 
       
  2621 		// Hide the page content from assistive technologies.
       
  2622 		this.focusManager.setAriaHiddenOnBodyChildren( $el );
       
  2623 
       
  2624 		return this.propagate('open');
       
  2625 	},
       
  2626 
       
  2627 	/**
       
  2628 	 * @param {Object} options
       
  2629 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  2630 	 */
       
  2631 	close: function( options ) {
       
  2632 		if ( ! this.views.attached || ! this.$el.is(':visible') ) {
       
  2633 			return this;
       
  2634 		}
       
  2635 
       
  2636 		// Pause current audio/video even after closing the modal.
       
  2637 		$( '.mejs-pause button' ).trigger( 'click' );
       
  2638 
       
  2639 		// Enable page scrolling.
       
  2640 		$( 'body' ).removeClass( 'modal-open' );
       
  2641 
       
  2642 		// Hide the modal element by adding display:none.
       
  2643 		this.$el.hide();
       
  2644 
       
  2645 		/*
       
  2646 		 * Make visible again to assistive technologies all body children that
       
  2647 		 * have been made hidden when the modal opened.
       
  2648 		 */
       
  2649 		this.focusManager.removeAriaHiddenFromBodyChildren();
       
  2650 
       
  2651 		// Move focus back in useful location once modal is closed.
       
  2652 		if ( null !== this.clickedOpenerEl ) {
       
  2653 			// Move focus back to the element that opened the modal.
       
  2654 			this.clickedOpenerEl.focus();
       
  2655 		} else {
       
  2656 			// Fallback to the admin page main element.
       
  2657 			$( '#wpbody-content' )
       
  2658 				.attr( 'tabindex', '-1' )
       
  2659 				.trigger( 'focus' );
       
  2660 		}
       
  2661 
       
  2662 		this.propagate('close');
       
  2663 
       
  2664 		if ( options && options.escape ) {
       
  2665 			this.propagate('escape');
       
  2666 		}
       
  2667 
       
  2668 		return this;
       
  2669 	},
       
  2670 	/**
       
  2671 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  2672 	 */
       
  2673 	escape: function() {
       
  2674 		return this.close({ escape: true });
       
  2675 	},
       
  2676 	/**
       
  2677 	 * @param {Object} event
       
  2678 	 */
       
  2679 	escapeHandler: function( event ) {
       
  2680 		event.preventDefault();
       
  2681 		this.escape();
       
  2682 	},
       
  2683 
       
  2684 	/**
       
  2685 	 * Handles the selection of attachments when the command or control key is pressed with the enter key.
       
  2686 	 *
       
  2687 	 * @since 6.7
       
  2688 	 *
       
  2689 	 * @param {Object} event The keydown event object.
       
  2690 	 */
       
  2691 	selectHandler: function( event ) {
       
  2692 		var selection = this.controller.state().get( 'selection' );
       
  2693 
       
  2694 		if ( selection.length <= 0 ) {
       
  2695 			return;
       
  2696 		}
       
  2697 
       
  2698 		if ( 'insert' === this.controller.options.state ) {
       
  2699 			this.controller.trigger( 'insert', selection );
       
  2700 		} else {
       
  2701 			this.controller.trigger( 'select', selection );
       
  2702 			event.preventDefault();
       
  2703 			this.escape();
       
  2704 		}
       
  2705 	},
       
  2706 
       
  2707 	/**
       
  2708 	 * @param {Array|Object} content Views to register to '.media-modal-content'
       
  2709 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  2710 	 */
       
  2711 	content: function( content ) {
       
  2712 		this.views.set( '.media-modal-content', content );
       
  2713 		return this;
       
  2714 	},
       
  2715 
       
  2716 	/**
       
  2717 	 * Triggers a modal event and if the `propagate` option is set,
       
  2718 	 * forwards events to the modal's controller.
       
  2719 	 *
       
  2720 	 * @param {string} id
       
  2721 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  2722 	 */
       
  2723 	propagate: function( id ) {
       
  2724 		this.trigger( id );
       
  2725 
       
  2726 		if ( this.options.propagate ) {
       
  2727 			this.controller.trigger( id );
       
  2728 		}
       
  2729 
       
  2730 		return this;
       
  2731 	},
       
  2732 	/**
       
  2733 	 * @param {Object} event
       
  2734 	 */
       
  2735 	keydown: function( event ) {
       
  2736 		// Close the modal when escape is pressed.
       
  2737 		if ( 27 === event.which && this.$el.is(':visible') ) {
       
  2738 			this.escape();
       
  2739 			event.stopImmediatePropagation();
       
  2740 		}
       
  2741 
       
  2742 		// Select the attachment when command or control and enter are pressed.
       
  2743 		if ( ( 13 === event.which || 10 === event.which ) && ( event.metaKey || event.ctrlKey ) ) {
       
  2744 			this.selectHandler( event );
       
  2745 			event.stopImmediatePropagation();
       
  2746 		}
       
  2747 
       
  2748 	}
       
  2749 });
       
  2750 
       
  2751 module.exports = Modal;
       
  2752 
       
  2753 
       
  2754 /***/ }),
       
  2755 
       
  2756 /***/ 2650:
       
  2757 /***/ ((module) => {
       
  2758 
       
  2759 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
       
  2760 	$ = jQuery,
       
  2761 	ImageDetails;
       
  2762 
       
  2763 /**
       
  2764  * wp.media.view.ImageDetails
       
  2765  *
       
  2766  * @memberOf wp.media.view
       
  2767  *
       
  2768  * @class
       
  2769  * @augments wp.media.view.Settings.AttachmentDisplay
       
  2770  * @augments wp.media.view.Settings
       
  2771  * @augments wp.media.View
       
  2772  * @augments wp.Backbone.View
       
  2773  * @augments Backbone.View
       
  2774  */
       
  2775 ImageDetails = AttachmentDisplay.extend(/** @lends wp.media.view.ImageDetails.prototype */{
       
  2776 	className: 'image-details',
       
  2777 	template:  wp.template('image-details'),
       
  2778 	events: _.defaults( AttachmentDisplay.prototype.events, {
       
  2779 		'click .edit-attachment': 'editAttachment',
       
  2780 		'click .replace-attachment': 'replaceAttachment',
       
  2781 		'click .advanced-toggle': 'onToggleAdvanced',
       
  2782 		'change [data-setting="customWidth"]': 'onCustomSize',
       
  2783 		'change [data-setting="customHeight"]': 'onCustomSize',
       
  2784 		'keyup [data-setting="customWidth"]': 'onCustomSize',
       
  2785 		'keyup [data-setting="customHeight"]': 'onCustomSize'
       
  2786 	} ),
       
  2787 	initialize: function() {
       
  2788 		// Used in AttachmentDisplay.prototype.updateLinkTo.
       
  2789 		this.options.attachment = this.model.attachment;
       
  2790 		this.listenTo( this.model, 'change:url', this.updateUrl );
       
  2791 		this.listenTo( this.model, 'change:link', this.toggleLinkSettings );
       
  2792 		this.listenTo( this.model, 'change:size', this.toggleCustomSize );
       
  2793 
       
  2794 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
       
  2795 	},
       
  2796 
       
  2797 	prepare: function() {
       
  2798 		var attachment = false;
       
  2799 
       
  2800 		if ( this.model.attachment ) {
       
  2801 			attachment = this.model.attachment.toJSON();
       
  2802 		}
       
  2803 		return _.defaults({
       
  2804 			model: this.model.toJSON(),
       
  2805 			attachment: attachment
       
  2806 		}, this.options );
       
  2807 	},
       
  2808 
       
  2809 	render: function() {
       
  2810 		var args = arguments;
       
  2811 
       
  2812 		if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
       
  2813 			this.model.dfd
       
  2814 				.done( _.bind( function() {
       
  2815 					AttachmentDisplay.prototype.render.apply( this, args );
       
  2816 					this.postRender();
       
  2817 				}, this ) )
       
  2818 				.fail( _.bind( function() {
       
  2819 					this.model.attachment = false;
       
  2820 					AttachmentDisplay.prototype.render.apply( this, args );
       
  2821 					this.postRender();
       
  2822 				}, this ) );
       
  2823 		} else {
       
  2824 			AttachmentDisplay.prototype.render.apply( this, arguments );
       
  2825 			this.postRender();
       
  2826 		}
       
  2827 
       
  2828 		return this;
       
  2829 	},
       
  2830 
       
  2831 	postRender: function() {
       
  2832 		setTimeout( _.bind( this.scrollToTop, this ), 10 );
       
  2833 		this.toggleLinkSettings();
       
  2834 		if ( window.getUserSetting( 'advImgDetails' ) === 'show' ) {
       
  2835 			this.toggleAdvanced( true );
       
  2836 		}
       
  2837 		this.trigger( 'post-render' );
       
  2838 	},
       
  2839 
       
  2840 	scrollToTop: function() {
       
  2841 		this.$( '.embed-media-settings' ).scrollTop( 0 );
       
  2842 	},
       
  2843 
       
  2844 	updateUrl: function() {
       
  2845 		this.$( '.image img' ).attr( 'src', this.model.get( 'url' ) );
       
  2846 		this.$( '.url' ).val( this.model.get( 'url' ) );
       
  2847 	},
       
  2848 
       
  2849 	toggleLinkSettings: function() {
       
  2850 		if ( this.model.get( 'link' ) === 'none' ) {
       
  2851 			this.$( '.link-settings' ).addClass('hidden');
       
  2852 		} else {
       
  2853 			this.$( '.link-settings' ).removeClass('hidden');
       
  2854 		}
       
  2855 	},
       
  2856 
       
  2857 	toggleCustomSize: function() {
       
  2858 		if ( this.model.get( 'size' ) !== 'custom' ) {
       
  2859 			this.$( '.custom-size' ).addClass('hidden');
       
  2860 		} else {
       
  2861 			this.$( '.custom-size' ).removeClass('hidden');
       
  2862 		}
       
  2863 	},
       
  2864 
       
  2865 	onCustomSize: function( event ) {
       
  2866 		var dimension = $( event.target ).data('setting'),
       
  2867 			num = $( event.target ).val(),
       
  2868 			value;
       
  2869 
       
  2870 		// Ignore bogus input.
       
  2871 		if ( ! /^\d+/.test( num ) || parseInt( num, 10 ) < 1 ) {
       
  2872 			event.preventDefault();
       
  2873 			return;
       
  2874 		}
       
  2875 
       
  2876 		if ( dimension === 'customWidth' ) {
       
  2877 			value = Math.round( 1 / this.model.get( 'aspectRatio' ) * num );
       
  2878 			this.model.set( 'customHeight', value, { silent: true } );
       
  2879 			this.$( '[data-setting="customHeight"]' ).val( value );
       
  2880 		} else {
       
  2881 			value = Math.round( this.model.get( 'aspectRatio' ) * num );
       
  2882 			this.model.set( 'customWidth', value, { silent: true  } );
       
  2883 			this.$( '[data-setting="customWidth"]' ).val( value );
       
  2884 		}
       
  2885 	},
       
  2886 
       
  2887 	onToggleAdvanced: function( event ) {
       
  2888 		event.preventDefault();
       
  2889 		this.toggleAdvanced();
       
  2890 	},
       
  2891 
       
  2892 	toggleAdvanced: function( show ) {
       
  2893 		var $advanced = this.$el.find( '.advanced-section' ),
       
  2894 			mode;
       
  2895 
       
  2896 		if ( $advanced.hasClass('advanced-visible') || show === false ) {
       
  2897 			$advanced.removeClass('advanced-visible');
       
  2898 			$advanced.find('.advanced-settings').addClass('hidden');
       
  2899 			mode = 'hide';
       
  2900 		} else {
       
  2901 			$advanced.addClass('advanced-visible');
       
  2902 			$advanced.find('.advanced-settings').removeClass('hidden');
       
  2903 			mode = 'show';
       
  2904 		}
       
  2905 
       
  2906 		window.setUserSetting( 'advImgDetails', mode );
       
  2907 	},
       
  2908 
       
  2909 	editAttachment: function( event ) {
       
  2910 		var editState = this.controller.states.get( 'edit-image' );
       
  2911 
       
  2912 		if ( window.imageEdit && editState ) {
       
  2913 			event.preventDefault();
       
  2914 			editState.set( 'image', this.model.attachment );
       
  2915 			this.controller.setState( 'edit-image' );
       
  2916 		}
       
  2917 	},
       
  2918 
       
  2919 	replaceAttachment: function( event ) {
       
  2920 		event.preventDefault();
       
  2921 		this.controller.setState( 'replace-image' );
       
  2922 	}
       
  2923 });
       
  2924 
       
  2925 module.exports = ImageDetails;
       
  2926 
       
  2927 
       
  2928 /***/ }),
       
  2929 
       
  2930 /***/ 2836:
       
  2931 /***/ ((module) => {
       
  2932 
       
  2933 var Frame = wp.media.view.Frame,
       
  2934 	l10n = wp.media.view.l10n,
       
  2935 	$ = jQuery,
       
  2936 	MediaFrame;
       
  2937 
       
  2938 /**
       
  2939  * wp.media.view.MediaFrame
       
  2940  *
       
  2941  * The frame used to create the media modal.
       
  2942  *
       
  2943  * @memberOf wp.media.view
       
  2944  *
       
  2945  * @class
       
  2946  * @augments wp.media.view.Frame
       
  2947  * @augments wp.media.View
       
  2948  * @augments wp.Backbone.View
       
  2949  * @augments Backbone.View
       
  2950  * @mixes wp.media.controller.StateMachine
       
  2951  */
       
  2952 MediaFrame = Frame.extend(/** @lends wp.media.view.MediaFrame.prototype */{
       
  2953 	className: 'media-frame',
       
  2954 	template:  wp.template('media-frame'),
       
  2955 	regions:   ['menu','title','content','toolbar','router'],
       
  2956 
       
  2957 	events: {
       
  2958 		'click .media-frame-menu-toggle': 'toggleMenu'
       
  2959 	},
       
  2960 
       
  2961 	/**
       
  2962 	 * @constructs
       
  2963 	 */
       
  2964 	initialize: function() {
       
  2965 		Frame.prototype.initialize.apply( this, arguments );
       
  2966 
       
  2967 		_.defaults( this.options, {
       
  2968 			title:    l10n.mediaFrameDefaultTitle,
       
  2969 			modal:    true,
       
  2970 			uploader: true
       
  2971 		});
       
  2972 
       
  2973 		// Ensure core UI is enabled.
       
  2974 		this.$el.addClass('wp-core-ui');
       
  2975 
       
  2976 		// Initialize modal container view.
       
  2977 		if ( this.options.modal ) {
       
  2978 			this.modal = new wp.media.view.Modal({
       
  2979 				controller: this,
       
  2980 				title:      this.options.title
       
  2981 			});
       
  2982 
       
  2983 			this.modal.content( this );
       
  2984 		}
       
  2985 
       
  2986 		// Force the uploader off if the upload limit has been exceeded or
       
  2987 		// if the browser isn't supported.
       
  2988 		if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
       
  2989 			this.options.uploader = false;
       
  2990 		}
       
  2991 
       
  2992 		// Initialize window-wide uploader.
       
  2993 		if ( this.options.uploader ) {
       
  2994 			this.uploader = new wp.media.view.UploaderWindow({
       
  2995 				controller: this,
       
  2996 				uploader: {
       
  2997 					dropzone:  this.modal ? this.modal.$el : this.$el,
       
  2998 					container: this.$el
       
  2999 				}
       
  3000 			});
       
  3001 			this.views.set( '.media-frame-uploader', this.uploader );
       
  3002 		}
       
  3003 
       
  3004 		this.on( 'attach', _.bind( this.views.ready, this.views ), this );
       
  3005 
       
  3006 		// Bind default title creation.
       
  3007 		this.on( 'title:create:default', this.createTitle, this );
       
  3008 		this.title.mode('default');
       
  3009 
       
  3010 		// Bind default menu.
       
  3011 		this.on( 'menu:create:default', this.createMenu, this );
       
  3012 
       
  3013 		// Set the menu ARIA tab panel attributes when the modal opens.
       
  3014 		this.on( 'open', this.setMenuTabPanelAriaAttributes, this );
       
  3015 		// Set the router ARIA tab panel attributes when the modal opens.
       
  3016 		this.on( 'open', this.setRouterTabPanelAriaAttributes, this );
       
  3017 
       
  3018 		// Update the menu ARIA tab panel attributes when the content updates.
       
  3019 		this.on( 'content:render', this.setMenuTabPanelAriaAttributes, this );
       
  3020 		// Update the router ARIA tab panel attributes when the content updates.
       
  3021 		this.on( 'content:render', this.setRouterTabPanelAriaAttributes, this );
       
  3022 	},
       
  3023 
       
  3024 	/**
       
  3025 	 * Sets the attributes to be used on the menu ARIA tab panel.
       
  3026 	 *
       
  3027 	 * @since 5.3.0
       
  3028 	 *
       
  3029 	 * @return {void}
       
  3030 	 */
       
  3031 	setMenuTabPanelAriaAttributes: function() {
       
  3032 		var stateId = this.state().get( 'id' ),
       
  3033 			tabPanelEl = this.$el.find( '.media-frame-tab-panel' ),
       
  3034 			ariaLabelledby;
       
  3035 
       
  3036 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
       
  3037 
       
  3038 		if ( this.state().get( 'menu' ) && this.menuView && this.menuView.isVisible ) {
       
  3039 			ariaLabelledby = 'menu-item-' + stateId;
       
  3040 
       
  3041 			// Set the tab panel attributes only if the tabs are visible.
       
  3042 			tabPanelEl
       
  3043 				.attr( {
       
  3044 					role: 'tabpanel',
       
  3045 					'aria-labelledby': ariaLabelledby,
       
  3046 					tabIndex: '0'
       
  3047 				} );
       
  3048 		}
       
  3049 	},
       
  3050 
       
  3051 	/**
       
  3052 	 * Sets the attributes to be used on the router ARIA tab panel.
       
  3053 	 *
       
  3054 	 * @since 5.3.0
       
  3055 	 *
       
  3056 	 * @return {void}
       
  3057 	 */
       
  3058 	setRouterTabPanelAriaAttributes: function() {
       
  3059 		var tabPanelEl = this.$el.find( '.media-frame-content' ),
       
  3060 			ariaLabelledby;
       
  3061 
       
  3062 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
       
  3063 
       
  3064 		// Set the tab panel attributes only if the tabs are visible.
       
  3065 		if ( this.state().get( 'router' ) && this.routerView && this.routerView.isVisible && this.content._mode ) {
       
  3066 			ariaLabelledby = 'menu-item-' + this.content._mode;
       
  3067 
       
  3068 			tabPanelEl
       
  3069 				.attr( {
       
  3070 					role: 'tabpanel',
       
  3071 					'aria-labelledby': ariaLabelledby,
       
  3072 					tabIndex: '0'
       
  3073 				} );
       
  3074 		}
       
  3075 	},
       
  3076 
       
  3077 	/**
       
  3078 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3079 	 */
       
  3080 	render: function() {
       
  3081 		// Activate the default state if no active state exists.
       
  3082 		if ( ! this.state() && this.options.state ) {
       
  3083 			this.setState( this.options.state );
       
  3084 		}
       
  3085 		/**
       
  3086 		 * call 'render' directly on the parent class
       
  3087 		 */
       
  3088 		return Frame.prototype.render.apply( this, arguments );
       
  3089 	},
       
  3090 	/**
       
  3091 	 * @param {Object} title
       
  3092 	 * @this wp.media.controller.Region
       
  3093 	 */
       
  3094 	createTitle: function( title ) {
       
  3095 		title.view = new wp.media.View({
       
  3096 			controller: this,
       
  3097 			tagName: 'h1'
       
  3098 		});
       
  3099 	},
       
  3100 	/**
       
  3101 	 * @param {Object} menu
       
  3102 	 * @this wp.media.controller.Region
       
  3103 	 */
       
  3104 	createMenu: function( menu ) {
       
  3105 		menu.view = new wp.media.view.Menu({
       
  3106 			controller: this,
       
  3107 
       
  3108 			attributes: {
       
  3109 				role:               'tablist',
       
  3110 				'aria-orientation': 'vertical'
       
  3111 			}
       
  3112 		});
       
  3113 
       
  3114 		this.menuView = menu.view;
       
  3115 	},
       
  3116 
       
  3117 	toggleMenu: function( event ) {
       
  3118 		var menu = this.$el.find( '.media-menu' );
       
  3119 
       
  3120 		menu.toggleClass( 'visible' );
       
  3121 		$( event.target ).attr( 'aria-expanded', menu.hasClass( 'visible' ) );
       
  3122 	},
       
  3123 
       
  3124 	/**
       
  3125 	 * @param {Object} toolbar
       
  3126 	 * @this wp.media.controller.Region
       
  3127 	 */
       
  3128 	createToolbar: function( toolbar ) {
       
  3129 		toolbar.view = new wp.media.view.Toolbar({
       
  3130 			controller: this
       
  3131 		});
       
  3132 	},
       
  3133 	/**
       
  3134 	 * @param {Object} router
       
  3135 	 * @this wp.media.controller.Region
       
  3136 	 */
       
  3137 	createRouter: function( router ) {
       
  3138 		router.view = new wp.media.view.Router({
       
  3139 			controller: this,
       
  3140 
       
  3141 			attributes: {
       
  3142 				role:               'tablist',
       
  3143 				'aria-orientation': 'horizontal'
       
  3144 			}
       
  3145 		});
       
  3146 
       
  3147 		this.routerView = router.view;
       
  3148 	},
       
  3149 	/**
       
  3150 	 * @param {Object} options
       
  3151 	 */
       
  3152 	createIframeStates: function( options ) {
       
  3153 		var settings = wp.media.view.settings,
       
  3154 			tabs = settings.tabs,
       
  3155 			tabUrl = settings.tabUrl,
       
  3156 			$postId;
       
  3157 
       
  3158 		if ( ! tabs || ! tabUrl ) {
       
  3159 			return;
       
  3160 		}
       
  3161 
       
  3162 		// Add the post ID to the tab URL if it exists.
       
  3163 		$postId = $('#post_ID');
       
  3164 		if ( $postId.length ) {
       
  3165 			tabUrl += '&post_id=' + $postId.val();
       
  3166 		}
       
  3167 
       
  3168 		// Generate the tab states.
       
  3169 		_.each( tabs, function( title, id ) {
       
  3170 			this.state( 'iframe:' + id ).set( _.defaults({
       
  3171 				tab:     id,
       
  3172 				src:     tabUrl + '&tab=' + id,
       
  3173 				title:   title,
       
  3174 				content: 'iframe',
       
  3175 				menu:    'default'
       
  3176 			}, options ) );
       
  3177 		}, this );
       
  3178 
       
  3179 		this.on( 'content:create:iframe', this.iframeContent, this );
       
  3180 		this.on( 'content:deactivate:iframe', this.iframeContentCleanup, this );
       
  3181 		this.on( 'menu:render:default', this.iframeMenu, this );
       
  3182 		this.on( 'open', this.hijackThickbox, this );
       
  3183 		this.on( 'close', this.restoreThickbox, this );
       
  3184 	},
       
  3185 
       
  3186 	/**
       
  3187 	 * @param {Object} content
       
  3188 	 * @this wp.media.controller.Region
       
  3189 	 */
       
  3190 	iframeContent: function( content ) {
       
  3191 		this.$el.addClass('hide-toolbar');
       
  3192 		content.view = new wp.media.view.Iframe({
       
  3193 			controller: this
       
  3194 		});
       
  3195 	},
       
  3196 
       
  3197 	iframeContentCleanup: function() {
       
  3198 		this.$el.removeClass('hide-toolbar');
       
  3199 	},
       
  3200 
       
  3201 	iframeMenu: function( view ) {
       
  3202 		var views = {};
       
  3203 
       
  3204 		if ( ! view ) {
       
  3205 			return;
       
  3206 		}
       
  3207 
       
  3208 		_.each( wp.media.view.settings.tabs, function( title, id ) {
       
  3209 			views[ 'iframe:' + id ] = {
       
  3210 				text: this.state( 'iframe:' + id ).get('title'),
       
  3211 				priority: 200
       
  3212 			};
       
  3213 		}, this );
       
  3214 
       
  3215 		view.set( views );
       
  3216 	},
       
  3217 
       
  3218 	hijackThickbox: function() {
       
  3219 		var frame = this;
       
  3220 
       
  3221 		if ( ! window.tb_remove || this._tb_remove ) {
       
  3222 			return;
       
  3223 		}
       
  3224 
       
  3225 		this._tb_remove = window.tb_remove;
       
  3226 		window.tb_remove = function() {
       
  3227 			frame.close();
       
  3228 			frame.reset();
       
  3229 			frame.setState( frame.options.state );
       
  3230 			frame._tb_remove.call( window );
       
  3231 		};
       
  3232 	},
       
  3233 
       
  3234 	restoreThickbox: function() {
       
  3235 		if ( ! this._tb_remove ) {
       
  3236 			return;
       
  3237 		}
       
  3238 
       
  3239 		window.tb_remove = this._tb_remove;
       
  3240 		delete this._tb_remove;
       
  3241 	}
       
  3242 });
       
  3243 
       
  3244 // Map some of the modal's methods to the frame.
       
  3245 _.each(['open','close','attach','detach','escape'], function( method ) {
       
  3246 	/**
       
  3247 	 * @function open
       
  3248 	 * @memberOf wp.media.view.MediaFrame
       
  3249 	 * @instance
       
  3250 	 *
       
  3251 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3252 	 */
       
  3253 	/**
       
  3254 	 * @function close
       
  3255 	 * @memberOf wp.media.view.MediaFrame
       
  3256 	 * @instance
       
  3257 	 *
       
  3258 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3259 	 */
       
  3260 	/**
       
  3261 	 * @function attach
       
  3262 	 * @memberOf wp.media.view.MediaFrame
       
  3263 	 * @instance
       
  3264 	 *
       
  3265 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3266 	 */
       
  3267 	/**
       
  3268 	 * @function detach
       
  3269 	 * @memberOf wp.media.view.MediaFrame
       
  3270 	 * @instance
       
  3271 	 *
       
  3272 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3273 	 */
       
  3274 	/**
       
  3275 	 * @function escape
       
  3276 	 * @memberOf wp.media.view.MediaFrame
       
  3277 	 * @instance
       
  3278 	 *
       
  3279 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3280 	 */
       
  3281 	MediaFrame.prototype[ method ] = function() {
       
  3282 		if ( this.modal ) {
       
  3283 			this.modal[ method ].apply( this.modal, arguments );
       
  3284 		}
       
  3285 		return this;
       
  3286 	};
       
  3287 });
       
  3288 
       
  3289 module.exports = MediaFrame;
       
  3290 
       
  3291 
       
  3292 /***/ }),
       
  3293 
       
  3294 /***/ 2982:
       
  3295 /***/ ((module) => {
       
  3296 
       
  3297 var View = wp.media.View,
       
  3298 	AttachmentCompat;
       
  3299 
       
  3300 /**
       
  3301  * wp.media.view.AttachmentCompat
       
  3302  *
       
  3303  * A view to display fields added via the `attachment_fields_to_edit` filter.
       
  3304  *
       
  3305  * @memberOf wp.media.view
       
  3306  *
       
  3307  * @class
       
  3308  * @augments wp.media.View
       
  3309  * @augments wp.Backbone.View
       
  3310  * @augments Backbone.View
       
  3311  */
       
  3312 AttachmentCompat = View.extend(/** @lends wp.media.view.AttachmentCompat.prototype */{
       
  3313 	tagName:   'form',
       
  3314 	className: 'compat-item',
       
  3315 
       
  3316 	events: {
       
  3317 		'submit':          'preventDefault',
       
  3318 		'change input':    'save',
       
  3319 		'change select':   'save',
       
  3320 		'change textarea': 'save'
       
  3321 	},
       
  3322 
       
  3323 	initialize: function() {
       
  3324 		// Render the view when a new item is added.
       
  3325 		this.listenTo( this.model, 'add', this.render );
       
  3326 	},
       
  3327 
       
  3328 	/**
       
  3329 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
       
  3330 	 */
       
  3331 	dispose: function() {
       
  3332 		if ( this.$(':focus').length ) {
       
  3333 			this.save();
       
  3334 		}
       
  3335 		/**
       
  3336 		 * call 'dispose' directly on the parent class
       
  3337 		 */
       
  3338 		return View.prototype.dispose.apply( this, arguments );
       
  3339 	},
       
  3340 	/**
       
  3341 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
       
  3342 	 */
       
  3343 	render: function() {
       
  3344 		var compat = this.model.get('compat');
       
  3345 		if ( ! compat || ! compat.item ) {
       
  3346 			return;
       
  3347 		}
       
  3348 
       
  3349 		this.views.detach();
       
  3350 		this.$el.html( compat.item );
       
  3351 		this.views.render();
       
  3352 		return this;
       
  3353 	},
       
  3354 	/**
       
  3355 	 * @param {Object} event
       
  3356 	 */
       
  3357 	preventDefault: function( event ) {
       
  3358 		event.preventDefault();
       
  3359 	},
       
  3360 	/**
       
  3361 	 * @param {Object} event
       
  3362 	 */
       
  3363 	save: function( event ) {
       
  3364 		var data = {};
       
  3365 
       
  3366 		if ( event ) {
       
  3367 			event.preventDefault();
       
  3368 		}
       
  3369 
       
  3370 		_.each( this.$el.serializeArray(), function( pair ) {
       
  3371 			data[ pair.name ] = pair.value;
       
  3372 		});
       
  3373 
       
  3374 		this.controller.trigger( 'attachment:compat:waiting', ['waiting'] );
       
  3375 		this.model.saveCompat( data ).always( _.bind( this.postSave, this ) );
       
  3376 	},
       
  3377 
       
  3378 	postSave: function() {
       
  3379 		this.controller.trigger( 'attachment:compat:ready', ['ready'] );
       
  3380 	}
       
  3381 });
       
  3382 
       
  3383 module.exports = AttachmentCompat;
       
  3384 
       
  3385 
       
  3386 /***/ }),
       
  3387 
       
  3388 /***/ 3443:
       
  3389 /***/ ((module) => {
       
  3390 
       
  3391 /**
       
  3392  * wp.media.view.Attachment.Library
       
  3393  *
       
  3394  * @memberOf wp.media.view.Attachment
       
  3395  *
       
  3396  * @class
       
  3397  * @augments wp.media.view.Attachment
       
  3398  * @augments wp.media.View
       
  3399  * @augments wp.Backbone.View
       
  3400  * @augments Backbone.View
       
  3401  */
       
  3402 var Library = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Library.prototype */{
       
  3403 	buttons: {
       
  3404 		check: true
       
  3405 	}
       
  3406 });
       
  3407 
       
  3408 module.exports = Library;
       
  3409 
       
  3410 
       
  3411 /***/ }),
       
  3412 
       
  3413 /***/ 3479:
       
  3414 /***/ ((module) => {
       
  3415 
       
  3416 var Attachments = wp.media.view.Attachments,
       
  3417 	Selection;
       
  3418 
       
  3419 /**
       
  3420  * wp.media.view.Attachments.Selection
       
  3421  *
       
  3422  * @memberOf wp.media.view.Attachments
       
  3423  *
       
  3424  * @class
       
  3425  * @augments wp.media.view.Attachments
       
  3426  * @augments wp.media.View
       
  3427  * @augments wp.Backbone.View
       
  3428  * @augments Backbone.View
       
  3429  */
       
  3430 Selection = Attachments.extend(/** @lends wp.media.view.Attachments.Selection.prototype */{
       
  3431 	events: {},
       
  3432 	initialize: function() {
       
  3433 		_.defaults( this.options, {
       
  3434 			sortable:   false,
       
  3435 			resize:     false,
       
  3436 
       
  3437 			// The single `Attachment` view to be used in the `Attachments` view.
       
  3438 			AttachmentView: wp.media.view.Attachment.Selection
       
  3439 		});
       
  3440 		// Call 'initialize' directly on the parent class.
       
  3441 		return Attachments.prototype.initialize.apply( this, arguments );
       
  3442 	}
       
  3443 });
       
  3444 
       
  3445 module.exports = Selection;
       
  3446 
       
  3447 
       
  3448 /***/ }),
       
  3449 
       
  3450 /***/ 3674:
       
  3451 /***/ ((module) => {
       
  3452 
       
  3453 var View = wp.media.View,
       
  3454 	l10n = wp.media.view.l10n,
       
  3455 	$ = jQuery,
       
  3456 	EditorUploader;
       
  3457 
       
  3458 /**
       
  3459  * Creates a dropzone on WP editor instances (elements with .wp-editor-wrap)
       
  3460  * and relays drag'n'dropped files to a media workflow.
       
  3461  *
       
  3462  * wp.media.view.EditorUploader
       
  3463  *
       
  3464  * @memberOf wp.media.view
       
  3465  *
       
  3466  * @class
       
  3467  * @augments wp.media.View
       
  3468  * @augments wp.Backbone.View
       
  3469  * @augments Backbone.View
       
  3470  */
       
  3471 EditorUploader = View.extend(/** @lends wp.media.view.EditorUploader.prototype */{
       
  3472 	tagName:   'div',
       
  3473 	className: 'uploader-editor',
       
  3474 	template:  wp.template( 'uploader-editor' ),
       
  3475 
       
  3476 	localDrag: false,
       
  3477 	overContainer: false,
       
  3478 	overDropzone: false,
       
  3479 	draggingFile: null,
       
  3480 
       
  3481 	/**
       
  3482 	 * Bind drag'n'drop events to callbacks.
       
  3483 	 */
       
  3484 	initialize: function() {
       
  3485 		this.initialized = false;
       
  3486 
       
  3487 		// Bail if not enabled or UA does not support drag'n'drop or File API.
       
  3488 		if ( ! window.tinyMCEPreInit || ! window.tinyMCEPreInit.dragDropUpload || ! this.browserSupport() ) {
       
  3489 			return this;
       
  3490 		}
       
  3491 
       
  3492 		this.$document = $(document);
       
  3493 		this.dropzones = [];
       
  3494 		this.files = [];
       
  3495 
       
  3496 		this.$document.on( 'drop', '.uploader-editor', _.bind( this.drop, this ) );
       
  3497 		this.$document.on( 'dragover', '.uploader-editor', _.bind( this.dropzoneDragover, this ) );
       
  3498 		this.$document.on( 'dragleave', '.uploader-editor', _.bind( this.dropzoneDragleave, this ) );
       
  3499 		this.$document.on( 'click', '.uploader-editor', _.bind( this.click, this ) );
       
  3500 
       
  3501 		this.$document.on( 'dragover', _.bind( this.containerDragover, this ) );
       
  3502 		this.$document.on( 'dragleave', _.bind( this.containerDragleave, this ) );
       
  3503 
       
  3504 		this.$document.on( 'dragstart dragend drop', _.bind( function( event ) {
       
  3505 			this.localDrag = event.type === 'dragstart';
       
  3506 
       
  3507 			if ( event.type === 'drop' ) {
       
  3508 				this.containerDragleave();
       
  3509 			}
       
  3510 		}, this ) );
       
  3511 
       
  3512 		this.initialized = true;
       
  3513 		return this;
       
  3514 	},
       
  3515 
       
  3516 	/**
       
  3517 	 * Check browser support for drag'n'drop.
       
  3518 	 *
       
  3519 	 * @return {boolean}
       
  3520 	 */
       
  3521 	browserSupport: function() {
       
  3522 		var supports = false, div = document.createElement('div');
       
  3523 
       
  3524 		supports = ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div );
       
  3525 		supports = supports && !! ( window.File && window.FileList && window.FileReader );
       
  3526 		return supports;
       
  3527 	},
       
  3528 
       
  3529 	isDraggingFile: function( event ) {
       
  3530 		if ( this.draggingFile !== null ) {
       
  3531 			return this.draggingFile;
       
  3532 		}
       
  3533 
       
  3534 		if ( _.isUndefined( event.originalEvent ) || _.isUndefined( event.originalEvent.dataTransfer ) ) {
       
  3535 			return false;
       
  3536 		}
       
  3537 
       
  3538 		this.draggingFile = _.indexOf( event.originalEvent.dataTransfer.types, 'Files' ) > -1 &&
       
  3539 			_.indexOf( event.originalEvent.dataTransfer.types, 'text/plain' ) === -1;
       
  3540 
       
  3541 		return this.draggingFile;
       
  3542 	},
       
  3543 
       
  3544 	refresh: function( e ) {
       
  3545 		var dropzone_id;
       
  3546 		for ( dropzone_id in this.dropzones ) {
       
  3547 			// Hide the dropzones only if dragging has left the screen.
       
  3548 			this.dropzones[ dropzone_id ].toggle( this.overContainer || this.overDropzone );
       
  3549 		}
       
  3550 
       
  3551 		if ( ! _.isUndefined( e ) ) {
       
  3552 			$( e.target ).closest( '.uploader-editor' ).toggleClass( 'droppable', this.overDropzone );
       
  3553 		}
       
  3554 
       
  3555 		if ( ! this.overContainer && ! this.overDropzone ) {
       
  3556 			this.draggingFile = null;
       
  3557 		}
       
  3558 
       
  3559 		return this;
       
  3560 	},
       
  3561 
       
  3562 	render: function() {
       
  3563 		if ( ! this.initialized ) {
       
  3564 			return this;
       
  3565 		}
       
  3566 
       
  3567 		View.prototype.render.apply( this, arguments );
       
  3568 		$( '.wp-editor-wrap' ).each( _.bind( this.attach, this ) );
       
  3569 		return this;
       
  3570 	},
       
  3571 
       
  3572 	attach: function( index, editor ) {
       
  3573 		// Attach a dropzone to an editor.
       
  3574 		var dropzone = this.$el.clone();
       
  3575 		this.dropzones.push( dropzone );
       
  3576 		$( editor ).append( dropzone );
       
  3577 		return this;
       
  3578 	},
       
  3579 
       
  3580 	/**
       
  3581 	 * When a file is dropped on the editor uploader, open up an editor media workflow
       
  3582 	 * and upload the file immediately.
       
  3583 	 *
       
  3584 	 * @param {jQuery.Event} event The 'drop' event.
       
  3585 	 */
       
  3586 	drop: function( event ) {
       
  3587 		var $wrap, uploadView;
       
  3588 
       
  3589 		this.containerDragleave( event );
       
  3590 		this.dropzoneDragleave( event );
       
  3591 
       
  3592 		this.files = event.originalEvent.dataTransfer.files;
       
  3593 		if ( this.files.length < 1 ) {
       
  3594 			return;
       
  3595 		}
       
  3596 
       
  3597 		// Set the active editor to the drop target.
       
  3598 		$wrap = $( event.target ).parents( '.wp-editor-wrap' );
       
  3599 		if ( $wrap.length > 0 && $wrap[0].id ) {
       
  3600 			window.wpActiveEditor = $wrap[0].id.slice( 3, -5 );
       
  3601 		}
       
  3602 
       
  3603 		if ( ! this.workflow ) {
       
  3604 			this.workflow = wp.media.editor.open( window.wpActiveEditor, {
       
  3605 				frame:    'post',
       
  3606 				state:    'insert',
       
  3607 				title:    l10n.addMedia,
       
  3608 				multiple: true
       
  3609 			});
       
  3610 
       
  3611 			uploadView = this.workflow.uploader;
       
  3612 
       
  3613 			if ( uploadView.uploader && uploadView.uploader.ready ) {
       
  3614 				this.addFiles.apply( this );
       
  3615 			} else {
       
  3616 				this.workflow.on( 'uploader:ready', this.addFiles, this );
       
  3617 			}
       
  3618 		} else {
       
  3619 			this.workflow.state().reset();
       
  3620 			this.addFiles.apply( this );
       
  3621 			this.workflow.open();
       
  3622 		}
       
  3623 
       
  3624 		return false;
       
  3625 	},
       
  3626 
       
  3627 	/**
       
  3628 	 * Add the files to the uploader.
       
  3629 	 */
       
  3630 	addFiles: function() {
       
  3631 		if ( this.files.length ) {
       
  3632 			this.workflow.uploader.uploader.uploader.addFile( _.toArray( this.files ) );
       
  3633 			this.files = [];
       
  3634 		}
       
  3635 		return this;
       
  3636 	},
       
  3637 
       
  3638 	containerDragover: function( event ) {
       
  3639 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
       
  3640 			return;
       
  3641 		}
       
  3642 
       
  3643 		this.overContainer = true;
       
  3644 		this.refresh();
       
  3645 	},
       
  3646 
       
  3647 	containerDragleave: function() {
       
  3648 		this.overContainer = false;
       
  3649 
       
  3650 		// Throttle dragleave because it's called when bouncing from some elements to others.
       
  3651 		_.delay( _.bind( this.refresh, this ), 50 );
       
  3652 	},
       
  3653 
       
  3654 	dropzoneDragover: function( event ) {
       
  3655 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
       
  3656 			return;
       
  3657 		}
       
  3658 
       
  3659 		this.overDropzone = true;
       
  3660 		this.refresh( event );
       
  3661 		return false;
       
  3662 	},
       
  3663 
       
  3664 	dropzoneDragleave: function( e ) {
       
  3665 		this.overDropzone = false;
       
  3666 		_.delay( _.bind( this.refresh, this, e ), 50 );
       
  3667 	},
       
  3668 
       
  3669 	click: function( e ) {
       
  3670 		// In the rare case where the dropzone gets stuck, hide it on click.
       
  3671 		this.containerDragleave( e );
       
  3672 		this.dropzoneDragleave( e );
       
  3673 		this.localDrag = false;
       
  3674 	}
       
  3675 });
       
  3676 
       
  3677 module.exports = EditorUploader;
       
  3678 
       
  3679 
       
  3680 /***/ }),
       
  3681 
       
  3682 /***/ 3962:
       
  3683 /***/ ((module) => {
       
  3684 
       
  3685 /**
       
  3686  * wp.media.view.Attachment.Selection
       
  3687  *
       
  3688  * @memberOf wp.media.view.Attachment
       
  3689  *
       
  3690  * @class
       
  3691  * @augments wp.media.view.Attachment
       
  3692  * @augments wp.media.View
       
  3693  * @augments wp.Backbone.View
       
  3694  * @augments Backbone.View
       
  3695  */
       
  3696 var Selection = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Selection.prototype */{
       
  3697 	className: 'attachment selection',
       
  3698 
       
  3699 	// On click, just select the model, instead of removing the model from
       
  3700 	// the selection.
       
  3701 	toggleSelection: function() {
       
  3702 		this.options.selection.single( this.model );
       
  3703 	}
       
  3704 });
       
  3705 
       
  3706 module.exports = Selection;
       
  3707 
       
  3708 
       
  3709 /***/ }),
       
  3710 
       
  3711 /***/ 4075:
       
  3712 /***/ ((module) => {
       
  3713 
       
  3714 var View = wp.media.View,
       
  3715 	$ = jQuery,
       
  3716 	Attachment;
       
  3717 
       
  3718 /**
       
  3719  * wp.media.view.Attachment
       
  3720  *
       
  3721  * @memberOf wp.media.view
       
  3722  *
       
  3723  * @class
       
  3724  * @augments wp.media.View
       
  3725  * @augments wp.Backbone.View
       
  3726  * @augments Backbone.View
       
  3727  */
       
  3728 Attachment = View.extend(/** @lends wp.media.view.Attachment.prototype */{
       
  3729 	tagName:   'li',
       
  3730 	className: 'attachment',
       
  3731 	template:  wp.template('attachment'),
       
  3732 
       
  3733 	attributes: function() {
       
  3734 		return {
       
  3735 			'tabIndex':     0,
       
  3736 			'role':         'checkbox',
       
  3737 			'aria-label':   this.model.get( 'title' ),
       
  3738 			'aria-checked': false,
       
  3739 			'data-id':      this.model.get( 'id' )
       
  3740 		};
       
  3741 	},
       
  3742 
       
  3743 	events: {
       
  3744 		'click':                          'toggleSelectionHandler',
       
  3745 		'change [data-setting]':          'updateSetting',
       
  3746 		'change [data-setting] input':    'updateSetting',
       
  3747 		'change [data-setting] select':   'updateSetting',
       
  3748 		'change [data-setting] textarea': 'updateSetting',
       
  3749 		'click .attachment-close':        'removeFromLibrary',
       
  3750 		'click .check':                   'checkClickHandler',
       
  3751 		'keydown':                        'toggleSelectionHandler'
       
  3752 	},
       
  3753 
       
  3754 	buttons: {},
       
  3755 
       
  3756 	initialize: function() {
       
  3757 		var selection = this.options.selection,
       
  3758 			options = _.defaults( this.options, {
       
  3759 				rerenderOnModelChange: true
       
  3760 			} );
       
  3761 
       
  3762 		if ( options.rerenderOnModelChange ) {
       
  3763 			this.listenTo( this.model, 'change', this.render );
       
  3764 		} else {
       
  3765 			this.listenTo( this.model, 'change:percent', this.progress );
       
  3766 		}
       
  3767 		this.listenTo( this.model, 'change:title', this._syncTitle );
       
  3768 		this.listenTo( this.model, 'change:caption', this._syncCaption );
       
  3769 		this.listenTo( this.model, 'change:artist', this._syncArtist );
       
  3770 		this.listenTo( this.model, 'change:album', this._syncAlbum );
       
  3771 
       
  3772 		// Update the selection.
       
  3773 		this.listenTo( this.model, 'add', this.select );
       
  3774 		this.listenTo( this.model, 'remove', this.deselect );
       
  3775 		if ( selection ) {
       
  3776 			selection.on( 'reset', this.updateSelect, this );
       
  3777 			// Update the model's details view.
       
  3778 			this.listenTo( this.model, 'selection:single selection:unsingle', this.details );
       
  3779 			this.details( this.model, this.controller.state().get('selection') );
       
  3780 		}
       
  3781 
       
  3782 		this.listenTo( this.controller.states, 'attachment:compat:waiting attachment:compat:ready', this.updateSave );
       
  3783 	},
       
  3784 	/**
       
  3785 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  3786 	 */
       
  3787 	dispose: function() {
       
  3788 		var selection = this.options.selection;
       
  3789 
       
  3790 		// Make sure all settings are saved before removing the view.
       
  3791 		this.updateAll();
       
  3792 
       
  3793 		if ( selection ) {
       
  3794 			selection.off( null, null, this );
       
  3795 		}
       
  3796 		/**
       
  3797 		 * call 'dispose' directly on the parent class
       
  3798 		 */
       
  3799 		View.prototype.dispose.apply( this, arguments );
       
  3800 		return this;
       
  3801 	},
       
  3802 	/**
       
  3803 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  3804 	 */
       
  3805 	render: function() {
       
  3806 		var options = _.defaults( this.model.toJSON(), {
       
  3807 				orientation:   'landscape',
       
  3808 				uploading:     false,
       
  3809 				type:          '',
       
  3810 				subtype:       '',
       
  3811 				icon:          '',
       
  3812 				filename:      '',
       
  3813 				caption:       '',
       
  3814 				title:         '',
       
  3815 				dateFormatted: '',
       
  3816 				width:         '',
       
  3817 				height:        '',
       
  3818 				compat:        false,
       
  3819 				alt:           '',
       
  3820 				description:   ''
       
  3821 			}, this.options );
       
  3822 
       
  3823 		options.buttons  = this.buttons;
       
  3824 		options.describe = this.controller.state().get('describe');
       
  3825 
       
  3826 		if ( 'image' === options.type ) {
       
  3827 			options.size = this.imageSize();
       
  3828 		}
       
  3829 
       
  3830 		options.can = {};
       
  3831 		if ( options.nonces ) {
       
  3832 			options.can.remove = !! options.nonces['delete'];
       
  3833 			options.can.save = !! options.nonces.update;
       
  3834 		}
       
  3835 
       
  3836 		if ( this.controller.state().get('allowLocalEdits') && ! options.uploading ) {
       
  3837 			options.allowLocalEdits = true;
       
  3838 		}
       
  3839 
       
  3840 		if ( options.uploading && ! options.percent ) {
       
  3841 			options.percent = 0;
       
  3842 		}
       
  3843 
       
  3844 		this.views.detach();
       
  3845 		this.$el.html( this.template( options ) );
       
  3846 
       
  3847 		this.$el.toggleClass( 'uploading', options.uploading );
       
  3848 
       
  3849 		if ( options.uploading ) {
       
  3850 			this.$bar = this.$('.media-progress-bar div');
       
  3851 		} else {
       
  3852 			delete this.$bar;
       
  3853 		}
       
  3854 
       
  3855 		// Check if the model is selected.
       
  3856 		this.updateSelect();
       
  3857 
       
  3858 		// Update the save status.
       
  3859 		this.updateSave();
       
  3860 
       
  3861 		this.views.render();
       
  3862 
       
  3863 		return this;
       
  3864 	},
       
  3865 
       
  3866 	progress: function() {
       
  3867 		if ( this.$bar && this.$bar.length ) {
       
  3868 			this.$bar.width( this.model.get('percent') + '%' );
       
  3869 		}
       
  3870 	},
       
  3871 
       
  3872 	/**
       
  3873 	 * @param {Object} event
       
  3874 	 */
       
  3875 	toggleSelectionHandler: function( event ) {
       
  3876 		var method;
       
  3877 
       
  3878 		// Don't do anything inside inputs and on the attachment check and remove buttons.
       
  3879 		if ( 'INPUT' === event.target.nodeName || 'BUTTON' === event.target.nodeName ) {
       
  3880 			return;
       
  3881 		}
       
  3882 
       
  3883 		// Catch arrow events.
       
  3884 		if ( 37 === event.keyCode || 38 === event.keyCode || 39 === event.keyCode || 40 === event.keyCode ) {
       
  3885 			this.controller.trigger( 'attachment:keydown:arrow', event );
       
  3886 			return;
       
  3887 		}
       
  3888 
       
  3889 		// Catch enter and space events.
       
  3890 		if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
       
  3891 			return;
       
  3892 		}
       
  3893 
       
  3894 		event.preventDefault();
       
  3895 
       
  3896 		// In the grid view, bubble up an edit:attachment event to the controller.
       
  3897 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  3898 			if ( this.controller.isModeActive( 'edit' ) ) {
       
  3899 				// Pass the current target to restore focus when closing.
       
  3900 				this.controller.trigger( 'edit:attachment', this.model, event.currentTarget );
       
  3901 				return;
       
  3902 			}
       
  3903 
       
  3904 			if ( this.controller.isModeActive( 'select' ) ) {
       
  3905 				method = 'toggle';
       
  3906 			}
       
  3907 		}
       
  3908 
       
  3909 		if ( event.shiftKey ) {
       
  3910 			method = 'between';
       
  3911 		} else if ( event.ctrlKey || event.metaKey ) {
       
  3912 			method = 'toggle';
       
  3913 		}
       
  3914 
       
  3915 		// Avoid toggles when the command or control key is pressed with the enter key to prevent deselecting the last selected attachment.
       
  3916 		if ( ( event.metaKey || event.ctrlKey ) && ( 13 === event.keyCode || 10 === event.keyCode ) ) {
       
  3917 			return;
       
  3918 		}
       
  3919 
       
  3920 		this.toggleSelection({
       
  3921 			method: method
       
  3922 		});
       
  3923 
       
  3924 		this.controller.trigger( 'selection:toggle' );
       
  3925 	},
       
  3926 	/**
       
  3927 	 * @param {Object} options
       
  3928 	 */
       
  3929 	toggleSelection: function( options ) {
       
  3930 		var collection = this.collection,
       
  3931 			selection = this.options.selection,
       
  3932 			model = this.model,
       
  3933 			method = options && options.method,
       
  3934 			single, models, singleIndex, modelIndex;
       
  3935 
       
  3936 		if ( ! selection ) {
       
  3937 			return;
       
  3938 		}
       
  3939 
       
  3940 		single = selection.single();
       
  3941 		method = _.isUndefined( method ) ? selection.multiple : method;
       
  3942 
       
  3943 		// If the `method` is set to `between`, select all models that
       
  3944 		// exist between the current and the selected model.
       
  3945 		if ( 'between' === method && single && selection.multiple ) {
       
  3946 			// If the models are the same, short-circuit.
       
  3947 			if ( single === model ) {
       
  3948 				return;
       
  3949 			}
       
  3950 
       
  3951 			singleIndex = collection.indexOf( single );
       
  3952 			modelIndex  = collection.indexOf( this.model );
       
  3953 
       
  3954 			if ( singleIndex < modelIndex ) {
       
  3955 				models = collection.models.slice( singleIndex, modelIndex + 1 );
       
  3956 			} else {
       
  3957 				models = collection.models.slice( modelIndex, singleIndex + 1 );
       
  3958 			}
       
  3959 
       
  3960 			selection.add( models );
       
  3961 			selection.single( model );
       
  3962 			return;
       
  3963 
       
  3964 		// If the `method` is set to `toggle`, just flip the selection
       
  3965 		// status, regardless of whether the model is the single model.
       
  3966 		} else if ( 'toggle' === method ) {
       
  3967 			selection[ this.selected() ? 'remove' : 'add' ]( model );
       
  3968 			selection.single( model );
       
  3969 			return;
       
  3970 		} else if ( 'add' === method ) {
       
  3971 			selection.add( model );
       
  3972 			selection.single( model );
       
  3973 			return;
       
  3974 		}
       
  3975 
       
  3976 		// Fixes bug that loses focus when selecting a featured image.
       
  3977 		if ( ! method ) {
       
  3978 			method = 'add';
       
  3979 		}
       
  3980 
       
  3981 		if ( method !== 'add' ) {
       
  3982 			method = 'reset';
       
  3983 		}
       
  3984 
       
  3985 		if ( this.selected() ) {
       
  3986 			/*
       
  3987 			 * If the model is the single model, remove it.
       
  3988 			 * If it is not the same as the single model,
       
  3989 			 * it now becomes the single model.
       
  3990 			 */
       
  3991 			selection[ single === model ? 'remove' : 'single' ]( model );
       
  3992 		} else {
       
  3993 			/*
       
  3994 			 * If the model is not selected, run the `method` on the
       
  3995 			 * selection. By default, we `reset` the selection, but the
       
  3996 			 * `method` can be set to `add` the model to the selection.
       
  3997 			 */
       
  3998 			selection[ method ]( model );
       
  3999 			selection.single( model );
       
  4000 		}
       
  4001 	},
       
  4002 
       
  4003 	updateSelect: function() {
       
  4004 		this[ this.selected() ? 'select' : 'deselect' ]();
       
  4005 	},
       
  4006 	/**
       
  4007 	 * @return {unresolved|boolean}
       
  4008 	 */
       
  4009 	selected: function() {
       
  4010 		var selection = this.options.selection;
       
  4011 		if ( selection ) {
       
  4012 			return !! selection.get( this.model.cid );
       
  4013 		}
       
  4014 	},
       
  4015 	/**
       
  4016 	 * @param {Backbone.Model} model
       
  4017 	 * @param {Backbone.Collection} collection
       
  4018 	 */
       
  4019 	select: function( model, collection ) {
       
  4020 		var selection = this.options.selection,
       
  4021 			controller = this.controller;
       
  4022 
       
  4023 		/*
       
  4024 		 * Check if a selection exists and if it's the collection provided.
       
  4025 		 * If they're not the same collection, bail; we're in another
       
  4026 		 * selection's event loop.
       
  4027 		 */
       
  4028 		if ( ! selection || ( collection && collection !== selection ) ) {
       
  4029 			return;
       
  4030 		}
       
  4031 
       
  4032 		// Bail if the model is already selected.
       
  4033 		if ( this.$el.hasClass( 'selected' ) ) {
       
  4034 			return;
       
  4035 		}
       
  4036 
       
  4037 		// Add 'selected' class to model, set aria-checked to true.
       
  4038 		this.$el.addClass( 'selected' ).attr( 'aria-checked', true );
       
  4039 		//  Make the checkbox tabable, except in media grid (bulk select mode).
       
  4040 		if ( ! ( controller.isModeActive( 'grid' ) && controller.isModeActive( 'select' ) ) ) {
       
  4041 			this.$( '.check' ).attr( 'tabindex', '0' );
       
  4042 		}
       
  4043 	},
       
  4044 	/**
       
  4045 	 * @param {Backbone.Model} model
       
  4046 	 * @param {Backbone.Collection} collection
       
  4047 	 */
       
  4048 	deselect: function( model, collection ) {
       
  4049 		var selection = this.options.selection;
       
  4050 
       
  4051 		/*
       
  4052 		 * Check if a selection exists and if it's the collection provided.
       
  4053 		 * If they're not the same collection, bail; we're in another
       
  4054 		 * selection's event loop.
       
  4055 		 */
       
  4056 		if ( ! selection || ( collection && collection !== selection ) ) {
       
  4057 			return;
       
  4058 		}
       
  4059 		this.$el.removeClass( 'selected' ).attr( 'aria-checked', false )
       
  4060 			.find( '.check' ).attr( 'tabindex', '-1' );
       
  4061 	},
       
  4062 	/**
       
  4063 	 * @param {Backbone.Model} model
       
  4064 	 * @param {Backbone.Collection} collection
       
  4065 	 */
       
  4066 	details: function( model, collection ) {
       
  4067 		var selection = this.options.selection,
       
  4068 			details;
       
  4069 
       
  4070 		if ( selection !== collection ) {
       
  4071 			return;
       
  4072 		}
       
  4073 
       
  4074 		details = selection.single();
       
  4075 		this.$el.toggleClass( 'details', details === this.model );
       
  4076 	},
       
  4077 	/**
       
  4078 	 * @param {string} size
       
  4079 	 * @return {Object}
       
  4080 	 */
       
  4081 	imageSize: function( size ) {
       
  4082 		var sizes = this.model.get('sizes'), matched = false;
       
  4083 
       
  4084 		size = size || 'medium';
       
  4085 
       
  4086 		// Use the provided image size if possible.
       
  4087 		if ( sizes ) {
       
  4088 			if ( sizes[ size ] ) {
       
  4089 				matched = sizes[ size ];
       
  4090 			} else if ( sizes.large ) {
       
  4091 				matched = sizes.large;
       
  4092 			} else if ( sizes.thumbnail ) {
       
  4093 				matched = sizes.thumbnail;
       
  4094 			} else if ( sizes.full ) {
       
  4095 				matched = sizes.full;
       
  4096 			}
       
  4097 
       
  4098 			if ( matched ) {
       
  4099 				return _.clone( matched );
       
  4100 			}
       
  4101 		}
       
  4102 
       
  4103 		return {
       
  4104 			url:         this.model.get('url'),
       
  4105 			width:       this.model.get('width'),
       
  4106 			height:      this.model.get('height'),
       
  4107 			orientation: this.model.get('orientation')
       
  4108 		};
       
  4109 	},
       
  4110 	/**
       
  4111 	 * @param {Object} event
       
  4112 	 */
       
  4113 	updateSetting: function( event ) {
       
  4114 		var $setting = $( event.target ).closest('[data-setting]'),
       
  4115 			setting, value;
       
  4116 
       
  4117 		if ( ! $setting.length ) {
       
  4118 			return;
       
  4119 		}
       
  4120 
       
  4121 		setting = $setting.data('setting');
       
  4122 		value   = event.target.value;
       
  4123 
       
  4124 		if ( this.model.get( setting ) !== value ) {
       
  4125 			this.save( setting, value );
       
  4126 		}
       
  4127 	},
       
  4128 
       
  4129 	/**
       
  4130 	 * Pass all the arguments to the model's save method.
       
  4131 	 *
       
  4132 	 * Records the aggregate status of all save requests and updates the
       
  4133 	 * view's classes accordingly.
       
  4134 	 */
       
  4135 	save: function() {
       
  4136 		var view = this,
       
  4137 			save = this._save = this._save || { status: 'ready' },
       
  4138 			request = this.model.save.apply( this.model, arguments ),
       
  4139 			requests = save.requests ? $.when( request, save.requests ) : request;
       
  4140 
       
  4141 		// If we're waiting to remove 'Saved.', stop.
       
  4142 		if ( save.savedTimer ) {
       
  4143 			clearTimeout( save.savedTimer );
       
  4144 		}
       
  4145 
       
  4146 		this.updateSave('waiting');
       
  4147 		save.requests = requests;
       
  4148 		requests.always( function() {
       
  4149 			// If we've performed another request since this one, bail.
       
  4150 			if ( save.requests !== requests ) {
       
  4151 				return;
       
  4152 			}
       
  4153 
       
  4154 			view.updateSave( requests.state() === 'resolved' ? 'complete' : 'error' );
       
  4155 			save.savedTimer = setTimeout( function() {
       
  4156 				view.updateSave('ready');
       
  4157 				delete save.savedTimer;
       
  4158 			}, 2000 );
       
  4159 		});
       
  4160 	},
       
  4161 	/**
       
  4162 	 * @param {string} status
       
  4163 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  4164 	 */
       
  4165 	updateSave: function( status ) {
       
  4166 		var save = this._save = this._save || { status: 'ready' };
       
  4167 
       
  4168 		if ( status && status !== save.status ) {
       
  4169 			this.$el.removeClass( 'save-' + save.status );
       
  4170 			save.status = status;
       
  4171 		}
       
  4172 
       
  4173 		this.$el.addClass( 'save-' + save.status );
       
  4174 		return this;
       
  4175 	},
       
  4176 
       
  4177 	updateAll: function() {
       
  4178 		var $settings = this.$('[data-setting]'),
       
  4179 			model = this.model,
       
  4180 			changed;
       
  4181 
       
  4182 		changed = _.chain( $settings ).map( function( el ) {
       
  4183 			var $input = $('input, textarea, select, [value]', el ),
       
  4184 				setting, value;
       
  4185 
       
  4186 			if ( ! $input.length ) {
       
  4187 				return;
       
  4188 			}
       
  4189 
       
  4190 			setting = $(el).data('setting');
       
  4191 			value = $input.val();
       
  4192 
       
  4193 			// Record the value if it changed.
       
  4194 			if ( model.get( setting ) !== value ) {
       
  4195 				return [ setting, value ];
       
  4196 			}
       
  4197 		}).compact().object().value();
       
  4198 
       
  4199 		if ( ! _.isEmpty( changed ) ) {
       
  4200 			model.save( changed );
       
  4201 		}
       
  4202 	},
       
  4203 	/**
       
  4204 	 * @param {Object} event
       
  4205 	 */
       
  4206 	removeFromLibrary: function( event ) {
       
  4207 		// Catch enter and space events.
       
  4208 		if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
       
  4209 			return;
       
  4210 		}
       
  4211 
       
  4212 		// Stop propagation so the model isn't selected.
       
  4213 		event.stopPropagation();
       
  4214 
       
  4215 		this.collection.remove( this.model );
       
  4216 	},
       
  4217 
       
  4218 	/**
       
  4219 	 * Add the model if it isn't in the selection, if it is in the selection,
       
  4220 	 * remove it.
       
  4221 	 *
       
  4222 	 * @param {[type]} event [description]
       
  4223 	 * @return {[type]} [description]
       
  4224 	 */
       
  4225 	checkClickHandler: function ( event ) {
       
  4226 		var selection = this.options.selection;
       
  4227 		if ( ! selection ) {
       
  4228 			return;
       
  4229 		}
       
  4230 		event.stopPropagation();
       
  4231 		if ( selection.where( { id: this.model.get( 'id' ) } ).length ) {
       
  4232 			selection.remove( this.model );
       
  4233 			// Move focus back to the attachment tile (from the check).
       
  4234 			this.$el.focus();
       
  4235 		} else {
       
  4236 			selection.add( this.model );
       
  4237 		}
       
  4238 
       
  4239 		// Trigger an action button update.
       
  4240 		this.controller.trigger( 'selection:toggle' );
       
  4241 	}
       
  4242 });
       
  4243 
       
  4244 // Ensure settings remain in sync between attachment views.
       
  4245 _.each({
       
  4246 	caption: '_syncCaption',
       
  4247 	title:   '_syncTitle',
       
  4248 	artist:  '_syncArtist',
       
  4249 	album:   '_syncAlbum'
       
  4250 }, function( method, setting ) {
       
  4251 	/**
       
  4252 	 * @function _syncCaption
       
  4253 	 * @memberOf wp.media.view.Attachment
       
  4254 	 * @instance
       
  4255 	 *
       
  4256 	 * @param {Backbone.Model} model
       
  4257 	 * @param {string} value
       
  4258 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  4259 	 */
       
  4260 	/**
       
  4261 	 * @function _syncTitle
       
  4262 	 * @memberOf wp.media.view.Attachment
       
  4263 	 * @instance
       
  4264 	 *
       
  4265 	 * @param {Backbone.Model} model
       
  4266 	 * @param {string} value
       
  4267 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  4268 	 */
       
  4269 	/**
       
  4270 	 * @function _syncArtist
       
  4271 	 * @memberOf wp.media.view.Attachment
       
  4272 	 * @instance
       
  4273 	 *
       
  4274 	 * @param {Backbone.Model} model
       
  4275 	 * @param {string} value
       
  4276 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  4277 	 */
       
  4278 	/**
       
  4279 	 * @function _syncAlbum
       
  4280 	 * @memberOf wp.media.view.Attachment
       
  4281 	 * @instance
       
  4282 	 *
       
  4283 	 * @param {Backbone.Model} model
       
  4284 	 * @param {string} value
       
  4285 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  4286 	 */
       
  4287 	Attachment.prototype[ method ] = function( model, value ) {
       
  4288 		var $setting = this.$('[data-setting="' + setting + '"]');
       
  4289 
       
  4290 		if ( ! $setting.length ) {
       
  4291 			return this;
       
  4292 		}
       
  4293 
       
  4294 		/*
       
  4295 		 * If the updated value is in sync with the value in the DOM, there
       
  4296 		 * is no need to re-render. If we're currently editing the value,
       
  4297 		 * it will automatically be in sync, suppressing the re-render for
       
  4298 		 * the view we're editing, while updating any others.
       
  4299 		 */
       
  4300 		if ( value === $setting.find('input, textarea, select, [value]').val() ) {
       
  4301 			return this;
       
  4302 		}
       
  4303 
       
  4304 		return this.render();
       
  4305 	};
       
  4306 });
       
  4307 
       
  4308 module.exports = Attachment;
       
  4309 
       
  4310 
       
  4311 /***/ }),
       
  4312 
       
  4313 /***/ 4181:
       
  4314 /***/ ((module) => {
       
  4315 
       
  4316 /**
       
  4317  * wp.media.selectionSync
       
  4318  *
       
  4319  * Sync an attachments selection in a state with another state.
       
  4320  *
       
  4321  * Allows for selecting multiple images in the Add Media workflow, and then
       
  4322  * switching to the Insert Gallery workflow while preserving the attachments selection.
       
  4323  *
       
  4324  * @memberOf wp.media
       
  4325  *
       
  4326  * @mixin
       
  4327  */
       
  4328 var selectionSync = {
       
  4329 	/**
       
  4330 	 * @since 3.5.0
       
  4331 	 */
       
  4332 	syncSelection: function() {
       
  4333 		var selection = this.get('selection'),
       
  4334 			manager = this.frame._selection;
       
  4335 
       
  4336 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
       
  4337 			return;
       
  4338 		}
       
  4339 
       
  4340 		/*
       
  4341 		 * If the selection supports multiple items, validate the stored
       
  4342 		 * attachments based on the new selection's conditions. Record
       
  4343 		 * the attachments that are not included; we'll maintain a
       
  4344 		 * reference to those. Other attachments are considered in flux.
       
  4345 		 */
       
  4346 		if ( selection.multiple ) {
       
  4347 			selection.reset( [], { silent: true });
       
  4348 			selection.validateAll( manager.attachments );
       
  4349 			manager.difference = _.difference( manager.attachments.models, selection.models );
       
  4350 		}
       
  4351 
       
  4352 		// Sync the selection's single item with the master.
       
  4353 		selection.single( manager.single );
       
  4354 	},
       
  4355 
       
  4356 	/**
       
  4357 	 * Record the currently active attachments, which is a combination
       
  4358 	 * of the selection's attachments and the set of selected
       
  4359 	 * attachments that this specific selection considered invalid.
       
  4360 	 * Reset the difference and record the single attachment.
       
  4361 	 *
       
  4362 	 * @since 3.5.0
       
  4363 	 */
       
  4364 	recordSelection: function() {
       
  4365 		var selection = this.get('selection'),
       
  4366 			manager = this.frame._selection;
       
  4367 
       
  4368 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
       
  4369 			return;
       
  4370 		}
       
  4371 
       
  4372 		if ( selection.multiple ) {
       
  4373 			manager.attachments.reset( selection.toArray().concat( manager.difference ) );
       
  4374 			manager.difference = [];
       
  4375 		} else {
       
  4376 			manager.attachments.add( selection.toArray() );
       
  4377 		}
       
  4378 
       
  4379 		manager.single = selection._single;
       
  4380 	}
       
  4381 };
       
  4382 
       
  4383 module.exports = selectionSync;
       
  4384 
       
  4385 
       
  4386 /***/ }),
       
  4387 
       
  4388 /***/ 4274:
       
  4389 /***/ ((module) => {
       
  4390 
       
  4391 var Select = wp.media.view.MediaFrame.Select,
       
  4392 	Library = wp.media.controller.Library,
       
  4393 	l10n = wp.media.view.l10n,
       
  4394 	Post;
       
  4395 
       
  4396 /**
       
  4397  * wp.media.view.MediaFrame.Post
       
  4398  *
       
  4399  * The frame for manipulating media on the Edit Post page.
       
  4400  *
       
  4401  * @memberOf wp.media.view.MediaFrame
       
  4402  *
       
  4403  * @class
       
  4404  * @augments wp.media.view.MediaFrame.Select
       
  4405  * @augments wp.media.view.MediaFrame
       
  4406  * @augments wp.media.view.Frame
       
  4407  * @augments wp.media.View
       
  4408  * @augments wp.Backbone.View
       
  4409  * @augments Backbone.View
       
  4410  * @mixes wp.media.controller.StateMachine
       
  4411  */
       
  4412 Post = Select.extend(/** @lends wp.media.view.MediaFrame.Post.prototype */{
       
  4413 	initialize: function() {
       
  4414 		this.counts = {
       
  4415 			audio: {
       
  4416 				count: wp.media.view.settings.attachmentCounts.audio,
       
  4417 				state: 'playlist'
       
  4418 			},
       
  4419 			video: {
       
  4420 				count: wp.media.view.settings.attachmentCounts.video,
       
  4421 				state: 'video-playlist'
       
  4422 			}
       
  4423 		};
       
  4424 
       
  4425 		_.defaults( this.options, {
       
  4426 			multiple:  true,
       
  4427 			editing:   false,
       
  4428 			state:    'insert',
       
  4429 			metadata:  {}
       
  4430 		});
       
  4431 
       
  4432 		// Call 'initialize' directly on the parent class.
       
  4433 		Select.prototype.initialize.apply( this, arguments );
       
  4434 		this.createIframeStates();
       
  4435 
       
  4436 	},
       
  4437 
       
  4438 	/**
       
  4439 	 * Create the default states.
       
  4440 	 */
       
  4441 	createStates: function() {
       
  4442 		var options = this.options;
       
  4443 
       
  4444 		this.states.add([
       
  4445 			// Main states.
       
  4446 			new Library({
       
  4447 				id:         'insert',
       
  4448 				title:      l10n.insertMediaTitle,
       
  4449 				priority:   20,
       
  4450 				toolbar:    'main-insert',
       
  4451 				filterable: 'all',
       
  4452 				library:    wp.media.query( options.library ),
       
  4453 				multiple:   options.multiple ? 'reset' : false,
       
  4454 				editable:   true,
       
  4455 
       
  4456 				// If the user isn't allowed to edit fields,
       
  4457 				// can they still edit it locally?
       
  4458 				allowLocalEdits: true,
       
  4459 
       
  4460 				// Show the attachment display settings.
       
  4461 				displaySettings: true,
       
  4462 				// Update user settings when users adjust the
       
  4463 				// attachment display settings.
       
  4464 				displayUserSettings: true
       
  4465 			}),
       
  4466 
       
  4467 			new Library({
       
  4468 				id:         'gallery',
       
  4469 				title:      l10n.createGalleryTitle,
       
  4470 				priority:   40,
       
  4471 				toolbar:    'main-gallery',
       
  4472 				filterable: 'uploaded',
       
  4473 				multiple:   'add',
       
  4474 				editable:   false,
       
  4475 
       
  4476 				library:  wp.media.query( _.defaults({
       
  4477 					type: 'image'
       
  4478 				}, options.library ) )
       
  4479 			}),
       
  4480 
       
  4481 			// Embed states.
       
  4482 			new wp.media.controller.Embed( { metadata: options.metadata } ),
       
  4483 
       
  4484 			new wp.media.controller.EditImage( { model: options.editImage } ),
       
  4485 
       
  4486 			// Gallery states.
       
  4487 			new wp.media.controller.GalleryEdit({
       
  4488 				library: options.selection,
       
  4489 				editing: options.editing,
       
  4490 				menu:    'gallery'
       
  4491 			}),
       
  4492 
       
  4493 			new wp.media.controller.GalleryAdd(),
       
  4494 
       
  4495 			new Library({
       
  4496 				id:         'playlist',
       
  4497 				title:      l10n.createPlaylistTitle,
       
  4498 				priority:   60,
       
  4499 				toolbar:    'main-playlist',
       
  4500 				filterable: 'uploaded',
       
  4501 				multiple:   'add',
       
  4502 				editable:   false,
       
  4503 
       
  4504 				library:  wp.media.query( _.defaults({
       
  4505 					type: 'audio'
       
  4506 				}, options.library ) )
       
  4507 			}),
       
  4508 
       
  4509 			// Playlist states.
       
  4510 			new wp.media.controller.CollectionEdit({
       
  4511 				type: 'audio',
       
  4512 				collectionType: 'playlist',
       
  4513 				title:          l10n.editPlaylistTitle,
       
  4514 				SettingsView:   wp.media.view.Settings.Playlist,
       
  4515 				library:        options.selection,
       
  4516 				editing:        options.editing,
       
  4517 				menu:           'playlist',
       
  4518 				dragInfoText:   l10n.playlistDragInfo,
       
  4519 				dragInfo:       false
       
  4520 			}),
       
  4521 
       
  4522 			new wp.media.controller.CollectionAdd({
       
  4523 				type: 'audio',
       
  4524 				collectionType: 'playlist',
       
  4525 				title: l10n.addToPlaylistTitle
       
  4526 			}),
       
  4527 
       
  4528 			new Library({
       
  4529 				id:         'video-playlist',
       
  4530 				title:      l10n.createVideoPlaylistTitle,
       
  4531 				priority:   60,
       
  4532 				toolbar:    'main-video-playlist',
       
  4533 				filterable: 'uploaded',
       
  4534 				multiple:   'add',
       
  4535 				editable:   false,
       
  4536 
       
  4537 				library:  wp.media.query( _.defaults({
       
  4538 					type: 'video'
       
  4539 				}, options.library ) )
       
  4540 			}),
       
  4541 
       
  4542 			new wp.media.controller.CollectionEdit({
       
  4543 				type: 'video',
       
  4544 				collectionType: 'playlist',
       
  4545 				title:          l10n.editVideoPlaylistTitle,
       
  4546 				SettingsView:   wp.media.view.Settings.Playlist,
       
  4547 				library:        options.selection,
       
  4548 				editing:        options.editing,
       
  4549 				menu:           'video-playlist',
       
  4550 				dragInfoText:   l10n.videoPlaylistDragInfo,
       
  4551 				dragInfo:       false
       
  4552 			}),
       
  4553 
       
  4554 			new wp.media.controller.CollectionAdd({
       
  4555 				type: 'video',
       
  4556 				collectionType: 'playlist',
       
  4557 				title: l10n.addToVideoPlaylistTitle
       
  4558 			})
       
  4559 		]);
       
  4560 
       
  4561 		if ( wp.media.view.settings.post.featuredImageId ) {
       
  4562 			this.states.add( new wp.media.controller.FeaturedImage() );
       
  4563 		}
       
  4564 	},
       
  4565 
       
  4566 	bindHandlers: function() {
       
  4567 		var handlers, checkCounts;
       
  4568 
       
  4569 		Select.prototype.bindHandlers.apply( this, arguments );
       
  4570 
       
  4571 		this.on( 'activate', this.activate, this );
       
  4572 
       
  4573 		// Only bother checking media type counts if one of the counts is zero.
       
  4574 		checkCounts = _.find( this.counts, function( type ) {
       
  4575 			return type.count === 0;
       
  4576 		} );
       
  4577 
       
  4578 		if ( typeof checkCounts !== 'undefined' ) {
       
  4579 			this.listenTo( wp.media.model.Attachments.all, 'change:type', this.mediaTypeCounts );
       
  4580 		}
       
  4581 
       
  4582 		this.on( 'menu:create:gallery', this.createMenu, this );
       
  4583 		this.on( 'menu:create:playlist', this.createMenu, this );
       
  4584 		this.on( 'menu:create:video-playlist', this.createMenu, this );
       
  4585 		this.on( 'toolbar:create:main-insert', this.createToolbar, this );
       
  4586 		this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
       
  4587 		this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
       
  4588 		this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
       
  4589 		this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
       
  4590 		this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
       
  4591 
       
  4592 		handlers = {
       
  4593 			menu: {
       
  4594 				'default': 'mainMenu',
       
  4595 				'gallery': 'galleryMenu',
       
  4596 				'playlist': 'playlistMenu',
       
  4597 				'video-playlist': 'videoPlaylistMenu'
       
  4598 			},
       
  4599 
       
  4600 			content: {
       
  4601 				'embed':          'embedContent',
       
  4602 				'edit-image':     'editImageContent',
       
  4603 				'edit-selection': 'editSelectionContent'
       
  4604 			},
       
  4605 
       
  4606 			toolbar: {
       
  4607 				'main-insert':      'mainInsertToolbar',
       
  4608 				'main-gallery':     'mainGalleryToolbar',
       
  4609 				'gallery-edit':     'galleryEditToolbar',
       
  4610 				'gallery-add':      'galleryAddToolbar',
       
  4611 				'main-playlist':	'mainPlaylistToolbar',
       
  4612 				'playlist-edit':	'playlistEditToolbar',
       
  4613 				'playlist-add':		'playlistAddToolbar',
       
  4614 				'main-video-playlist': 'mainVideoPlaylistToolbar',
       
  4615 				'video-playlist-edit': 'videoPlaylistEditToolbar',
       
  4616 				'video-playlist-add': 'videoPlaylistAddToolbar'
       
  4617 			}
       
  4618 		};
       
  4619 
       
  4620 		_.each( handlers, function( regionHandlers, region ) {
       
  4621 			_.each( regionHandlers, function( callback, handler ) {
       
  4622 				this.on( region + ':render:' + handler, this[ callback ], this );
       
  4623 			}, this );
       
  4624 		}, this );
       
  4625 	},
       
  4626 
       
  4627 	activate: function() {
       
  4628 		// Hide menu items for states tied to particular media types if there are no items.
       
  4629 		_.each( this.counts, function( type ) {
       
  4630 			if ( type.count < 1 ) {
       
  4631 				this.menuItemVisibility( type.state, 'hide' );
       
  4632 			}
       
  4633 		}, this );
       
  4634 	},
       
  4635 
       
  4636 	mediaTypeCounts: function( model, attr ) {
       
  4637 		if ( typeof this.counts[ attr ] !== 'undefined' && this.counts[ attr ].count < 1 ) {
       
  4638 			this.counts[ attr ].count++;
       
  4639 			this.menuItemVisibility( this.counts[ attr ].state, 'show' );
       
  4640 		}
       
  4641 	},
       
  4642 
       
  4643 	// Menus.
       
  4644 	/**
       
  4645 	 * @param {wp.Backbone.View} view
       
  4646 	 */
       
  4647 	mainMenu: function( view ) {
       
  4648 		view.set({
       
  4649 			'library-separator': new wp.media.View({
       
  4650 				className:  'separator',
       
  4651 				priority:   100,
       
  4652 				attributes: {
       
  4653 					role: 'presentation'
       
  4654 				}
       
  4655 			})
       
  4656 		});
       
  4657 	},
       
  4658 
       
  4659 	menuItemVisibility: function( state, visibility ) {
       
  4660 		var menu = this.menu.get();
       
  4661 		if ( visibility === 'hide' ) {
       
  4662 			menu.hide( state );
       
  4663 		} else if ( visibility === 'show' ) {
       
  4664 			menu.show( state );
       
  4665 		}
       
  4666 	},
       
  4667 	/**
       
  4668 	 * @param {wp.Backbone.View} view
       
  4669 	 */
       
  4670 	galleryMenu: function( view ) {
       
  4671 		var lastState = this.lastState(),
       
  4672 			previous = lastState && lastState.id,
       
  4673 			frame = this;
       
  4674 
       
  4675 		view.set({
       
  4676 			cancel: {
       
  4677 				text:     l10n.cancelGalleryTitle,
       
  4678 				priority: 20,
       
  4679 				click:    function() {
       
  4680 					if ( previous ) {
       
  4681 						frame.setState( previous );
       
  4682 					} else {
       
  4683 						frame.close();
       
  4684 					}
       
  4685 
       
  4686 					// Move focus to the modal after canceling a Gallery.
       
  4687 					this.controller.modal.focusManager.focus();
       
  4688 				}
       
  4689 			},
       
  4690 			separateCancel: new wp.media.View({
       
  4691 				className: 'separator',
       
  4692 				priority: 40
       
  4693 			})
       
  4694 		});
       
  4695 	},
       
  4696 
       
  4697 	playlistMenu: function( view ) {
       
  4698 		var lastState = this.lastState(),
       
  4699 			previous = lastState && lastState.id,
       
  4700 			frame = this;
       
  4701 
       
  4702 		view.set({
       
  4703 			cancel: {
       
  4704 				text:     l10n.cancelPlaylistTitle,
       
  4705 				priority: 20,
       
  4706 				click:    function() {
       
  4707 					if ( previous ) {
       
  4708 						frame.setState( previous );
       
  4709 					} else {
       
  4710 						frame.close();
       
  4711 					}
       
  4712 
       
  4713 					// Move focus to the modal after canceling an Audio Playlist.
       
  4714 					this.controller.modal.focusManager.focus();
       
  4715 				}
       
  4716 			},
       
  4717 			separateCancel: new wp.media.View({
       
  4718 				className: 'separator',
       
  4719 				priority: 40
       
  4720 			})
       
  4721 		});
       
  4722 	},
       
  4723 
       
  4724 	videoPlaylistMenu: function( view ) {
       
  4725 		var lastState = this.lastState(),
       
  4726 			previous = lastState && lastState.id,
       
  4727 			frame = this;
       
  4728 
       
  4729 		view.set({
       
  4730 			cancel: {
       
  4731 				text:     l10n.cancelVideoPlaylistTitle,
       
  4732 				priority: 20,
       
  4733 				click:    function() {
       
  4734 					if ( previous ) {
       
  4735 						frame.setState( previous );
       
  4736 					} else {
       
  4737 						frame.close();
       
  4738 					}
       
  4739 
       
  4740 					// Move focus to the modal after canceling a Video Playlist.
       
  4741 					this.controller.modal.focusManager.focus();
       
  4742 				}
       
  4743 			},
       
  4744 			separateCancel: new wp.media.View({
       
  4745 				className: 'separator',
       
  4746 				priority: 40
       
  4747 			})
       
  4748 		});
       
  4749 	},
       
  4750 
       
  4751 	// Content.
       
  4752 	embedContent: function() {
       
  4753 		var view = new wp.media.view.Embed({
       
  4754 			controller: this,
       
  4755 			model:      this.state()
       
  4756 		}).render();
       
  4757 
       
  4758 		this.content.set( view );
       
  4759 	},
       
  4760 
       
  4761 	editSelectionContent: function() {
       
  4762 		var state = this.state(),
       
  4763 			selection = state.get('selection'),
       
  4764 			view;
       
  4765 
       
  4766 		view = new wp.media.view.AttachmentsBrowser({
       
  4767 			controller: this,
       
  4768 			collection: selection,
       
  4769 			selection:  selection,
       
  4770 			model:      state,
       
  4771 			sortable:   true,
       
  4772 			search:     false,
       
  4773 			date:       false,
       
  4774 			dragInfo:   true,
       
  4775 
       
  4776 			AttachmentView: wp.media.view.Attachments.EditSelection
       
  4777 		}).render();
       
  4778 
       
  4779 		view.toolbar.set( 'backToLibrary', {
       
  4780 			text:     l10n.returnToLibrary,
       
  4781 			priority: -100,
       
  4782 
       
  4783 			click: function() {
       
  4784 				this.controller.content.mode('browse');
       
  4785 				// Move focus to the modal when jumping back from Edit Selection to Add Media view.
       
  4786 				this.controller.modal.focusManager.focus();
       
  4787 			}
       
  4788 		});
       
  4789 
       
  4790 		// Browse our library of attachments.
       
  4791 		this.content.set( view );
       
  4792 
       
  4793 		// Trigger the controller to set focus.
       
  4794 		this.trigger( 'edit:selection', this );
       
  4795 	},
       
  4796 
       
  4797 	editImageContent: function() {
       
  4798 		var image = this.state().get('image'),
       
  4799 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
       
  4800 
       
  4801 		this.content.set( view );
       
  4802 
       
  4803 		// After creating the wrapper view, load the actual editor via an Ajax call.
       
  4804 		view.loadEditor();
       
  4805 
       
  4806 	},
       
  4807 
       
  4808 	// Toolbars.
       
  4809 
       
  4810 	/**
       
  4811 	 * @param {wp.Backbone.View} view
       
  4812 	 */
       
  4813 	selectionStatusToolbar: function( view ) {
       
  4814 		var editable = this.state().get('editable');
       
  4815 
       
  4816 		view.set( 'selection', new wp.media.view.Selection({
       
  4817 			controller: this,
       
  4818 			collection: this.state().get('selection'),
       
  4819 			priority:   -40,
       
  4820 
       
  4821 			// If the selection is editable, pass the callback to
       
  4822 			// switch the content mode.
       
  4823 			editable: editable && function() {
       
  4824 				this.controller.content.mode('edit-selection');
       
  4825 			}
       
  4826 		}).render() );
       
  4827 	},
       
  4828 
       
  4829 	/**
       
  4830 	 * @param {wp.Backbone.View} view
       
  4831 	 */
       
  4832 	mainInsertToolbar: function( view ) {
       
  4833 		var controller = this;
       
  4834 
       
  4835 		this.selectionStatusToolbar( view );
       
  4836 
       
  4837 		view.set( 'insert', {
       
  4838 			style:    'primary',
       
  4839 			priority: 80,
       
  4840 			text:     l10n.insertIntoPost,
       
  4841 			requires: { selection: true },
       
  4842 
       
  4843 			/**
       
  4844 			 * @ignore
       
  4845 			 *
       
  4846 			 * @fires wp.media.controller.State#insert
       
  4847 			 */
       
  4848 			click: function() {
       
  4849 				var state = controller.state(),
       
  4850 					selection = state.get('selection');
       
  4851 
       
  4852 				controller.close();
       
  4853 				state.trigger( 'insert', selection ).reset();
       
  4854 			}
       
  4855 		});
       
  4856 	},
       
  4857 
       
  4858 	/**
       
  4859 	 * @param {wp.Backbone.View} view
       
  4860 	 */
       
  4861 	mainGalleryToolbar: function( view ) {
       
  4862 		var controller = this;
       
  4863 
       
  4864 		this.selectionStatusToolbar( view );
       
  4865 
       
  4866 		view.set( 'gallery', {
       
  4867 			style:    'primary',
       
  4868 			text:     l10n.createNewGallery,
       
  4869 			priority: 60,
       
  4870 			requires: { selection: true },
       
  4871 
       
  4872 			click: function() {
       
  4873 				var selection = controller.state().get('selection'),
       
  4874 					edit = controller.state('gallery-edit'),
       
  4875 					models = selection.where({ type: 'image' });
       
  4876 
       
  4877 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  4878 					props:    selection.props.toJSON(),
       
  4879 					multiple: true
       
  4880 				}) );
       
  4881 
       
  4882 				// Jump to Edit Gallery view.
       
  4883 				this.controller.setState( 'gallery-edit' );
       
  4884 
       
  4885 				// Move focus to the modal after jumping to Edit Gallery view.
       
  4886 				this.controller.modal.focusManager.focus();
       
  4887 			}
       
  4888 		});
       
  4889 	},
       
  4890 
       
  4891 	mainPlaylistToolbar: function( view ) {
       
  4892 		var controller = this;
       
  4893 
       
  4894 		this.selectionStatusToolbar( view );
       
  4895 
       
  4896 		view.set( 'playlist', {
       
  4897 			style:    'primary',
       
  4898 			text:     l10n.createNewPlaylist,
       
  4899 			priority: 100,
       
  4900 			requires: { selection: true },
       
  4901 
       
  4902 			click: function() {
       
  4903 				var selection = controller.state().get('selection'),
       
  4904 					edit = controller.state('playlist-edit'),
       
  4905 					models = selection.where({ type: 'audio' });
       
  4906 
       
  4907 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  4908 					props:    selection.props.toJSON(),
       
  4909 					multiple: true
       
  4910 				}) );
       
  4911 
       
  4912 				// Jump to Edit Audio Playlist view.
       
  4913 				this.controller.setState( 'playlist-edit' );
       
  4914 
       
  4915 				// Move focus to the modal after jumping to Edit Audio Playlist view.
       
  4916 				this.controller.modal.focusManager.focus();
       
  4917 			}
       
  4918 		});
       
  4919 	},
       
  4920 
       
  4921 	mainVideoPlaylistToolbar: function( view ) {
       
  4922 		var controller = this;
       
  4923 
       
  4924 		this.selectionStatusToolbar( view );
       
  4925 
       
  4926 		view.set( 'video-playlist', {
       
  4927 			style:    'primary',
       
  4928 			text:     l10n.createNewVideoPlaylist,
       
  4929 			priority: 100,
       
  4930 			requires: { selection: true },
       
  4931 
       
  4932 			click: function() {
       
  4933 				var selection = controller.state().get('selection'),
       
  4934 					edit = controller.state('video-playlist-edit'),
       
  4935 					models = selection.where({ type: 'video' });
       
  4936 
       
  4937 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  4938 					props:    selection.props.toJSON(),
       
  4939 					multiple: true
       
  4940 				}) );
       
  4941 
       
  4942 				// Jump to Edit Video Playlist view.
       
  4943 				this.controller.setState( 'video-playlist-edit' );
       
  4944 
       
  4945 				// Move focus to the modal after jumping to Edit Video Playlist view.
       
  4946 				this.controller.modal.focusManager.focus();
       
  4947 			}
       
  4948 		});
       
  4949 	},
       
  4950 
       
  4951 	featuredImageToolbar: function( toolbar ) {
       
  4952 		this.createSelectToolbar( toolbar, {
       
  4953 			text:  l10n.setFeaturedImage,
       
  4954 			state: this.options.state
       
  4955 		});
       
  4956 	},
       
  4957 
       
  4958 	mainEmbedToolbar: function( toolbar ) {
       
  4959 		toolbar.view = new wp.media.view.Toolbar.Embed({
       
  4960 			controller: this
       
  4961 		});
       
  4962 	},
       
  4963 
       
  4964 	galleryEditToolbar: function() {
       
  4965 		var editing = this.state().get('editing');
       
  4966 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4967 			controller: this,
       
  4968 			items: {
       
  4969 				insert: {
       
  4970 					style:    'primary',
       
  4971 					text:     editing ? l10n.updateGallery : l10n.insertGallery,
       
  4972 					priority: 80,
       
  4973 					requires: { library: true, uploadingComplete: true },
       
  4974 
       
  4975 					/**
       
  4976 					 * @fires wp.media.controller.State#update
       
  4977 					 */
       
  4978 					click: function() {
       
  4979 						var controller = this.controller,
       
  4980 							state = controller.state();
       
  4981 
       
  4982 						controller.close();
       
  4983 						state.trigger( 'update', state.get('library') );
       
  4984 
       
  4985 						// Restore and reset the default state.
       
  4986 						controller.setState( controller.options.state );
       
  4987 						controller.reset();
       
  4988 					}
       
  4989 				}
       
  4990 			}
       
  4991 		}) );
       
  4992 	},
       
  4993 
       
  4994 	galleryAddToolbar: function() {
       
  4995 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4996 			controller: this,
       
  4997 			items: {
       
  4998 				insert: {
       
  4999 					style:    'primary',
       
  5000 					text:     l10n.addToGallery,
       
  5001 					priority: 80,
       
  5002 					requires: { selection: true },
       
  5003 
       
  5004 					/**
       
  5005 					 * @fires wp.media.controller.State#reset
       
  5006 					 */
       
  5007 					click: function() {
       
  5008 						var controller = this.controller,
       
  5009 							state = controller.state(),
       
  5010 							edit = controller.state('gallery-edit');
       
  5011 
       
  5012 						edit.get('library').add( state.get('selection').models );
       
  5013 						state.trigger('reset');
       
  5014 						controller.setState('gallery-edit');
       
  5015 						// Move focus to the modal when jumping back from Add to Gallery to Edit Gallery view.
       
  5016 						this.controller.modal.focusManager.focus();
       
  5017 					}
       
  5018 				}
       
  5019 			}
       
  5020 		}) );
       
  5021 	},
       
  5022 
       
  5023 	playlistEditToolbar: function() {
       
  5024 		var editing = this.state().get('editing');
       
  5025 		this.toolbar.set( new wp.media.view.Toolbar({
       
  5026 			controller: this,
       
  5027 			items: {
       
  5028 				insert: {
       
  5029 					style:    'primary',
       
  5030 					text:     editing ? l10n.updatePlaylist : l10n.insertPlaylist,
       
  5031 					priority: 80,
       
  5032 					requires: { library: true },
       
  5033 
       
  5034 					/**
       
  5035 					 * @fires wp.media.controller.State#update
       
  5036 					 */
       
  5037 					click: function() {
       
  5038 						var controller = this.controller,
       
  5039 							state = controller.state();
       
  5040 
       
  5041 						controller.close();
       
  5042 						state.trigger( 'update', state.get('library') );
       
  5043 
       
  5044 						// Restore and reset the default state.
       
  5045 						controller.setState( controller.options.state );
       
  5046 						controller.reset();
       
  5047 					}
       
  5048 				}
       
  5049 			}
       
  5050 		}) );
       
  5051 	},
       
  5052 
       
  5053 	playlistAddToolbar: function() {
       
  5054 		this.toolbar.set( new wp.media.view.Toolbar({
       
  5055 			controller: this,
       
  5056 			items: {
       
  5057 				insert: {
       
  5058 					style:    'primary',
       
  5059 					text:     l10n.addToPlaylist,
       
  5060 					priority: 80,
       
  5061 					requires: { selection: true },
       
  5062 
       
  5063 					/**
       
  5064 					 * @fires wp.media.controller.State#reset
       
  5065 					 */
       
  5066 					click: function() {
       
  5067 						var controller = this.controller,
       
  5068 							state = controller.state(),
       
  5069 							edit = controller.state('playlist-edit');
       
  5070 
       
  5071 						edit.get('library').add( state.get('selection').models );
       
  5072 						state.trigger('reset');
       
  5073 						controller.setState('playlist-edit');
       
  5074 						// Move focus to the modal when jumping back from Add to Audio Playlist to Edit Audio Playlist view.
       
  5075 						this.controller.modal.focusManager.focus();
       
  5076 					}
       
  5077 				}
       
  5078 			}
       
  5079 		}) );
       
  5080 	},
       
  5081 
       
  5082 	videoPlaylistEditToolbar: function() {
       
  5083 		var editing = this.state().get('editing');
       
  5084 		this.toolbar.set( new wp.media.view.Toolbar({
       
  5085 			controller: this,
       
  5086 			items: {
       
  5087 				insert: {
       
  5088 					style:    'primary',
       
  5089 					text:     editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
       
  5090 					priority: 140,
       
  5091 					requires: { library: true },
       
  5092 
       
  5093 					click: function() {
       
  5094 						var controller = this.controller,
       
  5095 							state = controller.state(),
       
  5096 							library = state.get('library');
       
  5097 
       
  5098 						library.type = 'video';
       
  5099 
       
  5100 						controller.close();
       
  5101 						state.trigger( 'update', library );
       
  5102 
       
  5103 						// Restore and reset the default state.
       
  5104 						controller.setState( controller.options.state );
       
  5105 						controller.reset();
       
  5106 					}
       
  5107 				}
       
  5108 			}
       
  5109 		}) );
       
  5110 	},
       
  5111 
       
  5112 	videoPlaylistAddToolbar: function() {
       
  5113 		this.toolbar.set( new wp.media.view.Toolbar({
       
  5114 			controller: this,
       
  5115 			items: {
       
  5116 				insert: {
       
  5117 					style:    'primary',
       
  5118 					text:     l10n.addToVideoPlaylist,
       
  5119 					priority: 140,
       
  5120 					requires: { selection: true },
       
  5121 
       
  5122 					click: function() {
       
  5123 						var controller = this.controller,
       
  5124 							state = controller.state(),
       
  5125 							edit = controller.state('video-playlist-edit');
       
  5126 
       
  5127 						edit.get('library').add( state.get('selection').models );
       
  5128 						state.trigger('reset');
       
  5129 						controller.setState('video-playlist-edit');
       
  5130 						// Move focus to the modal when jumping back from Add to Video Playlist to Edit Video Playlist view.
       
  5131 						this.controller.modal.focusManager.focus();
       
  5132 					}
       
  5133 				}
       
  5134 			}
       
  5135 		}) );
       
  5136 	}
       
  5137 });
       
  5138 
       
  5139 module.exports = Post;
       
  5140 
       
  5141 
       
  5142 /***/ }),
       
  5143 
       
  5144 /***/ 4338:
       
  5145 /***/ ((module) => {
       
  5146 
       
  5147 /**
       
  5148  * wp.media.view.Label
       
  5149  *
       
  5150  * @memberOf wp.media.view
       
  5151  *
       
  5152  * @class
       
  5153  * @augments wp.media.View
       
  5154  * @augments wp.Backbone.View
       
  5155  * @augments Backbone.View
       
  5156  */
       
  5157 var Label = wp.media.View.extend(/** @lends wp.media.view.Label.prototype */{
       
  5158 	tagName: 'label',
       
  5159 	className: 'screen-reader-text',
       
  5160 
       
  5161 	initialize: function() {
       
  5162 		this.value = this.options.value;
       
  5163 	},
       
  5164 
       
  5165 	render: function() {
       
  5166 		this.$el.html( this.value );
       
  5167 
       
  5168 		return this;
       
  5169 	}
       
  5170 });
       
  5171 
       
  5172 module.exports = Label;
       
  5173 
       
  5174 
       
  5175 /***/ }),
       
  5176 
       
  5177 /***/ 4593:
       
  5178 /***/ ((module) => {
       
  5179 
       
  5180 /**
       
  5181  * wp.media.view.Attachment.EditSelection
       
  5182  *
       
  5183  * @memberOf wp.media.view.Attachment
       
  5184  *
       
  5185  * @class
       
  5186  * @augments wp.media.view.Attachment.Selection
       
  5187  * @augments wp.media.view.Attachment
       
  5188  * @augments wp.media.View
       
  5189  * @augments wp.Backbone.View
       
  5190  * @augments Backbone.View
       
  5191  */
       
  5192 var EditSelection = wp.media.view.Attachment.Selection.extend(/** @lends wp.media.view.Attachment.EditSelection.prototype */{
       
  5193 	buttons: {
       
  5194 		close: true
       
  5195 	}
       
  5196 });
       
  5197 
       
  5198 module.exports = EditSelection;
       
  5199 
       
  5200 
       
  5201 /***/ }),
       
  5202 
       
  5203 /***/ 4747:
       
  5204 /***/ ((module) => {
       
  5205 
       
  5206 /**
       
  5207  * wp.media.View
       
  5208  *
       
  5209  * The base view class for media.
       
  5210  *
       
  5211  * Undelegating events, removing events from the model, and
       
  5212  * removing events from the controller mirror the code for
       
  5213  * `Backbone.View.dispose` in Backbone 0.9.8 development.
       
  5214  *
       
  5215  * This behavior has since been removed, and should not be used
       
  5216  * outside of the media manager.
       
  5217  *
       
  5218  * @memberOf wp.media
       
  5219  *
       
  5220  * @class
       
  5221  * @augments wp.Backbone.View
       
  5222  * @augments Backbone.View
       
  5223  */
       
  5224 var View = wp.Backbone.View.extend(/** @lends wp.media.View.prototype */{
       
  5225 	constructor: function( options ) {
       
  5226 		if ( options && options.controller ) {
       
  5227 			this.controller = options.controller;
       
  5228 		}
       
  5229 		wp.Backbone.View.apply( this, arguments );
       
  5230 	},
       
  5231 	/**
       
  5232 	 * @todo The internal comment mentions this might have been a stop-gap
       
  5233 	 *       before Backbone 0.9.8 came out. Figure out if Backbone core takes
       
  5234 	 *       care of this in Backbone.View now.
       
  5235 	 *
       
  5236 	 * @return {wp.media.View} Returns itself to allow chaining.
       
  5237 	 */
       
  5238 	dispose: function() {
       
  5239 		/*
       
  5240 		 * Undelegating events, removing events from the model, and
       
  5241 		 * removing events from the controller mirror the code for
       
  5242 		 * `Backbone.View.dispose` in Backbone 0.9.8 development.
       
  5243 		 */
       
  5244 		this.undelegateEvents();
       
  5245 
       
  5246 		if ( this.model && this.model.off ) {
       
  5247 			this.model.off( null, null, this );
       
  5248 		}
       
  5249 
       
  5250 		if ( this.collection && this.collection.off ) {
       
  5251 			this.collection.off( null, null, this );
       
  5252 		}
       
  5253 
       
  5254 		// Unbind controller events.
       
  5255 		if ( this.controller && this.controller.off ) {
       
  5256 			this.controller.off( null, null, this );
       
  5257 		}
       
  5258 
       
  5259 		return this;
       
  5260 	},
       
  5261 	/**
       
  5262 	 * @return {wp.media.View} Returns itself to allow chaining.
       
  5263 	 */
       
  5264 	remove: function() {
       
  5265 		this.dispose();
       
  5266 		/**
       
  5267 		 * call 'remove' directly on the parent class
       
  5268 		 */
       
  5269 		return wp.Backbone.View.prototype.remove.apply( this, arguments );
       
  5270 	}
       
  5271 });
       
  5272 
       
  5273 module.exports = View;
       
  5274 
       
  5275 
       
  5276 /***/ }),
       
  5277 
       
  5278 /***/ 4783:
       
  5279 /***/ ((module) => {
       
  5280 
       
  5281 var Menu = wp.media.view.Menu,
       
  5282 	Router;
       
  5283 
       
  5284 /**
       
  5285  * wp.media.view.Router
       
  5286  *
       
  5287  * @memberOf wp.media.view
       
  5288  *
       
  5289  * @class
       
  5290  * @augments wp.media.view.Menu
       
  5291  * @augments wp.media.view.PriorityList
       
  5292  * @augments wp.media.View
       
  5293  * @augments wp.Backbone.View
       
  5294  * @augments Backbone.View
       
  5295  */
       
  5296 Router = Menu.extend(/** @lends wp.media.view.Router.prototype */{
       
  5297 	tagName:   'div',
       
  5298 	className: 'media-router',
       
  5299 	property:  'contentMode',
       
  5300 	ItemView:  wp.media.view.RouterItem,
       
  5301 	region:    'router',
       
  5302 
       
  5303 	attributes: {
       
  5304 		role:               'tablist',
       
  5305 		'aria-orientation': 'horizontal'
       
  5306 	},
       
  5307 
       
  5308 	initialize: function() {
       
  5309 		this.controller.on( 'content:render', this.update, this );
       
  5310 		// Call 'initialize' directly on the parent class.
       
  5311 		Menu.prototype.initialize.apply( this, arguments );
       
  5312 	},
       
  5313 
       
  5314 	update: function() {
       
  5315 		var mode = this.controller.content.mode();
       
  5316 		if ( mode ) {
       
  5317 			this.select( mode );
       
  5318 		}
       
  5319 	}
       
  5320 });
       
  5321 
       
  5322 module.exports = Router;
       
  5323 
       
  5324 
       
  5325 /***/ }),
       
  5326 
       
  5327 /***/ 4910:
       
  5328 /***/ ((module) => {
       
  5329 
       
  5330 var l10n = wp.media.view.l10n,
       
  5331 	$ = Backbone.$,
       
  5332 	Embed;
       
  5333 
       
  5334 /**
       
  5335  * wp.media.controller.Embed
       
  5336  *
       
  5337  * A state for embedding media from a URL.
  1926  *
  5338  *
  1927  * @memberOf wp.media.controller
  5339  * @memberOf wp.media.controller
  1928  *
  5340  *
  1929  * @class
  5341  * @class
  1930  * @augments wp.media.controller.Cropper
  5342  * @augments wp.media.controller.State
       
  5343  * @augments Backbone.Model
       
  5344  *
       
  5345  * @param {object} attributes                         The attributes hash passed to the state.
       
  5346  * @param {string} [attributes.id=embed]              Unique identifier.
       
  5347  * @param {string} [attributes.title=Insert From URL] Title for the state. Displays in the media menu and the frame's title region.
       
  5348  * @param {string} [attributes.content=embed]         Initial mode for the content region.
       
  5349  * @param {string} [attributes.menu=default]          Initial mode for the menu region.
       
  5350  * @param {string} [attributes.toolbar=main-embed]    Initial mode for the toolbar region.
       
  5351  * @param {string} [attributes.menu=false]            Initial mode for the menu region.
       
  5352  * @param {int}    [attributes.priority=120]          The priority for the state link in the media menu.
       
  5353  * @param {string} [attributes.type=link]             The type of embed. Currently only link is supported.
       
  5354  * @param {string} [attributes.url]                   The embed URL.
       
  5355  * @param {object} [attributes.metadata={}]           Properties of the embed, which will override attributes.url if set.
       
  5356  */
       
  5357 Embed = wp.media.controller.State.extend(/** @lends wp.media.controller.Embed.prototype */{
       
  5358 	defaults: {
       
  5359 		id:       'embed',
       
  5360 		title:    l10n.insertFromUrlTitle,
       
  5361 		content:  'embed',
       
  5362 		menu:     'default',
       
  5363 		toolbar:  'main-embed',
       
  5364 		priority: 120,
       
  5365 		type:     'link',
       
  5366 		url:      '',
       
  5367 		metadata: {}
       
  5368 	},
       
  5369 
       
  5370 	// The amount of time used when debouncing the scan.
       
  5371 	sensitivity: 400,
       
  5372 
       
  5373 	initialize: function(options) {
       
  5374 		this.metadata = options.metadata;
       
  5375 		this.debouncedScan = _.debounce( _.bind( this.scan, this ), this.sensitivity );
       
  5376 		this.props = new Backbone.Model( this.metadata || { url: '' });
       
  5377 		this.props.on( 'change:url', this.debouncedScan, this );
       
  5378 		this.props.on( 'change:url', this.refresh, this );
       
  5379 		this.on( 'scan', this.scanImage, this );
       
  5380 	},
       
  5381 
       
  5382 	/**
       
  5383 	 * Trigger a scan of the embedded URL's content for metadata required to embed.
       
  5384 	 *
       
  5385 	 * @fires wp.media.controller.Embed#scan
       
  5386 	 */
       
  5387 	scan: function() {
       
  5388 		var scanners,
       
  5389 			embed = this,
       
  5390 			attributes = {
       
  5391 				type: 'link',
       
  5392 				scanners: []
       
  5393 			};
       
  5394 
       
  5395 		/*
       
  5396 		 * Scan is triggered with the list of `attributes` to set on the
       
  5397 		 * state, useful for the 'type' attribute and 'scanners' attribute,
       
  5398 		 * an array of promise objects for asynchronous scan operations.
       
  5399 		 */
       
  5400 		if ( this.props.get('url') ) {
       
  5401 			this.trigger( 'scan', attributes );
       
  5402 		}
       
  5403 
       
  5404 		if ( attributes.scanners.length ) {
       
  5405 			scanners = attributes.scanners = $.when.apply( $, attributes.scanners );
       
  5406 			scanners.always( function() {
       
  5407 				if ( embed.get('scanners') === scanners ) {
       
  5408 					embed.set( 'loading', false );
       
  5409 				}
       
  5410 			});
       
  5411 		} else {
       
  5412 			attributes.scanners = null;
       
  5413 		}
       
  5414 
       
  5415 		attributes.loading = !! attributes.scanners;
       
  5416 		this.set( attributes );
       
  5417 	},
       
  5418 	/**
       
  5419 	 * Try scanning the embed as an image to discover its dimensions.
       
  5420 	 *
       
  5421 	 * @param {Object} attributes
       
  5422 	 */
       
  5423 	scanImage: function( attributes ) {
       
  5424 		var frame = this.frame,
       
  5425 			state = this,
       
  5426 			url = this.props.get('url'),
       
  5427 			image = new Image(),
       
  5428 			deferred = $.Deferred();
       
  5429 
       
  5430 		attributes.scanners.push( deferred.promise() );
       
  5431 
       
  5432 		// Try to load the image and find its width/height.
       
  5433 		image.onload = function() {
       
  5434 			deferred.resolve();
       
  5435 
       
  5436 			if ( state !== frame.state() || url !== state.props.get('url') ) {
       
  5437 				return;
       
  5438 			}
       
  5439 
       
  5440 			state.set({
       
  5441 				type: 'image'
       
  5442 			});
       
  5443 
       
  5444 			state.props.set({
       
  5445 				width:  image.width,
       
  5446 				height: image.height
       
  5447 			});
       
  5448 		};
       
  5449 
       
  5450 		image.onerror = deferred.reject;
       
  5451 		image.src = url;
       
  5452 	},
       
  5453 
       
  5454 	refresh: function() {
       
  5455 		this.frame.toolbar.get().refresh();
       
  5456 	},
       
  5457 
       
  5458 	reset: function() {
       
  5459 		this.props.clear().set({ url: '' });
       
  5460 
       
  5461 		if ( this.active ) {
       
  5462 			this.refresh();
       
  5463 		}
       
  5464 	}
       
  5465 });
       
  5466 
       
  5467 module.exports = Embed;
       
  5468 
       
  5469 
       
  5470 /***/ }),
       
  5471 
       
  5472 /***/ 5232:
       
  5473 /***/ ((module) => {
       
  5474 
       
  5475 /**
       
  5476  * wp.media.view.Attachment.EditLibrary
       
  5477  *
       
  5478  * @memberOf wp.media.view.Attachment
       
  5479  *
       
  5480  * @class
       
  5481  * @augments wp.media.view.Attachment
       
  5482  * @augments wp.media.View
       
  5483  * @augments wp.Backbone.View
       
  5484  * @augments Backbone.View
       
  5485  */
       
  5486 var EditLibrary = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.EditLibrary.prototype */{
       
  5487 	buttons: {
       
  5488 		close: true
       
  5489 	}
       
  5490 });
       
  5491 
       
  5492 module.exports = EditLibrary;
       
  5493 
       
  5494 
       
  5495 /***/ }),
       
  5496 
       
  5497 /***/ 5275:
       
  5498 /***/ ((module) => {
       
  5499 
       
  5500 var View = wp.media.View,
       
  5501 	Toolbar;
       
  5502 
       
  5503 /**
       
  5504  * wp.media.view.Toolbar
       
  5505  *
       
  5506  * A toolbar which consists of a primary and a secondary section. Each sections
       
  5507  * can be filled with views.
       
  5508  *
       
  5509  * @memberOf wp.media.view
       
  5510  *
       
  5511  * @class
       
  5512  * @augments wp.media.View
       
  5513  * @augments wp.Backbone.View
       
  5514  * @augments Backbone.View
       
  5515  */
       
  5516 Toolbar = View.extend(/** @lends wp.media.view.Toolbar.prototype */{
       
  5517 	tagName:   'div',
       
  5518 	className: 'media-toolbar',
       
  5519 
       
  5520 	initialize: function() {
       
  5521 		var state = this.controller.state(),
       
  5522 			selection = this.selection = state.get('selection'),
       
  5523 			library = this.library = state.get('library');
       
  5524 
       
  5525 		this._views = {};
       
  5526 
       
  5527 		// The toolbar is composed of two `PriorityList` views.
       
  5528 		this.primary   = new wp.media.view.PriorityList();
       
  5529 		this.secondary = new wp.media.view.PriorityList();
       
  5530 		this.tertiary  = new wp.media.view.PriorityList();
       
  5531 		this.primary.$el.addClass('media-toolbar-primary search-form');
       
  5532 		this.secondary.$el.addClass('media-toolbar-secondary');
       
  5533 		this.tertiary.$el.addClass('media-bg-overlay');
       
  5534 
       
  5535 		this.views.set([ this.secondary, this.primary, this.tertiary ]);
       
  5536 
       
  5537 		if ( this.options.items ) {
       
  5538 			this.set( this.options.items, { silent: true });
       
  5539 		}
       
  5540 
       
  5541 		if ( ! this.options.silent ) {
       
  5542 			this.render();
       
  5543 		}
       
  5544 
       
  5545 		if ( selection ) {
       
  5546 			selection.on( 'add remove reset', this.refresh, this );
       
  5547 		}
       
  5548 
       
  5549 		if ( library ) {
       
  5550 			library.on( 'add remove reset', this.refresh, this );
       
  5551 		}
       
  5552 	},
       
  5553 	/**
       
  5554 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining
       
  5555 	 */
       
  5556 	dispose: function() {
       
  5557 		if ( this.selection ) {
       
  5558 			this.selection.off( null, null, this );
       
  5559 		}
       
  5560 
       
  5561 		if ( this.library ) {
       
  5562 			this.library.off( null, null, this );
       
  5563 		}
       
  5564 		/**
       
  5565 		 * call 'dispose' directly on the parent class
       
  5566 		 */
       
  5567 		return View.prototype.dispose.apply( this, arguments );
       
  5568 	},
       
  5569 
       
  5570 	ready: function() {
       
  5571 		this.refresh();
       
  5572 	},
       
  5573 
       
  5574 	/**
       
  5575 	 * @param {string} id
       
  5576 	 * @param {Backbone.View|Object} view
       
  5577 	 * @param {Object} [options={}]
       
  5578 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
       
  5579 	 */
       
  5580 	set: function( id, view, options ) {
       
  5581 		var list;
       
  5582 		options = options || {};
       
  5583 
       
  5584 		// Accept an object with an `id` : `view` mapping.
       
  5585 		if ( _.isObject( id ) ) {
       
  5586 			_.each( id, function( view, id ) {
       
  5587 				this.set( id, view, { silent: true });
       
  5588 			}, this );
       
  5589 
       
  5590 		} else {
       
  5591 			if ( ! ( view instanceof Backbone.View ) ) {
       
  5592 				view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
       
  5593 				view = new wp.media.view.Button( view ).render();
       
  5594 			}
       
  5595 
       
  5596 			view.controller = view.controller || this.controller;
       
  5597 
       
  5598 			this._views[ id ] = view;
       
  5599 
       
  5600 			list = view.options.priority < 0 ? 'secondary' : 'primary';
       
  5601 			this[ list ].set( id, view, options );
       
  5602 		}
       
  5603 
       
  5604 		if ( ! options.silent ) {
       
  5605 			this.refresh();
       
  5606 		}
       
  5607 
       
  5608 		return this;
       
  5609 	},
       
  5610 	/**
       
  5611 	 * @param {string} id
       
  5612 	 * @return {wp.media.view.Button}
       
  5613 	 */
       
  5614 	get: function( id ) {
       
  5615 		return this._views[ id ];
       
  5616 	},
       
  5617 	/**
       
  5618 	 * @param {string} id
       
  5619 	 * @param {Object} options
       
  5620 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
       
  5621 	 */
       
  5622 	unset: function( id, options ) {
       
  5623 		delete this._views[ id ];
       
  5624 		this.primary.unset( id, options );
       
  5625 		this.secondary.unset( id, options );
       
  5626 		this.tertiary.unset( id, options );
       
  5627 
       
  5628 		if ( ! options || ! options.silent ) {
       
  5629 			this.refresh();
       
  5630 		}
       
  5631 		return this;
       
  5632 	},
       
  5633 
       
  5634 	refresh: function() {
       
  5635 		var state = this.controller.state(),
       
  5636 			library = state.get('library'),
       
  5637 			selection = state.get('selection');
       
  5638 
       
  5639 		_.each( this._views, function( button ) {
       
  5640 			if ( ! button.model || ! button.options || ! button.options.requires ) {
       
  5641 				return;
       
  5642 			}
       
  5643 
       
  5644 			var requires = button.options.requires,
       
  5645 				disabled = false,
       
  5646 				modelsUploading = library && ! _.isEmpty( library.findWhere( { 'uploading': true } ) );
       
  5647 
       
  5648 			// Prevent insertion of attachments if any of them are still uploading.
       
  5649 			if ( selection && selection.models ) {
       
  5650 				disabled = _.some( selection.models, function( attachment ) {
       
  5651 					return attachment.get('uploading') === true;
       
  5652 				});
       
  5653 			}
       
  5654 			if ( requires.uploadingComplete && modelsUploading ) {
       
  5655 				disabled = true;
       
  5656 			}
       
  5657 
       
  5658 			if ( requires.selection && selection && ! selection.length ) {
       
  5659 				disabled = true;
       
  5660 			} else if ( requires.library && library && ! library.length ) {
       
  5661 				disabled = true;
       
  5662 			}
       
  5663 			button.model.set( 'disabled', disabled );
       
  5664 		});
       
  5665 	}
       
  5666 });
       
  5667 
       
  5668 module.exports = Toolbar;
       
  5669 
       
  5670 
       
  5671 /***/ }),
       
  5672 
       
  5673 /***/ 5422:
       
  5674 /***/ ((module) => {
       
  5675 
       
  5676 var l10n = wp.media.view.l10n,
       
  5677 	Cropper;
       
  5678 
       
  5679 /**
       
  5680  * wp.media.controller.Cropper
       
  5681  *
       
  5682  * A class for cropping an image when called from the header media customization panel.
       
  5683  *
       
  5684  * @memberOf wp.media.controller
       
  5685  *
       
  5686  * @class
  1931  * @augments wp.media.controller.State
  5687  * @augments wp.media.controller.State
  1932  * @augments Backbone.Model
  5688  * @augments Backbone.Model
  1933  */
  5689  */
  1934 SiteIconCropper = Controller.Cropper.extend(/** @lends wp.media.controller.SiteIconCropper.prototype */{
  5690 Cropper = wp.media.controller.State.extend(/** @lends wp.media.controller.Cropper.prototype */{
       
  5691 	defaults: {
       
  5692 		id:          'cropper',
       
  5693 		title:       l10n.cropImage,
       
  5694 		// Region mode defaults.
       
  5695 		toolbar:     'crop',
       
  5696 		content:     'crop',
       
  5697 		router:      false,
       
  5698 		canSkipCrop: false,
       
  5699 
       
  5700 		// Default doCrop Ajax arguments to allow the Customizer (for example) to inject state.
       
  5701 		doCropArgs: {}
       
  5702 	},
       
  5703 
       
  5704 	/**
       
  5705 	 * Shows the crop image window when called from the Add new image button.
       
  5706 	 *
       
  5707 	 * @since 4.2.0
       
  5708 	 *
       
  5709 	 * @return {void}
       
  5710 	 */
  1935 	activate: function() {
  5711 	activate: function() {
  1936 		this.frame.on( 'content:create:crop', this.createCropContent, this );
  5712 		this.frame.on( 'content:create:crop', this.createCropContent, this );
  1937 		this.frame.on( 'close', this.removeCropper, this );
  5713 		this.frame.on( 'close', this.removeCropper, this );
  1938 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
  5714 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
  1939 	},
  5715 	},
  1940 
  5716 
       
  5717 	/**
       
  5718 	 * Changes the state of the toolbar window to browse mode.
       
  5719 	 *
       
  5720 	 * @since 4.2.0
       
  5721 	 *
       
  5722 	 * @return {void}
       
  5723 	 */
       
  5724 	deactivate: function() {
       
  5725 		this.frame.toolbar.mode('browse');
       
  5726 	},
       
  5727 
       
  5728 	/**
       
  5729 	 * Creates the crop image window.
       
  5730 	 *
       
  5731 	 * Initialized when clicking on the Select and Crop button.
       
  5732 	 *
       
  5733 	 * @since 4.2.0
       
  5734 	 *
       
  5735 	 * @fires crop window
       
  5736 	 *
       
  5737 	 * @return {void}
       
  5738 	 */
  1941 	createCropContent: function() {
  5739 	createCropContent: function() {
  1942 		this.cropperView = new wp.media.view.SiteIconCropper({
  5740 		this.cropperView = new wp.media.view.Cropper({
  1943 			controller: this,
  5741 			controller: this,
  1944 			attachment: this.get('selection').first()
  5742 			attachment: this.get('selection').first()
  1945 		});
  5743 		});
  1946 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
  5744 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
  1947 		this.frame.content.set(this.cropperView);
  5745 		this.frame.content.set(this.cropperView);
  1948 
  5746 
  1949 	},
  5747 	},
  1950 
  5748 
       
  5749 	/**
       
  5750 	 * Removes the image selection and closes the cropping window.
       
  5751 	 *
       
  5752 	 * @since 4.2.0
       
  5753 	 *
       
  5754 	 * @return {void}
       
  5755 	 */
       
  5756 	removeCropper: function() {
       
  5757 		this.imgSelect.cancelSelection();
       
  5758 		this.imgSelect.setOptions({remove: true});
       
  5759 		this.imgSelect.update();
       
  5760 		this.cropperView.remove();
       
  5761 	},
       
  5762 
       
  5763 	/**
       
  5764 	 * Checks if cropping can be skipped and creates crop toolbar accordingly.
       
  5765 	 *
       
  5766 	 * @since 4.2.0
       
  5767 	 *
       
  5768 	 * @return {void}
       
  5769 	 */
       
  5770 	createCropToolbar: function() {
       
  5771 		var canSkipCrop, hasRequiredAspectRatio, suggestedCropSize, toolbarOptions;
       
  5772 
       
  5773 		suggestedCropSize      = this.get( 'suggestedCropSize' );
       
  5774 		hasRequiredAspectRatio = this.get( 'hasRequiredAspectRatio' );
       
  5775 		canSkipCrop            = this.get( 'canSkipCrop' ) || false;
       
  5776 
       
  5777 		toolbarOptions = {
       
  5778 			controller: this.frame,
       
  5779 			items: {
       
  5780 				insert: {
       
  5781 					style:    'primary',
       
  5782 					text:     l10n.cropImage,
       
  5783 					priority: 80,
       
  5784 					requires: { library: false, selection: false },
       
  5785 
       
  5786 					click: function() {
       
  5787 						var controller = this.controller,
       
  5788 							selection;
       
  5789 
       
  5790 						selection = controller.state().get('selection').first();
       
  5791 						selection.set({cropDetails: controller.state().imgSelect.getSelection()});
       
  5792 
       
  5793 						this.$el.text(l10n.cropping);
       
  5794 						this.$el.attr('disabled', true);
       
  5795 
       
  5796 						controller.state().doCrop( selection ).done( function( croppedImage ) {
       
  5797 							controller.trigger('cropped', croppedImage );
       
  5798 							controller.close();
       
  5799 						}).fail( function() {
       
  5800 							controller.trigger('content:error:crop');
       
  5801 						});
       
  5802 					}
       
  5803 				}
       
  5804 			}
       
  5805 		};
       
  5806 
       
  5807 		if ( canSkipCrop || hasRequiredAspectRatio ) {
       
  5808 			_.extend( toolbarOptions.items, {
       
  5809 				skip: {
       
  5810 					style:      'secondary',
       
  5811 					text:       l10n.skipCropping,
       
  5812 					priority:   70,
       
  5813 					requires:   { library: false, selection: false },
       
  5814 					click:      function() {
       
  5815 						var controller = this.controller,
       
  5816 							selection = controller.state().get( 'selection' ).first();
       
  5817 
       
  5818 						controller.state().cropperView.remove();
       
  5819 
       
  5820 						// Apply the suggested crop size.
       
  5821 						if ( hasRequiredAspectRatio && !canSkipCrop ) {
       
  5822 							selection.set({cropDetails: suggestedCropSize});
       
  5823 							controller.state().doCrop( selection ).done( function( croppedImage ) {
       
  5824 								controller.trigger( 'cropped', croppedImage );
       
  5825 								controller.close();
       
  5826 							}).fail( function() {
       
  5827 								controller.trigger( 'content:error:crop' );
       
  5828 							});
       
  5829 							return;
       
  5830 						}
       
  5831 
       
  5832 						// Skip the cropping process.
       
  5833 						controller.trigger( 'skippedcrop', selection );
       
  5834 						controller.close();
       
  5835 					}
       
  5836 				}
       
  5837 			});
       
  5838 		}
       
  5839 
       
  5840 		this.frame.toolbar.set( new wp.media.view.Toolbar(toolbarOptions) );
       
  5841 	},
       
  5842 
       
  5843 	/**
       
  5844 	 * Creates an object with the image attachment and crop properties.
       
  5845 	 *
       
  5846 	 * @since 4.2.0
       
  5847 	 *
       
  5848 	 * @return {$.promise} A jQuery promise with the custom header crop details.
       
  5849 	 */
  1951 	doCrop: function( attachment ) {
  5850 	doCrop: function( attachment ) {
  1952 		var cropDetails = attachment.get( 'cropDetails' ),
  5851 		return wp.ajax.post( 'custom-header-crop', _.extend(
  1953 			control = this.get( 'control' );
  5852 			{},
  1954 
  5853 			this.defaults.doCropArgs,
  1955 		cropDetails.dst_width  = control.params.width;
  5854 			{
  1956 		cropDetails.dst_height = control.params.height;
  5855 				nonce: attachment.get( 'nonces' ).edit,
  1957 
  5856 				id: attachment.get( 'id' ),
  1958 		return wp.ajax.post( 'crop-image', {
  5857 				cropDetails: attachment.get( 'cropDetails' )
  1959 			nonce: attachment.get( 'nonces' ).edit,
  5858 			}
  1960 			id: attachment.get( 'id' ),
  5859 		) );
  1961 			context: 'site-icon',
       
  1962 			cropDetails: cropDetails
       
  1963 		} );
       
  1964 	}
  5860 	}
  1965 });
  5861 });
  1966 
  5862 
  1967 module.exports = SiteIconCropper;
  5863 module.exports = Cropper;
  1968 
  5864 
  1969 
  5865 
  1970 /***/ }),
  5866 /***/ }),
  1971 
  5867 
  1972 /***/ 6150:
  5868 /***/ 5424:
  1973 /***/ ((module) => {
  5869 /***/ ((module) => {
  1974 
  5870 
       
  5871 var Select = wp.media.view.MediaFrame.Select,
       
  5872 	l10n = wp.media.view.l10n,
       
  5873 	ImageDetails;
       
  5874 
  1975 /**
  5875 /**
  1976  * wp.media.controller.StateMachine
  5876  * wp.media.view.MediaFrame.ImageDetails
  1977  *
  5877  *
  1978  * A state machine keeps track of state. It is in one state at a time,
  5878  * A media frame for manipulating an image that's already been inserted
  1979  * and can change from one state to another.
  5879  * into a post.
  1980  *
  5880  *
  1981  * States are stored as models in a Backbone collection.
  5881  * @memberOf wp.media.view.MediaFrame
       
  5882  *
       
  5883  * @class
       
  5884  * @augments wp.media.view.MediaFrame.Select
       
  5885  * @augments wp.media.view.MediaFrame
       
  5886  * @augments wp.media.view.Frame
       
  5887  * @augments wp.media.View
       
  5888  * @augments wp.Backbone.View
       
  5889  * @augments Backbone.View
       
  5890  * @mixes wp.media.controller.StateMachine
       
  5891  */
       
  5892 ImageDetails = Select.extend(/** @lends wp.media.view.MediaFrame.ImageDetails.prototype */{
       
  5893 	defaults: {
       
  5894 		id:      'image',
       
  5895 		url:     '',
       
  5896 		menu:    'image-details',
       
  5897 		content: 'image-details',
       
  5898 		toolbar: 'image-details',
       
  5899 		type:    'link',
       
  5900 		title:    l10n.imageDetailsTitle,
       
  5901 		priority: 120
       
  5902 	},
       
  5903 
       
  5904 	initialize: function( options ) {
       
  5905 		this.image = new wp.media.model.PostImage( options.metadata );
       
  5906 		this.options.selection = new wp.media.model.Selection( this.image.attachment, { multiple: false } );
       
  5907 		Select.prototype.initialize.apply( this, arguments );
       
  5908 	},
       
  5909 
       
  5910 	bindHandlers: function() {
       
  5911 		Select.prototype.bindHandlers.apply( this, arguments );
       
  5912 		this.on( 'menu:create:image-details', this.createMenu, this );
       
  5913 		this.on( 'content:create:image-details', this.imageDetailsContent, this );
       
  5914 		this.on( 'content:render:edit-image', this.editImageContent, this );
       
  5915 		this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
       
  5916 		// Override the select toolbar.
       
  5917 		this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
       
  5918 	},
       
  5919 
       
  5920 	createStates: function() {
       
  5921 		this.states.add([
       
  5922 			new wp.media.controller.ImageDetails({
       
  5923 				image: this.image,
       
  5924 				editable: false
       
  5925 			}),
       
  5926 			new wp.media.controller.ReplaceImage({
       
  5927 				id: 'replace-image',
       
  5928 				library: wp.media.query( { type: 'image' } ),
       
  5929 				image: this.image,
       
  5930 				multiple:  false,
       
  5931 				title:     l10n.imageReplaceTitle,
       
  5932 				toolbar: 'replace',
       
  5933 				priority:  80,
       
  5934 				displaySettings: true
       
  5935 			}),
       
  5936 			new wp.media.controller.EditImage( {
       
  5937 				image: this.image,
       
  5938 				selection: this.options.selection
       
  5939 			} )
       
  5940 		]);
       
  5941 	},
       
  5942 
       
  5943 	imageDetailsContent: function( options ) {
       
  5944 		options.view = new wp.media.view.ImageDetails({
       
  5945 			controller: this,
       
  5946 			model: this.state().image,
       
  5947 			attachment: this.state().image.attachment
       
  5948 		});
       
  5949 	},
       
  5950 
       
  5951 	editImageContent: function() {
       
  5952 		var state = this.state(),
       
  5953 			model = state.get('image'),
       
  5954 			view;
       
  5955 
       
  5956 		if ( ! model ) {
       
  5957 			return;
       
  5958 		}
       
  5959 
       
  5960 		view = new wp.media.view.EditImage( { model: model, controller: this } ).render();
       
  5961 
       
  5962 		this.content.set( view );
       
  5963 
       
  5964 		// After bringing in the frame, load the actual editor via an Ajax call.
       
  5965 		view.loadEditor();
       
  5966 
       
  5967 	},
       
  5968 
       
  5969 	renderImageDetailsToolbar: function() {
       
  5970 		this.toolbar.set( new wp.media.view.Toolbar({
       
  5971 			controller: this,
       
  5972 			items: {
       
  5973 				select: {
       
  5974 					style:    'primary',
       
  5975 					text:     l10n.update,
       
  5976 					priority: 80,
       
  5977 
       
  5978 					click: function() {
       
  5979 						var controller = this.controller,
       
  5980 							state = controller.state();
       
  5981 
       
  5982 						controller.close();
       
  5983 
       
  5984 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
       
  5985 						// perhaps wp.html.string to at least to build the <img />.
       
  5986 						state.trigger( 'update', controller.image.toJSON() );
       
  5987 
       
  5988 						// Restore and reset the default state.
       
  5989 						controller.setState( controller.options.state );
       
  5990 						controller.reset();
       
  5991 					}
       
  5992 				}
       
  5993 			}
       
  5994 		}) );
       
  5995 	},
       
  5996 
       
  5997 	renderReplaceImageToolbar: function() {
       
  5998 		var frame = this,
       
  5999 			lastState = frame.lastState(),
       
  6000 			previous = lastState && lastState.id;
       
  6001 
       
  6002 		this.toolbar.set( new wp.media.view.Toolbar({
       
  6003 			controller: this,
       
  6004 			items: {
       
  6005 				back: {
       
  6006 					text:     l10n.back,
       
  6007 					priority: 80,
       
  6008 					click:    function() {
       
  6009 						if ( previous ) {
       
  6010 							frame.setState( previous );
       
  6011 						} else {
       
  6012 							frame.close();
       
  6013 						}
       
  6014 					}
       
  6015 				},
       
  6016 
       
  6017 				replace: {
       
  6018 					style:    'primary',
       
  6019 					text:     l10n.replace,
       
  6020 					priority: 20,
       
  6021 					requires: { selection: true },
       
  6022 
       
  6023 					click: function() {
       
  6024 						var controller = this.controller,
       
  6025 							state = controller.state(),
       
  6026 							selection = state.get( 'selection' ),
       
  6027 							attachment = selection.single();
       
  6028 
       
  6029 						controller.close();
       
  6030 
       
  6031 						controller.image.changeAttachment( attachment, state.display( attachment ) );
       
  6032 
       
  6033 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
       
  6034 						// perhaps wp.html.string to at least to build the <img />.
       
  6035 						state.trigger( 'replace', controller.image.toJSON() );
       
  6036 
       
  6037 						// Restore and reset the default state.
       
  6038 						controller.setState( controller.options.state );
       
  6039 						controller.reset();
       
  6040 					}
       
  6041 				}
       
  6042 			}
       
  6043 		}) );
       
  6044 	}
       
  6045 
       
  6046 });
       
  6047 
       
  6048 module.exports = ImageDetails;
       
  6049 
       
  6050 
       
  6051 /***/ }),
       
  6052 
       
  6053 /***/ 5663:
       
  6054 /***/ ((module) => {
       
  6055 
       
  6056 var l10n = wp.media.view.l10n,
       
  6057 	EditImage;
       
  6058 
       
  6059 /**
       
  6060  * wp.media.controller.EditImage
       
  6061  *
       
  6062  * A state for editing (cropping, etc.) an image.
  1982  *
  6063  *
  1983  * @memberOf wp.media.controller
  6064  * @memberOf wp.media.controller
  1984  *
  6065  *
  1985  * @since 3.5.0
       
  1986  *
       
  1987  * @class
  6066  * @class
       
  6067  * @augments wp.media.controller.State
  1988  * @augments Backbone.Model
  6068  * @augments Backbone.Model
  1989  * @mixin
  6069  *
  1990  * @mixes Backbone.Events
  6070  * @param {object}                    attributes                      The attributes hash passed to the state.
       
  6071  * @param {wp.media.model.Attachment} attributes.model                The attachment.
       
  6072  * @param {string}                    [attributes.id=edit-image]      Unique identifier.
       
  6073  * @param {string}                    [attributes.title=Edit Image]   Title for the state. Displays in the media menu and the frame's title region.
       
  6074  * @param {string}                    [attributes.content=edit-image] Initial mode for the content region.
       
  6075  * @param {string}                    [attributes.toolbar=edit-image] Initial mode for the toolbar region.
       
  6076  * @param {string}                    [attributes.menu=false]         Initial mode for the menu region.
       
  6077  * @param {string}                    [attributes.url]                Unused. @todo Consider removal.
  1991  */
  6078  */
  1992 var StateMachine = function() {
  6079 EditImage = wp.media.controller.State.extend(/** @lends wp.media.controller.EditImage.prototype */{
  1993 	return {
  6080 	defaults: {
  1994 		// Use Backbone's self-propagating `extend` inheritance method.
  6081 		id:      'edit-image',
  1995 		extend: Backbone.Model.extend
  6082 		title:   l10n.editImage,
  1996 	};
  6083 		menu:    false,
  1997 };
  6084 		toolbar: 'edit-image',
  1998 
  6085 		content: 'edit-image',
  1999 _.extend( StateMachine.prototype, Backbone.Events,/** @lends wp.media.controller.StateMachine.prototype */{
  6086 		url:     ''
  2000 	/**
  6087 	},
  2001 	 * Fetch a state.
  6088 
  2002 	 *
  6089 	/**
  2003 	 * If no `id` is provided, returns the active state.
  6090 	 * Activates a frame for editing a featured image.
  2004 	 *
  6091 	 *
  2005 	 * Implicitly creates states.
  6092 	 * @since 3.9.0
  2006 	 *
  6093 	 *
  2007 	 * Ensure that the `states` collection exists so the `StateMachine`
  6094 	 * @return {void}
  2008 	 * can be used as a mixin.
  6095 	 */
  2009 	 *
  6096 	activate: function() {
  2010 	 * @since 3.5.0
  6097 		this.frame.on( 'toolbar:render:edit-image', _.bind( this.toolbar, this ) );
  2011 	 *
  6098 	},
  2012 	 * @param {string} id
  6099 
  2013 	 * @return {wp.media.controller.State} Returns a State model from
  6100 	/**
  2014 	 *                                     the StateMachine collection.
  6101 	 * Deactivates a frame for editing a featured image.
  2015 	 */
  6102 	 *
  2016 	state: function( id ) {
  6103 	 * @since 3.9.0
  2017 		this.states = this.states || new Backbone.Collection();
  6104 	 *
  2018 
  6105 	 * @return {void}
  2019 		// Default to the active state.
  6106 	 */
  2020 		id = id || this._state;
  6107 	deactivate: function() {
  2021 
  6108 		this.frame.off( 'toolbar:render:edit-image' );
  2022 		if ( id && ! this.states.get( id ) ) {
  6109 	},
  2023 			this.states.add({ id: id });
  6110 
  2024 		}
  6111 	/**
  2025 		return this.states.get( id );
  6112 	 * Adds a toolbar with a back button.
  2026 	},
  6113 	 *
  2027 
  6114 	 * When the back button is pressed it checks whether there is a previous state.
  2028 	/**
  6115 	 * In case there is a previous state it sets that previous state otherwise it
  2029 	 * Sets the active state.
  6116 	 * closes the frame.
  2030 	 *
  6117 	 *
  2031 	 * Bail if we're trying to select the current state, if we haven't
  6118 	 * @since 3.9.0
  2032 	 * created the `states` collection, or are trying to select a state
  6119 	 *
  2033 	 * that does not exist.
  6120 	 * @return {void}
  2034 	 *
  6121 	 */
  2035 	 * @since 3.5.0
  6122 	toolbar: function() {
  2036 	 *
  6123 		var frame = this.frame,
  2037 	 * @param {string} id
  6124 			lastState = frame.lastState(),
  2038 	 *
  6125 			previous = lastState && lastState.id;
  2039 	 * @fires wp.media.controller.State#deactivate
  6126 
  2040 	 * @fires wp.media.controller.State#activate
  6127 		frame.toolbar.set( new wp.media.view.Toolbar({
  2041 	 *
  6128 			controller: frame,
  2042 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
  6129 			items: {
  2043 	 */
  6130 				back: {
  2044 	setState: function( id ) {
  6131 					style: 'primary',
  2045 		var previous = this.state();
  6132 					text:     l10n.back,
  2046 
  6133 					priority: 20,
  2047 		if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) {
  6134 					click:    function() {
  2048 			return this;
  6135 						if ( previous ) {
  2049 		}
  6136 							frame.setState( previous );
  2050 
  6137 						} else {
  2051 		if ( previous ) {
  6138 							frame.close();
  2052 			previous.trigger('deactivate');
  6139 						}
  2053 			this._lastState = previous.id;
  6140 					}
  2054 		}
  6141 				}
  2055 
  6142 			}
  2056 		this._state = id;
  6143 		}) );
  2057 		this.state().trigger('activate');
       
  2058 
       
  2059 		return this;
       
  2060 	},
       
  2061 
       
  2062 	/**
       
  2063 	 * Returns the previous active state.
       
  2064 	 *
       
  2065 	 * Call the `state()` method with no parameters to retrieve the current
       
  2066 	 * active state.
       
  2067 	 *
       
  2068 	 * @since 3.5.0
       
  2069 	 *
       
  2070 	 * @return {wp.media.controller.State} Returns a State model from
       
  2071 	 *                                     the StateMachine collection.
       
  2072 	 */
       
  2073 	lastState: function() {
       
  2074 		if ( this._lastState ) {
       
  2075 			return this.state( this._lastState );
       
  2076 		}
       
  2077 	}
  6144 	}
  2078 });
  6145 });
  2079 
  6146 
  2080 // Map all event binding and triggering on a StateMachine to its `states` collection.
  6147 module.exports = EditImage;
  2081 _.each([ 'on', 'off', 'trigger' ], function( method ) {
       
  2082 	/**
       
  2083 	 * @function on
       
  2084 	 * @memberOf wp.media.controller.StateMachine
       
  2085 	 * @instance
       
  2086 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  2087 	 */
       
  2088 	/**
       
  2089 	 * @function off
       
  2090 	 * @memberOf wp.media.controller.StateMachine
       
  2091 	 * @instance
       
  2092 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  2093 	 */
       
  2094 	/**
       
  2095 	 * @function trigger
       
  2096 	 * @memberOf wp.media.controller.StateMachine
       
  2097 	 * @instance
       
  2098 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  2099 	 */
       
  2100 	StateMachine.prototype[ method ] = function() {
       
  2101 		// Ensure that the `states` collection exists so the `StateMachine`
       
  2102 		// can be used as a mixin.
       
  2103 		this.states = this.states || new Backbone.Collection();
       
  2104 		// Forward the method to the `states` collection.
       
  2105 		this.states[ method ].apply( this.states, arguments );
       
  2106 		return this;
       
  2107 	};
       
  2108 });
       
  2109 
       
  2110 module.exports = StateMachine;
       
  2111 
  6148 
  2112 
  6149 
  2113 /***/ }),
  6150 /***/ }),
  2114 
  6151 
  2115 /***/ 5694:
  6152 /***/ 5694:
  2365 module.exports = State;
  6402 module.exports = State;
  2366 
  6403 
  2367 
  6404 
  2368 /***/ }),
  6405 /***/ }),
  2369 
  6406 
  2370 /***/ 4181:
  6407 /***/ 5741:
  2371 /***/ ((module) => {
  6408 /***/ ((module) => {
  2372 
  6409 
  2373 /**
  6410 /**
  2374  * wp.media.selectionSync
  6411  * wp.media.view.Embed
  2375  *
       
  2376  * Sync an attachments selection in a state with another state.
       
  2377  *
       
  2378  * Allows for selecting multiple images in the Add Media workflow, and then
       
  2379  * switching to the Insert Gallery workflow while preserving the attachments selection.
       
  2380  *
       
  2381  * @memberOf wp.media
       
  2382  *
       
  2383  * @mixin
       
  2384  */
       
  2385 var selectionSync = {
       
  2386 	/**
       
  2387 	 * @since 3.5.0
       
  2388 	 */
       
  2389 	syncSelection: function() {
       
  2390 		var selection = this.get('selection'),
       
  2391 			manager = this.frame._selection;
       
  2392 
       
  2393 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
       
  2394 			return;
       
  2395 		}
       
  2396 
       
  2397 		/*
       
  2398 		 * If the selection supports multiple items, validate the stored
       
  2399 		 * attachments based on the new selection's conditions. Record
       
  2400 		 * the attachments that are not included; we'll maintain a
       
  2401 		 * reference to those. Other attachments are considered in flux.
       
  2402 		 */
       
  2403 		if ( selection.multiple ) {
       
  2404 			selection.reset( [], { silent: true });
       
  2405 			selection.validateAll( manager.attachments );
       
  2406 			manager.difference = _.difference( manager.attachments.models, selection.models );
       
  2407 		}
       
  2408 
       
  2409 		// Sync the selection's single item with the master.
       
  2410 		selection.single( manager.single );
       
  2411 	},
       
  2412 
       
  2413 	/**
       
  2414 	 * Record the currently active attachments, which is a combination
       
  2415 	 * of the selection's attachments and the set of selected
       
  2416 	 * attachments that this specific selection considered invalid.
       
  2417 	 * Reset the difference and record the single attachment.
       
  2418 	 *
       
  2419 	 * @since 3.5.0
       
  2420 	 */
       
  2421 	recordSelection: function() {
       
  2422 		var selection = this.get('selection'),
       
  2423 			manager = this.frame._selection;
       
  2424 
       
  2425 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
       
  2426 			return;
       
  2427 		}
       
  2428 
       
  2429 		if ( selection.multiple ) {
       
  2430 			manager.attachments.reset( selection.toArray().concat( manager.difference ) );
       
  2431 			manager.difference = [];
       
  2432 		} else {
       
  2433 			manager.attachments.add( selection.toArray() );
       
  2434 		}
       
  2435 
       
  2436 		manager.single = selection._single;
       
  2437 	}
       
  2438 };
       
  2439 
       
  2440 module.exports = selectionSync;
       
  2441 
       
  2442 
       
  2443 /***/ }),
       
  2444 
       
  2445 /***/ 2982:
       
  2446 /***/ ((module) => {
       
  2447 
       
  2448 var View = wp.media.View,
       
  2449 	AttachmentCompat;
       
  2450 
       
  2451 /**
       
  2452  * wp.media.view.AttachmentCompat
       
  2453  *
       
  2454  * A view to display fields added via the `attachment_fields_to_edit` filter.
       
  2455  *
  6412  *
  2456  * @memberOf wp.media.view
  6413  * @memberOf wp.media.view
  2457  *
  6414  *
  2458  * @class
  6415  * @class
  2459  * @augments wp.media.View
  6416  * @augments wp.media.View
  2460  * @augments wp.Backbone.View
  6417  * @augments wp.Backbone.View
  2461  * @augments Backbone.View
  6418  * @augments Backbone.View
  2462  */
  6419  */
  2463 AttachmentCompat = View.extend(/** @lends wp.media.view.AttachmentCompat.prototype */{
  6420 var Embed = wp.media.View.extend(/** @lends wp.media.view.Ember.prototype */{
  2464 	tagName:   'form',
  6421 	className: 'media-embed',
  2465 	className: 'compat-item',
       
  2466 
       
  2467 	events: {
       
  2468 		'submit':          'preventDefault',
       
  2469 		'change input':    'save',
       
  2470 		'change select':   'save',
       
  2471 		'change textarea': 'save'
       
  2472 	},
       
  2473 
  6422 
  2474 	initialize: function() {
  6423 	initialize: function() {
  2475 		// Render the view when a new item is added.
       
  2476 		this.listenTo( this.model, 'add', this.render );
       
  2477 	},
       
  2478 
       
  2479 	/**
       
  2480 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
       
  2481 	 */
       
  2482 	dispose: function() {
       
  2483 		if ( this.$(':focus').length ) {
       
  2484 			this.save();
       
  2485 		}
       
  2486 		/**
  6424 		/**
  2487 		 * call 'dispose' directly on the parent class
  6425 		 * @member {wp.media.view.EmbedUrl}
  2488 		 */
  6426 		 */
  2489 		return View.prototype.dispose.apply( this, arguments );
  6427 		this.url = new wp.media.view.EmbedUrl({
  2490 	},
  6428 			controller: this.controller,
  2491 	/**
  6429 			model:      this.model.props
  2492 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
  6430 		}).render();
  2493 	 */
  6431 
  2494 	render: function() {
  6432 		this.views.set([ this.url ]);
  2495 		var compat = this.model.get('compat');
  6433 		this.refresh();
  2496 		if ( ! compat || ! compat.item ) {
  6434 		this.listenTo( this.model, 'change:type', this.refresh );
       
  6435 		this.listenTo( this.model, 'change:loading', this.loading );
       
  6436 	},
       
  6437 
       
  6438 	/**
       
  6439 	 * @param {Object} view
       
  6440 	 */
       
  6441 	settings: function( view ) {
       
  6442 		if ( this._settings ) {
       
  6443 			this._settings.remove();
       
  6444 		}
       
  6445 		this._settings = view;
       
  6446 		this.views.add( view );
       
  6447 	},
       
  6448 
       
  6449 	refresh: function() {
       
  6450 		var type = this.model.get('type'),
       
  6451 			constructor;
       
  6452 
       
  6453 		if ( 'image' === type ) {
       
  6454 			constructor = wp.media.view.EmbedImage;
       
  6455 		} else if ( 'link' === type ) {
       
  6456 			constructor = wp.media.view.EmbedLink;
       
  6457 		} else {
  2497 			return;
  6458 			return;
  2498 		}
  6459 		}
  2499 
  6460 
  2500 		this.views.detach();
  6461 		this.settings( new constructor({
  2501 		this.$el.html( compat.item );
  6462 			controller: this.controller,
  2502 		this.views.render();
  6463 			model:      this.model.props,
  2503 		return this;
  6464 			priority:   40
  2504 	},
  6465 		}) );
  2505 	/**
  6466 	},
  2506 	 * @param {Object} event
  6467 
  2507 	 */
  6468 	loading: function() {
  2508 	preventDefault: function( event ) {
  6469 		this.$el.toggleClass( 'embed-loading', this.model.get('loading') );
  2509 		event.preventDefault();
       
  2510 	},
       
  2511 	/**
       
  2512 	 * @param {Object} event
       
  2513 	 */
       
  2514 	save: function( event ) {
       
  2515 		var data = {};
       
  2516 
       
  2517 		if ( event ) {
       
  2518 			event.preventDefault();
       
  2519 		}
       
  2520 
       
  2521 		_.each( this.$el.serializeArray(), function( pair ) {
       
  2522 			data[ pair.name ] = pair.value;
       
  2523 		});
       
  2524 
       
  2525 		this.controller.trigger( 'attachment:compat:waiting', ['waiting'] );
       
  2526 		this.model.saveCompat( data ).always( _.bind( this.postSave, this ) );
       
  2527 	},
       
  2528 
       
  2529 	postSave: function() {
       
  2530 		this.controller.trigger( 'attachment:compat:ready', ['ready'] );
       
  2531 	}
  6470 	}
  2532 });
  6471 });
  2533 
  6472 
  2534 module.exports = AttachmentCompat;
  6473 module.exports = Embed;
  2535 
  6474 
  2536 
  6475 
  2537 /***/ }),
  6476 /***/ }),
  2538 
  6477 
  2539 /***/ 7709:
  6478 /***/ 6090:
  2540 /***/ ((module) => {
  6479 /***/ ((module) => {
  2541 
  6480 
  2542 var $ = jQuery,
  6481 /* global ClipboardJS */
  2543 	AttachmentFilters;
  6482 var Attachment = wp.media.view.Attachment,
       
  6483 	l10n = wp.media.view.l10n,
       
  6484 	$ = jQuery,
       
  6485 	Details,
       
  6486 	__ = wp.i18n.__;
       
  6487 
       
  6488 Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototype */{
       
  6489 	tagName:   'div',
       
  6490 	className: 'attachment-details',
       
  6491 	template:  wp.template('attachment-details'),
       
  6492 
       
  6493 	/*
       
  6494 	 * Reset all the attributes inherited from Attachment including role=checkbox,
       
  6495 	 * tabindex, etc., as they are inappropriate for this view. See #47458 and [30483] / #30390.
       
  6496 	 */
       
  6497 	attributes: {},
       
  6498 
       
  6499 	events: {
       
  6500 		'change [data-setting]':          'updateSetting',
       
  6501 		'change [data-setting] input':    'updateSetting',
       
  6502 		'change [data-setting] select':   'updateSetting',
       
  6503 		'change [data-setting] textarea': 'updateSetting',
       
  6504 		'click .delete-attachment':       'deleteAttachment',
       
  6505 		'click .trash-attachment':        'trashAttachment',
       
  6506 		'click .untrash-attachment':      'untrashAttachment',
       
  6507 		'click .edit-attachment':         'editAttachment',
       
  6508 		'keydown':                        'toggleSelectionHandler'
       
  6509 	},
       
  6510 
       
  6511 	/**
       
  6512 	 * Copies the attachment URL to the clipboard.
       
  6513 	 *
       
  6514 	 * @since 5.5.0
       
  6515 	 *
       
  6516 	 * @param {MouseEvent} event A click event.
       
  6517 	 *
       
  6518 	 * @return {void}
       
  6519 	 */
       
  6520 	 copyAttachmentDetailsURLClipboard: function() {
       
  6521 		var clipboard = new ClipboardJS( '.copy-attachment-url' ),
       
  6522 			successTimeout;
       
  6523 
       
  6524 		clipboard.on( 'success', function( event ) {
       
  6525 			var triggerElement = $( event.trigger ),
       
  6526 				successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
       
  6527 
       
  6528 			// Clear the selection and move focus back to the trigger.
       
  6529 			event.clearSelection();
       
  6530 
       
  6531 			// Show success visual feedback.
       
  6532 			clearTimeout( successTimeout );
       
  6533 			successElement.removeClass( 'hidden' );
       
  6534 
       
  6535 			// Hide success visual feedback after 3 seconds since last success.
       
  6536 			successTimeout = setTimeout( function() {
       
  6537 				successElement.addClass( 'hidden' );
       
  6538 			}, 3000 );
       
  6539 
       
  6540 			// Handle success audible feedback.
       
  6541 			wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
       
  6542 		} );
       
  6543 	 },
       
  6544 
       
  6545 	/**
       
  6546 	 * Shows the details of an attachment.
       
  6547 	 *
       
  6548 	 * @since 3.5.0
       
  6549 	 *
       
  6550 	 * @constructs wp.media.view.Attachment.Details
       
  6551 	 * @augments wp.media.view.Attachment
       
  6552 	 *
       
  6553 	 * @return {void}
       
  6554 	 */
       
  6555 	initialize: function() {
       
  6556 		this.options = _.defaults( this.options, {
       
  6557 			rerenderOnModelChange: false
       
  6558 		});
       
  6559 
       
  6560 		// Call 'initialize' directly on the parent class.
       
  6561 		Attachment.prototype.initialize.apply( this, arguments );
       
  6562 
       
  6563 		this.copyAttachmentDetailsURLClipboard();
       
  6564 	},
       
  6565 
       
  6566 	/**
       
  6567 	 * Gets the focusable elements to move focus to.
       
  6568 	 *
       
  6569 	 * @since 5.3.0
       
  6570 	 */
       
  6571 	getFocusableElements: function() {
       
  6572 		var editedAttachment = $( 'li[data-id="' + this.model.id + '"]' );
       
  6573 
       
  6574 		this.previousAttachment = editedAttachment.prev();
       
  6575 		this.nextAttachment = editedAttachment.next();
       
  6576 	},
       
  6577 
       
  6578 	/**
       
  6579 	 * Moves focus to the previous or next attachment in the grid.
       
  6580 	 * Fallbacks to the upload button or media frame when there are no attachments.
       
  6581 	 *
       
  6582 	 * @since 5.3.0
       
  6583 	 */
       
  6584 	moveFocus: function() {
       
  6585 		if ( this.previousAttachment.length ) {
       
  6586 			this.previousAttachment.trigger( 'focus' );
       
  6587 			return;
       
  6588 		}
       
  6589 
       
  6590 		if ( this.nextAttachment.length ) {
       
  6591 			this.nextAttachment.trigger( 'focus' );
       
  6592 			return;
       
  6593 		}
       
  6594 
       
  6595 		// Fallback: move focus to the "Select Files" button in the media modal.
       
  6596 		if ( this.controller.uploader && this.controller.uploader.$browser ) {
       
  6597 			this.controller.uploader.$browser.trigger( 'focus' );
       
  6598 			return;
       
  6599 		}
       
  6600 
       
  6601 		// Last fallback.
       
  6602 		this.moveFocusToLastFallback();
       
  6603 	},
       
  6604 
       
  6605 	/**
       
  6606 	 * Moves focus to the media frame as last fallback.
       
  6607 	 *
       
  6608 	 * @since 5.3.0
       
  6609 	 */
       
  6610 	moveFocusToLastFallback: function() {
       
  6611 		// Last fallback: make the frame focusable and move focus to it.
       
  6612 		$( '.media-frame' )
       
  6613 			.attr( 'tabindex', '-1' )
       
  6614 			.trigger( 'focus' );
       
  6615 	},
       
  6616 
       
  6617 	/**
       
  6618 	 * Deletes an attachment.
       
  6619 	 *
       
  6620 	 * Deletes an attachment after asking for confirmation. After deletion,
       
  6621 	 * keeps focus in the modal.
       
  6622 	 *
       
  6623 	 * @since 3.5.0
       
  6624 	 *
       
  6625 	 * @param {MouseEvent} event A click event.
       
  6626 	 *
       
  6627 	 * @return {void}
       
  6628 	 */
       
  6629 	deleteAttachment: function( event ) {
       
  6630 		event.preventDefault();
       
  6631 
       
  6632 		this.getFocusableElements();
       
  6633 
       
  6634 		if ( window.confirm( l10n.warnDelete ) ) {
       
  6635 			this.model.destroy( {
       
  6636 				wait: true,
       
  6637 				error: function() {
       
  6638 					window.alert( l10n.errorDeleting );
       
  6639 				}
       
  6640 			} );
       
  6641 
       
  6642 			this.moveFocus();
       
  6643 		}
       
  6644 	},
       
  6645 
       
  6646 	/**
       
  6647 	 * Sets the Trash state on an attachment, or destroys the model itself.
       
  6648 	 *
       
  6649 	 * If the mediaTrash setting is set to true, trashes the attachment.
       
  6650 	 * Otherwise, the model itself is destroyed.
       
  6651 	 *
       
  6652 	 * @since 3.9.0
       
  6653 	 *
       
  6654 	 * @param {MouseEvent} event A click event.
       
  6655 	 *
       
  6656 	 * @return {void}
       
  6657 	 */
       
  6658 	trashAttachment: function( event ) {
       
  6659 		var library = this.controller.library,
       
  6660 			self = this;
       
  6661 		event.preventDefault();
       
  6662 
       
  6663 		this.getFocusableElements();
       
  6664 
       
  6665 		// When in the Media Library and the Media Trash is enabled.
       
  6666 		if ( wp.media.view.settings.mediaTrash &&
       
  6667 			'edit-metadata' === this.controller.content.mode() ) {
       
  6668 
       
  6669 			this.model.set( 'status', 'trash' );
       
  6670 			this.model.save().done( function() {
       
  6671 				library._requery( true );
       
  6672 				/*
       
  6673 				 * @todo We need to move focus back to the previous, next, or first
       
  6674 				 * attachment but the library gets re-queried and refreshed.
       
  6675 				 * Thus, the references to the previous attachments are lost.
       
  6676 				 * We need an alternate method.
       
  6677 				 */
       
  6678 				self.moveFocusToLastFallback();
       
  6679 			} );
       
  6680 		} else {
       
  6681 			this.model.destroy();
       
  6682 			this.moveFocus();
       
  6683 		}
       
  6684 	},
       
  6685 
       
  6686 	/**
       
  6687 	 * Untrashes an attachment.
       
  6688 	 *
       
  6689 	 * @since 4.0.0
       
  6690 	 *
       
  6691 	 * @param {MouseEvent} event A click event.
       
  6692 	 *
       
  6693 	 * @return {void}
       
  6694 	 */
       
  6695 	untrashAttachment: function( event ) {
       
  6696 		var library = this.controller.library;
       
  6697 		event.preventDefault();
       
  6698 
       
  6699 		this.model.set( 'status', 'inherit' );
       
  6700 		this.model.save().done( function() {
       
  6701 			library._requery( true );
       
  6702 		} );
       
  6703 	},
       
  6704 
       
  6705 	/**
       
  6706 	 * Opens the edit page for a specific attachment.
       
  6707 	 *
       
  6708 	 * @since 3.5.0
       
  6709 	 *
       
  6710 	 * @param {MouseEvent} event A click event.
       
  6711 	 *
       
  6712 	 * @return {void}
       
  6713 	 */
       
  6714 	editAttachment: function( event ) {
       
  6715 		var editState = this.controller.states.get( 'edit-image' );
       
  6716 		if ( window.imageEdit && editState ) {
       
  6717 			event.preventDefault();
       
  6718 
       
  6719 			editState.set( 'image', this.model );
       
  6720 			this.controller.setState( 'edit-image' );
       
  6721 		} else {
       
  6722 			this.$el.addClass('needs-refresh');
       
  6723 		}
       
  6724 	},
       
  6725 
       
  6726 	/**
       
  6727 	 * Triggers an event on the controller when reverse tabbing (shift+tab).
       
  6728 	 *
       
  6729 	 * This event can be used to make sure to move the focus correctly.
       
  6730 	 *
       
  6731 	 * @since 4.0.0
       
  6732 	 *
       
  6733 	 * @fires wp.media.controller.MediaLibrary#attachment:details:shift-tab
       
  6734 	 * @fires wp.media.controller.MediaLibrary#attachment:keydown:arrow
       
  6735 	 *
       
  6736 	 * @param {KeyboardEvent} event A keyboard event.
       
  6737 	 *
       
  6738 	 * @return {boolean|void} Returns false or undefined.
       
  6739 	 */
       
  6740 	toggleSelectionHandler: function( event ) {
       
  6741 		if ( 'keydown' === event.type && 9 === event.keyCode && event.shiftKey && event.target === this.$( ':tabbable' ).get( 0 ) ) {
       
  6742 			this.controller.trigger( 'attachment:details:shift-tab', event );
       
  6743 			return false;
       
  6744 		}
       
  6745 	},
       
  6746 
       
  6747 	render: function() {
       
  6748 		Attachment.prototype.render.apply( this, arguments );
       
  6749 
       
  6750 		wp.media.mixin.removeAllPlayers();
       
  6751 		this.$( 'audio, video' ).each( function (i, elem) {
       
  6752 			var el = wp.media.view.MediaDetails.prepareSrc( elem );
       
  6753 			new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings );
       
  6754 		} );
       
  6755 	}
       
  6756 });
       
  6757 
       
  6758 module.exports = Details;
       
  6759 
       
  6760 
       
  6761 /***/ }),
       
  6762 
       
  6763 /***/ 6126:
       
  6764 /***/ ((module) => {
       
  6765 
       
  6766 var View = wp.media.View,
       
  6767 	EditImage;
  2544 
  6768 
  2545 /**
  6769 /**
  2546  * wp.media.view.AttachmentFilters
  6770  * wp.media.view.EditImage
  2547  *
  6771  *
  2548  * @memberOf wp.media.view
  6772  * @memberOf wp.media.view
  2549  *
  6773  *
  2550  * @class
  6774  * @class
  2551  * @augments wp.media.View
  6775  * @augments wp.media.View
  2552  * @augments wp.Backbone.View
  6776  * @augments wp.Backbone.View
  2553  * @augments Backbone.View
  6777  * @augments Backbone.View
  2554  */
  6778  */
  2555 AttachmentFilters = wp.media.View.extend(/** @lends wp.media.view.AttachmentFilters.prototype */{
  6779 EditImage = View.extend(/** @lends wp.media.view.EditImage.prototype */{
  2556 	tagName:   'select',
  6780 	className: 'image-editor',
  2557 	className: 'attachment-filters',
  6781 	template: wp.template('image-editor'),
  2558 	id:        'media-attachment-filters',
  6782 
  2559 
  6783 	initialize: function( options ) {
  2560 	events: {
  6784 		this.editor = window.imageEdit;
  2561 		change: 'change'
  6785 		this.controller = options.controller;
  2562 	},
  6786 		View.prototype.initialize.apply( this, arguments );
  2563 
  6787 	},
  2564 	keys: [],
  6788 
  2565 
  6789 	prepare: function() {
  2566 	initialize: function() {
  6790 		return this.model.toJSON();
  2567 		this.createFilters();
  6791 	},
  2568 		_.extend( this.filters, this.options.filters );
  6792 
  2569 
  6793 	loadEditor: function() {
  2570 		// Build `<option>` elements.
  6794 		this.editor.open( this.model.get( 'id' ), this.model.get( 'nonces' ).edit, this );
  2571 		this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
  6795 	},
  2572 			return {
  6796 
  2573 				el: $( '<option></option>' ).val( value ).html( filter.text )[0],
  6797 	back: function() {
  2574 				priority: filter.priority || 50
  6798 		var lastState = this.controller.lastState();
  2575 			};
  6799 		this.controller.setState( lastState );
  2576 		}, this ).sortBy('priority').pluck('el').value() );
  6800 	},
  2577 
  6801 
  2578 		this.listenTo( this.model, 'change', this.select );
  6802 	refresh: function() {
  2579 		this.select();
  6803 		this.model.fetch();
  2580 	},
  6804 	},
  2581 
  6805 
  2582 	/**
  6806 	save: function() {
  2583 	 * @abstract
  6807 		var lastState = this.controller.lastState();
  2584 	 */
  6808 
  2585 	createFilters: function() {
  6809 		this.model.fetch().done( _.bind( function() {
  2586 		this.filters = {};
  6810 			this.controller.setState( lastState );
  2587 	},
  6811 		}, this ) );
  2588 
  6812 	}
  2589 	/**
  6813 
  2590 	 * When the selected filter changes, update the Attachment Query properties to match.
  6814 });
  2591 	 */
  6815 
  2592 	change: function() {
  6816 module.exports = EditImage;
  2593 		var filter = this.filters[ this.el.value ];
  6817 
  2594 		if ( filter ) {
  6818 
  2595 			this.model.set( filter.props );
  6819 /***/ }),
  2596 		}
  6820 
  2597 	},
  6821 /***/ 6150:
  2598 
  6822 /***/ ((module) => {
  2599 	select: function() {
  6823 
  2600 		var model = this.model,
  6824 /**
  2601 			value = 'all',
  6825  * wp.media.controller.StateMachine
  2602 			props = model.toJSON();
  6826  *
  2603 
  6827  * A state machine keeps track of state. It is in one state at a time,
  2604 		_.find( this.filters, function( filter, id ) {
  6828  * and can change from one state to another.
  2605 			var equal = _.all( filter.props, function( prop, key ) {
  6829  *
  2606 				return prop === ( _.isUndefined( props[ key ] ) ? null : props[ key ] );
  6830  * States are stored as models in a Backbone collection.
  2607 			});
  6831  *
  2608 
  6832  * @memberOf wp.media.controller
  2609 			if ( equal ) {
  6833  *
  2610 				return value = id;
  6834  * @since 3.5.0
  2611 			}
  6835  *
  2612 		});
  6836  * @class
  2613 
  6837  * @augments Backbone.Model
  2614 		this.$el.val( value );
  6838  * @mixin
       
  6839  * @mixes Backbone.Events
       
  6840  */
       
  6841 var StateMachine = function() {
       
  6842 	return {
       
  6843 		// Use Backbone's self-propagating `extend` inheritance method.
       
  6844 		extend: Backbone.Model.extend
       
  6845 	};
       
  6846 };
       
  6847 
       
  6848 _.extend( StateMachine.prototype, Backbone.Events,/** @lends wp.media.controller.StateMachine.prototype */{
       
  6849 	/**
       
  6850 	 * Fetch a state.
       
  6851 	 *
       
  6852 	 * If no `id` is provided, returns the active state.
       
  6853 	 *
       
  6854 	 * Implicitly creates states.
       
  6855 	 *
       
  6856 	 * Ensure that the `states` collection exists so the `StateMachine`
       
  6857 	 * can be used as a mixin.
       
  6858 	 *
       
  6859 	 * @since 3.5.0
       
  6860 	 *
       
  6861 	 * @param {string} id
       
  6862 	 * @return {wp.media.controller.State} Returns a State model from
       
  6863 	 *                                     the StateMachine collection.
       
  6864 	 */
       
  6865 	state: function( id ) {
       
  6866 		this.states = this.states || new Backbone.Collection();
       
  6867 
       
  6868 		// Default to the active state.
       
  6869 		id = id || this._state;
       
  6870 
       
  6871 		if ( id && ! this.states.get( id ) ) {
       
  6872 			this.states.add({ id: id });
       
  6873 		}
       
  6874 		return this.states.get( id );
       
  6875 	},
       
  6876 
       
  6877 	/**
       
  6878 	 * Sets the active state.
       
  6879 	 *
       
  6880 	 * Bail if we're trying to select the current state, if we haven't
       
  6881 	 * created the `states` collection, or are trying to select a state
       
  6882 	 * that does not exist.
       
  6883 	 *
       
  6884 	 * @since 3.5.0
       
  6885 	 *
       
  6886 	 * @param {string} id
       
  6887 	 *
       
  6888 	 * @fires wp.media.controller.State#deactivate
       
  6889 	 * @fires wp.media.controller.State#activate
       
  6890 	 *
       
  6891 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  6892 	 */
       
  6893 	setState: function( id ) {
       
  6894 		var previous = this.state();
       
  6895 
       
  6896 		if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) {
       
  6897 			return this;
       
  6898 		}
       
  6899 
       
  6900 		if ( previous ) {
       
  6901 			previous.trigger('deactivate');
       
  6902 			this._lastState = previous.id;
       
  6903 		}
       
  6904 
       
  6905 		this._state = id;
       
  6906 		this.state().trigger('activate');
       
  6907 
       
  6908 		return this;
       
  6909 	},
       
  6910 
       
  6911 	/**
       
  6912 	 * Returns the previous active state.
       
  6913 	 *
       
  6914 	 * Call the `state()` method with no parameters to retrieve the current
       
  6915 	 * active state.
       
  6916 	 *
       
  6917 	 * @since 3.5.0
       
  6918 	 *
       
  6919 	 * @return {wp.media.controller.State} Returns a State model from
       
  6920 	 *                                     the StateMachine collection.
       
  6921 	 */
       
  6922 	lastState: function() {
       
  6923 		if ( this._lastState ) {
       
  6924 			return this.state( this._lastState );
       
  6925 		}
  2615 	}
  6926 	}
  2616 });
  6927 });
  2617 
  6928 
  2618 module.exports = AttachmentFilters;
  6929 // Map all event binding and triggering on a StateMachine to its `states` collection.
       
  6930 _.each([ 'on', 'off', 'trigger' ], function( method ) {
       
  6931 	/**
       
  6932 	 * @function on
       
  6933 	 * @memberOf wp.media.controller.StateMachine
       
  6934 	 * @instance
       
  6935 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  6936 	 */
       
  6937 	/**
       
  6938 	 * @function off
       
  6939 	 * @memberOf wp.media.controller.StateMachine
       
  6940 	 * @instance
       
  6941 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  6942 	 */
       
  6943 	/**
       
  6944 	 * @function trigger
       
  6945 	 * @memberOf wp.media.controller.StateMachine
       
  6946 	 * @instance
       
  6947 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  6948 	 */
       
  6949 	StateMachine.prototype[ method ] = function() {
       
  6950 		// Ensure that the `states` collection exists so the `StateMachine`
       
  6951 		// can be used as a mixin.
       
  6952 		this.states = this.states || new Backbone.Collection();
       
  6953 		// Forward the method to the `states` collection.
       
  6954 		this.states[ method ].apply( this.states, arguments );
       
  6955 		return this;
       
  6956 	};
       
  6957 });
       
  6958 
       
  6959 module.exports = StateMachine;
  2619 
  6960 
  2620 
  6961 
  2621 /***/ }),
  6962 /***/ }),
  2622 
  6963 
  2623 /***/ 7349:
  6964 /***/ 6172:
  2624 /***/ ((module) => {
  6965 /***/ ((module) => {
  2625 
  6966 
  2626 var l10n = wp.media.view.l10n,
  6967 var Controller = wp.media.controller,
  2627 	All;
  6968 	SiteIconCropper;
  2628 
  6969 
  2629 /**
  6970 /**
  2630  * wp.media.view.AttachmentFilters.All
  6971  * wp.media.controller.SiteIconCropper
  2631  *
  6972  *
  2632  * @memberOf wp.media.view.AttachmentFilters
  6973  * A state for cropping a Site Icon.
       
  6974  *
       
  6975  * @memberOf wp.media.controller
  2633  *
  6976  *
  2634  * @class
  6977  * @class
  2635  * @augments wp.media.view.AttachmentFilters
  6978  * @augments wp.media.controller.Cropper
       
  6979  * @augments wp.media.controller.State
       
  6980  * @augments Backbone.Model
       
  6981  */
       
  6982 SiteIconCropper = Controller.Cropper.extend(/** @lends wp.media.controller.SiteIconCropper.prototype */{
       
  6983 	activate: function() {
       
  6984 		this.frame.on( 'content:create:crop', this.createCropContent, this );
       
  6985 		this.frame.on( 'close', this.removeCropper, this );
       
  6986 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
       
  6987 	},
       
  6988 
       
  6989 	createCropContent: function() {
       
  6990 		this.cropperView = new wp.media.view.SiteIconCropper({
       
  6991 			controller: this,
       
  6992 			attachment: this.get('selection').first()
       
  6993 		});
       
  6994 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
       
  6995 		this.frame.content.set(this.cropperView);
       
  6996 
       
  6997 	},
       
  6998 
       
  6999 	doCrop: function( attachment ) {
       
  7000 		var cropDetails = attachment.get( 'cropDetails' ),
       
  7001 			control = this.get( 'control' );
       
  7002 
       
  7003 		cropDetails.dst_width  = control.params.width;
       
  7004 		cropDetails.dst_height = control.params.height;
       
  7005 
       
  7006 		return wp.ajax.post( 'crop-image', {
       
  7007 			nonce: attachment.get( 'nonces' ).edit,
       
  7008 			id: attachment.get( 'id' ),
       
  7009 			context: 'site-icon',
       
  7010 			cropDetails: cropDetails
       
  7011 		} );
       
  7012 	}
       
  7013 });
       
  7014 
       
  7015 module.exports = SiteIconCropper;
       
  7016 
       
  7017 
       
  7018 /***/ }),
       
  7019 
       
  7020 /***/ 6327:
       
  7021 /***/ ((module) => {
       
  7022 
       
  7023 /**
       
  7024  * wp.media.view.RouterItem
       
  7025  *
       
  7026  * @memberOf wp.media.view
       
  7027  *
       
  7028  * @class
       
  7029  * @augments wp.media.view.MenuItem
  2636  * @augments wp.media.View
  7030  * @augments wp.media.View
  2637  * @augments wp.Backbone.View
  7031  * @augments wp.Backbone.View
  2638  * @augments Backbone.View
  7032  * @augments Backbone.View
  2639  */
  7033  */
  2640 All = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.All.prototype */{
  7034 var RouterItem = wp.media.view.MenuItem.extend(/** @lends wp.media.view.RouterItem.prototype */{
  2641 	createFilters: function() {
  7035 	/**
  2642 		var filters = {},
  7036 	 * On click handler to activate the content region's corresponding mode.
  2643 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0;
  7037 	 */
  2644 
  7038 	click: function() {
  2645 		_.each( wp.media.view.settings.mimeTypes || {}, function( text, key ) {
  7039 		var contentMode = this.options.contentMode;
  2646 			filters[ key ] = {
  7040 		if ( contentMode ) {
  2647 				text: text,
  7041 			this.controller.content.mode( contentMode );
  2648 				props: {
  7042 		}
  2649 					status:  null,
       
  2650 					type:    key,
       
  2651 					uploadedTo: null,
       
  2652 					orderby: 'date',
       
  2653 					order:   'DESC',
       
  2654 					author:  null
       
  2655 				}
       
  2656 			};
       
  2657 		});
       
  2658 
       
  2659 		filters.all = {
       
  2660 			text:  l10n.allMediaItems,
       
  2661 			props: {
       
  2662 				status:  null,
       
  2663 				type:    null,
       
  2664 				uploadedTo: null,
       
  2665 				orderby: 'date',
       
  2666 				order:   'DESC',
       
  2667 				author:  null
       
  2668 			},
       
  2669 			priority: 10
       
  2670 		};
       
  2671 
       
  2672 		if ( wp.media.view.settings.post.id ) {
       
  2673 			filters.uploaded = {
       
  2674 				text:  l10n.uploadedToThisPost,
       
  2675 				props: {
       
  2676 					status:  null,
       
  2677 					type:    null,
       
  2678 					uploadedTo: wp.media.view.settings.post.id,
       
  2679 					orderby: 'menuOrder',
       
  2680 					order:   'ASC',
       
  2681 					author:  null
       
  2682 				},
       
  2683 				priority: 20
       
  2684 			};
       
  2685 		}
       
  2686 
       
  2687 		filters.unattached = {
       
  2688 			text:  l10n.unattached,
       
  2689 			props: {
       
  2690 				status:     null,
       
  2691 				uploadedTo: 0,
       
  2692 				type:       null,
       
  2693 				orderby:    'menuOrder',
       
  2694 				order:      'ASC',
       
  2695 				author:     null
       
  2696 			},
       
  2697 			priority: 50
       
  2698 		};
       
  2699 
       
  2700 		if ( uid ) {
       
  2701 			filters.mine = {
       
  2702 				text:  l10n.mine,
       
  2703 				props: {
       
  2704 					status:		null,
       
  2705 					type:		null,
       
  2706 					uploadedTo:	null,
       
  2707 					orderby:	'date',
       
  2708 					order:		'DESC',
       
  2709 					author:		uid
       
  2710 				},
       
  2711 				priority: 50
       
  2712 			};
       
  2713 		}
       
  2714 
       
  2715 		if ( wp.media.view.settings.mediaTrash &&
       
  2716 			this.controller.isModeActive( 'grid' ) ) {
       
  2717 
       
  2718 			filters.trash = {
       
  2719 				text:  l10n.trash,
       
  2720 				props: {
       
  2721 					uploadedTo: null,
       
  2722 					status:     'trash',
       
  2723 					type:       null,
       
  2724 					orderby:    'date',
       
  2725 					order:      'DESC',
       
  2726 					author:     null
       
  2727 				},
       
  2728 				priority: 50
       
  2729 			};
       
  2730 		}
       
  2731 
       
  2732 		this.filters = filters;
       
  2733 	}
  7043 	}
  2734 });
  7044 });
  2735 
  7045 
  2736 module.exports = All;
  7046 module.exports = RouterItem;
       
  7047 
       
  7048 
       
  7049 /***/ }),
       
  7050 
       
  7051 /***/ 6442:
       
  7052 /***/ ((module) => {
       
  7053 
       
  7054 /**
       
  7055  * wp.media.view.UploaderStatusError
       
  7056  *
       
  7057  * @memberOf wp.media.view
       
  7058  *
       
  7059  * @class
       
  7060  * @augments wp.media.View
       
  7061  * @augments wp.Backbone.View
       
  7062  * @augments Backbone.View
       
  7063  */
       
  7064 var UploaderStatusError = wp.media.View.extend(/** @lends wp.media.view.UploaderStatusError.prototype */{
       
  7065 	className: 'upload-error',
       
  7066 	template:  wp.template('uploader-status-error')
       
  7067 });
       
  7068 
       
  7069 module.exports = UploaderStatusError;
  2737 
  7070 
  2738 
  7071 
  2739 /***/ }),
  7072 /***/ }),
  2740 
  7073 
  2741 /***/ 6472:
  7074 /***/ 6472:
  2784 module.exports = DateFilter;
  7117 module.exports = DateFilter;
  2785 
  7118 
  2786 
  7119 
  2787 /***/ }),
  7120 /***/ }),
  2788 
  7121 
  2789 /***/ 1368:
  7122 /***/ 6829:
  2790 /***/ ((module) => {
  7123 /***/ ((module) => {
  2791 
  7124 
       
  7125 var View = wp.media.View,
       
  7126 	mediaTrash = wp.media.view.settings.mediaTrash,
       
  7127 	l10n = wp.media.view.l10n,
       
  7128 	$ = jQuery,
       
  7129 	AttachmentsBrowser,
       
  7130 	infiniteScrolling = wp.media.view.settings.infiniteScrolling,
       
  7131 	__ = wp.i18n.__,
       
  7132 	sprintf = wp.i18n.sprintf;
       
  7133 
       
  7134 /**
       
  7135  * wp.media.view.AttachmentsBrowser
       
  7136  *
       
  7137  * @memberOf wp.media.view
       
  7138  *
       
  7139  * @class
       
  7140  * @augments wp.media.View
       
  7141  * @augments wp.Backbone.View
       
  7142  * @augments Backbone.View
       
  7143  *
       
  7144  * @param {object}         [options]               The options hash passed to the view.
       
  7145  * @param {boolean|string} [options.filters=false] Which filters to show in the browser's toolbar.
       
  7146  *                                                 Accepts 'uploaded' and 'all'.
       
  7147  * @param {boolean}        [options.search=true]   Whether to show the search interface in the
       
  7148  *                                                 browser's toolbar.
       
  7149  * @param {boolean}        [options.date=true]     Whether to show the date filter in the
       
  7150  *                                                 browser's toolbar.
       
  7151  * @param {boolean}        [options.display=false] Whether to show the attachments display settings
       
  7152  *                                                 view in the sidebar.
       
  7153  * @param {boolean|string} [options.sidebar=true]  Whether to create a sidebar for the browser.
       
  7154  *                                                 Accepts true, false, and 'errors'.
       
  7155  */
       
  7156 AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.prototype */{
       
  7157 	tagName:   'div',
       
  7158 	className: 'attachments-browser',
       
  7159 
       
  7160 	initialize: function() {
       
  7161 		_.defaults( this.options, {
       
  7162 			filters: false,
       
  7163 			search:  true,
       
  7164 			date:    true,
       
  7165 			display: false,
       
  7166 			sidebar: true,
       
  7167 			AttachmentView: wp.media.view.Attachment.Library
       
  7168 		});
       
  7169 
       
  7170 		this.controller.on( 'toggle:upload:attachment', this.toggleUploader, this );
       
  7171 		this.controller.on( 'edit:selection', this.editSelection );
       
  7172 
       
  7173 		// In the Media Library, the sidebar is used to display errors before the attachments grid.
       
  7174 		if ( this.options.sidebar && 'errors' === this.options.sidebar ) {
       
  7175 			this.createSidebar();
       
  7176 		}
       
  7177 
       
  7178 		/*
       
  7179 		 * In the grid mode (the Media Library), place the Inline Uploader before
       
  7180 		 * other sections so that the visual order and the DOM order match. This way,
       
  7181 		 * the Inline Uploader in the Media Library is right after the "Add New"
       
  7182 		 * button, see ticket #37188.
       
  7183 		 */
       
  7184 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  7185 			this.createUploader();
       
  7186 
       
  7187 			/*
       
  7188 			 * Create a multi-purpose toolbar. Used as main toolbar in the Media Library
       
  7189 			 * and also for other things, for example the "Drag and drop to reorder" and
       
  7190 			 * "Suggested dimensions" info in the media modal.
       
  7191 			 */
       
  7192 			this.createToolbar();
       
  7193 		} else {
       
  7194 			this.createToolbar();
       
  7195 			this.createUploader();
       
  7196 		}
       
  7197 
       
  7198 		// Add a heading before the attachments list.
       
  7199 		this.createAttachmentsHeading();
       
  7200 
       
  7201 		// Create the attachments wrapper view.
       
  7202 		this.createAttachmentsWrapperView();
       
  7203 
       
  7204 		if ( ! infiniteScrolling ) {
       
  7205 			this.$el.addClass( 'has-load-more' );
       
  7206 			this.createLoadMoreView();
       
  7207 		}
       
  7208 
       
  7209 		// For accessibility reasons, place the normal sidebar after the attachments, see ticket #36909.
       
  7210 		if ( this.options.sidebar && 'errors' !== this.options.sidebar ) {
       
  7211 			this.createSidebar();
       
  7212 		}
       
  7213 
       
  7214 		this.updateContent();
       
  7215 
       
  7216 		if ( ! infiniteScrolling ) {
       
  7217 			this.updateLoadMoreView();
       
  7218 		}
       
  7219 
       
  7220 		if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
       
  7221 			this.$el.addClass( 'hide-sidebar' );
       
  7222 
       
  7223 			if ( 'errors' === this.options.sidebar ) {
       
  7224 				this.$el.addClass( 'sidebar-for-errors' );
       
  7225 			}
       
  7226 		}
       
  7227 
       
  7228 		this.collection.on( 'add remove reset', this.updateContent, this );
       
  7229 
       
  7230 		if ( ! infiniteScrolling ) {
       
  7231 			this.collection.on( 'add remove reset', this.updateLoadMoreView, this );
       
  7232 		}
       
  7233 
       
  7234 		// The non-cached or cached attachments query has completed.
       
  7235 		this.collection.on( 'attachments:received', this.announceSearchResults, this );
       
  7236 	},
       
  7237 
       
  7238 	/**
       
  7239 	 * Updates the `wp.a11y.speak()` ARIA live region with a message to communicate
       
  7240 	 * the number of search results to screen reader users. This function is
       
  7241 	 * debounced because the collection updates multiple times.
       
  7242 	 *
       
  7243 	 * @since 5.3.0
       
  7244 	 *
       
  7245 	 * @return {void}
       
  7246 	 */
       
  7247 	announceSearchResults: _.debounce( function() {
       
  7248 		var count,
       
  7249 			/* translators: Accessibility text. %d: Number of attachments found in a search. */
       
  7250 			mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Click load more for more results.' );
       
  7251 
       
  7252 		if ( infiniteScrolling ) {
       
  7253 			/* translators: Accessibility text. %d: Number of attachments found in a search. */
       
  7254 			mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Scroll the page for more results.' );
       
  7255 		}
       
  7256 
       
  7257 		if ( this.collection.mirroring && this.collection.mirroring.args.s ) {
       
  7258 			count = this.collection.length;
       
  7259 
       
  7260 			if ( 0 === count ) {
       
  7261 				wp.a11y.speak( l10n.noMediaTryNewSearch );
       
  7262 				return;
       
  7263 			}
       
  7264 
       
  7265 			if ( this.collection.hasMore() ) {
       
  7266 				wp.a11y.speak( mediaFoundHasMoreResultsMessage.replace( '%d', count ) );
       
  7267 				return;
       
  7268 			}
       
  7269 
       
  7270 			wp.a11y.speak( l10n.mediaFound.replace( '%d', count ) );
       
  7271 		}
       
  7272 	}, 200 ),
       
  7273 
       
  7274 	editSelection: function( modal ) {
       
  7275 		// When editing a selection, move focus to the "Go to library" button.
       
  7276 		modal.$( '.media-button-backToLibrary' ).focus();
       
  7277 	},
       
  7278 
       
  7279 	/**
       
  7280 	 * @return {wp.media.view.AttachmentsBrowser} Returns itself to allow chaining.
       
  7281 	 */
       
  7282 	dispose: function() {
       
  7283 		this.options.selection.off( null, null, this );
       
  7284 		View.prototype.dispose.apply( this, arguments );
       
  7285 		return this;
       
  7286 	},
       
  7287 
       
  7288 	createToolbar: function() {
       
  7289 		var LibraryViewSwitcher, Filters, toolbarOptions,
       
  7290 			showFilterByType = -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] );
       
  7291 
       
  7292 		toolbarOptions = {
       
  7293 			controller: this.controller
       
  7294 		};
       
  7295 
       
  7296 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  7297 			toolbarOptions.className = 'media-toolbar wp-filter';
       
  7298 		}
       
  7299 
       
  7300 		/**
       
  7301 		* @member {wp.media.view.Toolbar}
       
  7302 		*/
       
  7303 		this.toolbar = new wp.media.view.Toolbar( toolbarOptions );
       
  7304 
       
  7305 		this.views.add( this.toolbar );
       
  7306 
       
  7307 		this.toolbar.set( 'spinner', new wp.media.view.Spinner({
       
  7308 			priority: -20
       
  7309 		}) );
       
  7310 
       
  7311 		if ( showFilterByType || this.options.date ) {
       
  7312 			/*
       
  7313 			 * Create a h2 heading before the select elements that filter attachments.
       
  7314 			 * This heading is visible in the modal and visually hidden in the grid.
       
  7315 			 */
       
  7316 			this.toolbar.set( 'filters-heading', new wp.media.view.Heading( {
       
  7317 				priority:   -100,
       
  7318 				text:       l10n.filterAttachments,
       
  7319 				level:      'h2',
       
  7320 				className:  'media-attachments-filter-heading'
       
  7321 			}).render() );
       
  7322 		}
       
  7323 
       
  7324 		if ( showFilterByType ) {
       
  7325 			// "Filters" is a <select>, a visually hidden label element needs to be rendered before.
       
  7326 			this.toolbar.set( 'filtersLabel', new wp.media.view.Label({
       
  7327 				value: l10n.filterByType,
       
  7328 				attributes: {
       
  7329 					'for':  'media-attachment-filters'
       
  7330 				},
       
  7331 				priority:   -80
       
  7332 			}).render() );
       
  7333 
       
  7334 			if ( 'uploaded' === this.options.filters ) {
       
  7335 				this.toolbar.set( 'filters', new wp.media.view.AttachmentFilters.Uploaded({
       
  7336 					controller: this.controller,
       
  7337 					model:      this.collection.props,
       
  7338 					priority:   -80
       
  7339 				}).render() );
       
  7340 			} else {
       
  7341 				Filters = new wp.media.view.AttachmentFilters.All({
       
  7342 					controller: this.controller,
       
  7343 					model:      this.collection.props,
       
  7344 					priority:   -80
       
  7345 				});
       
  7346 
       
  7347 				this.toolbar.set( 'filters', Filters.render() );
       
  7348 			}
       
  7349 		}
       
  7350 
       
  7351 		/*
       
  7352 		 * Feels odd to bring the global media library switcher into the Attachment browser view.
       
  7353 		 * Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
       
  7354 		 * which the controller can tap into and add this view?
       
  7355 		 */
       
  7356 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  7357 			LibraryViewSwitcher = View.extend({
       
  7358 				className: 'view-switch media-grid-view-switch',
       
  7359 				template: wp.template( 'media-library-view-switcher')
       
  7360 			});
       
  7361 
       
  7362 			this.toolbar.set( 'libraryViewSwitcher', new LibraryViewSwitcher({
       
  7363 				controller: this.controller,
       
  7364 				priority: -90
       
  7365 			}).render() );
       
  7366 
       
  7367 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
       
  7368 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
       
  7369 				value: l10n.filterByDate,
       
  7370 				attributes: {
       
  7371 					'for': 'media-attachment-date-filters'
       
  7372 				},
       
  7373 				priority: -75
       
  7374 			}).render() );
       
  7375 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
       
  7376 				controller: this.controller,
       
  7377 				model:      this.collection.props,
       
  7378 				priority: -75
       
  7379 			}).render() );
       
  7380 
       
  7381 			// BulkSelection is a <div> with subviews, including screen reader text.
       
  7382 			this.toolbar.set( 'selectModeToggleButton', new wp.media.view.SelectModeToggleButton({
       
  7383 				text: l10n.bulkSelect,
       
  7384 				controller: this.controller,
       
  7385 				priority: -70
       
  7386 			}).render() );
       
  7387 
       
  7388 			this.toolbar.set( 'deleteSelectedButton', new wp.media.view.DeleteSelectedButton({
       
  7389 				filters: Filters,
       
  7390 				style: 'primary',
       
  7391 				disabled: true,
       
  7392 				text: mediaTrash ? l10n.trashSelected : l10n.deletePermanently,
       
  7393 				controller: this.controller,
       
  7394 				priority: -80,
       
  7395 				click: function() {
       
  7396 					var changed = [], removed = [],
       
  7397 						selection = this.controller.state().get( 'selection' ),
       
  7398 						library = this.controller.state().get( 'library' );
       
  7399 
       
  7400 					if ( ! selection.length ) {
       
  7401 						return;
       
  7402 					}
       
  7403 
       
  7404 					if ( ! mediaTrash && ! window.confirm( l10n.warnBulkDelete ) ) {
       
  7405 						return;
       
  7406 					}
       
  7407 
       
  7408 					if ( mediaTrash &&
       
  7409 						'trash' !== selection.at( 0 ).get( 'status' ) &&
       
  7410 						! window.confirm( l10n.warnBulkTrash ) ) {
       
  7411 
       
  7412 						return;
       
  7413 					}
       
  7414 
       
  7415 					selection.each( function( model ) {
       
  7416 						if ( ! model.get( 'nonces' )['delete'] ) {
       
  7417 							removed.push( model );
       
  7418 							return;
       
  7419 						}
       
  7420 
       
  7421 						if ( mediaTrash && 'trash' === model.get( 'status' ) ) {
       
  7422 							model.set( 'status', 'inherit' );
       
  7423 							changed.push( model.save() );
       
  7424 							removed.push( model );
       
  7425 						} else if ( mediaTrash ) {
       
  7426 							model.set( 'status', 'trash' );
       
  7427 							changed.push( model.save() );
       
  7428 							removed.push( model );
       
  7429 						} else {
       
  7430 							model.destroy({wait: true});
       
  7431 						}
       
  7432 					} );
       
  7433 
       
  7434 					if ( changed.length ) {
       
  7435 						selection.remove( removed );
       
  7436 
       
  7437 						$.when.apply( null, changed ).then( _.bind( function() {
       
  7438 							library._requery( true );
       
  7439 							this.controller.trigger( 'selection:action:done' );
       
  7440 						}, this ) );
       
  7441 					} else {
       
  7442 						this.controller.trigger( 'selection:action:done' );
       
  7443 					}
       
  7444 				}
       
  7445 			}).render() );
       
  7446 
       
  7447 			if ( mediaTrash ) {
       
  7448 				this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
       
  7449 					filters: Filters,
       
  7450 					style: 'link button-link-delete',
       
  7451 					disabled: true,
       
  7452 					text: l10n.deletePermanently,
       
  7453 					controller: this.controller,
       
  7454 					priority: -55,
       
  7455 					click: function() {
       
  7456 						var removed = [],
       
  7457 							destroy = [],
       
  7458 							selection = this.controller.state().get( 'selection' );
       
  7459 
       
  7460 						if ( ! selection.length || ! window.confirm( l10n.warnBulkDelete ) ) {
       
  7461 							return;
       
  7462 						}
       
  7463 
       
  7464 						selection.each( function( model ) {
       
  7465 							if ( ! model.get( 'nonces' )['delete'] ) {
       
  7466 								removed.push( model );
       
  7467 								return;
       
  7468 							}
       
  7469 
       
  7470 							destroy.push( model );
       
  7471 						} );
       
  7472 
       
  7473 						if ( removed.length ) {
       
  7474 							selection.remove( removed );
       
  7475 						}
       
  7476 
       
  7477 						if ( destroy.length ) {
       
  7478 							$.when.apply( null, destroy.map( function (item) {
       
  7479 								return item.destroy();
       
  7480 							} ) ).then( _.bind( function() {
       
  7481 								this.controller.trigger( 'selection:action:done' );
       
  7482 							}, this ) );
       
  7483 						}
       
  7484 					}
       
  7485 				}).render() );
       
  7486 			}
       
  7487 
       
  7488 		} else if ( this.options.date ) {
       
  7489 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
       
  7490 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
       
  7491 				value: l10n.filterByDate,
       
  7492 				attributes: {
       
  7493 					'for': 'media-attachment-date-filters'
       
  7494 				},
       
  7495 				priority: -75
       
  7496 			}).render() );
       
  7497 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
       
  7498 				controller: this.controller,
       
  7499 				model:      this.collection.props,
       
  7500 				priority: -75
       
  7501 			}).render() );
       
  7502 		}
       
  7503 
       
  7504 		if ( this.options.search ) {
       
  7505 			// Search is an input, a label element needs to be rendered before.
       
  7506 			this.toolbar.set( 'searchLabel', new wp.media.view.Label({
       
  7507 				value: l10n.searchLabel,
       
  7508 				className: 'media-search-input-label',
       
  7509 				attributes: {
       
  7510 					'for': 'media-search-input'
       
  7511 				},
       
  7512 				priority:   60
       
  7513 			}).render() );
       
  7514 			this.toolbar.set( 'search', new wp.media.view.Search({
       
  7515 				controller: this.controller,
       
  7516 				model:      this.collection.props,
       
  7517 				priority:   60
       
  7518 			}).render() );
       
  7519 		}
       
  7520 
       
  7521 		if ( this.options.dragInfo ) {
       
  7522 			this.toolbar.set( 'dragInfo', new View({
       
  7523 				el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
       
  7524 				priority: -40
       
  7525 			}) );
       
  7526 		}
       
  7527 
       
  7528 		if ( this.options.suggestedWidth && this.options.suggestedHeight ) {
       
  7529 			this.toolbar.set( 'suggestedDimensions', new View({
       
  7530 				el: $( '<div class="instructions">' + l10n.suggestedDimensions.replace( '%1$s', this.options.suggestedWidth ).replace( '%2$s', this.options.suggestedHeight ) + '</div>' )[0],
       
  7531 				priority: -40
       
  7532 			}) );
       
  7533 		}
       
  7534 	},
       
  7535 
       
  7536 	updateContent: function() {
       
  7537 		var view = this,
       
  7538 			noItemsView;
       
  7539 
       
  7540 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  7541 			// Usually the media library.
       
  7542 			noItemsView = view.attachmentsNoResults;
       
  7543 		} else {
       
  7544 			// Usually the media modal.
       
  7545 			noItemsView = view.uploader;
       
  7546 		}
       
  7547 
       
  7548 		if ( ! this.collection.length ) {
       
  7549 			this.toolbar.get( 'spinner' ).show();
       
  7550 			this.toolbar.$( '.media-bg-overlay' ).show();
       
  7551 			this.dfd = this.collection.more().done( function() {
       
  7552 				if ( ! view.collection.length ) {
       
  7553 					noItemsView.$el.removeClass( 'hidden' );
       
  7554 				} else {
       
  7555 					noItemsView.$el.addClass( 'hidden' );
       
  7556 				}
       
  7557 				view.toolbar.get( 'spinner' ).hide();
       
  7558 				view.toolbar.$( '.media-bg-overlay' ).hide();
       
  7559 			} );
       
  7560 		} else {
       
  7561 			noItemsView.$el.addClass( 'hidden' );
       
  7562 			view.toolbar.get( 'spinner' ).hide();
       
  7563 			this.toolbar.$( '.media-bg-overlay' ).hide();
       
  7564 		}
       
  7565 	},
       
  7566 
       
  7567 	createUploader: function() {
       
  7568 		this.uploader = new wp.media.view.UploaderInline({
       
  7569 			controller: this.controller,
       
  7570 			status:     false,
       
  7571 			message:    this.controller.isModeActive( 'grid' ) ? '' : l10n.noItemsFound,
       
  7572 			canClose:   this.controller.isModeActive( 'grid' )
       
  7573 		});
       
  7574 
       
  7575 		this.uploader.$el.addClass( 'hidden' );
       
  7576 		this.views.add( this.uploader );
       
  7577 	},
       
  7578 
       
  7579 	toggleUploader: function() {
       
  7580 		if ( this.uploader.$el.hasClass( 'hidden' ) ) {
       
  7581 			this.uploader.show();
       
  7582 		} else {
       
  7583 			this.uploader.hide();
       
  7584 		}
       
  7585 	},
       
  7586 
       
  7587 	/**
       
  7588 	 * Creates the Attachments wrapper view.
       
  7589 	 *
       
  7590 	 * @since 5.8.0
       
  7591 	 *
       
  7592 	 * @return {void}
       
  7593 	 */
       
  7594 	createAttachmentsWrapperView: function() {
       
  7595 		this.attachmentsWrapper = new wp.media.View( {
       
  7596 			className: 'attachments-wrapper'
       
  7597 		} );
       
  7598 
       
  7599 		// Create the list of attachments.
       
  7600 		this.views.add( this.attachmentsWrapper );
       
  7601 		this.createAttachments();
       
  7602 	},
       
  7603 
       
  7604 	createAttachments: function() {
       
  7605 		this.attachments = new wp.media.view.Attachments({
       
  7606 			controller:           this.controller,
       
  7607 			collection:           this.collection,
       
  7608 			selection:            this.options.selection,
       
  7609 			model:                this.model,
       
  7610 			sortable:             this.options.sortable,
       
  7611 			scrollElement:        this.options.scrollElement,
       
  7612 			idealColumnWidth:     this.options.idealColumnWidth,
       
  7613 
       
  7614 			// The single `Attachment` view to be used in the `Attachments` view.
       
  7615 			AttachmentView: this.options.AttachmentView
       
  7616 		});
       
  7617 
       
  7618 		// Add keydown listener to the instance of the Attachments view.
       
  7619 		this.controller.on( 'attachment:keydown:arrow',     _.bind( this.attachments.arrowEvent, this.attachments ) );
       
  7620 		this.controller.on( 'attachment:details:shift-tab', _.bind( this.attachments.restoreFocus, this.attachments ) );
       
  7621 
       
  7622 		this.views.add( '.attachments-wrapper', this.attachments );
       
  7623 
       
  7624 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  7625 			this.attachmentsNoResults = new View({
       
  7626 				controller: this.controller,
       
  7627 				tagName: 'p'
       
  7628 			});
       
  7629 
       
  7630 			this.attachmentsNoResults.$el.addClass( 'hidden no-media' );
       
  7631 			this.attachmentsNoResults.$el.html( l10n.noMedia );
       
  7632 
       
  7633 			this.views.add( this.attachmentsNoResults );
       
  7634 		}
       
  7635 	},
       
  7636 
       
  7637 	/**
       
  7638 	 * Creates the load more button and attachments counter view.
       
  7639 	 *
       
  7640 	 * @since 5.8.0
       
  7641 	 *
       
  7642 	 * @return {void}
       
  7643 	 */
       
  7644 	createLoadMoreView: function() {
       
  7645 		var view = this;
       
  7646 
       
  7647 		this.loadMoreWrapper = new View( {
       
  7648 			controller: this.controller,
       
  7649 			className: 'load-more-wrapper'
       
  7650 		} );
       
  7651 
       
  7652 		this.loadMoreCount = new View( {
       
  7653 			controller: this.controller,
       
  7654 			tagName: 'p',
       
  7655 			className: 'load-more-count hidden'
       
  7656 		} );
       
  7657 
       
  7658 		this.loadMoreButton = new wp.media.view.Button( {
       
  7659 			text: __( 'Load more' ),
       
  7660 			className: 'load-more hidden',
       
  7661 			style: 'primary',
       
  7662 			size: '',
       
  7663 			click: function() {
       
  7664 				view.loadMoreAttachments();
       
  7665 			}
       
  7666 		} );
       
  7667 
       
  7668 		this.loadMoreSpinner = new wp.media.view.Spinner();
       
  7669 
       
  7670 		this.loadMoreJumpToFirst = new wp.media.view.Button( {
       
  7671 			text: __( 'Jump to first loaded item' ),
       
  7672 			className: 'load-more-jump hidden',
       
  7673 			size: '',
       
  7674 			click: function() {
       
  7675 				view.jumpToFirstAddedItem();
       
  7676 			}
       
  7677 		} );
       
  7678 
       
  7679 		this.views.add( '.attachments-wrapper', this.loadMoreWrapper );
       
  7680 		this.views.add( '.load-more-wrapper', this.loadMoreSpinner );
       
  7681 		this.views.add( '.load-more-wrapper', this.loadMoreCount );
       
  7682 		this.views.add( '.load-more-wrapper', this.loadMoreButton );
       
  7683 		this.views.add( '.load-more-wrapper', this.loadMoreJumpToFirst );
       
  7684 	},
       
  7685 
       
  7686 	/**
       
  7687 	 * Updates the Load More view. This function is debounced because the
       
  7688 	 * collection updates multiple times at the add, remove, and reset events.
       
  7689 	 * We need it to run only once, after all attachments are added or removed.
       
  7690 	 *
       
  7691 	 * @since 5.8.0
       
  7692 	 *
       
  7693 	 * @return {void}
       
  7694 	 */
       
  7695 	updateLoadMoreView: _.debounce( function() {
       
  7696 		// Ensure the load more view elements are initially hidden at each update.
       
  7697 		this.loadMoreButton.$el.addClass( 'hidden' );
       
  7698 		this.loadMoreCount.$el.addClass( 'hidden' );
       
  7699 		this.loadMoreJumpToFirst.$el.addClass( 'hidden' ).prop( 'disabled', true );
       
  7700 
       
  7701 		if ( ! this.collection.getTotalAttachments() ) {
       
  7702 			return;
       
  7703 		}
       
  7704 
       
  7705 		if ( this.collection.length ) {
       
  7706 			this.loadMoreCount.$el.text(
       
  7707 				/* translators: 1: Number of displayed attachments, 2: Number of total attachments. */
       
  7708 				sprintf(
       
  7709 					__( 'Showing %1$s of %2$s media items' ),
       
  7710 					this.collection.length,
       
  7711 					this.collection.getTotalAttachments()
       
  7712 				)
       
  7713 			);
       
  7714 
       
  7715 			this.loadMoreCount.$el.removeClass( 'hidden' );
       
  7716 		}
       
  7717 
       
  7718 		/*
       
  7719 		 * Notice that while the collection updates multiple times hasMore() may
       
  7720 		 * return true when it's actually not true.
       
  7721 		 */
       
  7722 		if ( this.collection.hasMore() ) {
       
  7723 			this.loadMoreButton.$el.removeClass( 'hidden' );
       
  7724 		}
       
  7725 
       
  7726 		// Find the media item to move focus to. The jQuery `eq()` index is zero-based.
       
  7727 		this.firstAddedMediaItem = this.$el.find( '.attachment' ).eq( this.firstAddedMediaItemIndex );
       
  7728 
       
  7729 		// If there's a media item to move focus to, make the "Jump to" button available.
       
  7730 		if ( this.firstAddedMediaItem.length ) {
       
  7731 			this.firstAddedMediaItem.addClass( 'new-media' );
       
  7732 			this.loadMoreJumpToFirst.$el.removeClass( 'hidden' ).prop( 'disabled', false );
       
  7733 		}
       
  7734 
       
  7735 		// If there are new items added, but no more to be added, move focus to Jump button.
       
  7736 		if ( this.firstAddedMediaItem.length && ! this.collection.hasMore() ) {
       
  7737 			this.loadMoreJumpToFirst.$el.trigger( 'focus' );
       
  7738 		}
       
  7739 	}, 10 ),
       
  7740 
       
  7741 	/**
       
  7742 	 * Loads more attachments.
       
  7743 	 *
       
  7744 	 * @since 5.8.0
       
  7745 	 *
       
  7746 	 * @return {void}
       
  7747 	 */
       
  7748 	loadMoreAttachments: function() {
       
  7749 		var view = this;
       
  7750 
       
  7751 		if ( ! this.collection.hasMore() ) {
       
  7752 			return;
       
  7753 		}
       
  7754 
       
  7755 		/*
       
  7756 		 * The collection index is zero-based while the length counts the actual
       
  7757 		 * amount of items. Thus the length is equivalent to the position of the
       
  7758 		 * first added item.
       
  7759 		 */
       
  7760 		this.firstAddedMediaItemIndex = this.collection.length;
       
  7761 
       
  7762 		this.$el.addClass( 'more-loaded' );
       
  7763 		this.collection.each( function( attachment ) {
       
  7764 			var attach_id = attachment.attributes.id;
       
  7765 			$( '[data-id="' + attach_id + '"]' ).addClass( 'found-media' );
       
  7766 		});
       
  7767 
       
  7768 		view.loadMoreSpinner.show();
       
  7769 		this.collection.once( 'attachments:received', function() {
       
  7770 			view.loadMoreSpinner.hide();
       
  7771 		} );
       
  7772 		this.collection.more();
       
  7773 	},
       
  7774 
       
  7775 	/**
       
  7776 	 * Moves focus to the first new added item.	.
       
  7777 	 *
       
  7778 	 * @since 5.8.0
       
  7779 	 *
       
  7780 	 * @return {void}
       
  7781 	 */
       
  7782 	jumpToFirstAddedItem: function() {
       
  7783 		// Set focus on first added item.
       
  7784 		this.firstAddedMediaItem.focus();
       
  7785 	},
       
  7786 
       
  7787 	createAttachmentsHeading: function() {
       
  7788 		this.attachmentsHeading = new wp.media.view.Heading( {
       
  7789 			text: l10n.attachmentsList,
       
  7790 			level: 'h2',
       
  7791 			className: 'media-views-heading screen-reader-text'
       
  7792 		} );
       
  7793 		this.views.add( this.attachmentsHeading );
       
  7794 	},
       
  7795 
       
  7796 	createSidebar: function() {
       
  7797 		var options = this.options,
       
  7798 			selection = options.selection,
       
  7799 			sidebar = this.sidebar = new wp.media.view.Sidebar({
       
  7800 				controller: this.controller
       
  7801 			});
       
  7802 
       
  7803 		this.views.add( sidebar );
       
  7804 
       
  7805 		if ( this.controller.uploader ) {
       
  7806 			sidebar.set( 'uploads', new wp.media.view.UploaderStatus({
       
  7807 				controller: this.controller,
       
  7808 				priority:   40
       
  7809 			}) );
       
  7810 		}
       
  7811 
       
  7812 		selection.on( 'selection:single', this.createSingle, this );
       
  7813 		selection.on( 'selection:unsingle', this.disposeSingle, this );
       
  7814 
       
  7815 		if ( selection.single() ) {
       
  7816 			this.createSingle();
       
  7817 		}
       
  7818 	},
       
  7819 
       
  7820 	createSingle: function() {
       
  7821 		var sidebar = this.sidebar,
       
  7822 			single = this.options.selection.single();
       
  7823 
       
  7824 		sidebar.set( 'details', new wp.media.view.Attachment.Details({
       
  7825 			controller: this.controller,
       
  7826 			model:      single,
       
  7827 			priority:   80
       
  7828 		}) );
       
  7829 
       
  7830 		sidebar.set( 'compat', new wp.media.view.AttachmentCompat({
       
  7831 			controller: this.controller,
       
  7832 			model:      single,
       
  7833 			priority:   120
       
  7834 		}) );
       
  7835 
       
  7836 		if ( this.options.display ) {
       
  7837 			sidebar.set( 'display', new wp.media.view.Settings.AttachmentDisplay({
       
  7838 				controller:   this.controller,
       
  7839 				model:        this.model.display( single ),
       
  7840 				attachment:   single,
       
  7841 				priority:     160,
       
  7842 				userSettings: this.model.get('displayUserSettings')
       
  7843 			}) );
       
  7844 		}
       
  7845 
       
  7846 		// Show the sidebar on mobile.
       
  7847 		if ( this.model.id === 'insert' ) {
       
  7848 			sidebar.$el.addClass( 'visible' );
       
  7849 		}
       
  7850 	},
       
  7851 
       
  7852 	disposeSingle: function() {
       
  7853 		var sidebar = this.sidebar;
       
  7854 		sidebar.unset('details');
       
  7855 		sidebar.unset('compat');
       
  7856 		sidebar.unset('display');
       
  7857 		// Hide the sidebar on mobile.
       
  7858 		sidebar.$el.removeClass( 'visible' );
       
  7859 	}
       
  7860 });
       
  7861 
       
  7862 module.exports = AttachmentsBrowser;
       
  7863 
       
  7864 
       
  7865 /***/ }),
       
  7866 
       
  7867 /***/ 7127:
       
  7868 /***/ ((module) => {
       
  7869 
       
  7870 var Selection = wp.media.model.Selection,
       
  7871 	Library = wp.media.controller.Library,
       
  7872 	l10n = wp.media.view.l10n,
       
  7873 	GalleryAdd;
       
  7874 
       
  7875 /**
       
  7876  * wp.media.controller.GalleryAdd
       
  7877  *
       
  7878  * A state for selecting more images to add to a gallery.
       
  7879  *
       
  7880  * @since 3.5.0
       
  7881  *
       
  7882  * @class
       
  7883  * @augments wp.media.controller.Library
       
  7884  * @augments wp.media.controller.State
       
  7885  * @augments Backbone.Model
       
  7886  *
       
  7887  * @memberof wp.media.controller
       
  7888  *
       
  7889  * @param {Object}                     [attributes]                         The attributes hash passed to the state.
       
  7890  * @param {string}                     [attributes.id=gallery-library]      Unique identifier.
       
  7891  * @param {string}                     [attributes.title=Add to Gallery]    Title for the state. Displays in the frame's title region.
       
  7892  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
       
  7893  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
       
  7894  *                                                                          If one is not supplied, a collection of all images will be created.
       
  7895  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
       
  7896  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
       
  7897  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
       
  7898  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
       
  7899  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
       
  7900  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
       
  7901  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
       
  7902  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
       
  7903  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  7904  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
  7905  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
  7906  * @param {number}                     [attributes.priority=100]            The priority for the state link in the media menu.
       
  7907  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
       
  7908  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
       
  7909  */
       
  7910 GalleryAdd = Library.extend(/** @lends wp.media.controller.GalleryAdd.prototype */{
       
  7911 	defaults: _.defaults({
       
  7912 		id:            'gallery-library',
       
  7913 		title:         l10n.addToGalleryTitle,
       
  7914 		multiple:      'add',
       
  7915 		filterable:    'uploaded',
       
  7916 		menu:          'gallery',
       
  7917 		toolbar:       'gallery-add',
       
  7918 		priority:      100,
       
  7919 		syncSelection: false
       
  7920 	}, Library.prototype.defaults ),
       
  7921 
       
  7922 	/**
       
  7923 	 * Initializes the library. Creates a library of images if a library isn't supplied.
       
  7924 	 *
       
  7925 	 * @since 3.5.0
       
  7926 	 *
       
  7927 	 * @return {void}
       
  7928 	 */
       
  7929 	initialize: function() {
       
  7930 		if ( ! this.get('library') ) {
       
  7931 			this.set( 'library', wp.media.query({ type: 'image' }) );
       
  7932 		}
       
  7933 
       
  7934 		Library.prototype.initialize.apply( this, arguments );
       
  7935 	},
       
  7936 
       
  7937 	/**
       
  7938 	 * Activates the library.
       
  7939 	 *
       
  7940 	 * Removes all event listeners if in edit mode. Creates a validator to check an attachment.
       
  7941 	 * Resets library and re-enables event listeners. Activates edit mode. Calls the parent's activate method.
       
  7942 	 *
       
  7943 	 * @since 3.5.0
       
  7944 	 *
       
  7945 	 * @return {void}
       
  7946 	 */
       
  7947 	activate: function() {
       
  7948 		var library = this.get('library'),
       
  7949 			edit    = this.frame.state('gallery-edit').get('library');
       
  7950 
       
  7951 		if ( this.editLibrary && this.editLibrary !== edit ) {
       
  7952 			library.unobserve( this.editLibrary );
       
  7953 		}
       
  7954 
       
  7955 		/*
       
  7956 		 * Accept attachments that exist in the original library but
       
  7957 		 * that do not exist in gallery's library yet.
       
  7958 		 */
       
  7959 		library.validator = function( attachment ) {
       
  7960 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
       
  7961 		};
       
  7962 
       
  7963 		/*
       
  7964 		 * Reset the library to ensure that all attachments are re-added
       
  7965 		 * to the collection. Do so silently, as calling `observe` will
       
  7966 		 * trigger the `reset` event.
       
  7967 		 */
       
  7968 		library.reset( library.mirroring.models, { silent: true });
       
  7969 		library.observe( edit );
       
  7970 		this.editLibrary = edit;
       
  7971 
       
  7972 		Library.prototype.activate.apply( this, arguments );
       
  7973 	}
       
  7974 });
       
  7975 
       
  7976 module.exports = GalleryAdd;
       
  7977 
       
  7978 
       
  7979 /***/ }),
       
  7980 
       
  7981 /***/ 7145:
       
  7982 /***/ ((module) => {
       
  7983 
       
  7984 var Selection = wp.media.model.Selection,
       
  7985 	Library = wp.media.controller.Library,
       
  7986 	CollectionAdd;
       
  7987 
       
  7988 /**
       
  7989  * wp.media.controller.CollectionAdd
       
  7990  *
       
  7991  * A state for adding attachments to a collection (e.g. video playlist).
       
  7992  *
       
  7993  * @memberOf wp.media.controller
       
  7994  *
       
  7995  * @class
       
  7996  * @augments wp.media.controller.Library
       
  7997  * @augments wp.media.controller.State
       
  7998  * @augments Backbone.Model
       
  7999  *
       
  8000  * @param {object}                     [attributes]                         The attributes hash passed to the state.
       
  8001  * @param {string}                     [attributes.id=library]              Unique identifier.
       
  8002  * @param {string}                     attributes.title                     Title for the state. Displays in the frame's title region.
       
  8003  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
       
  8004  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
       
  8005  *                                                                          If one is not supplied, a collection of attachments of the specified type will be created.
       
  8006  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
       
  8007  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
       
  8008  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
       
  8009  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
       
  8010  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
       
  8011  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
       
  8012  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
       
  8013  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
       
  8014  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  8015  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
  8016  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
  8017  * @param {int}                        [attributes.priority=100]            The priority for the state link in the media menu.
       
  8018  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
       
  8019  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
       
  8020  * @param {string}                     attributes.type                      The collection's media type. (e.g. 'video').
       
  8021  * @param {string}                     attributes.collectionType            The collection type. (e.g. 'playlist').
       
  8022  */
       
  8023 CollectionAdd = Library.extend(/** @lends wp.media.controller.CollectionAdd.prototype */{
       
  8024 	defaults: _.defaults( {
       
  8025 		// Selection defaults. @see media.model.Selection
       
  8026 		multiple:      'add',
       
  8027 		// Attachments browser defaults. @see media.view.AttachmentsBrowser
       
  8028 		filterable:    'uploaded',
       
  8029 
       
  8030 		priority:      100,
       
  8031 		syncSelection: false
       
  8032 	}, Library.prototype.defaults ),
       
  8033 
       
  8034 	/**
       
  8035 	 * @since 3.9.0
       
  8036 	 */
       
  8037 	initialize: function() {
       
  8038 		var collectionType = this.get('collectionType');
       
  8039 
       
  8040 		if ( 'video' === this.get( 'type' ) ) {
       
  8041 			collectionType = 'video-' + collectionType;
       
  8042 		}
       
  8043 
       
  8044 		this.set( 'id', collectionType + '-library' );
       
  8045 		this.set( 'toolbar', collectionType + '-add' );
       
  8046 		this.set( 'menu', collectionType );
       
  8047 
       
  8048 		// If we haven't been provided a `library`, create a `Selection`.
       
  8049 		if ( ! this.get('library') ) {
       
  8050 			this.set( 'library', wp.media.query({ type: this.get('type') }) );
       
  8051 		}
       
  8052 		Library.prototype.initialize.apply( this, arguments );
       
  8053 	},
       
  8054 
       
  8055 	/**
       
  8056 	 * @since 3.9.0
       
  8057 	 */
       
  8058 	activate: function() {
       
  8059 		var library = this.get('library'),
       
  8060 			editLibrary = this.get('editLibrary'),
       
  8061 			edit = this.frame.state( this.get('collectionType') + '-edit' ).get('library');
       
  8062 
       
  8063 		if ( editLibrary && editLibrary !== edit ) {
       
  8064 			library.unobserve( editLibrary );
       
  8065 		}
       
  8066 
       
  8067 		// Accepts attachments that exist in the original library and
       
  8068 		// that do not exist in gallery's library.
       
  8069 		library.validator = function( attachment ) {
       
  8070 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
       
  8071 		};
       
  8072 
       
  8073 		/*
       
  8074 		 * Reset the library to ensure that all attachments are re-added
       
  8075 		 * to the collection. Do so silently, as calling `observe` will
       
  8076 		 * trigger the `reset` event.
       
  8077 		 */
       
  8078 		library.reset( library.mirroring.models, { silent: true });
       
  8079 		library.observe( edit );
       
  8080 		this.set('editLibrary', edit);
       
  8081 
       
  8082 		Library.prototype.activate.apply( this, arguments );
       
  8083 	}
       
  8084 });
       
  8085 
       
  8086 module.exports = CollectionAdd;
       
  8087 
       
  8088 
       
  8089 /***/ }),
       
  8090 
       
  8091 /***/ 7266:
       
  8092 /***/ ((module) => {
       
  8093 
       
  8094 /**
       
  8095  * wp.media.view.Settings.Gallery
       
  8096  *
       
  8097  * @memberOf wp.media.view.Settings
       
  8098  *
       
  8099  * @class
       
  8100  * @augments wp.media.view.Settings
       
  8101  * @augments wp.media.View
       
  8102  * @augments wp.Backbone.View
       
  8103  * @augments Backbone.View
       
  8104  */
       
  8105 var Gallery = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Gallery.prototype */{
       
  8106 	className: 'collection-settings gallery-settings',
       
  8107 	template:  wp.template('gallery-settings')
       
  8108 });
       
  8109 
       
  8110 module.exports = Gallery;
       
  8111 
       
  8112 
       
  8113 /***/ }),
       
  8114 
       
  8115 /***/ 7327:
       
  8116 /***/ ((module) => {
       
  8117 
       
  8118 var View = wp.media.View,
       
  8119 	$ = jQuery,
       
  8120 	l10n = wp.media.view.l10n,
       
  8121 	EmbedUrl;
       
  8122 
       
  8123 /**
       
  8124  * wp.media.view.EmbedUrl
       
  8125  *
       
  8126  * @memberOf wp.media.view
       
  8127  *
       
  8128  * @class
       
  8129  * @augments wp.media.View
       
  8130  * @augments wp.Backbone.View
       
  8131  * @augments Backbone.View
       
  8132  */
       
  8133 EmbedUrl = View.extend(/** @lends wp.media.view.EmbedUrl.prototype */{
       
  8134 	tagName:   'span',
       
  8135 	className: 'embed-url',
       
  8136 
       
  8137 	events: {
       
  8138 		'input': 'url'
       
  8139 	},
       
  8140 
       
  8141 	initialize: function() {
       
  8142 		this.$input = $( '<input id="embed-url-field" type="url" />' )
       
  8143 			.attr( 'aria-label', l10n.insertFromUrlTitle )
       
  8144 			.val( this.model.get('url') );
       
  8145 		this.input = this.$input[0];
       
  8146 
       
  8147 		this.spinner = $('<span class="spinner" />')[0];
       
  8148 		this.$el.append([ this.input, this.spinner ]);
       
  8149 
       
  8150 		this.listenTo( this.model, 'change:url', this.render );
       
  8151 
       
  8152 		if ( this.model.get( 'url' ) ) {
       
  8153 			_.delay( _.bind( function () {
       
  8154 				this.model.trigger( 'change:url' );
       
  8155 			}, this ), 500 );
       
  8156 		}
       
  8157 	},
       
  8158 	/**
       
  8159 	 * @return {wp.media.view.EmbedUrl} Returns itself to allow chaining.
       
  8160 	 */
       
  8161 	render: function() {
       
  8162 		var $input = this.$input;
       
  8163 
       
  8164 		if ( $input.is(':focus') ) {
       
  8165 			return;
       
  8166 		}
       
  8167 
       
  8168 		if ( this.model.get( 'url' ) ) {
       
  8169 			this.input.value = this.model.get('url');
       
  8170 		} else {
       
  8171 			this.input.setAttribute( 'placeholder', 'https://' );
       
  8172 		}
       
  8173 
       
  8174 		/**
       
  8175 		 * Call `render` directly on parent class with passed arguments
       
  8176 		 */
       
  8177 		View.prototype.render.apply( this, arguments );
       
  8178 		return this;
       
  8179 	},
       
  8180 
       
  8181 	url: function( event ) {
       
  8182 		var url = event.target.value || '';
       
  8183 		this.model.set( 'url', url.trim() );
       
  8184 	}
       
  8185 });
       
  8186 
       
  8187 module.exports = EmbedUrl;
       
  8188 
       
  8189 
       
  8190 /***/ }),
       
  8191 
       
  8192 /***/ 7349:
       
  8193 /***/ ((module) => {
       
  8194 
  2792 var l10n = wp.media.view.l10n,
  8195 var l10n = wp.media.view.l10n,
  2793 	Uploaded;
  8196 	All;
  2794 
  8197 
  2795 /**
  8198 /**
  2796  * wp.media.view.AttachmentFilters.Uploaded
  8199  * wp.media.view.AttachmentFilters.All
  2797  *
  8200  *
  2798  * @memberOf wp.media.view.AttachmentFilters
  8201  * @memberOf wp.media.view.AttachmentFilters
  2799  *
  8202  *
  2800  * @class
  8203  * @class
  2801  * @augments wp.media.view.AttachmentFilters
  8204  * @augments wp.media.view.AttachmentFilters
  2802  * @augments wp.media.View
  8205  * @augments wp.media.View
  2803  * @augments wp.Backbone.View
  8206  * @augments wp.Backbone.View
  2804  * @augments Backbone.View
  8207  * @augments Backbone.View
  2805  */
  8208  */
  2806 Uploaded = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Uploaded.prototype */{
  8209 All = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.All.prototype */{
  2807 	createFilters: function() {
  8210 	createFilters: function() {
  2808 		var type = this.model.get('type'),
  8211 		var filters = {},
  2809 			types = wp.media.view.settings.mimeTypes,
  8212 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0;
  2810 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0,
  8213 
  2811 			text;
  8214 		_.each( wp.media.view.settings.mimeTypes || {}, function( text, key ) {
  2812 
  8215 			filters[ key ] = {
  2813 		if ( types && type ) {
  8216 				text: text,
  2814 			text = types[ type ];
       
  2815 		}
       
  2816 
       
  2817 		this.filters = {
       
  2818 			all: {
       
  2819 				text:  text || l10n.allMediaItems,
       
  2820 				props: {
  8217 				props: {
       
  8218 					status:  null,
       
  8219 					type:    key,
  2821 					uploadedTo: null,
  8220 					uploadedTo: null,
  2822 					orderby: 'date',
  8221 					orderby: 'date',
  2823 					order:   'DESC',
  8222 					order:   'DESC',
  2824 					author:	 null
  8223 					author:  null
  2825 				},
  8224 				}
  2826 				priority: 10
  8225 			};
       
  8226 		});
       
  8227 
       
  8228 		filters.all = {
       
  8229 			text:  l10n.allMediaItems,
       
  8230 			props: {
       
  8231 				status:  null,
       
  8232 				type:    null,
       
  8233 				uploadedTo: null,
       
  8234 				orderby: 'date',
       
  8235 				order:   'DESC',
       
  8236 				author:  null
  2827 			},
  8237 			},
  2828 
  8238 			priority: 10
  2829 			uploaded: {
  8239 		};
       
  8240 
       
  8241 		if ( wp.media.view.settings.post.id ) {
       
  8242 			filters.uploaded = {
  2830 				text:  l10n.uploadedToThisPost,
  8243 				text:  l10n.uploadedToThisPost,
  2831 				props: {
  8244 				props: {
       
  8245 					status:  null,
       
  8246 					type:    null,
  2832 					uploadedTo: wp.media.view.settings.post.id,
  8247 					uploadedTo: wp.media.view.settings.post.id,
  2833 					orderby: 'menuOrder',
  8248 					orderby: 'menuOrder',
  2834 					order:   'ASC',
  8249 					order:   'ASC',
  2835 					author:	 null
  8250 					author:  null
  2836 				},
  8251 				},
  2837 				priority: 20
  8252 				priority: 20
       
  8253 			};
       
  8254 		}
       
  8255 
       
  8256 		filters.unattached = {
       
  8257 			text:  l10n.unattached,
       
  8258 			props: {
       
  8259 				status:     null,
       
  8260 				uploadedTo: 0,
       
  8261 				type:       null,
       
  8262 				orderby:    'menuOrder',
       
  8263 				order:      'ASC',
       
  8264 				author:     null
  2838 			},
  8265 			},
  2839 
  8266 			priority: 50
  2840 			unattached: {
       
  2841 				text:  l10n.unattached,
       
  2842 				props: {
       
  2843 					uploadedTo: 0,
       
  2844 					orderby: 'menuOrder',
       
  2845 					order:   'ASC',
       
  2846 					author:	 null
       
  2847 				},
       
  2848 				priority: 50
       
  2849 			}
       
  2850 		};
  8267 		};
  2851 
  8268 
  2852 		if ( uid ) {
  8269 		if ( uid ) {
  2853 			this.filters.mine = {
  8270 			filters.mine = {
  2854 				text:  l10n.mine,
  8271 				text:  l10n.mine,
  2855 				props: {
  8272 				props: {
  2856 					orderby: 'date',
  8273 					status:		null,
  2857 					order:   'DESC',
  8274 					type:		null,
  2858 					author:  uid
  8275 					uploadedTo:	null,
       
  8276 					orderby:	'date',
       
  8277 					order:		'DESC',
       
  8278 					author:		uid
  2859 				},
  8279 				},
  2860 				priority: 50
  8280 				priority: 50
  2861 			};
  8281 			};
  2862 		}
  8282 		}
       
  8283 
       
  8284 		if ( wp.media.view.settings.mediaTrash &&
       
  8285 			this.controller.isModeActive( 'grid' ) ) {
       
  8286 
       
  8287 			filters.trash = {
       
  8288 				text:  l10n.trash,
       
  8289 				props: {
       
  8290 					uploadedTo: null,
       
  8291 					status:     'trash',
       
  8292 					type:       null,
       
  8293 					orderby:    'date',
       
  8294 					order:      'DESC',
       
  8295 					author:     null
       
  8296 				},
       
  8297 				priority: 50
       
  8298 			};
       
  8299 		}
       
  8300 
       
  8301 		this.filters = filters;
  2863 	}
  8302 	}
  2864 });
  8303 });
  2865 
  8304 
  2866 module.exports = Uploaded;
  8305 module.exports = All;
  2867 
  8306 
  2868 
  8307 
  2869 /***/ }),
  8308 /***/ }),
  2870 
  8309 
  2871 /***/ 4075:
  8310 /***/ 7637:
  2872 /***/ ((module) => {
  8311 /***/ ((module) => {
  2873 
  8312 
  2874 var View = wp.media.View,
  8313 var View = wp.media.View,
       
  8314 	UploaderStatus = wp.media.view.UploaderStatus,
       
  8315 	l10n = wp.media.view.l10n,
  2875 	$ = jQuery,
  8316 	$ = jQuery,
  2876 	Attachment;
  8317 	Cropper;
  2877 
  8318 
  2878 /**
  8319 /**
  2879  * wp.media.view.Attachment
  8320  * wp.media.view.Cropper
       
  8321  *
       
  8322  * Uses the imgAreaSelect plugin to allow a user to crop an image.
       
  8323  *
       
  8324  * Takes imgAreaSelect options from
       
  8325  * wp.customize.HeaderControl.calculateImageSelectOptions via
       
  8326  * wp.customize.HeaderControl.openMM.
  2880  *
  8327  *
  2881  * @memberOf wp.media.view
  8328  * @memberOf wp.media.view
  2882  *
  8329  *
  2883  * @class
  8330  * @class
  2884  * @augments wp.media.View
  8331  * @augments wp.media.View
  2885  * @augments wp.Backbone.View
  8332  * @augments wp.Backbone.View
  2886  * @augments Backbone.View
  8333  * @augments Backbone.View
  2887  */
  8334  */
  2888 Attachment = View.extend(/** @lends wp.media.view.Attachment.prototype */{
  8335 Cropper = View.extend(/** @lends wp.media.view.Cropper.prototype */{
  2889 	tagName:   'li',
  8336 	className: 'crop-content',
  2890 	className: 'attachment',
  8337 	template: wp.template('crop-content'),
  2891 	template:  wp.template('attachment'),
  8338 	initialize: function() {
  2892 
  8339 		_.bindAll(this, 'onImageLoad');
  2893 	attributes: function() {
  8340 	},
       
  8341 	ready: function() {
       
  8342 		this.controller.frame.on('content:error:crop', this.onError, this);
       
  8343 		this.$image = this.$el.find('.crop-image');
       
  8344 		this.$image.on('load', this.onImageLoad);
       
  8345 		$(window).on('resize.cropper', _.debounce(this.onImageLoad, 250));
       
  8346 	},
       
  8347 	remove: function() {
       
  8348 		$(window).off('resize.cropper');
       
  8349 		this.$el.remove();
       
  8350 		this.$el.off();
       
  8351 		View.prototype.remove.apply(this, arguments);
       
  8352 	},
       
  8353 	prepare: function() {
  2894 		return {
  8354 		return {
  2895 			'tabIndex':     0,
  8355 			title: l10n.cropYourImage,
  2896 			'role':         'checkbox',
  8356 			url: this.options.attachment.get('url')
  2897 			'aria-label':   this.model.get( 'title' ),
       
  2898 			'aria-checked': false,
       
  2899 			'data-id':      this.model.get( 'id' )
       
  2900 		};
  8357 		};
  2901 	},
  8358 	},
  2902 
  8359 	onImageLoad: function() {
  2903 	events: {
  8360 		var imgOptions = this.controller.get('imgSelectOptions'),
  2904 		'click':                          'toggleSelectionHandler',
  8361 			imgSelect;
  2905 		'change [data-setting]':          'updateSetting',
  8362 
  2906 		'change [data-setting] input':    'updateSetting',
  8363 		if (typeof imgOptions === 'function') {
  2907 		'change [data-setting] select':   'updateSetting',
  8364 			imgOptions = imgOptions(this.options.attachment, this.controller);
  2908 		'change [data-setting] textarea': 'updateSetting',
  8365 		}
  2909 		'click .attachment-close':        'removeFromLibrary',
  8366 
  2910 		'click .check':                   'checkClickHandler',
  8367 		imgOptions = _.extend(imgOptions, {
  2911 		'keydown':                        'toggleSelectionHandler'
  8368 			parent: this.$el,
  2912 	},
  8369 			onInit: function() {
  2913 
  8370 
  2914 	buttons: {},
  8371 				// Store the set ratio.
  2915 
  8372 				var setRatio = imgSelect.getOptions().aspectRatio;
  2916 	initialize: function() {
  8373 
  2917 		var selection = this.options.selection,
  8374 				// On mousedown, if no ratio is set and the Shift key is down, use a 1:1 ratio.
  2918 			options = _.defaults( this.options, {
  8375 				this.parent.children().on( 'mousedown touchstart', function( e ) {
  2919 				rerenderOnModelChange: true
  8376 
  2920 			} );
  8377 					// If no ratio is set and the shift key is down, use a 1:1 ratio.
  2921 
  8378 					if ( ! setRatio && e.shiftKey ) {
  2922 		if ( options.rerenderOnModelChange ) {
  8379 						imgSelect.setOptions( {
  2923 			this.listenTo( this.model, 'change', this.render );
  8380 							aspectRatio: '1:1'
  2924 		} else {
  8381 						} );
  2925 			this.listenTo( this.model, 'change:percent', this.progress );
  8382 					}
  2926 		}
  8383 				} );
  2927 		this.listenTo( this.model, 'change:title', this._syncTitle );
  8384 
  2928 		this.listenTo( this.model, 'change:caption', this._syncCaption );
  8385 				this.parent.children().on( 'mouseup touchend', function() {
  2929 		this.listenTo( this.model, 'change:artist', this._syncArtist );
  8386 
  2930 		this.listenTo( this.model, 'change:album', this._syncAlbum );
  8387 					// Restore the set ratio.
  2931 
  8388 					imgSelect.setOptions( {
  2932 		// Update the selection.
  8389 						aspectRatio: setRatio ? setRatio : false
  2933 		this.listenTo( this.model, 'add', this.select );
  8390 					} );
  2934 		this.listenTo( this.model, 'remove', this.deselect );
  8391 				} );
  2935 		if ( selection ) {
       
  2936 			selection.on( 'reset', this.updateSelect, this );
       
  2937 			// Update the model's details view.
       
  2938 			this.listenTo( this.model, 'selection:single selection:unsingle', this.details );
       
  2939 			this.details( this.model, this.controller.state().get('selection') );
       
  2940 		}
       
  2941 
       
  2942 		this.listenTo( this.controller.states, 'attachment:compat:waiting attachment:compat:ready', this.updateSave );
       
  2943 	},
       
  2944 	/**
       
  2945 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  2946 	 */
       
  2947 	dispose: function() {
       
  2948 		var selection = this.options.selection;
       
  2949 
       
  2950 		// Make sure all settings are saved before removing the view.
       
  2951 		this.updateAll();
       
  2952 
       
  2953 		if ( selection ) {
       
  2954 			selection.off( null, null, this );
       
  2955 		}
       
  2956 		/**
       
  2957 		 * call 'dispose' directly on the parent class
       
  2958 		 */
       
  2959 		View.prototype.dispose.apply( this, arguments );
       
  2960 		return this;
       
  2961 	},
       
  2962 	/**
       
  2963 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  2964 	 */
       
  2965 	render: function() {
       
  2966 		var options = _.defaults( this.model.toJSON(), {
       
  2967 				orientation:   'landscape',
       
  2968 				uploading:     false,
       
  2969 				type:          '',
       
  2970 				subtype:       '',
       
  2971 				icon:          '',
       
  2972 				filename:      '',
       
  2973 				caption:       '',
       
  2974 				title:         '',
       
  2975 				dateFormatted: '',
       
  2976 				width:         '',
       
  2977 				height:        '',
       
  2978 				compat:        false,
       
  2979 				alt:           '',
       
  2980 				description:   ''
       
  2981 			}, this.options );
       
  2982 
       
  2983 		options.buttons  = this.buttons;
       
  2984 		options.describe = this.controller.state().get('describe');
       
  2985 
       
  2986 		if ( 'image' === options.type ) {
       
  2987 			options.size = this.imageSize();
       
  2988 		}
       
  2989 
       
  2990 		options.can = {};
       
  2991 		if ( options.nonces ) {
       
  2992 			options.can.remove = !! options.nonces['delete'];
       
  2993 			options.can.save = !! options.nonces.update;
       
  2994 		}
       
  2995 
       
  2996 		if ( this.controller.state().get('allowLocalEdits') && ! options.uploading ) {
       
  2997 			options.allowLocalEdits = true;
       
  2998 		}
       
  2999 
       
  3000 		if ( options.uploading && ! options.percent ) {
       
  3001 			options.percent = 0;
       
  3002 		}
       
  3003 
       
  3004 		this.views.detach();
       
  3005 		this.$el.html( this.template( options ) );
       
  3006 
       
  3007 		this.$el.toggleClass( 'uploading', options.uploading );
       
  3008 
       
  3009 		if ( options.uploading ) {
       
  3010 			this.$bar = this.$('.media-progress-bar div');
       
  3011 		} else {
       
  3012 			delete this.$bar;
       
  3013 		}
       
  3014 
       
  3015 		// Check if the model is selected.
       
  3016 		this.updateSelect();
       
  3017 
       
  3018 		// Update the save status.
       
  3019 		this.updateSave();
       
  3020 
       
  3021 		this.views.render();
       
  3022 
       
  3023 		return this;
       
  3024 	},
       
  3025 
       
  3026 	progress: function() {
       
  3027 		if ( this.$bar && this.$bar.length ) {
       
  3028 			this.$bar.width( this.model.get('percent') + '%' );
       
  3029 		}
       
  3030 	},
       
  3031 
       
  3032 	/**
       
  3033 	 * @param {Object} event
       
  3034 	 */
       
  3035 	toggleSelectionHandler: function( event ) {
       
  3036 		var method;
       
  3037 
       
  3038 		// Don't do anything inside inputs and on the attachment check and remove buttons.
       
  3039 		if ( 'INPUT' === event.target.nodeName || 'BUTTON' === event.target.nodeName ) {
       
  3040 			return;
       
  3041 		}
       
  3042 
       
  3043 		// Catch arrow events.
       
  3044 		if ( 37 === event.keyCode || 38 === event.keyCode || 39 === event.keyCode || 40 === event.keyCode ) {
       
  3045 			this.controller.trigger( 'attachment:keydown:arrow', event );
       
  3046 			return;
       
  3047 		}
       
  3048 
       
  3049 		// Catch enter and space events.
       
  3050 		if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
       
  3051 			return;
       
  3052 		}
       
  3053 
       
  3054 		event.preventDefault();
       
  3055 
       
  3056 		// In the grid view, bubble up an edit:attachment event to the controller.
       
  3057 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  3058 			if ( this.controller.isModeActive( 'edit' ) ) {
       
  3059 				// Pass the current target to restore focus when closing.
       
  3060 				this.controller.trigger( 'edit:attachment', this.model, event.currentTarget );
       
  3061 				return;
       
  3062 			}
  8392 			}
  3063 
  8393 		} );
  3064 			if ( this.controller.isModeActive( 'select' ) ) {
  8394 		this.trigger('image-loaded');
  3065 				method = 'toggle';
  8395 		imgSelect = this.controller.imgSelect = this.$image.imgAreaSelect(imgOptions);
  3066 			}
  8396 	},
  3067 		}
  8397 	onError: function() {
  3068 
  8398 		var filename = this.options.attachment.get('filename');
  3069 		if ( event.shiftKey ) {
  8399 
  3070 			method = 'between';
  8400 		this.views.add( '.upload-errors', new wp.media.view.UploaderStatusError({
  3071 		} else if ( event.ctrlKey || event.metaKey ) {
  8401 			filename: UploaderStatus.prototype.filename(filename),
  3072 			method = 'toggle';
  8402 			message: window._wpMediaViewsL10n.cropError
  3073 		}
  8403 		}), { at: 0 });
  3074 
       
  3075 		this.toggleSelection({
       
  3076 			method: method
       
  3077 		});
       
  3078 
       
  3079 		this.controller.trigger( 'selection:toggle' );
       
  3080 	},
       
  3081 	/**
       
  3082 	 * @param {Object} options
       
  3083 	 */
       
  3084 	toggleSelection: function( options ) {
       
  3085 		var collection = this.collection,
       
  3086 			selection = this.options.selection,
       
  3087 			model = this.model,
       
  3088 			method = options && options.method,
       
  3089 			single, models, singleIndex, modelIndex;
       
  3090 
       
  3091 		if ( ! selection ) {
       
  3092 			return;
       
  3093 		}
       
  3094 
       
  3095 		single = selection.single();
       
  3096 		method = _.isUndefined( method ) ? selection.multiple : method;
       
  3097 
       
  3098 		// If the `method` is set to `between`, select all models that
       
  3099 		// exist between the current and the selected model.
       
  3100 		if ( 'between' === method && single && selection.multiple ) {
       
  3101 			// If the models are the same, short-circuit.
       
  3102 			if ( single === model ) {
       
  3103 				return;
       
  3104 			}
       
  3105 
       
  3106 			singleIndex = collection.indexOf( single );
       
  3107 			modelIndex  = collection.indexOf( this.model );
       
  3108 
       
  3109 			if ( singleIndex < modelIndex ) {
       
  3110 				models = collection.models.slice( singleIndex, modelIndex + 1 );
       
  3111 			} else {
       
  3112 				models = collection.models.slice( modelIndex, singleIndex + 1 );
       
  3113 			}
       
  3114 
       
  3115 			selection.add( models );
       
  3116 			selection.single( model );
       
  3117 			return;
       
  3118 
       
  3119 		// If the `method` is set to `toggle`, just flip the selection
       
  3120 		// status, regardless of whether the model is the single model.
       
  3121 		} else if ( 'toggle' === method ) {
       
  3122 			selection[ this.selected() ? 'remove' : 'add' ]( model );
       
  3123 			selection.single( model );
       
  3124 			return;
       
  3125 		} else if ( 'add' === method ) {
       
  3126 			selection.add( model );
       
  3127 			selection.single( model );
       
  3128 			return;
       
  3129 		}
       
  3130 
       
  3131 		// Fixes bug that loses focus when selecting a featured image.
       
  3132 		if ( ! method ) {
       
  3133 			method = 'add';
       
  3134 		}
       
  3135 
       
  3136 		if ( method !== 'add' ) {
       
  3137 			method = 'reset';
       
  3138 		}
       
  3139 
       
  3140 		if ( this.selected() ) {
       
  3141 			/*
       
  3142 			 * If the model is the single model, remove it.
       
  3143 			 * If it is not the same as the single model,
       
  3144 			 * it now becomes the single model.
       
  3145 			 */
       
  3146 			selection[ single === model ? 'remove' : 'single' ]( model );
       
  3147 		} else {
       
  3148 			/*
       
  3149 			 * If the model is not selected, run the `method` on the
       
  3150 			 * selection. By default, we `reset` the selection, but the
       
  3151 			 * `method` can be set to `add` the model to the selection.
       
  3152 			 */
       
  3153 			selection[ method ]( model );
       
  3154 			selection.single( model );
       
  3155 		}
       
  3156 	},
       
  3157 
       
  3158 	updateSelect: function() {
       
  3159 		this[ this.selected() ? 'select' : 'deselect' ]();
       
  3160 	},
       
  3161 	/**
       
  3162 	 * @return {unresolved|boolean}
       
  3163 	 */
       
  3164 	selected: function() {
       
  3165 		var selection = this.options.selection;
       
  3166 		if ( selection ) {
       
  3167 			return !! selection.get( this.model.cid );
       
  3168 		}
       
  3169 	},
       
  3170 	/**
       
  3171 	 * @param {Backbone.Model} model
       
  3172 	 * @param {Backbone.Collection} collection
       
  3173 	 */
       
  3174 	select: function( model, collection ) {
       
  3175 		var selection = this.options.selection,
       
  3176 			controller = this.controller;
       
  3177 
       
  3178 		/*
       
  3179 		 * Check if a selection exists and if it's the collection provided.
       
  3180 		 * If they're not the same collection, bail; we're in another
       
  3181 		 * selection's event loop.
       
  3182 		 */
       
  3183 		if ( ! selection || ( collection && collection !== selection ) ) {
       
  3184 			return;
       
  3185 		}
       
  3186 
       
  3187 		// Bail if the model is already selected.
       
  3188 		if ( this.$el.hasClass( 'selected' ) ) {
       
  3189 			return;
       
  3190 		}
       
  3191 
       
  3192 		// Add 'selected' class to model, set aria-checked to true.
       
  3193 		this.$el.addClass( 'selected' ).attr( 'aria-checked', true );
       
  3194 		//  Make the checkbox tabable, except in media grid (bulk select mode).
       
  3195 		if ( ! ( controller.isModeActive( 'grid' ) && controller.isModeActive( 'select' ) ) ) {
       
  3196 			this.$( '.check' ).attr( 'tabindex', '0' );
       
  3197 		}
       
  3198 	},
       
  3199 	/**
       
  3200 	 * @param {Backbone.Model} model
       
  3201 	 * @param {Backbone.Collection} collection
       
  3202 	 */
       
  3203 	deselect: function( model, collection ) {
       
  3204 		var selection = this.options.selection;
       
  3205 
       
  3206 		/*
       
  3207 		 * Check if a selection exists and if it's the collection provided.
       
  3208 		 * If they're not the same collection, bail; we're in another
       
  3209 		 * selection's event loop.
       
  3210 		 */
       
  3211 		if ( ! selection || ( collection && collection !== selection ) ) {
       
  3212 			return;
       
  3213 		}
       
  3214 		this.$el.removeClass( 'selected' ).attr( 'aria-checked', false )
       
  3215 			.find( '.check' ).attr( 'tabindex', '-1' );
       
  3216 	},
       
  3217 	/**
       
  3218 	 * @param {Backbone.Model} model
       
  3219 	 * @param {Backbone.Collection} collection
       
  3220 	 */
       
  3221 	details: function( model, collection ) {
       
  3222 		var selection = this.options.selection,
       
  3223 			details;
       
  3224 
       
  3225 		if ( selection !== collection ) {
       
  3226 			return;
       
  3227 		}
       
  3228 
       
  3229 		details = selection.single();
       
  3230 		this.$el.toggleClass( 'details', details === this.model );
       
  3231 	},
       
  3232 	/**
       
  3233 	 * @param {string} size
       
  3234 	 * @return {Object}
       
  3235 	 */
       
  3236 	imageSize: function( size ) {
       
  3237 		var sizes = this.model.get('sizes'), matched = false;
       
  3238 
       
  3239 		size = size || 'medium';
       
  3240 
       
  3241 		// Use the provided image size if possible.
       
  3242 		if ( sizes ) {
       
  3243 			if ( sizes[ size ] ) {
       
  3244 				matched = sizes[ size ];
       
  3245 			} else if ( sizes.large ) {
       
  3246 				matched = sizes.large;
       
  3247 			} else if ( sizes.thumbnail ) {
       
  3248 				matched = sizes.thumbnail;
       
  3249 			} else if ( sizes.full ) {
       
  3250 				matched = sizes.full;
       
  3251 			}
       
  3252 
       
  3253 			if ( matched ) {
       
  3254 				return _.clone( matched );
       
  3255 			}
       
  3256 		}
       
  3257 
       
  3258 		return {
       
  3259 			url:         this.model.get('url'),
       
  3260 			width:       this.model.get('width'),
       
  3261 			height:      this.model.get('height'),
       
  3262 			orientation: this.model.get('orientation')
       
  3263 		};
       
  3264 	},
       
  3265 	/**
       
  3266 	 * @param {Object} event
       
  3267 	 */
       
  3268 	updateSetting: function( event ) {
       
  3269 		var $setting = $( event.target ).closest('[data-setting]'),
       
  3270 			setting, value;
       
  3271 
       
  3272 		if ( ! $setting.length ) {
       
  3273 			return;
       
  3274 		}
       
  3275 
       
  3276 		setting = $setting.data('setting');
       
  3277 		value   = event.target.value;
       
  3278 
       
  3279 		if ( this.model.get( setting ) !== value ) {
       
  3280 			this.save( setting, value );
       
  3281 		}
       
  3282 	},
       
  3283 
       
  3284 	/**
       
  3285 	 * Pass all the arguments to the model's save method.
       
  3286 	 *
       
  3287 	 * Records the aggregate status of all save requests and updates the
       
  3288 	 * view's classes accordingly.
       
  3289 	 */
       
  3290 	save: function() {
       
  3291 		var view = this,
       
  3292 			save = this._save = this._save || { status: 'ready' },
       
  3293 			request = this.model.save.apply( this.model, arguments ),
       
  3294 			requests = save.requests ? $.when( request, save.requests ) : request;
       
  3295 
       
  3296 		// If we're waiting to remove 'Saved.', stop.
       
  3297 		if ( save.savedTimer ) {
       
  3298 			clearTimeout( save.savedTimer );
       
  3299 		}
       
  3300 
       
  3301 		this.updateSave('waiting');
       
  3302 		save.requests = requests;
       
  3303 		requests.always( function() {
       
  3304 			// If we've performed another request since this one, bail.
       
  3305 			if ( save.requests !== requests ) {
       
  3306 				return;
       
  3307 			}
       
  3308 
       
  3309 			view.updateSave( requests.state() === 'resolved' ? 'complete' : 'error' );
       
  3310 			save.savedTimer = setTimeout( function() {
       
  3311 				view.updateSave('ready');
       
  3312 				delete save.savedTimer;
       
  3313 			}, 2000 );
       
  3314 		});
       
  3315 	},
       
  3316 	/**
       
  3317 	 * @param {string} status
       
  3318 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  3319 	 */
       
  3320 	updateSave: function( status ) {
       
  3321 		var save = this._save = this._save || { status: 'ready' };
       
  3322 
       
  3323 		if ( status && status !== save.status ) {
       
  3324 			this.$el.removeClass( 'save-' + save.status );
       
  3325 			save.status = status;
       
  3326 		}
       
  3327 
       
  3328 		this.$el.addClass( 'save-' + save.status );
       
  3329 		return this;
       
  3330 	},
       
  3331 
       
  3332 	updateAll: function() {
       
  3333 		var $settings = this.$('[data-setting]'),
       
  3334 			model = this.model,
       
  3335 			changed;
       
  3336 
       
  3337 		changed = _.chain( $settings ).map( function( el ) {
       
  3338 			var $input = $('input, textarea, select, [value]', el ),
       
  3339 				setting, value;
       
  3340 
       
  3341 			if ( ! $input.length ) {
       
  3342 				return;
       
  3343 			}
       
  3344 
       
  3345 			setting = $(el).data('setting');
       
  3346 			value = $input.val();
       
  3347 
       
  3348 			// Record the value if it changed.
       
  3349 			if ( model.get( setting ) !== value ) {
       
  3350 				return [ setting, value ];
       
  3351 			}
       
  3352 		}).compact().object().value();
       
  3353 
       
  3354 		if ( ! _.isEmpty( changed ) ) {
       
  3355 			model.save( changed );
       
  3356 		}
       
  3357 	},
       
  3358 	/**
       
  3359 	 * @param {Object} event
       
  3360 	 */
       
  3361 	removeFromLibrary: function( event ) {
       
  3362 		// Catch enter and space events.
       
  3363 		if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
       
  3364 			return;
       
  3365 		}
       
  3366 
       
  3367 		// Stop propagation so the model isn't selected.
       
  3368 		event.stopPropagation();
       
  3369 
       
  3370 		this.collection.remove( this.model );
       
  3371 	},
       
  3372 
       
  3373 	/**
       
  3374 	 * Add the model if it isn't in the selection, if it is in the selection,
       
  3375 	 * remove it.
       
  3376 	 *
       
  3377 	 * @param {[type]} event [description]
       
  3378 	 * @return {[type]} [description]
       
  3379 	 */
       
  3380 	checkClickHandler: function ( event ) {
       
  3381 		var selection = this.options.selection;
       
  3382 		if ( ! selection ) {
       
  3383 			return;
       
  3384 		}
       
  3385 		event.stopPropagation();
       
  3386 		if ( selection.where( { id: this.model.get( 'id' ) } ).length ) {
       
  3387 			selection.remove( this.model );
       
  3388 			// Move focus back to the attachment tile (from the check).
       
  3389 			this.$el.focus();
       
  3390 		} else {
       
  3391 			selection.add( this.model );
       
  3392 		}
       
  3393 
       
  3394 		// Trigger an action button update.
       
  3395 		this.controller.trigger( 'selection:toggle' );
       
  3396 	}
  8404 	}
  3397 });
  8405 });
  3398 
  8406 
  3399 // Ensure settings remain in sync between attachment views.
  8407 module.exports = Cropper;
  3400 _.each({
       
  3401 	caption: '_syncCaption',
       
  3402 	title:   '_syncTitle',
       
  3403 	artist:  '_syncArtist',
       
  3404 	album:   '_syncAlbum'
       
  3405 }, function( method, setting ) {
       
  3406 	/**
       
  3407 	 * @function _syncCaption
       
  3408 	 * @memberOf wp.media.view.Attachment
       
  3409 	 * @instance
       
  3410 	 *
       
  3411 	 * @param {Backbone.Model} model
       
  3412 	 * @param {string} value
       
  3413 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  3414 	 */
       
  3415 	/**
       
  3416 	 * @function _syncTitle
       
  3417 	 * @memberOf wp.media.view.Attachment
       
  3418 	 * @instance
       
  3419 	 *
       
  3420 	 * @param {Backbone.Model} model
       
  3421 	 * @param {string} value
       
  3422 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  3423 	 */
       
  3424 	/**
       
  3425 	 * @function _syncArtist
       
  3426 	 * @memberOf wp.media.view.Attachment
       
  3427 	 * @instance
       
  3428 	 *
       
  3429 	 * @param {Backbone.Model} model
       
  3430 	 * @param {string} value
       
  3431 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  3432 	 */
       
  3433 	/**
       
  3434 	 * @function _syncAlbum
       
  3435 	 * @memberOf wp.media.view.Attachment
       
  3436 	 * @instance
       
  3437 	 *
       
  3438 	 * @param {Backbone.Model} model
       
  3439 	 * @param {string} value
       
  3440 	 * @return {wp.media.view.Attachment} Returns itself to allow chaining.
       
  3441 	 */
       
  3442 	Attachment.prototype[ method ] = function( model, value ) {
       
  3443 		var $setting = this.$('[data-setting="' + setting + '"]');
       
  3444 
       
  3445 		if ( ! $setting.length ) {
       
  3446 			return this;
       
  3447 		}
       
  3448 
       
  3449 		/*
       
  3450 		 * If the updated value is in sync with the value in the DOM, there
       
  3451 		 * is no need to re-render. If we're currently editing the value,
       
  3452 		 * it will automatically be in sync, suppressing the re-render for
       
  3453 		 * the view we're editing, while updating any others.
       
  3454 		 */
       
  3455 		if ( value === $setting.find('input, textarea, select, [value]').val() ) {
       
  3456 			return this;
       
  3457 		}
       
  3458 
       
  3459 		return this.render();
       
  3460 	};
       
  3461 });
       
  3462 
       
  3463 module.exports = Attachment;
       
  3464 
  8408 
  3465 
  8409 
  3466 /***/ }),
  8410 /***/ }),
  3467 
  8411 
  3468 /***/ 6090:
  8412 /***/ 7656:
  3469 /***/ ((module) => {
  8413 /***/ ((module) => {
  3470 
  8414 
  3471 /* global ClipboardJS */
  8415 var Settings = wp.media.view.Settings,
  3472 var Attachment = wp.media.view.Attachment,
  8416 	AttachmentDisplay;
  3473 	l10n = wp.media.view.l10n,
       
  3474 	$ = jQuery,
       
  3475 	Details,
       
  3476 	__ = wp.i18n.__;
       
  3477 
       
  3478 Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototype */{
       
  3479 	tagName:   'div',
       
  3480 	className: 'attachment-details',
       
  3481 	template:  wp.template('attachment-details'),
       
  3482 
       
  3483 	/*
       
  3484 	 * Reset all the attributes inherited from Attachment including role=checkbox,
       
  3485 	 * tabindex, etc., as they are inappropriate for this view. See #47458 and [30483] / #30390.
       
  3486 	 */
       
  3487 	attributes: {},
       
  3488 
       
  3489 	events: {
       
  3490 		'change [data-setting]':          'updateSetting',
       
  3491 		'change [data-setting] input':    'updateSetting',
       
  3492 		'change [data-setting] select':   'updateSetting',
       
  3493 		'change [data-setting] textarea': 'updateSetting',
       
  3494 		'click .delete-attachment':       'deleteAttachment',
       
  3495 		'click .trash-attachment':        'trashAttachment',
       
  3496 		'click .untrash-attachment':      'untrashAttachment',
       
  3497 		'click .edit-attachment':         'editAttachment',
       
  3498 		'keydown':                        'toggleSelectionHandler'
       
  3499 	},
       
  3500 
       
  3501 	/**
       
  3502 	 * Copies the attachment URL to the clipboard.
       
  3503 	 *
       
  3504 	 * @since 5.5.0
       
  3505 	 *
       
  3506 	 * @param {MouseEvent} event A click event.
       
  3507 	 *
       
  3508 	 * @return {void}
       
  3509 	 */
       
  3510 	 copyAttachmentDetailsURLClipboard: function() {
       
  3511 		var clipboard = new ClipboardJS( '.copy-attachment-url' ),
       
  3512 			successTimeout;
       
  3513 
       
  3514 		clipboard.on( 'success', function( event ) {
       
  3515 			var triggerElement = $( event.trigger ),
       
  3516 				successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
       
  3517 
       
  3518 			// Clear the selection and move focus back to the trigger.
       
  3519 			event.clearSelection();
       
  3520 
       
  3521 			// Show success visual feedback.
       
  3522 			clearTimeout( successTimeout );
       
  3523 			successElement.removeClass( 'hidden' );
       
  3524 
       
  3525 			// Hide success visual feedback after 3 seconds since last success.
       
  3526 			successTimeout = setTimeout( function() {
       
  3527 				successElement.addClass( 'hidden' );
       
  3528 			}, 3000 );
       
  3529 
       
  3530 			// Handle success audible feedback.
       
  3531 			wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
       
  3532 		} );
       
  3533 	 },
       
  3534 
       
  3535 	/**
       
  3536 	 * Shows the details of an attachment.
       
  3537 	 *
       
  3538 	 * @since 3.5.0
       
  3539 	 *
       
  3540 	 * @constructs wp.media.view.Attachment.Details
       
  3541 	 * @augments wp.media.view.Attachment
       
  3542 	 *
       
  3543 	 * @return {void}
       
  3544 	 */
       
  3545 	initialize: function() {
       
  3546 		this.options = _.defaults( this.options, {
       
  3547 			rerenderOnModelChange: false
       
  3548 		});
       
  3549 
       
  3550 		// Call 'initialize' directly on the parent class.
       
  3551 		Attachment.prototype.initialize.apply( this, arguments );
       
  3552 
       
  3553 		this.copyAttachmentDetailsURLClipboard();
       
  3554 	},
       
  3555 
       
  3556 	/**
       
  3557 	 * Gets the focusable elements to move focus to.
       
  3558 	 *
       
  3559 	 * @since 5.3.0
       
  3560 	 */
       
  3561 	getFocusableElements: function() {
       
  3562 		var editedAttachment = $( 'li[data-id="' + this.model.id + '"]' );
       
  3563 
       
  3564 		this.previousAttachment = editedAttachment.prev();
       
  3565 		this.nextAttachment = editedAttachment.next();
       
  3566 	},
       
  3567 
       
  3568 	/**
       
  3569 	 * Moves focus to the previous or next attachment in the grid.
       
  3570 	 * Fallbacks to the upload button or media frame when there are no attachments.
       
  3571 	 *
       
  3572 	 * @since 5.3.0
       
  3573 	 */
       
  3574 	moveFocus: function() {
       
  3575 		if ( this.previousAttachment.length ) {
       
  3576 			this.previousAttachment.trigger( 'focus' );
       
  3577 			return;
       
  3578 		}
       
  3579 
       
  3580 		if ( this.nextAttachment.length ) {
       
  3581 			this.nextAttachment.trigger( 'focus' );
       
  3582 			return;
       
  3583 		}
       
  3584 
       
  3585 		// Fallback: move focus to the "Select Files" button in the media modal.
       
  3586 		if ( this.controller.uploader && this.controller.uploader.$browser ) {
       
  3587 			this.controller.uploader.$browser.trigger( 'focus' );
       
  3588 			return;
       
  3589 		}
       
  3590 
       
  3591 		// Last fallback.
       
  3592 		this.moveFocusToLastFallback();
       
  3593 	},
       
  3594 
       
  3595 	/**
       
  3596 	 * Moves focus to the media frame as last fallback.
       
  3597 	 *
       
  3598 	 * @since 5.3.0
       
  3599 	 */
       
  3600 	moveFocusToLastFallback: function() {
       
  3601 		// Last fallback: make the frame focusable and move focus to it.
       
  3602 		$( '.media-frame' )
       
  3603 			.attr( 'tabindex', '-1' )
       
  3604 			.trigger( 'focus' );
       
  3605 	},
       
  3606 
       
  3607 	/**
       
  3608 	 * Deletes an attachment.
       
  3609 	 *
       
  3610 	 * Deletes an attachment after asking for confirmation. After deletion,
       
  3611 	 * keeps focus in the modal.
       
  3612 	 *
       
  3613 	 * @since 3.5.0
       
  3614 	 *
       
  3615 	 * @param {MouseEvent} event A click event.
       
  3616 	 *
       
  3617 	 * @return {void}
       
  3618 	 */
       
  3619 	deleteAttachment: function( event ) {
       
  3620 		event.preventDefault();
       
  3621 
       
  3622 		this.getFocusableElements();
       
  3623 
       
  3624 		if ( window.confirm( l10n.warnDelete ) ) {
       
  3625 			this.model.destroy( {
       
  3626 				wait: true,
       
  3627 				error: function() {
       
  3628 					window.alert( l10n.errorDeleting );
       
  3629 				}
       
  3630 			} );
       
  3631 
       
  3632 			this.moveFocus();
       
  3633 		}
       
  3634 	},
       
  3635 
       
  3636 	/**
       
  3637 	 * Sets the Trash state on an attachment, or destroys the model itself.
       
  3638 	 *
       
  3639 	 * If the mediaTrash setting is set to true, trashes the attachment.
       
  3640 	 * Otherwise, the model itself is destroyed.
       
  3641 	 *
       
  3642 	 * @since 3.9.0
       
  3643 	 *
       
  3644 	 * @param {MouseEvent} event A click event.
       
  3645 	 *
       
  3646 	 * @return {void}
       
  3647 	 */
       
  3648 	trashAttachment: function( event ) {
       
  3649 		var library = this.controller.library,
       
  3650 			self = this;
       
  3651 		event.preventDefault();
       
  3652 
       
  3653 		this.getFocusableElements();
       
  3654 
       
  3655 		// When in the Media Library and the Media Trash is enabled.
       
  3656 		if ( wp.media.view.settings.mediaTrash &&
       
  3657 			'edit-metadata' === this.controller.content.mode() ) {
       
  3658 
       
  3659 			this.model.set( 'status', 'trash' );
       
  3660 			this.model.save().done( function() {
       
  3661 				library._requery( true );
       
  3662 				/*
       
  3663 				 * @todo We need to move focus back to the previous, next, or first
       
  3664 				 * attachment but the library gets re-queried and refreshed.
       
  3665 				 * Thus, the references to the previous attachments are lost.
       
  3666 				 * We need an alternate method.
       
  3667 				 */
       
  3668 				self.moveFocusToLastFallback();
       
  3669 			} );
       
  3670 		} else {
       
  3671 			this.model.destroy();
       
  3672 			this.moveFocus();
       
  3673 		}
       
  3674 	},
       
  3675 
       
  3676 	/**
       
  3677 	 * Untrashes an attachment.
       
  3678 	 *
       
  3679 	 * @since 4.0.0
       
  3680 	 *
       
  3681 	 * @param {MouseEvent} event A click event.
       
  3682 	 *
       
  3683 	 * @return {void}
       
  3684 	 */
       
  3685 	untrashAttachment: function( event ) {
       
  3686 		var library = this.controller.library;
       
  3687 		event.preventDefault();
       
  3688 
       
  3689 		this.model.set( 'status', 'inherit' );
       
  3690 		this.model.save().done( function() {
       
  3691 			library._requery( true );
       
  3692 		} );
       
  3693 	},
       
  3694 
       
  3695 	/**
       
  3696 	 * Opens the edit page for a specific attachment.
       
  3697 	 *
       
  3698 	 * @since 3.5.0
       
  3699 	 *
       
  3700 	 * @param {MouseEvent} event A click event.
       
  3701 	 *
       
  3702 	 * @return {void}
       
  3703 	 */
       
  3704 	editAttachment: function( event ) {
       
  3705 		var editState = this.controller.states.get( 'edit-image' );
       
  3706 		if ( window.imageEdit && editState ) {
       
  3707 			event.preventDefault();
       
  3708 
       
  3709 			editState.set( 'image', this.model );
       
  3710 			this.controller.setState( 'edit-image' );
       
  3711 		} else {
       
  3712 			this.$el.addClass('needs-refresh');
       
  3713 		}
       
  3714 	},
       
  3715 
       
  3716 	/**
       
  3717 	 * Triggers an event on the controller when reverse tabbing (shift+tab).
       
  3718 	 *
       
  3719 	 * This event can be used to make sure to move the focus correctly.
       
  3720 	 *
       
  3721 	 * @since 4.0.0
       
  3722 	 *
       
  3723 	 * @fires wp.media.controller.MediaLibrary#attachment:details:shift-tab
       
  3724 	 * @fires wp.media.controller.MediaLibrary#attachment:keydown:arrow
       
  3725 	 *
       
  3726 	 * @param {KeyboardEvent} event A keyboard event.
       
  3727 	 *
       
  3728 	 * @return {boolean|void} Returns false or undefined.
       
  3729 	 */
       
  3730 	toggleSelectionHandler: function( event ) {
       
  3731 		if ( 'keydown' === event.type && 9 === event.keyCode && event.shiftKey && event.target === this.$( ':tabbable' ).get( 0 ) ) {
       
  3732 			this.controller.trigger( 'attachment:details:shift-tab', event );
       
  3733 			return false;
       
  3734 		}
       
  3735 	},
       
  3736 
       
  3737 	render: function() {
       
  3738 		Attachment.prototype.render.apply( this, arguments );
       
  3739 
       
  3740 		wp.media.mixin.removeAllPlayers();
       
  3741 		this.$( 'audio, video' ).each( function (i, elem) {
       
  3742 			var el = wp.media.view.MediaDetails.prepareSrc( elem );
       
  3743 			new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings );
       
  3744 		} );
       
  3745 	}
       
  3746 });
       
  3747 
       
  3748 module.exports = Details;
       
  3749 
       
  3750 
       
  3751 /***/ }),
       
  3752 
       
  3753 /***/ 5232:
       
  3754 /***/ ((module) => {
       
  3755 
  8417 
  3756 /**
  8418 /**
  3757  * wp.media.view.Attachment.EditLibrary
  8419  * wp.media.view.Settings.AttachmentDisplay
  3758  *
  8420  *
  3759  * @memberOf wp.media.view.Attachment
  8421  * @memberOf wp.media.view.Settings
  3760  *
  8422  *
  3761  * @class
  8423  * @class
  3762  * @augments wp.media.view.Attachment
  8424  * @augments wp.media.view.Settings
  3763  * @augments wp.media.View
  8425  * @augments wp.media.View
  3764  * @augments wp.Backbone.View
  8426  * @augments wp.Backbone.View
  3765  * @augments Backbone.View
  8427  * @augments Backbone.View
  3766  */
  8428  */
  3767 var EditLibrary = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.EditLibrary.prototype */{
  8429 AttachmentDisplay = Settings.extend(/** @lends wp.media.view.Settings.AttachmentDisplay.prototype */{
  3768 	buttons: {
  8430 	className: 'attachment-display-settings',
  3769 		close: true
  8431 	template:  wp.template('attachment-display-settings'),
       
  8432 
       
  8433 	initialize: function() {
       
  8434 		var attachment = this.options.attachment;
       
  8435 
       
  8436 		_.defaults( this.options, {
       
  8437 			userSettings: false
       
  8438 		});
       
  8439 		// Call 'initialize' directly on the parent class.
       
  8440 		Settings.prototype.initialize.apply( this, arguments );
       
  8441 		this.listenTo( this.model, 'change:link', this.updateLinkTo );
       
  8442 
       
  8443 		if ( attachment ) {
       
  8444 			attachment.on( 'change:uploading', this.render, this );
       
  8445 		}
       
  8446 	},
       
  8447 
       
  8448 	dispose: function() {
       
  8449 		var attachment = this.options.attachment;
       
  8450 		if ( attachment ) {
       
  8451 			attachment.off( null, null, this );
       
  8452 		}
       
  8453 		/**
       
  8454 		 * call 'dispose' directly on the parent class
       
  8455 		 */
       
  8456 		Settings.prototype.dispose.apply( this, arguments );
       
  8457 	},
       
  8458 	/**
       
  8459 	 * @return {wp.media.view.AttachmentDisplay} Returns itself to allow chaining.
       
  8460 	 */
       
  8461 	render: function() {
       
  8462 		var attachment = this.options.attachment;
       
  8463 		if ( attachment ) {
       
  8464 			_.extend( this.options, {
       
  8465 				sizes: attachment.get('sizes'),
       
  8466 				type:  attachment.get('type')
       
  8467 			});
       
  8468 		}
       
  8469 		/**
       
  8470 		 * call 'render' directly on the parent class
       
  8471 		 */
       
  8472 		Settings.prototype.render.call( this );
       
  8473 		this.updateLinkTo();
       
  8474 		return this;
       
  8475 	},
       
  8476 
       
  8477 	updateLinkTo: function() {
       
  8478 		var linkTo = this.model.get('link'),
       
  8479 			$input = this.$('.link-to-custom'),
       
  8480 			attachment = this.options.attachment;
       
  8481 
       
  8482 		if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
       
  8483 			$input.closest( '.setting' ).addClass( 'hidden' );
       
  8484 			return;
       
  8485 		}
       
  8486 
       
  8487 		if ( attachment ) {
       
  8488 			if ( 'post' === linkTo ) {
       
  8489 				$input.val( attachment.get('link') );
       
  8490 			} else if ( 'file' === linkTo ) {
       
  8491 				$input.val( attachment.get('url') );
       
  8492 			} else if ( ! this.model.get('linkUrl') ) {
       
  8493 				$input.val('http://');
       
  8494 			}
       
  8495 
       
  8496 			$input.prop( 'readonly', 'custom' !== linkTo );
       
  8497 		}
       
  8498 
       
  8499 		$input.closest( '.setting' ).removeClass( 'hidden' );
       
  8500 		if ( $input.length ) {
       
  8501 			$input[0].scrollIntoView();
       
  8502 		}
  3770 	}
  8503 	}
  3771 });
  8504 });
  3772 
  8505 
  3773 module.exports = EditLibrary;
  8506 module.exports = AttachmentDisplay;
  3774 
  8507 
  3775 
  8508 
  3776 /***/ }),
  8509 /***/ }),
  3777 
  8510 
  3778 /***/ 4593:
  8511 /***/ 7709:
  3779 /***/ ((module) => {
  8512 /***/ ((module) => {
  3780 
  8513 
       
  8514 var $ = jQuery,
       
  8515 	AttachmentFilters;
       
  8516 
  3781 /**
  8517 /**
  3782  * wp.media.view.Attachment.EditSelection
  8518  * wp.media.view.AttachmentFilters
  3783  *
  8519  *
  3784  * @memberOf wp.media.view.Attachment
  8520  * @memberOf wp.media.view
  3785  *
  8521  *
  3786  * @class
  8522  * @class
  3787  * @augments wp.media.view.Attachment.Selection
       
  3788  * @augments wp.media.view.Attachment
       
  3789  * @augments wp.media.View
  8523  * @augments wp.media.View
  3790  * @augments wp.Backbone.View
  8524  * @augments wp.Backbone.View
  3791  * @augments Backbone.View
  8525  * @augments Backbone.View
  3792  */
  8526  */
  3793 var EditSelection = wp.media.view.Attachment.Selection.extend(/** @lends wp.media.view.Attachment.EditSelection.prototype */{
  8527 AttachmentFilters = wp.media.View.extend(/** @lends wp.media.view.AttachmentFilters.prototype */{
  3794 	buttons: {
  8528 	tagName:   'select',
  3795 		close: true
  8529 	className: 'attachment-filters',
       
  8530 	id:        'media-attachment-filters',
       
  8531 
       
  8532 	events: {
       
  8533 		change: 'change'
       
  8534 	},
       
  8535 
       
  8536 	keys: [],
       
  8537 
       
  8538 	initialize: function() {
       
  8539 		this.createFilters();
       
  8540 		_.extend( this.filters, this.options.filters );
       
  8541 
       
  8542 		// Build `<option>` elements.
       
  8543 		this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
       
  8544 			return {
       
  8545 				el: $( '<option></option>' ).val( value ).html( filter.text )[0],
       
  8546 				priority: filter.priority || 50
       
  8547 			};
       
  8548 		}, this ).sortBy('priority').pluck('el').value() );
       
  8549 
       
  8550 		this.listenTo( this.model, 'change', this.select );
       
  8551 		this.select();
       
  8552 	},
       
  8553 
       
  8554 	/**
       
  8555 	 * @abstract
       
  8556 	 */
       
  8557 	createFilters: function() {
       
  8558 		this.filters = {};
       
  8559 	},
       
  8560 
       
  8561 	/**
       
  8562 	 * When the selected filter changes, update the Attachment Query properties to match.
       
  8563 	 */
       
  8564 	change: function() {
       
  8565 		var filter = this.filters[ this.el.value ];
       
  8566 		if ( filter ) {
       
  8567 			this.model.set( filter.props );
       
  8568 		}
       
  8569 	},
       
  8570 
       
  8571 	select: function() {
       
  8572 		var model = this.model,
       
  8573 			value = 'all',
       
  8574 			props = model.toJSON();
       
  8575 
       
  8576 		_.find( this.filters, function( filter, id ) {
       
  8577 			var equal = _.all( filter.props, function( prop, key ) {
       
  8578 				return prop === ( _.isUndefined( props[ key ] ) ? null : props[ key ] );
       
  8579 			});
       
  8580 
       
  8581 			if ( equal ) {
       
  8582 				return value = id;
       
  8583 			}
       
  8584 		});
       
  8585 
       
  8586 		this.$el.val( value );
  3796 	}
  8587 	}
  3797 });
  8588 });
  3798 
  8589 
  3799 module.exports = EditSelection;
  8590 module.exports = AttachmentFilters;
  3800 
  8591 
  3801 
  8592 
  3802 /***/ }),
  8593 /***/ }),
  3803 
  8594 
  3804 /***/ 3443:
  8595 /***/ 7810:
  3805 /***/ ((module) => {
  8596 /***/ ((module) => {
  3806 
  8597 
       
  8598 var View = wp.media.View,
       
  8599 	$ = jQuery,
       
  8600 	SiteIconPreview;
       
  8601 
  3807 /**
  8602 /**
  3808  * wp.media.view.Attachment.Library
  8603  * wp.media.view.SiteIconPreview
  3809  *
  8604  *
  3810  * @memberOf wp.media.view.Attachment
  8605  * Shows a preview of the Site Icon as a favicon and app icon while cropping.
       
  8606  *
       
  8607  * @memberOf wp.media.view
  3811  *
  8608  *
  3812  * @class
  8609  * @class
  3813  * @augments wp.media.view.Attachment
       
  3814  * @augments wp.media.View
  8610  * @augments wp.media.View
  3815  * @augments wp.Backbone.View
  8611  * @augments wp.Backbone.View
  3816  * @augments Backbone.View
  8612  * @augments Backbone.View
  3817  */
  8613  */
  3818 var Library = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Library.prototype */{
  8614 SiteIconPreview = View.extend(/** @lends wp.media.view.SiteIconPreview.prototype */{
  3819 	buttons: {
  8615 	className: 'site-icon-preview-crop-modal',
  3820 		check: true
  8616 	template: wp.template( 'site-icon-preview-crop' ),
       
  8617 
       
  8618 	ready: function() {
       
  8619 		this.controller.imgSelect.setOptions({
       
  8620 			onInit: this.updatePreview,
       
  8621 			onSelectChange: this.updatePreview
       
  8622 		});
       
  8623 	},
       
  8624 
       
  8625 	prepare: function() {
       
  8626 		return {
       
  8627 			url: this.options.attachment.get( 'url' )
       
  8628 		};
       
  8629 	},
       
  8630 
       
  8631 	updatePreview: function( img, coords ) {
       
  8632 		var rx = 64 / coords.width,
       
  8633 			ry = 64 / coords.height,
       
  8634 			preview_rx = 24 / coords.width,
       
  8635 			preview_ry = 24 / coords.height;
       
  8636 
       
  8637 		$( '#preview-app-icon' ).css({
       
  8638 			width: Math.round(rx * this.imageWidth ) + 'px',
       
  8639 			height: Math.round(ry * this.imageHeight ) + 'px',
       
  8640 			marginLeft: '-' + Math.round(rx * coords.x1) + 'px',
       
  8641 			marginTop: '-' + Math.round(ry * coords.y1) + 'px'
       
  8642 		});
       
  8643 
       
  8644 		$( '#preview-favicon' ).css({
       
  8645 			width: Math.round( preview_rx * this.imageWidth ) + 'px',
       
  8646 			height: Math.round( preview_ry * this.imageHeight ) + 'px',
       
  8647 			marginLeft: '-' + Math.round( preview_rx * coords.x1 ) + 'px',
       
  8648 			marginTop: '-' + Math.floor( preview_ry* coords.y1 ) + 'px'
       
  8649 		});
  3821 	}
  8650 	}
  3822 });
  8651 });
  3823 
  8652 
  3824 module.exports = Library;
  8653 module.exports = SiteIconPreview;
  3825 
  8654 
  3826 
  8655 
  3827 /***/ }),
  8656 /***/ }),
  3828 
  8657 
  3829 /***/ 3962:
  8658 /***/ 8065:
  3830 /***/ ((module) => {
  8659 /***/ ((module) => {
  3831 
  8660 
  3832 /**
  8661 /**
  3833  * wp.media.view.Attachment.Selection
  8662  * wp.media.controller.MediaLibrary
  3834  *
  8663  *
  3835  * @memberOf wp.media.view.Attachment
  8664  * @memberOf wp.media.controller
  3836  *
  8665  *
  3837  * @class
  8666  * @class
  3838  * @augments wp.media.view.Attachment
  8667  * @augments wp.media.controller.Library
  3839  * @augments wp.media.View
  8668  * @augments wp.media.controller.State
  3840  * @augments wp.Backbone.View
  8669  * @augments Backbone.Model
  3841  * @augments Backbone.View
       
  3842  */
  8670  */
  3843 var Selection = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Selection.prototype */{
  8671 var Library = wp.media.controller.Library,
  3844 	className: 'attachment selection',
  8672 	MediaLibrary;
  3845 
  8673 
  3846 	// On click, just select the model, instead of removing the model from
  8674 MediaLibrary = Library.extend(/** @lends wp.media.controller.MediaLibrary.prototype */{
  3847 	// the selection.
  8675 	defaults: _.defaults({
  3848 	toggleSelection: function() {
  8676 		// Attachments browser defaults. @see media.view.AttachmentsBrowser
  3849 		this.options.selection.single( this.model );
  8677 		filterable:      'uploaded',
       
  8678 
       
  8679 		displaySettings: false,
       
  8680 		priority:        80,
       
  8681 		syncSelection:   false
       
  8682 	}, Library.prototype.defaults ),
       
  8683 
       
  8684 	/**
       
  8685 	 * @since 3.9.0
       
  8686 	 *
       
  8687 	 * @param options
       
  8688 	 */
       
  8689 	initialize: function( options ) {
       
  8690 		this.media = options.media;
       
  8691 		this.type = options.type;
       
  8692 		this.set( 'library', wp.media.query({ type: this.type }) );
       
  8693 
       
  8694 		Library.prototype.initialize.apply( this, arguments );
       
  8695 	},
       
  8696 
       
  8697 	/**
       
  8698 	 * @since 3.9.0
       
  8699 	 */
       
  8700 	activate: function() {
       
  8701 		// @todo this should use this.frame.
       
  8702 		if ( wp.media.frame.lastMime ) {
       
  8703 			this.set( 'library', wp.media.query({ type: wp.media.frame.lastMime }) );
       
  8704 			delete wp.media.frame.lastMime;
       
  8705 		}
       
  8706 		Library.prototype.activate.apply( this, arguments );
  3850 	}
  8707 	}
  3851 });
  8708 });
  3852 
  8709 
  3853 module.exports = Selection;
  8710 module.exports = MediaLibrary;
  3854 
  8711 
  3855 
  8712 
  3856 /***/ }),
  8713 /***/ }),
  3857 
  8714 
  3858 /***/ 8142:
  8715 /***/ 8142:
  4323 module.exports = Attachments;
  9180 module.exports = Attachments;
  4324 
  9181 
  4325 
  9182 
  4326 /***/ }),
  9183 /***/ }),
  4327 
  9184 
  4328 /***/ 6829:
  9185 /***/ 8197:
  4329 /***/ ((module) => {
  9186 /***/ ((module) => {
  4330 
  9187 
  4331 var View = wp.media.View,
  9188 var View = wp.media.View,
  4332 	mediaTrash = wp.media.view.settings.mediaTrash,
  9189 	UploaderStatus;
  4333 	l10n = wp.media.view.l10n,
       
  4334 	$ = jQuery,
       
  4335 	AttachmentsBrowser,
       
  4336 	infiniteScrolling = wp.media.view.settings.infiniteScrolling,
       
  4337 	__ = wp.i18n.__,
       
  4338 	sprintf = wp.i18n.sprintf;
       
  4339 
  9190 
  4340 /**
  9191 /**
  4341  * wp.media.view.AttachmentsBrowser
  9192  * wp.media.view.UploaderStatus
  4342  *
  9193  *
  4343  * @memberOf wp.media.view
  9194  * An uploader status for on-going uploads.
  4344  *
       
  4345  * @class
       
  4346  * @augments wp.media.View
       
  4347  * @augments wp.Backbone.View
       
  4348  * @augments Backbone.View
       
  4349  *
       
  4350  * @param {object}         [options]               The options hash passed to the view.
       
  4351  * @param {boolean|string} [options.filters=false] Which filters to show in the browser's toolbar.
       
  4352  *                                                 Accepts 'uploaded' and 'all'.
       
  4353  * @param {boolean}        [options.search=true]   Whether to show the search interface in the
       
  4354  *                                                 browser's toolbar.
       
  4355  * @param {boolean}        [options.date=true]     Whether to show the date filter in the
       
  4356  *                                                 browser's toolbar.
       
  4357  * @param {boolean}        [options.display=false] Whether to show the attachments display settings
       
  4358  *                                                 view in the sidebar.
       
  4359  * @param {boolean|string} [options.sidebar=true]  Whether to create a sidebar for the browser.
       
  4360  *                                                 Accepts true, false, and 'errors'.
       
  4361  */
       
  4362 AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.prototype */{
       
  4363 	tagName:   'div',
       
  4364 	className: 'attachments-browser',
       
  4365 
       
  4366 	initialize: function() {
       
  4367 		_.defaults( this.options, {
       
  4368 			filters: false,
       
  4369 			search:  true,
       
  4370 			date:    true,
       
  4371 			display: false,
       
  4372 			sidebar: true,
       
  4373 			AttachmentView: wp.media.view.Attachment.Library
       
  4374 		});
       
  4375 
       
  4376 		this.controller.on( 'toggle:upload:attachment', this.toggleUploader, this );
       
  4377 		this.controller.on( 'edit:selection', this.editSelection );
       
  4378 
       
  4379 		// In the Media Library, the sidebar is used to display errors before the attachments grid.
       
  4380 		if ( this.options.sidebar && 'errors' === this.options.sidebar ) {
       
  4381 			this.createSidebar();
       
  4382 		}
       
  4383 
       
  4384 		/*
       
  4385 		 * In the grid mode (the Media Library), place the Inline Uploader before
       
  4386 		 * other sections so that the visual order and the DOM order match. This way,
       
  4387 		 * the Inline Uploader in the Media Library is right after the "Add New"
       
  4388 		 * button, see ticket #37188.
       
  4389 		 */
       
  4390 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  4391 			this.createUploader();
       
  4392 
       
  4393 			/*
       
  4394 			 * Create a multi-purpose toolbar. Used as main toolbar in the Media Library
       
  4395 			 * and also for other things, for example the "Drag and drop to reorder" and
       
  4396 			 * "Suggested dimensions" info in the media modal.
       
  4397 			 */
       
  4398 			this.createToolbar();
       
  4399 		} else {
       
  4400 			this.createToolbar();
       
  4401 			this.createUploader();
       
  4402 		}
       
  4403 
       
  4404 		// Add a heading before the attachments list.
       
  4405 		this.createAttachmentsHeading();
       
  4406 
       
  4407 		// Create the attachments wrapper view.
       
  4408 		this.createAttachmentsWrapperView();
       
  4409 
       
  4410 		if ( ! infiniteScrolling ) {
       
  4411 			this.$el.addClass( 'has-load-more' );
       
  4412 			this.createLoadMoreView();
       
  4413 		}
       
  4414 
       
  4415 		// For accessibility reasons, place the normal sidebar after the attachments, see ticket #36909.
       
  4416 		if ( this.options.sidebar && 'errors' !== this.options.sidebar ) {
       
  4417 			this.createSidebar();
       
  4418 		}
       
  4419 
       
  4420 		this.updateContent();
       
  4421 
       
  4422 		if ( ! infiniteScrolling ) {
       
  4423 			this.updateLoadMoreView();
       
  4424 		}
       
  4425 
       
  4426 		if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
       
  4427 			this.$el.addClass( 'hide-sidebar' );
       
  4428 
       
  4429 			if ( 'errors' === this.options.sidebar ) {
       
  4430 				this.$el.addClass( 'sidebar-for-errors' );
       
  4431 			}
       
  4432 		}
       
  4433 
       
  4434 		this.collection.on( 'add remove reset', this.updateContent, this );
       
  4435 
       
  4436 		if ( ! infiniteScrolling ) {
       
  4437 			this.collection.on( 'add remove reset', this.updateLoadMoreView, this );
       
  4438 		}
       
  4439 
       
  4440 		// The non-cached or cached attachments query has completed.
       
  4441 		this.collection.on( 'attachments:received', this.announceSearchResults, this );
       
  4442 	},
       
  4443 
       
  4444 	/**
       
  4445 	 * Updates the `wp.a11y.speak()` ARIA live region with a message to communicate
       
  4446 	 * the number of search results to screen reader users. This function is
       
  4447 	 * debounced because the collection updates multiple times.
       
  4448 	 *
       
  4449 	 * @since 5.3.0
       
  4450 	 *
       
  4451 	 * @return {void}
       
  4452 	 */
       
  4453 	announceSearchResults: _.debounce( function() {
       
  4454 		var count,
       
  4455 			/* translators: Accessibility text. %d: Number of attachments found in a search. */
       
  4456 			mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Click load more for more results.' );
       
  4457 
       
  4458 		if ( infiniteScrolling ) {
       
  4459 			/* translators: Accessibility text. %d: Number of attachments found in a search. */
       
  4460 			mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Scroll the page for more results.' );
       
  4461 		}
       
  4462 
       
  4463 		if ( this.collection.mirroring && this.collection.mirroring.args.s ) {
       
  4464 			count = this.collection.length;
       
  4465 
       
  4466 			if ( 0 === count ) {
       
  4467 				wp.a11y.speak( l10n.noMediaTryNewSearch );
       
  4468 				return;
       
  4469 			}
       
  4470 
       
  4471 			if ( this.collection.hasMore() ) {
       
  4472 				wp.a11y.speak( mediaFoundHasMoreResultsMessage.replace( '%d', count ) );
       
  4473 				return;
       
  4474 			}
       
  4475 
       
  4476 			wp.a11y.speak( l10n.mediaFound.replace( '%d', count ) );
       
  4477 		}
       
  4478 	}, 200 ),
       
  4479 
       
  4480 	editSelection: function( modal ) {
       
  4481 		// When editing a selection, move focus to the "Go to library" button.
       
  4482 		modal.$( '.media-button-backToLibrary' ).focus();
       
  4483 	},
       
  4484 
       
  4485 	/**
       
  4486 	 * @return {wp.media.view.AttachmentsBrowser} Returns itself to allow chaining.
       
  4487 	 */
       
  4488 	dispose: function() {
       
  4489 		this.options.selection.off( null, null, this );
       
  4490 		View.prototype.dispose.apply( this, arguments );
       
  4491 		return this;
       
  4492 	},
       
  4493 
       
  4494 	createToolbar: function() {
       
  4495 		var LibraryViewSwitcher, Filters, toolbarOptions,
       
  4496 			showFilterByType = -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] );
       
  4497 
       
  4498 		toolbarOptions = {
       
  4499 			controller: this.controller
       
  4500 		};
       
  4501 
       
  4502 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  4503 			toolbarOptions.className = 'media-toolbar wp-filter';
       
  4504 		}
       
  4505 
       
  4506 		/**
       
  4507 		* @member {wp.media.view.Toolbar}
       
  4508 		*/
       
  4509 		this.toolbar = new wp.media.view.Toolbar( toolbarOptions );
       
  4510 
       
  4511 		this.views.add( this.toolbar );
       
  4512 
       
  4513 		this.toolbar.set( 'spinner', new wp.media.view.Spinner({
       
  4514 			priority: -20
       
  4515 		}) );
       
  4516 
       
  4517 		if ( showFilterByType || this.options.date ) {
       
  4518 			/*
       
  4519 			 * Create a h2 heading before the select elements that filter attachments.
       
  4520 			 * This heading is visible in the modal and visually hidden in the grid.
       
  4521 			 */
       
  4522 			this.toolbar.set( 'filters-heading', new wp.media.view.Heading( {
       
  4523 				priority:   -100,
       
  4524 				text:       l10n.filterAttachments,
       
  4525 				level:      'h2',
       
  4526 				className:  'media-attachments-filter-heading'
       
  4527 			}).render() );
       
  4528 		}
       
  4529 
       
  4530 		if ( showFilterByType ) {
       
  4531 			// "Filters" is a <select>, a visually hidden label element needs to be rendered before.
       
  4532 			this.toolbar.set( 'filtersLabel', new wp.media.view.Label({
       
  4533 				value: l10n.filterByType,
       
  4534 				attributes: {
       
  4535 					'for':  'media-attachment-filters'
       
  4536 				},
       
  4537 				priority:   -80
       
  4538 			}).render() );
       
  4539 
       
  4540 			if ( 'uploaded' === this.options.filters ) {
       
  4541 				this.toolbar.set( 'filters', new wp.media.view.AttachmentFilters.Uploaded({
       
  4542 					controller: this.controller,
       
  4543 					model:      this.collection.props,
       
  4544 					priority:   -80
       
  4545 				}).render() );
       
  4546 			} else {
       
  4547 				Filters = new wp.media.view.AttachmentFilters.All({
       
  4548 					controller: this.controller,
       
  4549 					model:      this.collection.props,
       
  4550 					priority:   -80
       
  4551 				});
       
  4552 
       
  4553 				this.toolbar.set( 'filters', Filters.render() );
       
  4554 			}
       
  4555 		}
       
  4556 
       
  4557 		/*
       
  4558 		 * Feels odd to bring the global media library switcher into the Attachment browser view.
       
  4559 		 * Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
       
  4560 		 * which the controller can tap into and add this view?
       
  4561 		 */
       
  4562 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  4563 			LibraryViewSwitcher = View.extend({
       
  4564 				className: 'view-switch media-grid-view-switch',
       
  4565 				template: wp.template( 'media-library-view-switcher')
       
  4566 			});
       
  4567 
       
  4568 			this.toolbar.set( 'libraryViewSwitcher', new LibraryViewSwitcher({
       
  4569 				controller: this.controller,
       
  4570 				priority: -90
       
  4571 			}).render() );
       
  4572 
       
  4573 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
       
  4574 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
       
  4575 				value: l10n.filterByDate,
       
  4576 				attributes: {
       
  4577 					'for': 'media-attachment-date-filters'
       
  4578 				},
       
  4579 				priority: -75
       
  4580 			}).render() );
       
  4581 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
       
  4582 				controller: this.controller,
       
  4583 				model:      this.collection.props,
       
  4584 				priority: -75
       
  4585 			}).render() );
       
  4586 
       
  4587 			// BulkSelection is a <div> with subviews, including screen reader text.
       
  4588 			this.toolbar.set( 'selectModeToggleButton', new wp.media.view.SelectModeToggleButton({
       
  4589 				text: l10n.bulkSelect,
       
  4590 				controller: this.controller,
       
  4591 				priority: -70
       
  4592 			}).render() );
       
  4593 
       
  4594 			this.toolbar.set( 'deleteSelectedButton', new wp.media.view.DeleteSelectedButton({
       
  4595 				filters: Filters,
       
  4596 				style: 'primary',
       
  4597 				disabled: true,
       
  4598 				text: mediaTrash ? l10n.trashSelected : l10n.deletePermanently,
       
  4599 				controller: this.controller,
       
  4600 				priority: -80,
       
  4601 				click: function() {
       
  4602 					var changed = [], removed = [],
       
  4603 						selection = this.controller.state().get( 'selection' ),
       
  4604 						library = this.controller.state().get( 'library' );
       
  4605 
       
  4606 					if ( ! selection.length ) {
       
  4607 						return;
       
  4608 					}
       
  4609 
       
  4610 					if ( ! mediaTrash && ! window.confirm( l10n.warnBulkDelete ) ) {
       
  4611 						return;
       
  4612 					}
       
  4613 
       
  4614 					if ( mediaTrash &&
       
  4615 						'trash' !== selection.at( 0 ).get( 'status' ) &&
       
  4616 						! window.confirm( l10n.warnBulkTrash ) ) {
       
  4617 
       
  4618 						return;
       
  4619 					}
       
  4620 
       
  4621 					selection.each( function( model ) {
       
  4622 						if ( ! model.get( 'nonces' )['delete'] ) {
       
  4623 							removed.push( model );
       
  4624 							return;
       
  4625 						}
       
  4626 
       
  4627 						if ( mediaTrash && 'trash' === model.get( 'status' ) ) {
       
  4628 							model.set( 'status', 'inherit' );
       
  4629 							changed.push( model.save() );
       
  4630 							removed.push( model );
       
  4631 						} else if ( mediaTrash ) {
       
  4632 							model.set( 'status', 'trash' );
       
  4633 							changed.push( model.save() );
       
  4634 							removed.push( model );
       
  4635 						} else {
       
  4636 							model.destroy({wait: true});
       
  4637 						}
       
  4638 					} );
       
  4639 
       
  4640 					if ( changed.length ) {
       
  4641 						selection.remove( removed );
       
  4642 
       
  4643 						$.when.apply( null, changed ).then( _.bind( function() {
       
  4644 							library._requery( true );
       
  4645 							this.controller.trigger( 'selection:action:done' );
       
  4646 						}, this ) );
       
  4647 					} else {
       
  4648 						this.controller.trigger( 'selection:action:done' );
       
  4649 					}
       
  4650 				}
       
  4651 			}).render() );
       
  4652 
       
  4653 			if ( mediaTrash ) {
       
  4654 				this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
       
  4655 					filters: Filters,
       
  4656 					style: 'link button-link-delete',
       
  4657 					disabled: true,
       
  4658 					text: l10n.deletePermanently,
       
  4659 					controller: this.controller,
       
  4660 					priority: -55,
       
  4661 					click: function() {
       
  4662 						var removed = [],
       
  4663 							destroy = [],
       
  4664 							selection = this.controller.state().get( 'selection' );
       
  4665 
       
  4666 						if ( ! selection.length || ! window.confirm( l10n.warnBulkDelete ) ) {
       
  4667 							return;
       
  4668 						}
       
  4669 
       
  4670 						selection.each( function( model ) {
       
  4671 							if ( ! model.get( 'nonces' )['delete'] ) {
       
  4672 								removed.push( model );
       
  4673 								return;
       
  4674 							}
       
  4675 
       
  4676 							destroy.push( model );
       
  4677 						} );
       
  4678 
       
  4679 						if ( removed.length ) {
       
  4680 							selection.remove( removed );
       
  4681 						}
       
  4682 
       
  4683 						if ( destroy.length ) {
       
  4684 							$.when.apply( null, destroy.map( function (item) {
       
  4685 								return item.destroy();
       
  4686 							} ) ).then( _.bind( function() {
       
  4687 								this.controller.trigger( 'selection:action:done' );
       
  4688 							}, this ) );
       
  4689 						}
       
  4690 					}
       
  4691 				}).render() );
       
  4692 			}
       
  4693 
       
  4694 		} else if ( this.options.date ) {
       
  4695 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
       
  4696 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
       
  4697 				value: l10n.filterByDate,
       
  4698 				attributes: {
       
  4699 					'for': 'media-attachment-date-filters'
       
  4700 				},
       
  4701 				priority: -75
       
  4702 			}).render() );
       
  4703 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
       
  4704 				controller: this.controller,
       
  4705 				model:      this.collection.props,
       
  4706 				priority: -75
       
  4707 			}).render() );
       
  4708 		}
       
  4709 
       
  4710 		if ( this.options.search ) {
       
  4711 			// Search is an input, a label element needs to be rendered before.
       
  4712 			this.toolbar.set( 'searchLabel', new wp.media.view.Label({
       
  4713 				value: l10n.searchLabel,
       
  4714 				className: 'media-search-input-label',
       
  4715 				attributes: {
       
  4716 					'for': 'media-search-input'
       
  4717 				},
       
  4718 				priority:   60
       
  4719 			}).render() );
       
  4720 			this.toolbar.set( 'search', new wp.media.view.Search({
       
  4721 				controller: this.controller,
       
  4722 				model:      this.collection.props,
       
  4723 				priority:   60
       
  4724 			}).render() );
       
  4725 		}
       
  4726 
       
  4727 		if ( this.options.dragInfo ) {
       
  4728 			this.toolbar.set( 'dragInfo', new View({
       
  4729 				el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
       
  4730 				priority: -40
       
  4731 			}) );
       
  4732 		}
       
  4733 
       
  4734 		if ( this.options.suggestedWidth && this.options.suggestedHeight ) {
       
  4735 			this.toolbar.set( 'suggestedDimensions', new View({
       
  4736 				el: $( '<div class="instructions">' + l10n.suggestedDimensions.replace( '%1$s', this.options.suggestedWidth ).replace( '%2$s', this.options.suggestedHeight ) + '</div>' )[0],
       
  4737 				priority: -40
       
  4738 			}) );
       
  4739 		}
       
  4740 	},
       
  4741 
       
  4742 	updateContent: function() {
       
  4743 		var view = this,
       
  4744 			noItemsView;
       
  4745 
       
  4746 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  4747 			// Usually the media library.
       
  4748 			noItemsView = view.attachmentsNoResults;
       
  4749 		} else {
       
  4750 			// Usually the media modal.
       
  4751 			noItemsView = view.uploader;
       
  4752 		}
       
  4753 
       
  4754 		if ( ! this.collection.length ) {
       
  4755 			this.toolbar.get( 'spinner' ).show();
       
  4756 			this.toolbar.$( '.media-bg-overlay' ).show();
       
  4757 			this.dfd = this.collection.more().done( function() {
       
  4758 				if ( ! view.collection.length ) {
       
  4759 					noItemsView.$el.removeClass( 'hidden' );
       
  4760 				} else {
       
  4761 					noItemsView.$el.addClass( 'hidden' );
       
  4762 				}
       
  4763 				view.toolbar.get( 'spinner' ).hide();
       
  4764 				view.toolbar.$( '.media-bg-overlay' ).hide();
       
  4765 			} );
       
  4766 		} else {
       
  4767 			noItemsView.$el.addClass( 'hidden' );
       
  4768 			view.toolbar.get( 'spinner' ).hide();
       
  4769 			this.toolbar.$( '.media-bg-overlay' ).hide();
       
  4770 		}
       
  4771 	},
       
  4772 
       
  4773 	createUploader: function() {
       
  4774 		this.uploader = new wp.media.view.UploaderInline({
       
  4775 			controller: this.controller,
       
  4776 			status:     false,
       
  4777 			message:    this.controller.isModeActive( 'grid' ) ? '' : l10n.noItemsFound,
       
  4778 			canClose:   this.controller.isModeActive( 'grid' )
       
  4779 		});
       
  4780 
       
  4781 		this.uploader.$el.addClass( 'hidden' );
       
  4782 		this.views.add( this.uploader );
       
  4783 	},
       
  4784 
       
  4785 	toggleUploader: function() {
       
  4786 		if ( this.uploader.$el.hasClass( 'hidden' ) ) {
       
  4787 			this.uploader.show();
       
  4788 		} else {
       
  4789 			this.uploader.hide();
       
  4790 		}
       
  4791 	},
       
  4792 
       
  4793 	/**
       
  4794 	 * Creates the Attachments wrapper view.
       
  4795 	 *
       
  4796 	 * @since 5.8.0
       
  4797 	 *
       
  4798 	 * @return {void}
       
  4799 	 */
       
  4800 	createAttachmentsWrapperView: function() {
       
  4801 		this.attachmentsWrapper = new wp.media.View( {
       
  4802 			className: 'attachments-wrapper'
       
  4803 		} );
       
  4804 
       
  4805 		// Create the list of attachments.
       
  4806 		this.views.add( this.attachmentsWrapper );
       
  4807 		this.createAttachments();
       
  4808 	},
       
  4809 
       
  4810 	createAttachments: function() {
       
  4811 		this.attachments = new wp.media.view.Attachments({
       
  4812 			controller:           this.controller,
       
  4813 			collection:           this.collection,
       
  4814 			selection:            this.options.selection,
       
  4815 			model:                this.model,
       
  4816 			sortable:             this.options.sortable,
       
  4817 			scrollElement:        this.options.scrollElement,
       
  4818 			idealColumnWidth:     this.options.idealColumnWidth,
       
  4819 
       
  4820 			// The single `Attachment` view to be used in the `Attachments` view.
       
  4821 			AttachmentView: this.options.AttachmentView
       
  4822 		});
       
  4823 
       
  4824 		// Add keydown listener to the instance of the Attachments view.
       
  4825 		this.controller.on( 'attachment:keydown:arrow',     _.bind( this.attachments.arrowEvent, this.attachments ) );
       
  4826 		this.controller.on( 'attachment:details:shift-tab', _.bind( this.attachments.restoreFocus, this.attachments ) );
       
  4827 
       
  4828 		this.views.add( '.attachments-wrapper', this.attachments );
       
  4829 
       
  4830 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  4831 			this.attachmentsNoResults = new View({
       
  4832 				controller: this.controller,
       
  4833 				tagName: 'p'
       
  4834 			});
       
  4835 
       
  4836 			this.attachmentsNoResults.$el.addClass( 'hidden no-media' );
       
  4837 			this.attachmentsNoResults.$el.html( l10n.noMedia );
       
  4838 
       
  4839 			this.views.add( this.attachmentsNoResults );
       
  4840 		}
       
  4841 	},
       
  4842 
       
  4843 	/**
       
  4844 	 * Creates the load more button and attachments counter view.
       
  4845 	 *
       
  4846 	 * @since 5.8.0
       
  4847 	 *
       
  4848 	 * @return {void}
       
  4849 	 */
       
  4850 	createLoadMoreView: function() {
       
  4851 		var view = this;
       
  4852 
       
  4853 		this.loadMoreWrapper = new View( {
       
  4854 			controller: this.controller,
       
  4855 			className: 'load-more-wrapper'
       
  4856 		} );
       
  4857 
       
  4858 		this.loadMoreCount = new View( {
       
  4859 			controller: this.controller,
       
  4860 			tagName: 'p',
       
  4861 			className: 'load-more-count hidden'
       
  4862 		} );
       
  4863 
       
  4864 		this.loadMoreButton = new wp.media.view.Button( {
       
  4865 			text: __( 'Load more' ),
       
  4866 			className: 'load-more hidden',
       
  4867 			style: 'primary',
       
  4868 			size: '',
       
  4869 			click: function() {
       
  4870 				view.loadMoreAttachments();
       
  4871 			}
       
  4872 		} );
       
  4873 
       
  4874 		this.loadMoreSpinner = new wp.media.view.Spinner();
       
  4875 
       
  4876 		this.loadMoreJumpToFirst = new wp.media.view.Button( {
       
  4877 			text: __( 'Jump to first loaded item' ),
       
  4878 			className: 'load-more-jump hidden',
       
  4879 			size: '',
       
  4880 			click: function() {
       
  4881 				view.jumpToFirstAddedItem();
       
  4882 			}
       
  4883 		} );
       
  4884 
       
  4885 		this.views.add( '.attachments-wrapper', this.loadMoreWrapper );
       
  4886 		this.views.add( '.load-more-wrapper', this.loadMoreSpinner );
       
  4887 		this.views.add( '.load-more-wrapper', this.loadMoreCount );
       
  4888 		this.views.add( '.load-more-wrapper', this.loadMoreButton );
       
  4889 		this.views.add( '.load-more-wrapper', this.loadMoreJumpToFirst );
       
  4890 	},
       
  4891 
       
  4892 	/**
       
  4893 	 * Updates the Load More view. This function is debounced because the
       
  4894 	 * collection updates multiple times at the add, remove, and reset events.
       
  4895 	 * We need it to run only once, after all attachments are added or removed.
       
  4896 	 *
       
  4897 	 * @since 5.8.0
       
  4898 	 *
       
  4899 	 * @return {void}
       
  4900 	 */
       
  4901 	updateLoadMoreView: _.debounce( function() {
       
  4902 		// Ensure the load more view elements are initially hidden at each update.
       
  4903 		this.loadMoreButton.$el.addClass( 'hidden' );
       
  4904 		this.loadMoreCount.$el.addClass( 'hidden' );
       
  4905 		this.loadMoreJumpToFirst.$el.addClass( 'hidden' ).prop( 'disabled', true );
       
  4906 
       
  4907 		if ( ! this.collection.getTotalAttachments() ) {
       
  4908 			return;
       
  4909 		}
       
  4910 
       
  4911 		if ( this.collection.length ) {
       
  4912 			this.loadMoreCount.$el.text(
       
  4913 				/* translators: 1: Number of displayed attachments, 2: Number of total attachments. */
       
  4914 				sprintf(
       
  4915 					__( 'Showing %1$s of %2$s media items' ),
       
  4916 					this.collection.length,
       
  4917 					this.collection.getTotalAttachments()
       
  4918 				)
       
  4919 			);
       
  4920 
       
  4921 			this.loadMoreCount.$el.removeClass( 'hidden' );
       
  4922 		}
       
  4923 
       
  4924 		/*
       
  4925 		 * Notice that while the collection updates multiple times hasMore() may
       
  4926 		 * return true when it's actually not true.
       
  4927 		 */
       
  4928 		if ( this.collection.hasMore() ) {
       
  4929 			this.loadMoreButton.$el.removeClass( 'hidden' );
       
  4930 		}
       
  4931 
       
  4932 		// Find the media item to move focus to. The jQuery `eq()` index is zero-based.
       
  4933 		this.firstAddedMediaItem = this.$el.find( '.attachment' ).eq( this.firstAddedMediaItemIndex );
       
  4934 
       
  4935 		// If there's a media item to move focus to, make the "Jump to" button available.
       
  4936 		if ( this.firstAddedMediaItem.length ) {
       
  4937 			this.firstAddedMediaItem.addClass( 'new-media' );
       
  4938 			this.loadMoreJumpToFirst.$el.removeClass( 'hidden' ).prop( 'disabled', false );
       
  4939 		}
       
  4940 
       
  4941 		// If there are new items added, but no more to be added, move focus to Jump button.
       
  4942 		if ( this.firstAddedMediaItem.length && ! this.collection.hasMore() ) {
       
  4943 			this.loadMoreJumpToFirst.$el.trigger( 'focus' );
       
  4944 		}
       
  4945 	}, 10 ),
       
  4946 
       
  4947 	/**
       
  4948 	 * Loads more attachments.
       
  4949 	 *
       
  4950 	 * @since 5.8.0
       
  4951 	 *
       
  4952 	 * @return {void}
       
  4953 	 */
       
  4954 	loadMoreAttachments: function() {
       
  4955 		var view = this;
       
  4956 
       
  4957 		if ( ! this.collection.hasMore() ) {
       
  4958 			return;
       
  4959 		}
       
  4960 
       
  4961 		/*
       
  4962 		 * The collection index is zero-based while the length counts the actual
       
  4963 		 * amount of items. Thus the length is equivalent to the position of the
       
  4964 		 * first added item.
       
  4965 		 */
       
  4966 		this.firstAddedMediaItemIndex = this.collection.length;
       
  4967 
       
  4968 		this.$el.addClass( 'more-loaded' );
       
  4969 		this.collection.each( function( attachment ) {
       
  4970 			var attach_id = attachment.attributes.id;
       
  4971 			$( '[data-id="' + attach_id + '"]' ).addClass( 'found-media' );
       
  4972 		});
       
  4973 
       
  4974 		view.loadMoreSpinner.show();
       
  4975 		this.collection.once( 'attachments:received', function() {
       
  4976 			view.loadMoreSpinner.hide();
       
  4977 		} );
       
  4978 		this.collection.more();
       
  4979 	},
       
  4980 
       
  4981 	/**
       
  4982 	 * Moves focus to the first new added item.	.
       
  4983 	 *
       
  4984 	 * @since 5.8.0
       
  4985 	 *
       
  4986 	 * @return {void}
       
  4987 	 */
       
  4988 	jumpToFirstAddedItem: function() {
       
  4989 		// Set focus on first added item.
       
  4990 		this.firstAddedMediaItem.focus();
       
  4991 	},
       
  4992 
       
  4993 	createAttachmentsHeading: function() {
       
  4994 		this.attachmentsHeading = new wp.media.view.Heading( {
       
  4995 			text: l10n.attachmentsList,
       
  4996 			level: 'h2',
       
  4997 			className: 'media-views-heading screen-reader-text'
       
  4998 		} );
       
  4999 		this.views.add( this.attachmentsHeading );
       
  5000 	},
       
  5001 
       
  5002 	createSidebar: function() {
       
  5003 		var options = this.options,
       
  5004 			selection = options.selection,
       
  5005 			sidebar = this.sidebar = new wp.media.view.Sidebar({
       
  5006 				controller: this.controller
       
  5007 			});
       
  5008 
       
  5009 		this.views.add( sidebar );
       
  5010 
       
  5011 		if ( this.controller.uploader ) {
       
  5012 			sidebar.set( 'uploads', new wp.media.view.UploaderStatus({
       
  5013 				controller: this.controller,
       
  5014 				priority:   40
       
  5015 			}) );
       
  5016 		}
       
  5017 
       
  5018 		selection.on( 'selection:single', this.createSingle, this );
       
  5019 		selection.on( 'selection:unsingle', this.disposeSingle, this );
       
  5020 
       
  5021 		if ( selection.single() ) {
       
  5022 			this.createSingle();
       
  5023 		}
       
  5024 	},
       
  5025 
       
  5026 	createSingle: function() {
       
  5027 		var sidebar = this.sidebar,
       
  5028 			single = this.options.selection.single();
       
  5029 
       
  5030 		sidebar.set( 'details', new wp.media.view.Attachment.Details({
       
  5031 			controller: this.controller,
       
  5032 			model:      single,
       
  5033 			priority:   80
       
  5034 		}) );
       
  5035 
       
  5036 		sidebar.set( 'compat', new wp.media.view.AttachmentCompat({
       
  5037 			controller: this.controller,
       
  5038 			model:      single,
       
  5039 			priority:   120
       
  5040 		}) );
       
  5041 
       
  5042 		if ( this.options.display ) {
       
  5043 			sidebar.set( 'display', new wp.media.view.Settings.AttachmentDisplay({
       
  5044 				controller:   this.controller,
       
  5045 				model:        this.model.display( single ),
       
  5046 				attachment:   single,
       
  5047 				priority:     160,
       
  5048 				userSettings: this.model.get('displayUserSettings')
       
  5049 			}) );
       
  5050 		}
       
  5051 
       
  5052 		// Show the sidebar on mobile.
       
  5053 		if ( this.model.id === 'insert' ) {
       
  5054 			sidebar.$el.addClass( 'visible' );
       
  5055 		}
       
  5056 	},
       
  5057 
       
  5058 	disposeSingle: function() {
       
  5059 		var sidebar = this.sidebar;
       
  5060 		sidebar.unset('details');
       
  5061 		sidebar.unset('compat');
       
  5062 		sidebar.unset('display');
       
  5063 		// Hide the sidebar on mobile.
       
  5064 		sidebar.$el.removeClass( 'visible' );
       
  5065 	}
       
  5066 });
       
  5067 
       
  5068 module.exports = AttachmentsBrowser;
       
  5069 
       
  5070 
       
  5071 /***/ }),
       
  5072 
       
  5073 /***/ 3479:
       
  5074 /***/ ((module) => {
       
  5075 
       
  5076 var Attachments = wp.media.view.Attachments,
       
  5077 	Selection;
       
  5078 
       
  5079 /**
       
  5080  * wp.media.view.Attachments.Selection
       
  5081  *
       
  5082  * @memberOf wp.media.view.Attachments
       
  5083  *
       
  5084  * @class
       
  5085  * @augments wp.media.view.Attachments
       
  5086  * @augments wp.media.View
       
  5087  * @augments wp.Backbone.View
       
  5088  * @augments Backbone.View
       
  5089  */
       
  5090 Selection = Attachments.extend(/** @lends wp.media.view.Attachments.Selection.prototype */{
       
  5091 	events: {},
       
  5092 	initialize: function() {
       
  5093 		_.defaults( this.options, {
       
  5094 			sortable:   false,
       
  5095 			resize:     false,
       
  5096 
       
  5097 			// The single `Attachment` view to be used in the `Attachments` view.
       
  5098 			AttachmentView: wp.media.view.Attachment.Selection
       
  5099 		});
       
  5100 		// Call 'initialize' directly on the parent class.
       
  5101 		return Attachments.prototype.initialize.apply( this, arguments );
       
  5102 	}
       
  5103 });
       
  5104 
       
  5105 module.exports = Selection;
       
  5106 
       
  5107 
       
  5108 /***/ }),
       
  5109 
       
  5110 /***/ 168:
       
  5111 /***/ ((module) => {
       
  5112 
       
  5113 var $ = Backbone.$,
       
  5114 	ButtonGroup;
       
  5115 
       
  5116 /**
       
  5117  * wp.media.view.ButtonGroup
       
  5118  *
  9195  *
  5119  * @memberOf wp.media.view
  9196  * @memberOf wp.media.view
  5120  *
  9197  *
  5121  * @class
  9198  * @class
  5122  * @augments wp.media.View
  9199  * @augments wp.media.View
  5123  * @augments wp.Backbone.View
  9200  * @augments wp.Backbone.View
  5124  * @augments Backbone.View
  9201  * @augments Backbone.View
  5125  */
  9202  */
  5126 ButtonGroup = wp.media.View.extend(/** @lends wp.media.view.ButtonGroup.prototype */{
  9203 UploaderStatus = View.extend(/** @lends wp.media.view.UploaderStatus.prototype */{
  5127 	tagName:   'div',
  9204 	className: 'media-uploader-status',
  5128 	className: 'button-group button-large media-button-group',
  9205 	template:  wp.template('uploader-status'),
       
  9206 
       
  9207 	events: {
       
  9208 		'click .upload-dismiss-errors': 'dismiss'
       
  9209 	},
  5129 
  9210 
  5130 	initialize: function() {
  9211 	initialize: function() {
       
  9212 		this.queue = wp.Uploader.queue;
       
  9213 		this.queue.on( 'add remove reset', this.visibility, this );
       
  9214 		this.queue.on( 'add remove reset change:percent', this.progress, this );
       
  9215 		this.queue.on( 'add remove reset change:uploading', this.info, this );
       
  9216 
       
  9217 		this.errors = wp.Uploader.errors;
       
  9218 		this.errors.reset();
       
  9219 		this.errors.on( 'add remove reset', this.visibility, this );
       
  9220 		this.errors.on( 'add', this.error, this );
       
  9221 	},
       
  9222 	/**
       
  9223 	 * @return {wp.media.view.UploaderStatus}
       
  9224 	 */
       
  9225 	dispose: function() {
       
  9226 		wp.Uploader.queue.off( null, null, this );
  5131 		/**
  9227 		/**
  5132 		 * @member {wp.media.view.Button[]}
  9228 		 * call 'dispose' directly on the parent class
  5133 		 */
  9229 		 */
  5134 		this.buttons = _.map( this.options.buttons || [], function( button ) {
  9230 		View.prototype.dispose.apply( this, arguments );
  5135 			if ( button instanceof Backbone.View ) {
  9231 		return this;
  5136 				return button;
  9232 	},
  5137 			} else {
  9233 
  5138 				return new wp.media.view.Button( button ).render();
  9234 	visibility: function() {
       
  9235 		this.$el.toggleClass( 'uploading', !! this.queue.length );
       
  9236 		this.$el.toggleClass( 'errors', !! this.errors.length );
       
  9237 		this.$el.toggle( !! this.queue.length || !! this.errors.length );
       
  9238 	},
       
  9239 
       
  9240 	ready: function() {
       
  9241 		_.each({
       
  9242 			'$bar':      '.media-progress-bar div',
       
  9243 			'$index':    '.upload-index',
       
  9244 			'$total':    '.upload-total',
       
  9245 			'$filename': '.upload-filename'
       
  9246 		}, function( selector, key ) {
       
  9247 			this[ key ] = this.$( selector );
       
  9248 		}, this );
       
  9249 
       
  9250 		this.visibility();
       
  9251 		this.progress();
       
  9252 		this.info();
       
  9253 	},
       
  9254 
       
  9255 	progress: function() {
       
  9256 		var queue = this.queue,
       
  9257 			$bar = this.$bar;
       
  9258 
       
  9259 		if ( ! $bar || ! queue.length ) {
       
  9260 			return;
       
  9261 		}
       
  9262 
       
  9263 		$bar.width( ( queue.reduce( function( memo, attachment ) {
       
  9264 			if ( ! attachment.get('uploading') ) {
       
  9265 				return memo + 100;
  5139 			}
  9266 			}
       
  9267 
       
  9268 			var percent = attachment.get('percent');
       
  9269 			return memo + ( _.isNumber( percent ) ? percent : 100 );
       
  9270 		}, 0 ) / queue.length ) + '%' );
       
  9271 	},
       
  9272 
       
  9273 	info: function() {
       
  9274 		var queue = this.queue,
       
  9275 			index = 0, active;
       
  9276 
       
  9277 		if ( ! queue.length ) {
       
  9278 			return;
       
  9279 		}
       
  9280 
       
  9281 		active = this.queue.find( function( attachment, i ) {
       
  9282 			index = i;
       
  9283 			return attachment.get('uploading');
  5140 		});
  9284 		});
  5141 
  9285 
  5142 		delete this.options.buttons;
  9286 		if ( this.$index && this.$total && this.$filename ) {
  5143 
  9287 			this.$index.text( index + 1 );
  5144 		if ( this.options.classes ) {
  9288 			this.$total.text( queue.length );
  5145 			this.$el.addClass( this.options.classes );
  9289 			this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
  5146 		}
  9290 		}
  5147 	},
  9291 	},
  5148 
  9292 	/**
  5149 	/**
  9293 	 * @param {string} filename
  5150 	 * @return {wp.media.view.ButtonGroup}
  9294 	 * @return {string}
  5151 	 */
  9295 	 */
  5152 	render: function() {
  9296 	filename: function( filename ) {
  5153 		this.$el.html( $( _.pluck( this.buttons, 'el' ) ).detach() );
  9297 		return _.escape( filename );
  5154 		return this;
  9298 	},
       
  9299 	/**
       
  9300 	 * @param {Backbone.Model} error
       
  9301 	 */
       
  9302 	error: function( error ) {
       
  9303 		var statusError = new wp.media.view.UploaderStatusError( {
       
  9304 			filename: this.filename( error.get( 'file' ).name ),
       
  9305 			message:  error.get( 'message' )
       
  9306 		} );
       
  9307 
       
  9308 		var buttonClose = this.$el.find( 'button' );
       
  9309 
       
  9310 		// Can show additional info here while retrying to create image sub-sizes.
       
  9311 		this.views.add( '.upload-errors', statusError, { at: 0 } );
       
  9312 		_.delay( function() {
       
  9313 			buttonClose.trigger( 'focus' );
       
  9314 			wp.a11y.speak( error.get( 'message' ), 'assertive' );
       
  9315 		}, 1000 );
       
  9316 	},
       
  9317 
       
  9318 	dismiss: function() {
       
  9319 		var errors = this.views.get('.upload-errors');
       
  9320 
       
  9321 		if ( errors ) {
       
  9322 			_.invoke( errors, 'remove' );
       
  9323 		}
       
  9324 		wp.Uploader.errors.reset();
       
  9325 		// Move focus to the modal after the dismiss button gets removed from the DOM.
       
  9326 		if ( this.controller.modal ) {
       
  9327 			this.controller.modal.focusManager.focus();
       
  9328 		}
  5155 	}
  9329 	}
  5156 });
  9330 });
  5157 
  9331 
  5158 module.exports = ButtonGroup;
  9332 module.exports = UploaderStatus;
  5159 
       
  5160 
       
  5161 /***/ }),
       
  5162 
       
  5163 /***/ 846:
       
  5164 /***/ ((module) => {
       
  5165 
       
  5166 /**
       
  5167  * wp.media.view.Button
       
  5168  *
       
  5169  * @memberOf wp.media.view
       
  5170  *
       
  5171  * @class
       
  5172  * @augments wp.media.View
       
  5173  * @augments wp.Backbone.View
       
  5174  * @augments Backbone.View
       
  5175  */
       
  5176 var Button = wp.media.View.extend(/** @lends wp.media.view.Button.prototype */{
       
  5177 	tagName:    'button',
       
  5178 	className:  'media-button',
       
  5179 	attributes: { type: 'button' },
       
  5180 
       
  5181 	events: {
       
  5182 		'click': 'click'
       
  5183 	},
       
  5184 
       
  5185 	defaults: {
       
  5186 		text:     '',
       
  5187 		style:    '',
       
  5188 		size:     'large',
       
  5189 		disabled: false
       
  5190 	},
       
  5191 
       
  5192 	initialize: function() {
       
  5193 		/**
       
  5194 		 * Create a model with the provided `defaults`.
       
  5195 		 *
       
  5196 		 * @member {Backbone.Model}
       
  5197 		 */
       
  5198 		this.model = new Backbone.Model( this.defaults );
       
  5199 
       
  5200 		// If any of the `options` have a key from `defaults`, apply its
       
  5201 		// value to the `model` and remove it from the `options object.
       
  5202 		_.each( this.defaults, function( def, key ) {
       
  5203 			var value = this.options[ key ];
       
  5204 			if ( _.isUndefined( value ) ) {
       
  5205 				return;
       
  5206 			}
       
  5207 
       
  5208 			this.model.set( key, value );
       
  5209 			delete this.options[ key ];
       
  5210 		}, this );
       
  5211 
       
  5212 		this.listenTo( this.model, 'change', this.render );
       
  5213 	},
       
  5214 	/**
       
  5215 	 * @return {wp.media.view.Button} Returns itself to allow chaining.
       
  5216 	 */
       
  5217 	render: function() {
       
  5218 		var classes = [ 'button', this.className ],
       
  5219 			model = this.model.toJSON();
       
  5220 
       
  5221 		if ( model.style ) {
       
  5222 			classes.push( 'button-' + model.style );
       
  5223 		}
       
  5224 
       
  5225 		if ( model.size ) {
       
  5226 			classes.push( 'button-' + model.size );
       
  5227 		}
       
  5228 
       
  5229 		classes = _.uniq( classes.concat( this.options.classes ) );
       
  5230 		this.el.className = classes.join(' ');
       
  5231 
       
  5232 		this.$el.attr( 'disabled', model.disabled );
       
  5233 		this.$el.text( this.model.get('text') );
       
  5234 
       
  5235 		return this;
       
  5236 	},
       
  5237 	/**
       
  5238 	 * @param {Object} event
       
  5239 	 */
       
  5240 	click: function( event ) {
       
  5241 		if ( '#' === this.attributes.href ) {
       
  5242 			event.preventDefault();
       
  5243 		}
       
  5244 
       
  5245 		if ( this.options.click && ! this.model.get('disabled') ) {
       
  5246 			this.options.click.apply( this, arguments );
       
  5247 		}
       
  5248 	}
       
  5249 });
       
  5250 
       
  5251 module.exports = Button;
       
  5252 
       
  5253 
       
  5254 /***/ }),
       
  5255 
       
  5256 /***/ 7637:
       
  5257 /***/ ((module) => {
       
  5258 
       
  5259 var View = wp.media.View,
       
  5260 	UploaderStatus = wp.media.view.UploaderStatus,
       
  5261 	l10n = wp.media.view.l10n,
       
  5262 	$ = jQuery,
       
  5263 	Cropper;
       
  5264 
       
  5265 /**
       
  5266  * wp.media.view.Cropper
       
  5267  *
       
  5268  * Uses the imgAreaSelect plugin to allow a user to crop an image.
       
  5269  *
       
  5270  * Takes imgAreaSelect options from
       
  5271  * wp.customize.HeaderControl.calculateImageSelectOptions via
       
  5272  * wp.customize.HeaderControl.openMM.
       
  5273  *
       
  5274  * @memberOf wp.media.view
       
  5275  *
       
  5276  * @class
       
  5277  * @augments wp.media.View
       
  5278  * @augments wp.Backbone.View
       
  5279  * @augments Backbone.View
       
  5280  */
       
  5281 Cropper = View.extend(/** @lends wp.media.view.Cropper.prototype */{
       
  5282 	className: 'crop-content',
       
  5283 	template: wp.template('crop-content'),
       
  5284 	initialize: function() {
       
  5285 		_.bindAll(this, 'onImageLoad');
       
  5286 	},
       
  5287 	ready: function() {
       
  5288 		this.controller.frame.on('content:error:crop', this.onError, this);
       
  5289 		this.$image = this.$el.find('.crop-image');
       
  5290 		this.$image.on('load', this.onImageLoad);
       
  5291 		$(window).on('resize.cropper', _.debounce(this.onImageLoad, 250));
       
  5292 	},
       
  5293 	remove: function() {
       
  5294 		$(window).off('resize.cropper');
       
  5295 		this.$el.remove();
       
  5296 		this.$el.off();
       
  5297 		View.prototype.remove.apply(this, arguments);
       
  5298 	},
       
  5299 	prepare: function() {
       
  5300 		return {
       
  5301 			title: l10n.cropYourImage,
       
  5302 			url: this.options.attachment.get('url')
       
  5303 		};
       
  5304 	},
       
  5305 	onImageLoad: function() {
       
  5306 		var imgOptions = this.controller.get('imgSelectOptions'),
       
  5307 			imgSelect;
       
  5308 
       
  5309 		if (typeof imgOptions === 'function') {
       
  5310 			imgOptions = imgOptions(this.options.attachment, this.controller);
       
  5311 		}
       
  5312 
       
  5313 		imgOptions = _.extend(imgOptions, {
       
  5314 			parent: this.$el,
       
  5315 			onInit: function() {
       
  5316 
       
  5317 				// Store the set ratio.
       
  5318 				var setRatio = imgSelect.getOptions().aspectRatio;
       
  5319 
       
  5320 				// On mousedown, if no ratio is set and the Shift key is down, use a 1:1 ratio.
       
  5321 				this.parent.children().on( 'mousedown touchstart', function( e ) {
       
  5322 
       
  5323 					// If no ratio is set and the shift key is down, use a 1:1 ratio.
       
  5324 					if ( ! setRatio && e.shiftKey ) {
       
  5325 						imgSelect.setOptions( {
       
  5326 							aspectRatio: '1:1'
       
  5327 						} );
       
  5328 					}
       
  5329 				} );
       
  5330 
       
  5331 				this.parent.children().on( 'mouseup touchend', function() {
       
  5332 
       
  5333 					// Restore the set ratio.
       
  5334 					imgSelect.setOptions( {
       
  5335 						aspectRatio: setRatio ? setRatio : false
       
  5336 					} );
       
  5337 				} );
       
  5338 			}
       
  5339 		} );
       
  5340 		this.trigger('image-loaded');
       
  5341 		imgSelect = this.controller.imgSelect = this.$image.imgAreaSelect(imgOptions);
       
  5342 	},
       
  5343 	onError: function() {
       
  5344 		var filename = this.options.attachment.get('filename');
       
  5345 
       
  5346 		this.views.add( '.upload-errors', new wp.media.view.UploaderStatusError({
       
  5347 			filename: UploaderStatus.prototype.filename(filename),
       
  5348 			message: window._wpMediaViewsL10n.cropError
       
  5349 		}), { at: 0 });
       
  5350 	}
       
  5351 });
       
  5352 
       
  5353 module.exports = Cropper;
       
  5354 
       
  5355 
       
  5356 /***/ }),
       
  5357 
       
  5358 /***/ 6126:
       
  5359 /***/ ((module) => {
       
  5360 
       
  5361 var View = wp.media.View,
       
  5362 	EditImage;
       
  5363 
       
  5364 /**
       
  5365  * wp.media.view.EditImage
       
  5366  *
       
  5367  * @memberOf wp.media.view
       
  5368  *
       
  5369  * @class
       
  5370  * @augments wp.media.View
       
  5371  * @augments wp.Backbone.View
       
  5372  * @augments Backbone.View
       
  5373  */
       
  5374 EditImage = View.extend(/** @lends wp.media.view.EditImage.prototype */{
       
  5375 	className: 'image-editor',
       
  5376 	template: wp.template('image-editor'),
       
  5377 
       
  5378 	initialize: function( options ) {
       
  5379 		this.editor = window.imageEdit;
       
  5380 		this.controller = options.controller;
       
  5381 		View.prototype.initialize.apply( this, arguments );
       
  5382 	},
       
  5383 
       
  5384 	prepare: function() {
       
  5385 		return this.model.toJSON();
       
  5386 	},
       
  5387 
       
  5388 	loadEditor: function() {
       
  5389 		this.editor.open( this.model.get( 'id' ), this.model.get( 'nonces' ).edit, this );
       
  5390 	},
       
  5391 
       
  5392 	back: function() {
       
  5393 		var lastState = this.controller.lastState();
       
  5394 		this.controller.setState( lastState );
       
  5395 	},
       
  5396 
       
  5397 	refresh: function() {
       
  5398 		this.model.fetch();
       
  5399 	},
       
  5400 
       
  5401 	save: function() {
       
  5402 		var lastState = this.controller.lastState();
       
  5403 
       
  5404 		this.model.fetch().done( _.bind( function() {
       
  5405 			this.controller.setState( lastState );
       
  5406 		}, this ) );
       
  5407 	}
       
  5408 
       
  5409 });
       
  5410 
       
  5411 module.exports = EditImage;
       
  5412 
       
  5413 
       
  5414 /***/ }),
       
  5415 
       
  5416 /***/ 5741:
       
  5417 /***/ ((module) => {
       
  5418 
       
  5419 /**
       
  5420  * wp.media.view.Embed
       
  5421  *
       
  5422  * @memberOf wp.media.view
       
  5423  *
       
  5424  * @class
       
  5425  * @augments wp.media.View
       
  5426  * @augments wp.Backbone.View
       
  5427  * @augments Backbone.View
       
  5428  */
       
  5429 var Embed = wp.media.View.extend(/** @lends wp.media.view.Ember.prototype */{
       
  5430 	className: 'media-embed',
       
  5431 
       
  5432 	initialize: function() {
       
  5433 		/**
       
  5434 		 * @member {wp.media.view.EmbedUrl}
       
  5435 		 */
       
  5436 		this.url = new wp.media.view.EmbedUrl({
       
  5437 			controller: this.controller,
       
  5438 			model:      this.model.props
       
  5439 		}).render();
       
  5440 
       
  5441 		this.views.set([ this.url ]);
       
  5442 		this.refresh();
       
  5443 		this.listenTo( this.model, 'change:type', this.refresh );
       
  5444 		this.listenTo( this.model, 'change:loading', this.loading );
       
  5445 	},
       
  5446 
       
  5447 	/**
       
  5448 	 * @param {Object} view
       
  5449 	 */
       
  5450 	settings: function( view ) {
       
  5451 		if ( this._settings ) {
       
  5452 			this._settings.remove();
       
  5453 		}
       
  5454 		this._settings = view;
       
  5455 		this.views.add( view );
       
  5456 	},
       
  5457 
       
  5458 	refresh: function() {
       
  5459 		var type = this.model.get('type'),
       
  5460 			constructor;
       
  5461 
       
  5462 		if ( 'image' === type ) {
       
  5463 			constructor = wp.media.view.EmbedImage;
       
  5464 		} else if ( 'link' === type ) {
       
  5465 			constructor = wp.media.view.EmbedLink;
       
  5466 		} else {
       
  5467 			return;
       
  5468 		}
       
  5469 
       
  5470 		this.settings( new constructor({
       
  5471 			controller: this.controller,
       
  5472 			model:      this.model.props,
       
  5473 			priority:   40
       
  5474 		}) );
       
  5475 	},
       
  5476 
       
  5477 	loading: function() {
       
  5478 		this.$el.toggleClass( 'embed-loading', this.model.get('loading') );
       
  5479 	}
       
  5480 });
       
  5481 
       
  5482 module.exports = Embed;
       
  5483 
       
  5484 
       
  5485 /***/ }),
       
  5486 
       
  5487 /***/ 2395:
       
  5488 /***/ ((module) => {
       
  5489 
       
  5490 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
       
  5491 	EmbedImage;
       
  5492 
       
  5493 /**
       
  5494  * wp.media.view.EmbedImage
       
  5495  *
       
  5496  * @memberOf wp.media.view
       
  5497  *
       
  5498  * @class
       
  5499  * @augments wp.media.view.Settings.AttachmentDisplay
       
  5500  * @augments wp.media.view.Settings
       
  5501  * @augments wp.media.View
       
  5502  * @augments wp.Backbone.View
       
  5503  * @augments Backbone.View
       
  5504  */
       
  5505 EmbedImage = AttachmentDisplay.extend(/** @lends wp.media.view.EmbedImage.prototype */{
       
  5506 	className: 'embed-media-settings',
       
  5507 	template:  wp.template('embed-image-settings'),
       
  5508 
       
  5509 	initialize: function() {
       
  5510 		/**
       
  5511 		 * Call `initialize` directly on parent class with passed arguments
       
  5512 		 */
       
  5513 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
       
  5514 		this.listenTo( this.model, 'change:url', this.updateImage );
       
  5515 	},
       
  5516 
       
  5517 	updateImage: function() {
       
  5518 		this.$('img').attr( 'src', this.model.get('url') );
       
  5519 	}
       
  5520 });
       
  5521 
       
  5522 module.exports = EmbedImage;
       
  5523 
  9333 
  5524 
  9334 
  5525 /***/ }),
  9335 /***/ }),
  5526 
  9336 
  5527 /***/ 8232:
  9337 /***/ 8232:
  5626 module.exports = EmbedLink;
  9436 module.exports = EmbedLink;
  5627 
  9437 
  5628 
  9438 
  5629 /***/ }),
  9439 /***/ }),
  5630 
  9440 
  5631 /***/ 7327:
       
  5632 /***/ ((module) => {
       
  5633 
       
  5634 var View = wp.media.View,
       
  5635 	$ = jQuery,
       
  5636 	l10n = wp.media.view.l10n,
       
  5637 	EmbedUrl;
       
  5638 
       
  5639 /**
       
  5640  * wp.media.view.EmbedUrl
       
  5641  *
       
  5642  * @memberOf wp.media.view
       
  5643  *
       
  5644  * @class
       
  5645  * @augments wp.media.View
       
  5646  * @augments wp.Backbone.View
       
  5647  * @augments Backbone.View
       
  5648  */
       
  5649 EmbedUrl = View.extend(/** @lends wp.media.view.EmbedUrl.prototype */{
       
  5650 	tagName:   'span',
       
  5651 	className: 'embed-url',
       
  5652 
       
  5653 	events: {
       
  5654 		'input': 'url'
       
  5655 	},
       
  5656 
       
  5657 	initialize: function() {
       
  5658 		this.$input = $( '<input id="embed-url-field" type="url" />' )
       
  5659 			.attr( 'aria-label', l10n.insertFromUrlTitle )
       
  5660 			.val( this.model.get('url') );
       
  5661 		this.input = this.$input[0];
       
  5662 
       
  5663 		this.spinner = $('<span class="spinner" />')[0];
       
  5664 		this.$el.append([ this.input, this.spinner ]);
       
  5665 
       
  5666 		this.listenTo( this.model, 'change:url', this.render );
       
  5667 
       
  5668 		if ( this.model.get( 'url' ) ) {
       
  5669 			_.delay( _.bind( function () {
       
  5670 				this.model.trigger( 'change:url' );
       
  5671 			}, this ), 500 );
       
  5672 		}
       
  5673 	},
       
  5674 	/**
       
  5675 	 * @return {wp.media.view.EmbedUrl} Returns itself to allow chaining.
       
  5676 	 */
       
  5677 	render: function() {
       
  5678 		var $input = this.$input;
       
  5679 
       
  5680 		if ( $input.is(':focus') ) {
       
  5681 			return;
       
  5682 		}
       
  5683 
       
  5684 		if ( this.model.get( 'url' ) ) {
       
  5685 			this.input.value = this.model.get('url');
       
  5686 		} else {
       
  5687 			this.input.setAttribute( 'placeholder', 'https://' );
       
  5688 		}
       
  5689 
       
  5690 		/**
       
  5691 		 * Call `render` directly on parent class with passed arguments
       
  5692 		 */
       
  5693 		View.prototype.render.apply( this, arguments );
       
  5694 		return this;
       
  5695 	},
       
  5696 
       
  5697 	url: function( event ) {
       
  5698 		var url = event.target.value || '';
       
  5699 		this.model.set( 'url', url.trim() );
       
  5700 	}
       
  5701 });
       
  5702 
       
  5703 module.exports = EmbedUrl;
       
  5704 
       
  5705 
       
  5706 /***/ }),
       
  5707 
       
  5708 /***/ 718:
       
  5709 /***/ ((module) => {
       
  5710 
       
  5711 var $ = jQuery;
       
  5712 
       
  5713 /**
       
  5714  * wp.media.view.FocusManager
       
  5715  *
       
  5716  * @memberOf wp.media.view
       
  5717  *
       
  5718  * @class
       
  5719  * @augments wp.media.View
       
  5720  * @augments wp.Backbone.View
       
  5721  * @augments Backbone.View
       
  5722  */
       
  5723 var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.prototype */{
       
  5724 
       
  5725 	events: {
       
  5726 		'keydown': 'focusManagementMode'
       
  5727 	},
       
  5728 
       
  5729 	/**
       
  5730 	 * Initializes the Focus Manager.
       
  5731 	 *
       
  5732 	 * @param {Object} options The Focus Manager options.
       
  5733 	 *
       
  5734 	 * @since 5.3.0
       
  5735 	 *
       
  5736 	 * @return {void}
       
  5737 	 */
       
  5738 	initialize: function( options ) {
       
  5739 		this.mode                    = options.mode || 'constrainTabbing';
       
  5740 		this.tabsAutomaticActivation = options.tabsAutomaticActivation || false;
       
  5741 	},
       
  5742 
       
  5743  	/**
       
  5744 	 * Determines which focus management mode to use.
       
  5745 	 *
       
  5746 	 * @since 5.3.0
       
  5747 	 *
       
  5748 	 * @param {Object} event jQuery event object.
       
  5749 	 *
       
  5750 	 * @return {void}
       
  5751 	 */
       
  5752 	focusManagementMode: function( event ) {
       
  5753 		if ( this.mode === 'constrainTabbing' ) {
       
  5754 			this.constrainTabbing( event );
       
  5755 		}
       
  5756 
       
  5757 		if ( this.mode === 'tabsNavigation' ) {
       
  5758 			this.tabsNavigation( event );
       
  5759 		}
       
  5760 	},
       
  5761 
       
  5762 	/**
       
  5763 	 * Gets all the tabbable elements.
       
  5764 	 *
       
  5765 	 * @since 5.3.0
       
  5766 	 *
       
  5767 	 * @return {Object} A jQuery collection of tabbable elements.
       
  5768 	 */
       
  5769 	getTabbables: function() {
       
  5770 		// Skip the file input added by Plupload.
       
  5771 		return this.$( ':tabbable' ).not( '.moxie-shim input[type="file"]' );
       
  5772 	},
       
  5773 
       
  5774 	/**
       
  5775 	 * Moves focus to the modal dialog.
       
  5776 	 *
       
  5777 	 * @since 3.5.0
       
  5778 	 *
       
  5779 	 * @return {void}
       
  5780 	 */
       
  5781 	focus: function() {
       
  5782 		this.$( '.media-modal' ).trigger( 'focus' );
       
  5783 	},
       
  5784 
       
  5785 	/**
       
  5786 	 * Constrains navigation with the Tab key within the media view element.
       
  5787 	 *
       
  5788 	 * @since 4.0.0
       
  5789 	 *
       
  5790 	 * @param {Object} event A keydown jQuery event.
       
  5791 	 *
       
  5792 	 * @return {void}
       
  5793 	 */
       
  5794 	constrainTabbing: function( event ) {
       
  5795 		var tabbables;
       
  5796 
       
  5797 		// Look for the tab key.
       
  5798 		if ( 9 !== event.keyCode ) {
       
  5799 			return;
       
  5800 		}
       
  5801 
       
  5802 		tabbables = this.getTabbables();
       
  5803 
       
  5804 		// Keep tab focus within media modal while it's open.
       
  5805 		if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
       
  5806 			tabbables.first().focus();
       
  5807 			return false;
       
  5808 		} else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
       
  5809 			tabbables.last().focus();
       
  5810 			return false;
       
  5811 		}
       
  5812 	},
       
  5813 
       
  5814 	/**
       
  5815 	 * Hides from assistive technologies all the body children.
       
  5816 	 *
       
  5817 	 * Sets an `aria-hidden="true"` attribute on all the body children except
       
  5818 	 * the provided element and other elements that should not be hidden.
       
  5819 	 *
       
  5820 	 * The reason why we use `aria-hidden` is that `aria-modal="true"` is buggy
       
  5821 	 * in Safari 11.1 and support is spotty in other browsers. Also, `aria-modal="true"`
       
  5822 	 * prevents the `wp.a11y.speak()` ARIA live regions to work as they're outside
       
  5823 	 * of the modal dialog and get hidden from assistive technologies.
       
  5824 	 *
       
  5825 	 * @since 5.2.3
       
  5826 	 *
       
  5827 	 * @param {Object} visibleElement The jQuery object representing the element that should not be hidden.
       
  5828 	 *
       
  5829 	 * @return {void}
       
  5830 	 */
       
  5831 	setAriaHiddenOnBodyChildren: function( visibleElement ) {
       
  5832 		var bodyChildren,
       
  5833 			self = this;
       
  5834 
       
  5835 		if ( this.isBodyAriaHidden ) {
       
  5836 			return;
       
  5837 		}
       
  5838 
       
  5839 		// Get all the body children.
       
  5840 		bodyChildren = document.body.children;
       
  5841 
       
  5842 		// Loop through the body children and hide the ones that should be hidden.
       
  5843 		_.each( bodyChildren, function( element ) {
       
  5844 			// Don't hide the modal element.
       
  5845 			if ( element === visibleElement[0] ) {
       
  5846 				return;
       
  5847 			}
       
  5848 
       
  5849 			// Determine the body children to hide.
       
  5850 			if ( self.elementShouldBeHidden( element ) ) {
       
  5851 				element.setAttribute( 'aria-hidden', 'true' );
       
  5852 				// Store the hidden elements.
       
  5853 				self.ariaHiddenElements.push( element );
       
  5854 			}
       
  5855 		} );
       
  5856 
       
  5857 		this.isBodyAriaHidden = true;
       
  5858 	},
       
  5859 
       
  5860 	/**
       
  5861 	 * Unhides from assistive technologies all the body children.
       
  5862 	 *
       
  5863 	 * Makes visible again to assistive technologies all the body children
       
  5864 	 * previously hidden and stored in this.ariaHiddenElements.
       
  5865 	 *
       
  5866 	 * @since 5.2.3
       
  5867 	 *
       
  5868 	 * @return {void}
       
  5869 	 */
       
  5870 	removeAriaHiddenFromBodyChildren: function() {
       
  5871 		_.each( this.ariaHiddenElements, function( element ) {
       
  5872 			element.removeAttribute( 'aria-hidden' );
       
  5873 		} );
       
  5874 
       
  5875 		this.ariaHiddenElements = [];
       
  5876 		this.isBodyAriaHidden   = false;
       
  5877 	},
       
  5878 
       
  5879 	/**
       
  5880 	 * Determines if the passed element should not be hidden from assistive technologies.
       
  5881 	 *
       
  5882 	 * @since 5.2.3
       
  5883 	 *
       
  5884 	 * @param {Object} element The DOM element that should be checked.
       
  5885 	 *
       
  5886 	 * @return {boolean} Whether the element should not be hidden from assistive technologies.
       
  5887 	 */
       
  5888 	elementShouldBeHidden: function( element ) {
       
  5889 		var role = element.getAttribute( 'role' ),
       
  5890 			liveRegionsRoles = [ 'alert', 'status', 'log', 'marquee', 'timer' ];
       
  5891 
       
  5892 		/*
       
  5893 		 * Don't hide scripts, elements that already have `aria-hidden`, and
       
  5894 		 * ARIA live regions.
       
  5895 		 */
       
  5896 		return ! (
       
  5897 			element.tagName === 'SCRIPT' ||
       
  5898 			element.hasAttribute( 'aria-hidden' ) ||
       
  5899 			element.hasAttribute( 'aria-live' ) ||
       
  5900 			liveRegionsRoles.indexOf( role ) !== -1
       
  5901 		);
       
  5902 	},
       
  5903 
       
  5904 	/**
       
  5905 	 * Whether the body children are hidden from assistive technologies.
       
  5906 	 *
       
  5907 	 * @since 5.2.3
       
  5908 	 */
       
  5909 	isBodyAriaHidden: false,
       
  5910 
       
  5911 	/**
       
  5912 	 * Stores an array of DOM elements that should be hidden from assistive
       
  5913 	 * technologies, for example when the media modal dialog opens.
       
  5914 	 *
       
  5915 	 * @since 5.2.3
       
  5916 	 */
       
  5917 	ariaHiddenElements: [],
       
  5918 
       
  5919 	/**
       
  5920 	 * Holds the jQuery collection of ARIA tabs.
       
  5921 	 *
       
  5922 	 * @since 5.3.0
       
  5923 	 */
       
  5924 	tabs: $(),
       
  5925 
       
  5926 	/**
       
  5927 	 * Sets up tabs in an ARIA tabbed interface.
       
  5928 	 *
       
  5929 	 * @since 5.3.0
       
  5930 	 *
       
  5931 	 * @param {Object} event jQuery event object.
       
  5932 	 *
       
  5933 	 * @return {void}
       
  5934 	 */
       
  5935 	setupAriaTabs: function() {
       
  5936 		this.tabs = this.$( '[role="tab"]' );
       
  5937 
       
  5938 		// Set up initial attributes.
       
  5939 		this.tabs.attr( {
       
  5940 			'aria-selected': 'false',
       
  5941 			tabIndex: '-1'
       
  5942 		} );
       
  5943 
       
  5944 		// Set up attributes on the initially active tab.
       
  5945 		this.tabs.filter( '.active' )
       
  5946 			.removeAttr( 'tabindex' )
       
  5947 			.attr( 'aria-selected', 'true' );
       
  5948 	},
       
  5949 
       
  5950 	/**
       
  5951 	 * Enables arrows navigation within the ARIA tabbed interface.
       
  5952 	 *
       
  5953 	 * @since 5.3.0
       
  5954 	 *
       
  5955 	 * @param {Object} event jQuery event object.
       
  5956 	 *
       
  5957 	 * @return {void}
       
  5958 	 */
       
  5959 	tabsNavigation: function( event ) {
       
  5960 		var orientation = 'horizontal',
       
  5961 			keys = [ 32, 35, 36, 37, 38, 39, 40 ];
       
  5962 
       
  5963 		// Return if not Spacebar, End, Home, or Arrow keys.
       
  5964 		if ( keys.indexOf( event.which ) === -1 ) {
       
  5965 			return;
       
  5966 		}
       
  5967 
       
  5968 		// Determine navigation direction.
       
  5969 		if ( this.$el.attr( 'aria-orientation' ) === 'vertical' ) {
       
  5970 			orientation = 'vertical';
       
  5971 		}
       
  5972 
       
  5973 		// Make Up and Down arrow keys do nothing with horizontal tabs.
       
  5974 		if ( orientation === 'horizontal' && [ 38, 40 ].indexOf( event.which ) !== -1 ) {
       
  5975 			return;
       
  5976 		}
       
  5977 
       
  5978 		// Make Left and Right arrow keys do nothing with vertical tabs.
       
  5979 		if ( orientation === 'vertical' && [ 37, 39 ].indexOf( event.which ) !== -1 ) {
       
  5980 			return;
       
  5981 		}
       
  5982 
       
  5983 		this.switchTabs( event, this.tabs );
       
  5984 	},
       
  5985 
       
  5986 	/**
       
  5987 	 * Switches tabs in the ARIA tabbed interface.
       
  5988 	 *
       
  5989 	 * @since 5.3.0
       
  5990 	 *
       
  5991 	 * @param {Object} event jQuery event object.
       
  5992 	 *
       
  5993 	 * @return {void}
       
  5994 	 */
       
  5995 	switchTabs: function( event ) {
       
  5996 		var key   = event.which,
       
  5997 			index = this.tabs.index( $( event.target ) ),
       
  5998 			newIndex;
       
  5999 
       
  6000 		switch ( key ) {
       
  6001 			// Space bar: Activate current targeted tab.
       
  6002 			case 32: {
       
  6003 				this.activateTab( this.tabs[ index ] );
       
  6004 				break;
       
  6005 			}
       
  6006 			// End key: Activate last tab.
       
  6007 			case 35: {
       
  6008 				event.preventDefault();
       
  6009 				this.activateTab( this.tabs[ this.tabs.length - 1 ] );
       
  6010 				break;
       
  6011 			}
       
  6012 			// Home key: Activate first tab.
       
  6013 			case 36: {
       
  6014 				event.preventDefault();
       
  6015 				this.activateTab( this.tabs[ 0 ] );
       
  6016 				break;
       
  6017 			}
       
  6018 			// Left and up keys: Activate previous tab.
       
  6019 			case 37:
       
  6020 			case 38: {
       
  6021 				event.preventDefault();
       
  6022 				newIndex = ( index - 1 ) < 0 ? this.tabs.length - 1 : index - 1;
       
  6023 				this.activateTab( this.tabs[ newIndex ] );
       
  6024 				break;
       
  6025 			}
       
  6026 			// Right and down keys: Activate next tab.
       
  6027 			case 39:
       
  6028 			case 40: {
       
  6029 				event.preventDefault();
       
  6030 				newIndex = ( index + 1 ) === this.tabs.length ? 0 : index + 1;
       
  6031 				this.activateTab( this.tabs[ newIndex ] );
       
  6032 				break;
       
  6033 			}
       
  6034 		}
       
  6035 	},
       
  6036 
       
  6037 	/**
       
  6038 	 * Sets a single tab to be focusable and semantically selected.
       
  6039 	 *
       
  6040 	 * @since 5.3.0
       
  6041 	 *
       
  6042 	 * @param {Object} tab The tab DOM element.
       
  6043 	 *
       
  6044 	 * @return {void}
       
  6045 	 */
       
  6046 	activateTab: function( tab ) {
       
  6047 		if ( ! tab ) {
       
  6048 			return;
       
  6049 		}
       
  6050 
       
  6051 		// The tab is a DOM element: no need for jQuery methods.
       
  6052 		tab.focus();
       
  6053 
       
  6054 		// Handle automatic activation.
       
  6055 		if ( this.tabsAutomaticActivation ) {
       
  6056 			tab.removeAttribute( 'tabindex' );
       
  6057 			tab.setAttribute( 'aria-selected', 'true' );
       
  6058 			tab.click();
       
  6059 
       
  6060 			return;
       
  6061 		}
       
  6062 
       
  6063 		// Handle manual activation.
       
  6064 		$( tab ).on( 'click', function() {
       
  6065 			tab.removeAttribute( 'tabindex' );
       
  6066 			tab.setAttribute( 'aria-selected', 'true' );
       
  6067 		} );
       
  6068  	}
       
  6069 });
       
  6070 
       
  6071 module.exports = FocusManager;
       
  6072 
       
  6073 
       
  6074 /***/ }),
       
  6075 
       
  6076 /***/ 1061:
       
  6077 /***/ ((module) => {
       
  6078 
       
  6079 /**
       
  6080  * wp.media.view.Frame
       
  6081  *
       
  6082  * A frame is a composite view consisting of one or more regions and one or more
       
  6083  * states.
       
  6084  *
       
  6085  * @memberOf wp.media.view
       
  6086  *
       
  6087  * @see wp.media.controller.State
       
  6088  * @see wp.media.controller.Region
       
  6089  *
       
  6090  * @class
       
  6091  * @augments wp.media.View
       
  6092  * @augments wp.Backbone.View
       
  6093  * @augments Backbone.View
       
  6094  * @mixes wp.media.controller.StateMachine
       
  6095  */
       
  6096 var Frame = wp.media.View.extend(/** @lends wp.media.view.Frame.prototype */{
       
  6097 	initialize: function() {
       
  6098 		_.defaults( this.options, {
       
  6099 			mode: [ 'select' ]
       
  6100 		});
       
  6101 		this._createRegions();
       
  6102 		this._createStates();
       
  6103 		this._createModes();
       
  6104 	},
       
  6105 
       
  6106 	_createRegions: function() {
       
  6107 		// Clone the regions array.
       
  6108 		this.regions = this.regions ? this.regions.slice() : [];
       
  6109 
       
  6110 		// Initialize regions.
       
  6111 		_.each( this.regions, function( region ) {
       
  6112 			this[ region ] = new wp.media.controller.Region({
       
  6113 				view:     this,
       
  6114 				id:       region,
       
  6115 				selector: '.media-frame-' + region
       
  6116 			});
       
  6117 		}, this );
       
  6118 	},
       
  6119 	/**
       
  6120 	 * Create the frame's states.
       
  6121 	 *
       
  6122 	 * @see wp.media.controller.State
       
  6123 	 * @see wp.media.controller.StateMachine
       
  6124 	 *
       
  6125 	 * @fires wp.media.controller.State#ready
       
  6126 	 */
       
  6127 	_createStates: function() {
       
  6128 		// Create the default `states` collection.
       
  6129 		this.states = new Backbone.Collection( null, {
       
  6130 			model: wp.media.controller.State
       
  6131 		});
       
  6132 
       
  6133 		// Ensure states have a reference to the frame.
       
  6134 		this.states.on( 'add', function( model ) {
       
  6135 			model.frame = this;
       
  6136 			model.trigger('ready');
       
  6137 		}, this );
       
  6138 
       
  6139 		if ( this.options.states ) {
       
  6140 			this.states.add( this.options.states );
       
  6141 		}
       
  6142 	},
       
  6143 
       
  6144 	/**
       
  6145 	 * A frame can be in a mode or multiple modes at one time.
       
  6146 	 *
       
  6147 	 * For example, the manage media frame can be in the `Bulk Select` or `Edit` mode.
       
  6148 	 */
       
  6149 	_createModes: function() {
       
  6150 		// Store active "modes" that the frame is in. Unrelated to region modes.
       
  6151 		this.activeModes = new Backbone.Collection();
       
  6152 		this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
       
  6153 
       
  6154 		_.each( this.options.mode, function( mode ) {
       
  6155 			this.activateMode( mode );
       
  6156 		}, this );
       
  6157 	},
       
  6158 	/**
       
  6159 	 * Reset all states on the frame to their defaults.
       
  6160 	 *
       
  6161 	 * @return {wp.media.view.Frame} Returns itself to allow chaining.
       
  6162 	 */
       
  6163 	reset: function() {
       
  6164 		this.states.invoke( 'trigger', 'reset' );
       
  6165 		return this;
       
  6166 	},
       
  6167 	/**
       
  6168 	 * Map activeMode collection events to the frame.
       
  6169 	 */
       
  6170 	triggerModeEvents: function( model, collection, options ) {
       
  6171 		var collectionEvent,
       
  6172 			modeEventMap = {
       
  6173 				add: 'activate',
       
  6174 				remove: 'deactivate'
       
  6175 			},
       
  6176 			eventToTrigger;
       
  6177 		// Probably a better way to do this.
       
  6178 		_.each( options, function( value, key ) {
       
  6179 			if ( value ) {
       
  6180 				collectionEvent = key;
       
  6181 			}
       
  6182 		} );
       
  6183 
       
  6184 		if ( ! _.has( modeEventMap, collectionEvent ) ) {
       
  6185 			return;
       
  6186 		}
       
  6187 
       
  6188 		eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
       
  6189 		this.trigger( eventToTrigger );
       
  6190 	},
       
  6191 	/**
       
  6192 	 * Activate a mode on the frame.
       
  6193 	 *
       
  6194 	 * @param string mode Mode ID.
       
  6195 	 * @return {this} Returns itself to allow chaining.
       
  6196 	 */
       
  6197 	activateMode: function( mode ) {
       
  6198 		// Bail if the mode is already active.
       
  6199 		if ( this.isModeActive( mode ) ) {
       
  6200 			return;
       
  6201 		}
       
  6202 		this.activeModes.add( [ { id: mode } ] );
       
  6203 		// Add a CSS class to the frame so elements can be styled for the mode.
       
  6204 		this.$el.addClass( 'mode-' + mode );
       
  6205 
       
  6206 		return this;
       
  6207 	},
       
  6208 	/**
       
  6209 	 * Deactivate a mode on the frame.
       
  6210 	 *
       
  6211 	 * @param string mode Mode ID.
       
  6212 	 * @return {this} Returns itself to allow chaining.
       
  6213 	 */
       
  6214 	deactivateMode: function( mode ) {
       
  6215 		// Bail if the mode isn't active.
       
  6216 		if ( ! this.isModeActive( mode ) ) {
       
  6217 			return this;
       
  6218 		}
       
  6219 		this.activeModes.remove( this.activeModes.where( { id: mode } ) );
       
  6220 		this.$el.removeClass( 'mode-' + mode );
       
  6221 		/**
       
  6222 		 * Frame mode deactivation event.
       
  6223 		 *
       
  6224 		 * @event wp.media.view.Frame#{mode}:deactivate
       
  6225 		 */
       
  6226 		this.trigger( mode + ':deactivate' );
       
  6227 
       
  6228 		return this;
       
  6229 	},
       
  6230 	/**
       
  6231 	 * Check if a mode is enabled on the frame.
       
  6232 	 *
       
  6233 	 * @param string mode Mode ID.
       
  6234 	 * @return bool
       
  6235 	 */
       
  6236 	isModeActive: function( mode ) {
       
  6237 		return Boolean( this.activeModes.where( { id: mode } ).length );
       
  6238 	}
       
  6239 });
       
  6240 
       
  6241 // Make the `Frame` a `StateMachine`.
       
  6242 _.extend( Frame.prototype, wp.media.controller.StateMachine.prototype );
       
  6243 
       
  6244 module.exports = Frame;
       
  6245 
       
  6246 
       
  6247 /***/ }),
       
  6248 
       
  6249 /***/ 5424:
       
  6250 /***/ ((module) => {
       
  6251 
       
  6252 var Select = wp.media.view.MediaFrame.Select,
       
  6253 	l10n = wp.media.view.l10n,
       
  6254 	ImageDetails;
       
  6255 
       
  6256 /**
       
  6257  * wp.media.view.MediaFrame.ImageDetails
       
  6258  *
       
  6259  * A media frame for manipulating an image that's already been inserted
       
  6260  * into a post.
       
  6261  *
       
  6262  * @memberOf wp.media.view.MediaFrame
       
  6263  *
       
  6264  * @class
       
  6265  * @augments wp.media.view.MediaFrame.Select
       
  6266  * @augments wp.media.view.MediaFrame
       
  6267  * @augments wp.media.view.Frame
       
  6268  * @augments wp.media.View
       
  6269  * @augments wp.Backbone.View
       
  6270  * @augments Backbone.View
       
  6271  * @mixes wp.media.controller.StateMachine
       
  6272  */
       
  6273 ImageDetails = Select.extend(/** @lends wp.media.view.MediaFrame.ImageDetails.prototype */{
       
  6274 	defaults: {
       
  6275 		id:      'image',
       
  6276 		url:     '',
       
  6277 		menu:    'image-details',
       
  6278 		content: 'image-details',
       
  6279 		toolbar: 'image-details',
       
  6280 		type:    'link',
       
  6281 		title:    l10n.imageDetailsTitle,
       
  6282 		priority: 120
       
  6283 	},
       
  6284 
       
  6285 	initialize: function( options ) {
       
  6286 		this.image = new wp.media.model.PostImage( options.metadata );
       
  6287 		this.options.selection = new wp.media.model.Selection( this.image.attachment, { multiple: false } );
       
  6288 		Select.prototype.initialize.apply( this, arguments );
       
  6289 	},
       
  6290 
       
  6291 	bindHandlers: function() {
       
  6292 		Select.prototype.bindHandlers.apply( this, arguments );
       
  6293 		this.on( 'menu:create:image-details', this.createMenu, this );
       
  6294 		this.on( 'content:create:image-details', this.imageDetailsContent, this );
       
  6295 		this.on( 'content:render:edit-image', this.editImageContent, this );
       
  6296 		this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
       
  6297 		// Override the select toolbar.
       
  6298 		this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
       
  6299 	},
       
  6300 
       
  6301 	createStates: function() {
       
  6302 		this.states.add([
       
  6303 			new wp.media.controller.ImageDetails({
       
  6304 				image: this.image,
       
  6305 				editable: false
       
  6306 			}),
       
  6307 			new wp.media.controller.ReplaceImage({
       
  6308 				id: 'replace-image',
       
  6309 				library: wp.media.query( { type: 'image' } ),
       
  6310 				image: this.image,
       
  6311 				multiple:  false,
       
  6312 				title:     l10n.imageReplaceTitle,
       
  6313 				toolbar: 'replace',
       
  6314 				priority:  80,
       
  6315 				displaySettings: true
       
  6316 			}),
       
  6317 			new wp.media.controller.EditImage( {
       
  6318 				image: this.image,
       
  6319 				selection: this.options.selection
       
  6320 			} )
       
  6321 		]);
       
  6322 	},
       
  6323 
       
  6324 	imageDetailsContent: function( options ) {
       
  6325 		options.view = new wp.media.view.ImageDetails({
       
  6326 			controller: this,
       
  6327 			model: this.state().image,
       
  6328 			attachment: this.state().image.attachment
       
  6329 		});
       
  6330 	},
       
  6331 
       
  6332 	editImageContent: function() {
       
  6333 		var state = this.state(),
       
  6334 			model = state.get('image'),
       
  6335 			view;
       
  6336 
       
  6337 		if ( ! model ) {
       
  6338 			return;
       
  6339 		}
       
  6340 
       
  6341 		view = new wp.media.view.EditImage( { model: model, controller: this } ).render();
       
  6342 
       
  6343 		this.content.set( view );
       
  6344 
       
  6345 		// After bringing in the frame, load the actual editor via an Ajax call.
       
  6346 		view.loadEditor();
       
  6347 
       
  6348 	},
       
  6349 
       
  6350 	renderImageDetailsToolbar: function() {
       
  6351 		this.toolbar.set( new wp.media.view.Toolbar({
       
  6352 			controller: this,
       
  6353 			items: {
       
  6354 				select: {
       
  6355 					style:    'primary',
       
  6356 					text:     l10n.update,
       
  6357 					priority: 80,
       
  6358 
       
  6359 					click: function() {
       
  6360 						var controller = this.controller,
       
  6361 							state = controller.state();
       
  6362 
       
  6363 						controller.close();
       
  6364 
       
  6365 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
       
  6366 						// perhaps wp.html.string to at least to build the <img />.
       
  6367 						state.trigger( 'update', controller.image.toJSON() );
       
  6368 
       
  6369 						// Restore and reset the default state.
       
  6370 						controller.setState( controller.options.state );
       
  6371 						controller.reset();
       
  6372 					}
       
  6373 				}
       
  6374 			}
       
  6375 		}) );
       
  6376 	},
       
  6377 
       
  6378 	renderReplaceImageToolbar: function() {
       
  6379 		var frame = this,
       
  6380 			lastState = frame.lastState(),
       
  6381 			previous = lastState && lastState.id;
       
  6382 
       
  6383 		this.toolbar.set( new wp.media.view.Toolbar({
       
  6384 			controller: this,
       
  6385 			items: {
       
  6386 				back: {
       
  6387 					text:     l10n.back,
       
  6388 					priority: 80,
       
  6389 					click:    function() {
       
  6390 						if ( previous ) {
       
  6391 							frame.setState( previous );
       
  6392 						} else {
       
  6393 							frame.close();
       
  6394 						}
       
  6395 					}
       
  6396 				},
       
  6397 
       
  6398 				replace: {
       
  6399 					style:    'primary',
       
  6400 					text:     l10n.replace,
       
  6401 					priority: 20,
       
  6402 					requires: { selection: true },
       
  6403 
       
  6404 					click: function() {
       
  6405 						var controller = this.controller,
       
  6406 							state = controller.state(),
       
  6407 							selection = state.get( 'selection' ),
       
  6408 							attachment = selection.single();
       
  6409 
       
  6410 						controller.close();
       
  6411 
       
  6412 						controller.image.changeAttachment( attachment, state.display( attachment ) );
       
  6413 
       
  6414 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
       
  6415 						// perhaps wp.html.string to at least to build the <img />.
       
  6416 						state.trigger( 'replace', controller.image.toJSON() );
       
  6417 
       
  6418 						// Restore and reset the default state.
       
  6419 						controller.setState( controller.options.state );
       
  6420 						controller.reset();
       
  6421 					}
       
  6422 				}
       
  6423 			}
       
  6424 		}) );
       
  6425 	}
       
  6426 
       
  6427 });
       
  6428 
       
  6429 module.exports = ImageDetails;
       
  6430 
       
  6431 
       
  6432 /***/ }),
       
  6433 
       
  6434 /***/ 4274:
       
  6435 /***/ ((module) => {
       
  6436 
       
  6437 var Select = wp.media.view.MediaFrame.Select,
       
  6438 	Library = wp.media.controller.Library,
       
  6439 	l10n = wp.media.view.l10n,
       
  6440 	Post;
       
  6441 
       
  6442 /**
       
  6443  * wp.media.view.MediaFrame.Post
       
  6444  *
       
  6445  * The frame for manipulating media on the Edit Post page.
       
  6446  *
       
  6447  * @memberOf wp.media.view.MediaFrame
       
  6448  *
       
  6449  * @class
       
  6450  * @augments wp.media.view.MediaFrame.Select
       
  6451  * @augments wp.media.view.MediaFrame
       
  6452  * @augments wp.media.view.Frame
       
  6453  * @augments wp.media.View
       
  6454  * @augments wp.Backbone.View
       
  6455  * @augments Backbone.View
       
  6456  * @mixes wp.media.controller.StateMachine
       
  6457  */
       
  6458 Post = Select.extend(/** @lends wp.media.view.MediaFrame.Post.prototype */{
       
  6459 	initialize: function() {
       
  6460 		this.counts = {
       
  6461 			audio: {
       
  6462 				count: wp.media.view.settings.attachmentCounts.audio,
       
  6463 				state: 'playlist'
       
  6464 			},
       
  6465 			video: {
       
  6466 				count: wp.media.view.settings.attachmentCounts.video,
       
  6467 				state: 'video-playlist'
       
  6468 			}
       
  6469 		};
       
  6470 
       
  6471 		_.defaults( this.options, {
       
  6472 			multiple:  true,
       
  6473 			editing:   false,
       
  6474 			state:    'insert',
       
  6475 			metadata:  {}
       
  6476 		});
       
  6477 
       
  6478 		// Call 'initialize' directly on the parent class.
       
  6479 		Select.prototype.initialize.apply( this, arguments );
       
  6480 		this.createIframeStates();
       
  6481 
       
  6482 	},
       
  6483 
       
  6484 	/**
       
  6485 	 * Create the default states.
       
  6486 	 */
       
  6487 	createStates: function() {
       
  6488 		var options = this.options;
       
  6489 
       
  6490 		this.states.add([
       
  6491 			// Main states.
       
  6492 			new Library({
       
  6493 				id:         'insert',
       
  6494 				title:      l10n.insertMediaTitle,
       
  6495 				priority:   20,
       
  6496 				toolbar:    'main-insert',
       
  6497 				filterable: 'all',
       
  6498 				library:    wp.media.query( options.library ),
       
  6499 				multiple:   options.multiple ? 'reset' : false,
       
  6500 				editable:   true,
       
  6501 
       
  6502 				// If the user isn't allowed to edit fields,
       
  6503 				// can they still edit it locally?
       
  6504 				allowLocalEdits: true,
       
  6505 
       
  6506 				// Show the attachment display settings.
       
  6507 				displaySettings: true,
       
  6508 				// Update user settings when users adjust the
       
  6509 				// attachment display settings.
       
  6510 				displayUserSettings: true
       
  6511 			}),
       
  6512 
       
  6513 			new Library({
       
  6514 				id:         'gallery',
       
  6515 				title:      l10n.createGalleryTitle,
       
  6516 				priority:   40,
       
  6517 				toolbar:    'main-gallery',
       
  6518 				filterable: 'uploaded',
       
  6519 				multiple:   'add',
       
  6520 				editable:   false,
       
  6521 
       
  6522 				library:  wp.media.query( _.defaults({
       
  6523 					type: 'image'
       
  6524 				}, options.library ) )
       
  6525 			}),
       
  6526 
       
  6527 			// Embed states.
       
  6528 			new wp.media.controller.Embed( { metadata: options.metadata } ),
       
  6529 
       
  6530 			new wp.media.controller.EditImage( { model: options.editImage } ),
       
  6531 
       
  6532 			// Gallery states.
       
  6533 			new wp.media.controller.GalleryEdit({
       
  6534 				library: options.selection,
       
  6535 				editing: options.editing,
       
  6536 				menu:    'gallery'
       
  6537 			}),
       
  6538 
       
  6539 			new wp.media.controller.GalleryAdd(),
       
  6540 
       
  6541 			new Library({
       
  6542 				id:         'playlist',
       
  6543 				title:      l10n.createPlaylistTitle,
       
  6544 				priority:   60,
       
  6545 				toolbar:    'main-playlist',
       
  6546 				filterable: 'uploaded',
       
  6547 				multiple:   'add',
       
  6548 				editable:   false,
       
  6549 
       
  6550 				library:  wp.media.query( _.defaults({
       
  6551 					type: 'audio'
       
  6552 				}, options.library ) )
       
  6553 			}),
       
  6554 
       
  6555 			// Playlist states.
       
  6556 			new wp.media.controller.CollectionEdit({
       
  6557 				type: 'audio',
       
  6558 				collectionType: 'playlist',
       
  6559 				title:          l10n.editPlaylistTitle,
       
  6560 				SettingsView:   wp.media.view.Settings.Playlist,
       
  6561 				library:        options.selection,
       
  6562 				editing:        options.editing,
       
  6563 				menu:           'playlist',
       
  6564 				dragInfoText:   l10n.playlistDragInfo,
       
  6565 				dragInfo:       false
       
  6566 			}),
       
  6567 
       
  6568 			new wp.media.controller.CollectionAdd({
       
  6569 				type: 'audio',
       
  6570 				collectionType: 'playlist',
       
  6571 				title: l10n.addToPlaylistTitle
       
  6572 			}),
       
  6573 
       
  6574 			new Library({
       
  6575 				id:         'video-playlist',
       
  6576 				title:      l10n.createVideoPlaylistTitle,
       
  6577 				priority:   60,
       
  6578 				toolbar:    'main-video-playlist',
       
  6579 				filterable: 'uploaded',
       
  6580 				multiple:   'add',
       
  6581 				editable:   false,
       
  6582 
       
  6583 				library:  wp.media.query( _.defaults({
       
  6584 					type: 'video'
       
  6585 				}, options.library ) )
       
  6586 			}),
       
  6587 
       
  6588 			new wp.media.controller.CollectionEdit({
       
  6589 				type: 'video',
       
  6590 				collectionType: 'playlist',
       
  6591 				title:          l10n.editVideoPlaylistTitle,
       
  6592 				SettingsView:   wp.media.view.Settings.Playlist,
       
  6593 				library:        options.selection,
       
  6594 				editing:        options.editing,
       
  6595 				menu:           'video-playlist',
       
  6596 				dragInfoText:   l10n.videoPlaylistDragInfo,
       
  6597 				dragInfo:       false
       
  6598 			}),
       
  6599 
       
  6600 			new wp.media.controller.CollectionAdd({
       
  6601 				type: 'video',
       
  6602 				collectionType: 'playlist',
       
  6603 				title: l10n.addToVideoPlaylistTitle
       
  6604 			})
       
  6605 		]);
       
  6606 
       
  6607 		if ( wp.media.view.settings.post.featuredImageId ) {
       
  6608 			this.states.add( new wp.media.controller.FeaturedImage() );
       
  6609 		}
       
  6610 	},
       
  6611 
       
  6612 	bindHandlers: function() {
       
  6613 		var handlers, checkCounts;
       
  6614 
       
  6615 		Select.prototype.bindHandlers.apply( this, arguments );
       
  6616 
       
  6617 		this.on( 'activate', this.activate, this );
       
  6618 
       
  6619 		// Only bother checking media type counts if one of the counts is zero.
       
  6620 		checkCounts = _.find( this.counts, function( type ) {
       
  6621 			return type.count === 0;
       
  6622 		} );
       
  6623 
       
  6624 		if ( typeof checkCounts !== 'undefined' ) {
       
  6625 			this.listenTo( wp.media.model.Attachments.all, 'change:type', this.mediaTypeCounts );
       
  6626 		}
       
  6627 
       
  6628 		this.on( 'menu:create:gallery', this.createMenu, this );
       
  6629 		this.on( 'menu:create:playlist', this.createMenu, this );
       
  6630 		this.on( 'menu:create:video-playlist', this.createMenu, this );
       
  6631 		this.on( 'toolbar:create:main-insert', this.createToolbar, this );
       
  6632 		this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
       
  6633 		this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
       
  6634 		this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
       
  6635 		this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
       
  6636 		this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
       
  6637 
       
  6638 		handlers = {
       
  6639 			menu: {
       
  6640 				'default': 'mainMenu',
       
  6641 				'gallery': 'galleryMenu',
       
  6642 				'playlist': 'playlistMenu',
       
  6643 				'video-playlist': 'videoPlaylistMenu'
       
  6644 			},
       
  6645 
       
  6646 			content: {
       
  6647 				'embed':          'embedContent',
       
  6648 				'edit-image':     'editImageContent',
       
  6649 				'edit-selection': 'editSelectionContent'
       
  6650 			},
       
  6651 
       
  6652 			toolbar: {
       
  6653 				'main-insert':      'mainInsertToolbar',
       
  6654 				'main-gallery':     'mainGalleryToolbar',
       
  6655 				'gallery-edit':     'galleryEditToolbar',
       
  6656 				'gallery-add':      'galleryAddToolbar',
       
  6657 				'main-playlist':	'mainPlaylistToolbar',
       
  6658 				'playlist-edit':	'playlistEditToolbar',
       
  6659 				'playlist-add':		'playlistAddToolbar',
       
  6660 				'main-video-playlist': 'mainVideoPlaylistToolbar',
       
  6661 				'video-playlist-edit': 'videoPlaylistEditToolbar',
       
  6662 				'video-playlist-add': 'videoPlaylistAddToolbar'
       
  6663 			}
       
  6664 		};
       
  6665 
       
  6666 		_.each( handlers, function( regionHandlers, region ) {
       
  6667 			_.each( regionHandlers, function( callback, handler ) {
       
  6668 				this.on( region + ':render:' + handler, this[ callback ], this );
       
  6669 			}, this );
       
  6670 		}, this );
       
  6671 	},
       
  6672 
       
  6673 	activate: function() {
       
  6674 		// Hide menu items for states tied to particular media types if there are no items.
       
  6675 		_.each( this.counts, function( type ) {
       
  6676 			if ( type.count < 1 ) {
       
  6677 				this.menuItemVisibility( type.state, 'hide' );
       
  6678 			}
       
  6679 		}, this );
       
  6680 	},
       
  6681 
       
  6682 	mediaTypeCounts: function( model, attr ) {
       
  6683 		if ( typeof this.counts[ attr ] !== 'undefined' && this.counts[ attr ].count < 1 ) {
       
  6684 			this.counts[ attr ].count++;
       
  6685 			this.menuItemVisibility( this.counts[ attr ].state, 'show' );
       
  6686 		}
       
  6687 	},
       
  6688 
       
  6689 	// Menus.
       
  6690 	/**
       
  6691 	 * @param {wp.Backbone.View} view
       
  6692 	 */
       
  6693 	mainMenu: function( view ) {
       
  6694 		view.set({
       
  6695 			'library-separator': new wp.media.View({
       
  6696 				className:  'separator',
       
  6697 				priority:   100,
       
  6698 				attributes: {
       
  6699 					role: 'presentation'
       
  6700 				}
       
  6701 			})
       
  6702 		});
       
  6703 	},
       
  6704 
       
  6705 	menuItemVisibility: function( state, visibility ) {
       
  6706 		var menu = this.menu.get();
       
  6707 		if ( visibility === 'hide' ) {
       
  6708 			menu.hide( state );
       
  6709 		} else if ( visibility === 'show' ) {
       
  6710 			menu.show( state );
       
  6711 		}
       
  6712 	},
       
  6713 	/**
       
  6714 	 * @param {wp.Backbone.View} view
       
  6715 	 */
       
  6716 	galleryMenu: function( view ) {
       
  6717 		var lastState = this.lastState(),
       
  6718 			previous = lastState && lastState.id,
       
  6719 			frame = this;
       
  6720 
       
  6721 		view.set({
       
  6722 			cancel: {
       
  6723 				text:     l10n.cancelGalleryTitle,
       
  6724 				priority: 20,
       
  6725 				click:    function() {
       
  6726 					if ( previous ) {
       
  6727 						frame.setState( previous );
       
  6728 					} else {
       
  6729 						frame.close();
       
  6730 					}
       
  6731 
       
  6732 					// Move focus to the modal after canceling a Gallery.
       
  6733 					this.controller.modal.focusManager.focus();
       
  6734 				}
       
  6735 			},
       
  6736 			separateCancel: new wp.media.View({
       
  6737 				className: 'separator',
       
  6738 				priority: 40
       
  6739 			})
       
  6740 		});
       
  6741 	},
       
  6742 
       
  6743 	playlistMenu: function( view ) {
       
  6744 		var lastState = this.lastState(),
       
  6745 			previous = lastState && lastState.id,
       
  6746 			frame = this;
       
  6747 
       
  6748 		view.set({
       
  6749 			cancel: {
       
  6750 				text:     l10n.cancelPlaylistTitle,
       
  6751 				priority: 20,
       
  6752 				click:    function() {
       
  6753 					if ( previous ) {
       
  6754 						frame.setState( previous );
       
  6755 					} else {
       
  6756 						frame.close();
       
  6757 					}
       
  6758 
       
  6759 					// Move focus to the modal after canceling an Audio Playlist.
       
  6760 					this.controller.modal.focusManager.focus();
       
  6761 				}
       
  6762 			},
       
  6763 			separateCancel: new wp.media.View({
       
  6764 				className: 'separator',
       
  6765 				priority: 40
       
  6766 			})
       
  6767 		});
       
  6768 	},
       
  6769 
       
  6770 	videoPlaylistMenu: function( view ) {
       
  6771 		var lastState = this.lastState(),
       
  6772 			previous = lastState && lastState.id,
       
  6773 			frame = this;
       
  6774 
       
  6775 		view.set({
       
  6776 			cancel: {
       
  6777 				text:     l10n.cancelVideoPlaylistTitle,
       
  6778 				priority: 20,
       
  6779 				click:    function() {
       
  6780 					if ( previous ) {
       
  6781 						frame.setState( previous );
       
  6782 					} else {
       
  6783 						frame.close();
       
  6784 					}
       
  6785 
       
  6786 					// Move focus to the modal after canceling a Video Playlist.
       
  6787 					this.controller.modal.focusManager.focus();
       
  6788 				}
       
  6789 			},
       
  6790 			separateCancel: new wp.media.View({
       
  6791 				className: 'separator',
       
  6792 				priority: 40
       
  6793 			})
       
  6794 		});
       
  6795 	},
       
  6796 
       
  6797 	// Content.
       
  6798 	embedContent: function() {
       
  6799 		var view = new wp.media.view.Embed({
       
  6800 			controller: this,
       
  6801 			model:      this.state()
       
  6802 		}).render();
       
  6803 
       
  6804 		this.content.set( view );
       
  6805 	},
       
  6806 
       
  6807 	editSelectionContent: function() {
       
  6808 		var state = this.state(),
       
  6809 			selection = state.get('selection'),
       
  6810 			view;
       
  6811 
       
  6812 		view = new wp.media.view.AttachmentsBrowser({
       
  6813 			controller: this,
       
  6814 			collection: selection,
       
  6815 			selection:  selection,
       
  6816 			model:      state,
       
  6817 			sortable:   true,
       
  6818 			search:     false,
       
  6819 			date:       false,
       
  6820 			dragInfo:   true,
       
  6821 
       
  6822 			AttachmentView: wp.media.view.Attachments.EditSelection
       
  6823 		}).render();
       
  6824 
       
  6825 		view.toolbar.set( 'backToLibrary', {
       
  6826 			text:     l10n.returnToLibrary,
       
  6827 			priority: -100,
       
  6828 
       
  6829 			click: function() {
       
  6830 				this.controller.content.mode('browse');
       
  6831 				// Move focus to the modal when jumping back from Edit Selection to Add Media view.
       
  6832 				this.controller.modal.focusManager.focus();
       
  6833 			}
       
  6834 		});
       
  6835 
       
  6836 		// Browse our library of attachments.
       
  6837 		this.content.set( view );
       
  6838 
       
  6839 		// Trigger the controller to set focus.
       
  6840 		this.trigger( 'edit:selection', this );
       
  6841 	},
       
  6842 
       
  6843 	editImageContent: function() {
       
  6844 		var image = this.state().get('image'),
       
  6845 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
       
  6846 
       
  6847 		this.content.set( view );
       
  6848 
       
  6849 		// After creating the wrapper view, load the actual editor via an Ajax call.
       
  6850 		view.loadEditor();
       
  6851 
       
  6852 	},
       
  6853 
       
  6854 	// Toolbars.
       
  6855 
       
  6856 	/**
       
  6857 	 * @param {wp.Backbone.View} view
       
  6858 	 */
       
  6859 	selectionStatusToolbar: function( view ) {
       
  6860 		var editable = this.state().get('editable');
       
  6861 
       
  6862 		view.set( 'selection', new wp.media.view.Selection({
       
  6863 			controller: this,
       
  6864 			collection: this.state().get('selection'),
       
  6865 			priority:   -40,
       
  6866 
       
  6867 			// If the selection is editable, pass the callback to
       
  6868 			// switch the content mode.
       
  6869 			editable: editable && function() {
       
  6870 				this.controller.content.mode('edit-selection');
       
  6871 			}
       
  6872 		}).render() );
       
  6873 	},
       
  6874 
       
  6875 	/**
       
  6876 	 * @param {wp.Backbone.View} view
       
  6877 	 */
       
  6878 	mainInsertToolbar: function( view ) {
       
  6879 		var controller = this;
       
  6880 
       
  6881 		this.selectionStatusToolbar( view );
       
  6882 
       
  6883 		view.set( 'insert', {
       
  6884 			style:    'primary',
       
  6885 			priority: 80,
       
  6886 			text:     l10n.insertIntoPost,
       
  6887 			requires: { selection: true },
       
  6888 
       
  6889 			/**
       
  6890 			 * @ignore
       
  6891 			 *
       
  6892 			 * @fires wp.media.controller.State#insert
       
  6893 			 */
       
  6894 			click: function() {
       
  6895 				var state = controller.state(),
       
  6896 					selection = state.get('selection');
       
  6897 
       
  6898 				controller.close();
       
  6899 				state.trigger( 'insert', selection ).reset();
       
  6900 			}
       
  6901 		});
       
  6902 	},
       
  6903 
       
  6904 	/**
       
  6905 	 * @param {wp.Backbone.View} view
       
  6906 	 */
       
  6907 	mainGalleryToolbar: function( view ) {
       
  6908 		var controller = this;
       
  6909 
       
  6910 		this.selectionStatusToolbar( view );
       
  6911 
       
  6912 		view.set( 'gallery', {
       
  6913 			style:    'primary',
       
  6914 			text:     l10n.createNewGallery,
       
  6915 			priority: 60,
       
  6916 			requires: { selection: true },
       
  6917 
       
  6918 			click: function() {
       
  6919 				var selection = controller.state().get('selection'),
       
  6920 					edit = controller.state('gallery-edit'),
       
  6921 					models = selection.where({ type: 'image' });
       
  6922 
       
  6923 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  6924 					props:    selection.props.toJSON(),
       
  6925 					multiple: true
       
  6926 				}) );
       
  6927 
       
  6928 				// Jump to Edit Gallery view.
       
  6929 				this.controller.setState( 'gallery-edit' );
       
  6930 
       
  6931 				// Move focus to the modal after jumping to Edit Gallery view.
       
  6932 				this.controller.modal.focusManager.focus();
       
  6933 			}
       
  6934 		});
       
  6935 	},
       
  6936 
       
  6937 	mainPlaylistToolbar: function( view ) {
       
  6938 		var controller = this;
       
  6939 
       
  6940 		this.selectionStatusToolbar( view );
       
  6941 
       
  6942 		view.set( 'playlist', {
       
  6943 			style:    'primary',
       
  6944 			text:     l10n.createNewPlaylist,
       
  6945 			priority: 100,
       
  6946 			requires: { selection: true },
       
  6947 
       
  6948 			click: function() {
       
  6949 				var selection = controller.state().get('selection'),
       
  6950 					edit = controller.state('playlist-edit'),
       
  6951 					models = selection.where({ type: 'audio' });
       
  6952 
       
  6953 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  6954 					props:    selection.props.toJSON(),
       
  6955 					multiple: true
       
  6956 				}) );
       
  6957 
       
  6958 				// Jump to Edit Audio Playlist view.
       
  6959 				this.controller.setState( 'playlist-edit' );
       
  6960 
       
  6961 				// Move focus to the modal after jumping to Edit Audio Playlist view.
       
  6962 				this.controller.modal.focusManager.focus();
       
  6963 			}
       
  6964 		});
       
  6965 	},
       
  6966 
       
  6967 	mainVideoPlaylistToolbar: function( view ) {
       
  6968 		var controller = this;
       
  6969 
       
  6970 		this.selectionStatusToolbar( view );
       
  6971 
       
  6972 		view.set( 'video-playlist', {
       
  6973 			style:    'primary',
       
  6974 			text:     l10n.createNewVideoPlaylist,
       
  6975 			priority: 100,
       
  6976 			requires: { selection: true },
       
  6977 
       
  6978 			click: function() {
       
  6979 				var selection = controller.state().get('selection'),
       
  6980 					edit = controller.state('video-playlist-edit'),
       
  6981 					models = selection.where({ type: 'video' });
       
  6982 
       
  6983 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  6984 					props:    selection.props.toJSON(),
       
  6985 					multiple: true
       
  6986 				}) );
       
  6987 
       
  6988 				// Jump to Edit Video Playlist view.
       
  6989 				this.controller.setState( 'video-playlist-edit' );
       
  6990 
       
  6991 				// Move focus to the modal after jumping to Edit Video Playlist view.
       
  6992 				this.controller.modal.focusManager.focus();
       
  6993 			}
       
  6994 		});
       
  6995 	},
       
  6996 
       
  6997 	featuredImageToolbar: function( toolbar ) {
       
  6998 		this.createSelectToolbar( toolbar, {
       
  6999 			text:  l10n.setFeaturedImage,
       
  7000 			state: this.options.state
       
  7001 		});
       
  7002 	},
       
  7003 
       
  7004 	mainEmbedToolbar: function( toolbar ) {
       
  7005 		toolbar.view = new wp.media.view.Toolbar.Embed({
       
  7006 			controller: this
       
  7007 		});
       
  7008 	},
       
  7009 
       
  7010 	galleryEditToolbar: function() {
       
  7011 		var editing = this.state().get('editing');
       
  7012 		this.toolbar.set( new wp.media.view.Toolbar({
       
  7013 			controller: this,
       
  7014 			items: {
       
  7015 				insert: {
       
  7016 					style:    'primary',
       
  7017 					text:     editing ? l10n.updateGallery : l10n.insertGallery,
       
  7018 					priority: 80,
       
  7019 					requires: { library: true },
       
  7020 
       
  7021 					/**
       
  7022 					 * @fires wp.media.controller.State#update
       
  7023 					 */
       
  7024 					click: function() {
       
  7025 						var controller = this.controller,
       
  7026 							state = controller.state();
       
  7027 
       
  7028 						controller.close();
       
  7029 						state.trigger( 'update', state.get('library') );
       
  7030 
       
  7031 						// Restore and reset the default state.
       
  7032 						controller.setState( controller.options.state );
       
  7033 						controller.reset();
       
  7034 					}
       
  7035 				}
       
  7036 			}
       
  7037 		}) );
       
  7038 	},
       
  7039 
       
  7040 	galleryAddToolbar: function() {
       
  7041 		this.toolbar.set( new wp.media.view.Toolbar({
       
  7042 			controller: this,
       
  7043 			items: {
       
  7044 				insert: {
       
  7045 					style:    'primary',
       
  7046 					text:     l10n.addToGallery,
       
  7047 					priority: 80,
       
  7048 					requires: { selection: true },
       
  7049 
       
  7050 					/**
       
  7051 					 * @fires wp.media.controller.State#reset
       
  7052 					 */
       
  7053 					click: function() {
       
  7054 						var controller = this.controller,
       
  7055 							state = controller.state(),
       
  7056 							edit = controller.state('gallery-edit');
       
  7057 
       
  7058 						edit.get('library').add( state.get('selection').models );
       
  7059 						state.trigger('reset');
       
  7060 						controller.setState('gallery-edit');
       
  7061 						// Move focus to the modal when jumping back from Add to Gallery to Edit Gallery view.
       
  7062 						this.controller.modal.focusManager.focus();
       
  7063 					}
       
  7064 				}
       
  7065 			}
       
  7066 		}) );
       
  7067 	},
       
  7068 
       
  7069 	playlistEditToolbar: function() {
       
  7070 		var editing = this.state().get('editing');
       
  7071 		this.toolbar.set( new wp.media.view.Toolbar({
       
  7072 			controller: this,
       
  7073 			items: {
       
  7074 				insert: {
       
  7075 					style:    'primary',
       
  7076 					text:     editing ? l10n.updatePlaylist : l10n.insertPlaylist,
       
  7077 					priority: 80,
       
  7078 					requires: { library: true },
       
  7079 
       
  7080 					/**
       
  7081 					 * @fires wp.media.controller.State#update
       
  7082 					 */
       
  7083 					click: function() {
       
  7084 						var controller = this.controller,
       
  7085 							state = controller.state();
       
  7086 
       
  7087 						controller.close();
       
  7088 						state.trigger( 'update', state.get('library') );
       
  7089 
       
  7090 						// Restore and reset the default state.
       
  7091 						controller.setState( controller.options.state );
       
  7092 						controller.reset();
       
  7093 					}
       
  7094 				}
       
  7095 			}
       
  7096 		}) );
       
  7097 	},
       
  7098 
       
  7099 	playlistAddToolbar: function() {
       
  7100 		this.toolbar.set( new wp.media.view.Toolbar({
       
  7101 			controller: this,
       
  7102 			items: {
       
  7103 				insert: {
       
  7104 					style:    'primary',
       
  7105 					text:     l10n.addToPlaylist,
       
  7106 					priority: 80,
       
  7107 					requires: { selection: true },
       
  7108 
       
  7109 					/**
       
  7110 					 * @fires wp.media.controller.State#reset
       
  7111 					 */
       
  7112 					click: function() {
       
  7113 						var controller = this.controller,
       
  7114 							state = controller.state(),
       
  7115 							edit = controller.state('playlist-edit');
       
  7116 
       
  7117 						edit.get('library').add( state.get('selection').models );
       
  7118 						state.trigger('reset');
       
  7119 						controller.setState('playlist-edit');
       
  7120 						// Move focus to the modal when jumping back from Add to Audio Playlist to Edit Audio Playlist view.
       
  7121 						this.controller.modal.focusManager.focus();
       
  7122 					}
       
  7123 				}
       
  7124 			}
       
  7125 		}) );
       
  7126 	},
       
  7127 
       
  7128 	videoPlaylistEditToolbar: function() {
       
  7129 		var editing = this.state().get('editing');
       
  7130 		this.toolbar.set( new wp.media.view.Toolbar({
       
  7131 			controller: this,
       
  7132 			items: {
       
  7133 				insert: {
       
  7134 					style:    'primary',
       
  7135 					text:     editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
       
  7136 					priority: 140,
       
  7137 					requires: { library: true },
       
  7138 
       
  7139 					click: function() {
       
  7140 						var controller = this.controller,
       
  7141 							state = controller.state(),
       
  7142 							library = state.get('library');
       
  7143 
       
  7144 						library.type = 'video';
       
  7145 
       
  7146 						controller.close();
       
  7147 						state.trigger( 'update', library );
       
  7148 
       
  7149 						// Restore and reset the default state.
       
  7150 						controller.setState( controller.options.state );
       
  7151 						controller.reset();
       
  7152 					}
       
  7153 				}
       
  7154 			}
       
  7155 		}) );
       
  7156 	},
       
  7157 
       
  7158 	videoPlaylistAddToolbar: function() {
       
  7159 		this.toolbar.set( new wp.media.view.Toolbar({
       
  7160 			controller: this,
       
  7161 			items: {
       
  7162 				insert: {
       
  7163 					style:    'primary',
       
  7164 					text:     l10n.addToVideoPlaylist,
       
  7165 					priority: 140,
       
  7166 					requires: { selection: true },
       
  7167 
       
  7168 					click: function() {
       
  7169 						var controller = this.controller,
       
  7170 							state = controller.state(),
       
  7171 							edit = controller.state('video-playlist-edit');
       
  7172 
       
  7173 						edit.get('library').add( state.get('selection').models );
       
  7174 						state.trigger('reset');
       
  7175 						controller.setState('video-playlist-edit');
       
  7176 						// Move focus to the modal when jumping back from Add to Video Playlist to Edit Video Playlist view.
       
  7177 						this.controller.modal.focusManager.focus();
       
  7178 					}
       
  7179 				}
       
  7180 			}
       
  7181 		}) );
       
  7182 	}
       
  7183 });
       
  7184 
       
  7185 module.exports = Post;
       
  7186 
       
  7187 
       
  7188 /***/ }),
       
  7189 
       
  7190 /***/ 455:
       
  7191 /***/ ((module) => {
       
  7192 
       
  7193 var MediaFrame = wp.media.view.MediaFrame,
       
  7194 	l10n = wp.media.view.l10n,
       
  7195 	Select;
       
  7196 
       
  7197 /**
       
  7198  * wp.media.view.MediaFrame.Select
       
  7199  *
       
  7200  * A frame for selecting an item or items from the media library.
       
  7201  *
       
  7202  * @memberOf wp.media.view.MediaFrame
       
  7203  *
       
  7204  * @class
       
  7205  * @augments wp.media.view.MediaFrame
       
  7206  * @augments wp.media.view.Frame
       
  7207  * @augments wp.media.View
       
  7208  * @augments wp.Backbone.View
       
  7209  * @augments Backbone.View
       
  7210  * @mixes wp.media.controller.StateMachine
       
  7211  */
       
  7212 Select = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Select.prototype */{
       
  7213 	initialize: function() {
       
  7214 		// Call 'initialize' directly on the parent class.
       
  7215 		MediaFrame.prototype.initialize.apply( this, arguments );
       
  7216 
       
  7217 		_.defaults( this.options, {
       
  7218 			selection: [],
       
  7219 			library:   {},
       
  7220 			multiple:  false,
       
  7221 			state:    'library'
       
  7222 		});
       
  7223 
       
  7224 		this.createSelection();
       
  7225 		this.createStates();
       
  7226 		this.bindHandlers();
       
  7227 	},
       
  7228 
       
  7229 	/**
       
  7230 	 * Attach a selection collection to the frame.
       
  7231 	 *
       
  7232 	 * A selection is a collection of attachments used for a specific purpose
       
  7233 	 * by a media frame. e.g. Selecting an attachment (or many) to insert into
       
  7234 	 * post content.
       
  7235 	 *
       
  7236 	 * @see media.model.Selection
       
  7237 	 */
       
  7238 	createSelection: function() {
       
  7239 		var selection = this.options.selection;
       
  7240 
       
  7241 		if ( ! (selection instanceof wp.media.model.Selection) ) {
       
  7242 			this.options.selection = new wp.media.model.Selection( selection, {
       
  7243 				multiple: this.options.multiple
       
  7244 			});
       
  7245 		}
       
  7246 
       
  7247 		this._selection = {
       
  7248 			attachments: new wp.media.model.Attachments(),
       
  7249 			difference: []
       
  7250 		};
       
  7251 	},
       
  7252 
       
  7253 	editImageContent: function() {
       
  7254 		var image = this.state().get('image'),
       
  7255 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
       
  7256 
       
  7257 		this.content.set( view );
       
  7258 
       
  7259 		// After creating the wrapper view, load the actual editor via an Ajax call.
       
  7260 		view.loadEditor();
       
  7261 	},
       
  7262 
       
  7263 	/**
       
  7264 	 * Create the default states on the frame.
       
  7265 	 */
       
  7266 	createStates: function() {
       
  7267 		var options = this.options;
       
  7268 
       
  7269 		if ( this.options.states ) {
       
  7270 			return;
       
  7271 		}
       
  7272 
       
  7273 		// Add the default states.
       
  7274 		this.states.add([
       
  7275 			// Main states.
       
  7276 			new wp.media.controller.Library({
       
  7277 				library:   wp.media.query( options.library ),
       
  7278 				multiple:  options.multiple,
       
  7279 				title:     options.title,
       
  7280 				priority:  20
       
  7281 			}),
       
  7282 			new wp.media.controller.EditImage( { model: options.editImage } )
       
  7283 		]);
       
  7284 	},
       
  7285 
       
  7286 	/**
       
  7287 	 * Bind region mode event callbacks.
       
  7288 	 *
       
  7289 	 * @see media.controller.Region.render
       
  7290 	 */
       
  7291 	bindHandlers: function() {
       
  7292 		this.on( 'router:create:browse', this.createRouter, this );
       
  7293 		this.on( 'router:render:browse', this.browseRouter, this );
       
  7294 		this.on( 'content:create:browse', this.browseContent, this );
       
  7295 		this.on( 'content:render:upload', this.uploadContent, this );
       
  7296 		this.on( 'toolbar:create:select', this.createSelectToolbar, this );
       
  7297 		this.on( 'content:render:edit-image', this.editImageContent, this );
       
  7298 	},
       
  7299 
       
  7300 	/**
       
  7301 	 * Render callback for the router region in the `browse` mode.
       
  7302 	 *
       
  7303 	 * @param {wp.media.view.Router} routerView
       
  7304 	 */
       
  7305 	browseRouter: function( routerView ) {
       
  7306 		routerView.set({
       
  7307 			upload: {
       
  7308 				text:     l10n.uploadFilesTitle,
       
  7309 				priority: 20
       
  7310 			},
       
  7311 			browse: {
       
  7312 				text:     l10n.mediaLibraryTitle,
       
  7313 				priority: 40
       
  7314 			}
       
  7315 		});
       
  7316 	},
       
  7317 
       
  7318 	/**
       
  7319 	 * Render callback for the content region in the `browse` mode.
       
  7320 	 *
       
  7321 	 * @param {wp.media.controller.Region} contentRegion
       
  7322 	 */
       
  7323 	browseContent: function( contentRegion ) {
       
  7324 		var state = this.state();
       
  7325 
       
  7326 		this.$el.removeClass('hide-toolbar');
       
  7327 
       
  7328 		// Browse our library of attachments.
       
  7329 		contentRegion.view = new wp.media.view.AttachmentsBrowser({
       
  7330 			controller: this,
       
  7331 			collection: state.get('library'),
       
  7332 			selection:  state.get('selection'),
       
  7333 			model:      state,
       
  7334 			sortable:   state.get('sortable'),
       
  7335 			search:     state.get('searchable'),
       
  7336 			filters:    state.get('filterable'),
       
  7337 			date:       state.get('date'),
       
  7338 			display:    state.has('display') ? state.get('display') : state.get('displaySettings'),
       
  7339 			dragInfo:   state.get('dragInfo'),
       
  7340 
       
  7341 			idealColumnWidth: state.get('idealColumnWidth'),
       
  7342 			suggestedWidth:   state.get('suggestedWidth'),
       
  7343 			suggestedHeight:  state.get('suggestedHeight'),
       
  7344 
       
  7345 			AttachmentView: state.get('AttachmentView')
       
  7346 		});
       
  7347 	},
       
  7348 
       
  7349 	/**
       
  7350 	 * Render callback for the content region in the `upload` mode.
       
  7351 	 */
       
  7352 	uploadContent: function() {
       
  7353 		this.$el.removeClass( 'hide-toolbar' );
       
  7354 		this.content.set( new wp.media.view.UploaderInline({
       
  7355 			controller: this
       
  7356 		}) );
       
  7357 	},
       
  7358 
       
  7359 	/**
       
  7360 	 * Toolbars
       
  7361 	 *
       
  7362 	 * @param {Object} toolbar
       
  7363 	 * @param {Object} [options={}]
       
  7364 	 * @this wp.media.controller.Region
       
  7365 	 */
       
  7366 	createSelectToolbar: function( toolbar, options ) {
       
  7367 		options = options || this.options.button || {};
       
  7368 		options.controller = this;
       
  7369 
       
  7370 		toolbar.view = new wp.media.view.Toolbar.Select( options );
       
  7371 	}
       
  7372 });
       
  7373 
       
  7374 module.exports = Select;
       
  7375 
       
  7376 
       
  7377 /***/ }),
       
  7378 
       
  7379 /***/ 170:
       
  7380 /***/ ((module) => {
       
  7381 
       
  7382 /**
       
  7383  * wp.media.view.Heading
       
  7384  *
       
  7385  * A reusable heading component for the media library
       
  7386  *
       
  7387  * Used to add accessibility friendly headers in the media library/modal.
       
  7388  *
       
  7389  * @class
       
  7390  * @augments wp.media.View
       
  7391  * @augments wp.Backbone.View
       
  7392  * @augments Backbone.View
       
  7393  */
       
  7394 var Heading = wp.media.View.extend( {
       
  7395 	tagName: function() {
       
  7396 		return this.options.level || 'h1';
       
  7397 	},
       
  7398 	className: 'media-views-heading',
       
  7399 
       
  7400 	initialize: function() {
       
  7401 
       
  7402 		if ( this.options.className ) {
       
  7403 			this.$el.addClass( this.options.className );
       
  7404 		}
       
  7405 
       
  7406 		this.text = this.options.text;
       
  7407 	},
       
  7408 
       
  7409 	render: function() {
       
  7410 		this.$el.html( this.text );
       
  7411 		return this;
       
  7412 	}
       
  7413 } );
       
  7414 
       
  7415 module.exports = Heading;
       
  7416 
       
  7417 
       
  7418 /***/ }),
       
  7419 
       
  7420 /***/ 1982:
       
  7421 /***/ ((module) => {
       
  7422 
       
  7423 /**
       
  7424  * wp.media.view.Iframe
       
  7425  *
       
  7426  * @memberOf wp.media.view
       
  7427  *
       
  7428  * @class
       
  7429  * @augments wp.media.View
       
  7430  * @augments wp.Backbone.View
       
  7431  * @augments Backbone.View
       
  7432  */
       
  7433 var Iframe = wp.media.View.extend(/** @lends wp.media.view.Iframe.prototype */{
       
  7434 	className: 'media-iframe',
       
  7435 	/**
       
  7436 	 * @return {wp.media.view.Iframe} Returns itself to allow chaining.
       
  7437 	 */
       
  7438 	render: function() {
       
  7439 		this.views.detach();
       
  7440 		this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
       
  7441 		this.views.render();
       
  7442 		return this;
       
  7443 	}
       
  7444 });
       
  7445 
       
  7446 module.exports = Iframe;
       
  7447 
       
  7448 
       
  7449 /***/ }),
       
  7450 
       
  7451 /***/ 2650:
       
  7452 /***/ ((module) => {
       
  7453 
       
  7454 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
       
  7455 	$ = jQuery,
       
  7456 	ImageDetails;
       
  7457 
       
  7458 /**
       
  7459  * wp.media.view.ImageDetails
       
  7460  *
       
  7461  * @memberOf wp.media.view
       
  7462  *
       
  7463  * @class
       
  7464  * @augments wp.media.view.Settings.AttachmentDisplay
       
  7465  * @augments wp.media.view.Settings
       
  7466  * @augments wp.media.View
       
  7467  * @augments wp.Backbone.View
       
  7468  * @augments Backbone.View
       
  7469  */
       
  7470 ImageDetails = AttachmentDisplay.extend(/** @lends wp.media.view.ImageDetails.prototype */{
       
  7471 	className: 'image-details',
       
  7472 	template:  wp.template('image-details'),
       
  7473 	events: _.defaults( AttachmentDisplay.prototype.events, {
       
  7474 		'click .edit-attachment': 'editAttachment',
       
  7475 		'click .replace-attachment': 'replaceAttachment',
       
  7476 		'click .advanced-toggle': 'onToggleAdvanced',
       
  7477 		'change [data-setting="customWidth"]': 'onCustomSize',
       
  7478 		'change [data-setting="customHeight"]': 'onCustomSize',
       
  7479 		'keyup [data-setting="customWidth"]': 'onCustomSize',
       
  7480 		'keyup [data-setting="customHeight"]': 'onCustomSize'
       
  7481 	} ),
       
  7482 	initialize: function() {
       
  7483 		// Used in AttachmentDisplay.prototype.updateLinkTo.
       
  7484 		this.options.attachment = this.model.attachment;
       
  7485 		this.listenTo( this.model, 'change:url', this.updateUrl );
       
  7486 		this.listenTo( this.model, 'change:link', this.toggleLinkSettings );
       
  7487 		this.listenTo( this.model, 'change:size', this.toggleCustomSize );
       
  7488 
       
  7489 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
       
  7490 	},
       
  7491 
       
  7492 	prepare: function() {
       
  7493 		var attachment = false;
       
  7494 
       
  7495 		if ( this.model.attachment ) {
       
  7496 			attachment = this.model.attachment.toJSON();
       
  7497 		}
       
  7498 		return _.defaults({
       
  7499 			model: this.model.toJSON(),
       
  7500 			attachment: attachment
       
  7501 		}, this.options );
       
  7502 	},
       
  7503 
       
  7504 	render: function() {
       
  7505 		var args = arguments;
       
  7506 
       
  7507 		if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
       
  7508 			this.model.dfd
       
  7509 				.done( _.bind( function() {
       
  7510 					AttachmentDisplay.prototype.render.apply( this, args );
       
  7511 					this.postRender();
       
  7512 				}, this ) )
       
  7513 				.fail( _.bind( function() {
       
  7514 					this.model.attachment = false;
       
  7515 					AttachmentDisplay.prototype.render.apply( this, args );
       
  7516 					this.postRender();
       
  7517 				}, this ) );
       
  7518 		} else {
       
  7519 			AttachmentDisplay.prototype.render.apply( this, arguments );
       
  7520 			this.postRender();
       
  7521 		}
       
  7522 
       
  7523 		return this;
       
  7524 	},
       
  7525 
       
  7526 	postRender: function() {
       
  7527 		setTimeout( _.bind( this.scrollToTop, this ), 10 );
       
  7528 		this.toggleLinkSettings();
       
  7529 		if ( window.getUserSetting( 'advImgDetails' ) === 'show' ) {
       
  7530 			this.toggleAdvanced( true );
       
  7531 		}
       
  7532 		this.trigger( 'post-render' );
       
  7533 	},
       
  7534 
       
  7535 	scrollToTop: function() {
       
  7536 		this.$( '.embed-media-settings' ).scrollTop( 0 );
       
  7537 	},
       
  7538 
       
  7539 	updateUrl: function() {
       
  7540 		this.$( '.image img' ).attr( 'src', this.model.get( 'url' ) );
       
  7541 		this.$( '.url' ).val( this.model.get( 'url' ) );
       
  7542 	},
       
  7543 
       
  7544 	toggleLinkSettings: function() {
       
  7545 		if ( this.model.get( 'link' ) === 'none' ) {
       
  7546 			this.$( '.link-settings' ).addClass('hidden');
       
  7547 		} else {
       
  7548 			this.$( '.link-settings' ).removeClass('hidden');
       
  7549 		}
       
  7550 	},
       
  7551 
       
  7552 	toggleCustomSize: function() {
       
  7553 		if ( this.model.get( 'size' ) !== 'custom' ) {
       
  7554 			this.$( '.custom-size' ).addClass('hidden');
       
  7555 		} else {
       
  7556 			this.$( '.custom-size' ).removeClass('hidden');
       
  7557 		}
       
  7558 	},
       
  7559 
       
  7560 	onCustomSize: function( event ) {
       
  7561 		var dimension = $( event.target ).data('setting'),
       
  7562 			num = $( event.target ).val(),
       
  7563 			value;
       
  7564 
       
  7565 		// Ignore bogus input.
       
  7566 		if ( ! /^\d+/.test( num ) || parseInt( num, 10 ) < 1 ) {
       
  7567 			event.preventDefault();
       
  7568 			return;
       
  7569 		}
       
  7570 
       
  7571 		if ( dimension === 'customWidth' ) {
       
  7572 			value = Math.round( 1 / this.model.get( 'aspectRatio' ) * num );
       
  7573 			this.model.set( 'customHeight', value, { silent: true } );
       
  7574 			this.$( '[data-setting="customHeight"]' ).val( value );
       
  7575 		} else {
       
  7576 			value = Math.round( this.model.get( 'aspectRatio' ) * num );
       
  7577 			this.model.set( 'customWidth', value, { silent: true  } );
       
  7578 			this.$( '[data-setting="customWidth"]' ).val( value );
       
  7579 		}
       
  7580 	},
       
  7581 
       
  7582 	onToggleAdvanced: function( event ) {
       
  7583 		event.preventDefault();
       
  7584 		this.toggleAdvanced();
       
  7585 	},
       
  7586 
       
  7587 	toggleAdvanced: function( show ) {
       
  7588 		var $advanced = this.$el.find( '.advanced-section' ),
       
  7589 			mode;
       
  7590 
       
  7591 		if ( $advanced.hasClass('advanced-visible') || show === false ) {
       
  7592 			$advanced.removeClass('advanced-visible');
       
  7593 			$advanced.find('.advanced-settings').addClass('hidden');
       
  7594 			mode = 'hide';
       
  7595 		} else {
       
  7596 			$advanced.addClass('advanced-visible');
       
  7597 			$advanced.find('.advanced-settings').removeClass('hidden');
       
  7598 			mode = 'show';
       
  7599 		}
       
  7600 
       
  7601 		window.setUserSetting( 'advImgDetails', mode );
       
  7602 	},
       
  7603 
       
  7604 	editAttachment: function( event ) {
       
  7605 		var editState = this.controller.states.get( 'edit-image' );
       
  7606 
       
  7607 		if ( window.imageEdit && editState ) {
       
  7608 			event.preventDefault();
       
  7609 			editState.set( 'image', this.model.attachment );
       
  7610 			this.controller.setState( 'edit-image' );
       
  7611 		}
       
  7612 	},
       
  7613 
       
  7614 	replaceAttachment: function( event ) {
       
  7615 		event.preventDefault();
       
  7616 		this.controller.setState( 'replace-image' );
       
  7617 	}
       
  7618 });
       
  7619 
       
  7620 module.exports = ImageDetails;
       
  7621 
       
  7622 
       
  7623 /***/ }),
       
  7624 
       
  7625 /***/ 4338:
       
  7626 /***/ ((module) => {
       
  7627 
       
  7628 /**
       
  7629  * wp.media.view.Label
       
  7630  *
       
  7631  * @memberOf wp.media.view
       
  7632  *
       
  7633  * @class
       
  7634  * @augments wp.media.View
       
  7635  * @augments wp.Backbone.View
       
  7636  * @augments Backbone.View
       
  7637  */
       
  7638 var Label = wp.media.View.extend(/** @lends wp.media.view.Label.prototype */{
       
  7639 	tagName: 'label',
       
  7640 	className: 'screen-reader-text',
       
  7641 
       
  7642 	initialize: function() {
       
  7643 		this.value = this.options.value;
       
  7644 	},
       
  7645 
       
  7646 	render: function() {
       
  7647 		this.$el.html( this.value );
       
  7648 
       
  7649 		return this;
       
  7650 	}
       
  7651 });
       
  7652 
       
  7653 module.exports = Label;
       
  7654 
       
  7655 
       
  7656 /***/ }),
       
  7657 
       
  7658 /***/ 2836:
       
  7659 /***/ ((module) => {
       
  7660 
       
  7661 var Frame = wp.media.view.Frame,
       
  7662 	l10n = wp.media.view.l10n,
       
  7663 	$ = jQuery,
       
  7664 	MediaFrame;
       
  7665 
       
  7666 /**
       
  7667  * wp.media.view.MediaFrame
       
  7668  *
       
  7669  * The frame used to create the media modal.
       
  7670  *
       
  7671  * @memberOf wp.media.view
       
  7672  *
       
  7673  * @class
       
  7674  * @augments wp.media.view.Frame
       
  7675  * @augments wp.media.View
       
  7676  * @augments wp.Backbone.View
       
  7677  * @augments Backbone.View
       
  7678  * @mixes wp.media.controller.StateMachine
       
  7679  */
       
  7680 MediaFrame = Frame.extend(/** @lends wp.media.view.MediaFrame.prototype */{
       
  7681 	className: 'media-frame',
       
  7682 	template:  wp.template('media-frame'),
       
  7683 	regions:   ['menu','title','content','toolbar','router'],
       
  7684 
       
  7685 	events: {
       
  7686 		'click .media-frame-menu-toggle': 'toggleMenu'
       
  7687 	},
       
  7688 
       
  7689 	/**
       
  7690 	 * @constructs
       
  7691 	 */
       
  7692 	initialize: function() {
       
  7693 		Frame.prototype.initialize.apply( this, arguments );
       
  7694 
       
  7695 		_.defaults( this.options, {
       
  7696 			title:    l10n.mediaFrameDefaultTitle,
       
  7697 			modal:    true,
       
  7698 			uploader: true
       
  7699 		});
       
  7700 
       
  7701 		// Ensure core UI is enabled.
       
  7702 		this.$el.addClass('wp-core-ui');
       
  7703 
       
  7704 		// Initialize modal container view.
       
  7705 		if ( this.options.modal ) {
       
  7706 			this.modal = new wp.media.view.Modal({
       
  7707 				controller: this,
       
  7708 				title:      this.options.title
       
  7709 			});
       
  7710 
       
  7711 			this.modal.content( this );
       
  7712 		}
       
  7713 
       
  7714 		// Force the uploader off if the upload limit has been exceeded or
       
  7715 		// if the browser isn't supported.
       
  7716 		if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
       
  7717 			this.options.uploader = false;
       
  7718 		}
       
  7719 
       
  7720 		// Initialize window-wide uploader.
       
  7721 		if ( this.options.uploader ) {
       
  7722 			this.uploader = new wp.media.view.UploaderWindow({
       
  7723 				controller: this,
       
  7724 				uploader: {
       
  7725 					dropzone:  this.modal ? this.modal.$el : this.$el,
       
  7726 					container: this.$el
       
  7727 				}
       
  7728 			});
       
  7729 			this.views.set( '.media-frame-uploader', this.uploader );
       
  7730 		}
       
  7731 
       
  7732 		this.on( 'attach', _.bind( this.views.ready, this.views ), this );
       
  7733 
       
  7734 		// Bind default title creation.
       
  7735 		this.on( 'title:create:default', this.createTitle, this );
       
  7736 		this.title.mode('default');
       
  7737 
       
  7738 		// Bind default menu.
       
  7739 		this.on( 'menu:create:default', this.createMenu, this );
       
  7740 
       
  7741 		// Set the menu ARIA tab panel attributes when the modal opens.
       
  7742 		this.on( 'open', this.setMenuTabPanelAriaAttributes, this );
       
  7743 		// Set the router ARIA tab panel attributes when the modal opens.
       
  7744 		this.on( 'open', this.setRouterTabPanelAriaAttributes, this );
       
  7745 
       
  7746 		// Update the menu ARIA tab panel attributes when the content updates.
       
  7747 		this.on( 'content:render', this.setMenuTabPanelAriaAttributes, this );
       
  7748 		// Update the router ARIA tab panel attributes when the content updates.
       
  7749 		this.on( 'content:render', this.setRouterTabPanelAriaAttributes, this );
       
  7750 	},
       
  7751 
       
  7752 	/**
       
  7753 	 * Sets the attributes to be used on the menu ARIA tab panel.
       
  7754 	 *
       
  7755 	 * @since 5.3.0
       
  7756 	 *
       
  7757 	 * @return {void}
       
  7758 	 */
       
  7759 	setMenuTabPanelAriaAttributes: function() {
       
  7760 		var stateId = this.state().get( 'id' ),
       
  7761 			tabPanelEl = this.$el.find( '.media-frame-tab-panel' ),
       
  7762 			ariaLabelledby;
       
  7763 
       
  7764 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
       
  7765 
       
  7766 		if ( this.state().get( 'menu' ) && this.menuView && this.menuView.isVisible ) {
       
  7767 			ariaLabelledby = 'menu-item-' + stateId;
       
  7768 
       
  7769 			// Set the tab panel attributes only if the tabs are visible.
       
  7770 			tabPanelEl
       
  7771 				.attr( {
       
  7772 					role: 'tabpanel',
       
  7773 					'aria-labelledby': ariaLabelledby,
       
  7774 					tabIndex: '0'
       
  7775 				} );
       
  7776 		}
       
  7777 	},
       
  7778 
       
  7779 	/**
       
  7780 	 * Sets the attributes to be used on the router ARIA tab panel.
       
  7781 	 *
       
  7782 	 * @since 5.3.0
       
  7783 	 *
       
  7784 	 * @return {void}
       
  7785 	 */
       
  7786 	setRouterTabPanelAriaAttributes: function() {
       
  7787 		var tabPanelEl = this.$el.find( '.media-frame-content' ),
       
  7788 			ariaLabelledby;
       
  7789 
       
  7790 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
       
  7791 
       
  7792 		// Set the tab panel attributes only if the tabs are visible.
       
  7793 		if ( this.state().get( 'router' ) && this.routerView && this.routerView.isVisible && this.content._mode ) {
       
  7794 			ariaLabelledby = 'menu-item-' + this.content._mode;
       
  7795 
       
  7796 			tabPanelEl
       
  7797 				.attr( {
       
  7798 					role: 'tabpanel',
       
  7799 					'aria-labelledby': ariaLabelledby,
       
  7800 					tabIndex: '0'
       
  7801 				} );
       
  7802 		}
       
  7803 	},
       
  7804 
       
  7805 	/**
       
  7806 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  7807 	 */
       
  7808 	render: function() {
       
  7809 		// Activate the default state if no active state exists.
       
  7810 		if ( ! this.state() && this.options.state ) {
       
  7811 			this.setState( this.options.state );
       
  7812 		}
       
  7813 		/**
       
  7814 		 * call 'render' directly on the parent class
       
  7815 		 */
       
  7816 		return Frame.prototype.render.apply( this, arguments );
       
  7817 	},
       
  7818 	/**
       
  7819 	 * @param {Object} title
       
  7820 	 * @this wp.media.controller.Region
       
  7821 	 */
       
  7822 	createTitle: function( title ) {
       
  7823 		title.view = new wp.media.View({
       
  7824 			controller: this,
       
  7825 			tagName: 'h1'
       
  7826 		});
       
  7827 	},
       
  7828 	/**
       
  7829 	 * @param {Object} menu
       
  7830 	 * @this wp.media.controller.Region
       
  7831 	 */
       
  7832 	createMenu: function( menu ) {
       
  7833 		menu.view = new wp.media.view.Menu({
       
  7834 			controller: this,
       
  7835 
       
  7836 			attributes: {
       
  7837 				role:               'tablist',
       
  7838 				'aria-orientation': 'vertical'
       
  7839 			}
       
  7840 		});
       
  7841 
       
  7842 		this.menuView = menu.view;
       
  7843 	},
       
  7844 
       
  7845 	toggleMenu: function( event ) {
       
  7846 		var menu = this.$el.find( '.media-menu' );
       
  7847 
       
  7848 		menu.toggleClass( 'visible' );
       
  7849 		$( event.target ).attr( 'aria-expanded', menu.hasClass( 'visible' ) );
       
  7850 	},
       
  7851 
       
  7852 	/**
       
  7853 	 * @param {Object} toolbar
       
  7854 	 * @this wp.media.controller.Region
       
  7855 	 */
       
  7856 	createToolbar: function( toolbar ) {
       
  7857 		toolbar.view = new wp.media.view.Toolbar({
       
  7858 			controller: this
       
  7859 		});
       
  7860 	},
       
  7861 	/**
       
  7862 	 * @param {Object} router
       
  7863 	 * @this wp.media.controller.Region
       
  7864 	 */
       
  7865 	createRouter: function( router ) {
       
  7866 		router.view = new wp.media.view.Router({
       
  7867 			controller: this,
       
  7868 
       
  7869 			attributes: {
       
  7870 				role:               'tablist',
       
  7871 				'aria-orientation': 'horizontal'
       
  7872 			}
       
  7873 		});
       
  7874 
       
  7875 		this.routerView = router.view;
       
  7876 	},
       
  7877 	/**
       
  7878 	 * @param {Object} options
       
  7879 	 */
       
  7880 	createIframeStates: function( options ) {
       
  7881 		var settings = wp.media.view.settings,
       
  7882 			tabs = settings.tabs,
       
  7883 			tabUrl = settings.tabUrl,
       
  7884 			$postId;
       
  7885 
       
  7886 		if ( ! tabs || ! tabUrl ) {
       
  7887 			return;
       
  7888 		}
       
  7889 
       
  7890 		// Add the post ID to the tab URL if it exists.
       
  7891 		$postId = $('#post_ID');
       
  7892 		if ( $postId.length ) {
       
  7893 			tabUrl += '&post_id=' + $postId.val();
       
  7894 		}
       
  7895 
       
  7896 		// Generate the tab states.
       
  7897 		_.each( tabs, function( title, id ) {
       
  7898 			this.state( 'iframe:' + id ).set( _.defaults({
       
  7899 				tab:     id,
       
  7900 				src:     tabUrl + '&tab=' + id,
       
  7901 				title:   title,
       
  7902 				content: 'iframe',
       
  7903 				menu:    'default'
       
  7904 			}, options ) );
       
  7905 		}, this );
       
  7906 
       
  7907 		this.on( 'content:create:iframe', this.iframeContent, this );
       
  7908 		this.on( 'content:deactivate:iframe', this.iframeContentCleanup, this );
       
  7909 		this.on( 'menu:render:default', this.iframeMenu, this );
       
  7910 		this.on( 'open', this.hijackThickbox, this );
       
  7911 		this.on( 'close', this.restoreThickbox, this );
       
  7912 	},
       
  7913 
       
  7914 	/**
       
  7915 	 * @param {Object} content
       
  7916 	 * @this wp.media.controller.Region
       
  7917 	 */
       
  7918 	iframeContent: function( content ) {
       
  7919 		this.$el.addClass('hide-toolbar');
       
  7920 		content.view = new wp.media.view.Iframe({
       
  7921 			controller: this
       
  7922 		});
       
  7923 	},
       
  7924 
       
  7925 	iframeContentCleanup: function() {
       
  7926 		this.$el.removeClass('hide-toolbar');
       
  7927 	},
       
  7928 
       
  7929 	iframeMenu: function( view ) {
       
  7930 		var views = {};
       
  7931 
       
  7932 		if ( ! view ) {
       
  7933 			return;
       
  7934 		}
       
  7935 
       
  7936 		_.each( wp.media.view.settings.tabs, function( title, id ) {
       
  7937 			views[ 'iframe:' + id ] = {
       
  7938 				text: this.state( 'iframe:' + id ).get('title'),
       
  7939 				priority: 200
       
  7940 			};
       
  7941 		}, this );
       
  7942 
       
  7943 		view.set( views );
       
  7944 	},
       
  7945 
       
  7946 	hijackThickbox: function() {
       
  7947 		var frame = this;
       
  7948 
       
  7949 		if ( ! window.tb_remove || this._tb_remove ) {
       
  7950 			return;
       
  7951 		}
       
  7952 
       
  7953 		this._tb_remove = window.tb_remove;
       
  7954 		window.tb_remove = function() {
       
  7955 			frame.close();
       
  7956 			frame.reset();
       
  7957 			frame.setState( frame.options.state );
       
  7958 			frame._tb_remove.call( window );
       
  7959 		};
       
  7960 	},
       
  7961 
       
  7962 	restoreThickbox: function() {
       
  7963 		if ( ! this._tb_remove ) {
       
  7964 			return;
       
  7965 		}
       
  7966 
       
  7967 		window.tb_remove = this._tb_remove;
       
  7968 		delete this._tb_remove;
       
  7969 	}
       
  7970 });
       
  7971 
       
  7972 // Map some of the modal's methods to the frame.
       
  7973 _.each(['open','close','attach','detach','escape'], function( method ) {
       
  7974 	/**
       
  7975 	 * @function open
       
  7976 	 * @memberOf wp.media.view.MediaFrame
       
  7977 	 * @instance
       
  7978 	 *
       
  7979 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  7980 	 */
       
  7981 	/**
       
  7982 	 * @function close
       
  7983 	 * @memberOf wp.media.view.MediaFrame
       
  7984 	 * @instance
       
  7985 	 *
       
  7986 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  7987 	 */
       
  7988 	/**
       
  7989 	 * @function attach
       
  7990 	 * @memberOf wp.media.view.MediaFrame
       
  7991 	 * @instance
       
  7992 	 *
       
  7993 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  7994 	 */
       
  7995 	/**
       
  7996 	 * @function detach
       
  7997 	 * @memberOf wp.media.view.MediaFrame
       
  7998 	 * @instance
       
  7999 	 *
       
  8000 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  8001 	 */
       
  8002 	/**
       
  8003 	 * @function escape
       
  8004 	 * @memberOf wp.media.view.MediaFrame
       
  8005 	 * @instance
       
  8006 	 *
       
  8007 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  8008 	 */
       
  8009 	MediaFrame.prototype[ method ] = function() {
       
  8010 		if ( this.modal ) {
       
  8011 			this.modal[ method ].apply( this.modal, arguments );
       
  8012 		}
       
  8013 		return this;
       
  8014 	};
       
  8015 });
       
  8016 
       
  8017 module.exports = MediaFrame;
       
  8018 
       
  8019 
       
  8020 /***/ }),
       
  8021 
       
  8022 /***/ 9013:
       
  8023 /***/ ((module) => {
       
  8024 
       
  8025 var MenuItem;
       
  8026 
       
  8027 /**
       
  8028  * wp.media.view.MenuItem
       
  8029  *
       
  8030  * @memberOf wp.media.view
       
  8031  *
       
  8032  * @class
       
  8033  * @augments wp.media.View
       
  8034  * @augments wp.Backbone.View
       
  8035  * @augments Backbone.View
       
  8036  */
       
  8037 MenuItem = wp.media.View.extend(/** @lends wp.media.view.MenuItem.prototype */{
       
  8038 	tagName:   'button',
       
  8039 	className: 'media-menu-item',
       
  8040 
       
  8041 	attributes: {
       
  8042 		type: 'button',
       
  8043 		role: 'tab'
       
  8044 	},
       
  8045 
       
  8046 	events: {
       
  8047 		'click': '_click'
       
  8048 	},
       
  8049 
       
  8050 	/**
       
  8051 	 * Allows to override the click event.
       
  8052 	 */
       
  8053 	_click: function() {
       
  8054 		var clickOverride = this.options.click;
       
  8055 
       
  8056 		if ( clickOverride ) {
       
  8057 			clickOverride.call( this );
       
  8058 		} else {
       
  8059 			this.click();
       
  8060 		}
       
  8061 	},
       
  8062 
       
  8063 	click: function() {
       
  8064 		var state = this.options.state;
       
  8065 
       
  8066 		if ( state ) {
       
  8067 			this.controller.setState( state );
       
  8068 			// Toggle the menu visibility in the responsive view.
       
  8069 			this.views.parent.$el.removeClass( 'visible' ); // @todo Or hide on any click, see below.
       
  8070 		}
       
  8071 	},
       
  8072 
       
  8073 	/**
       
  8074 	 * @return {wp.media.view.MenuItem} returns itself to allow chaining.
       
  8075 	 */
       
  8076 	render: function() {
       
  8077 		var options = this.options,
       
  8078 			menuProperty = options.state || options.contentMode;
       
  8079 
       
  8080 		if ( options.text ) {
       
  8081 			this.$el.text( options.text );
       
  8082 		} else if ( options.html ) {
       
  8083 			this.$el.html( options.html );
       
  8084 		}
       
  8085 
       
  8086 		// Set the menu item ID based on the frame state associated to the menu item.
       
  8087 		this.$el.attr( 'id', 'menu-item-' + menuProperty );
       
  8088 
       
  8089 		return this;
       
  8090 	}
       
  8091 });
       
  8092 
       
  8093 module.exports = MenuItem;
       
  8094 
       
  8095 
       
  8096 /***/ }),
       
  8097 
       
  8098 /***/ 1:
       
  8099 /***/ ((module) => {
       
  8100 
       
  8101 var MenuItem = wp.media.view.MenuItem,
       
  8102 	PriorityList = wp.media.view.PriorityList,
       
  8103 	Menu;
       
  8104 
       
  8105 /**
       
  8106  * wp.media.view.Menu
       
  8107  *
       
  8108  * @memberOf wp.media.view
       
  8109  *
       
  8110  * @class
       
  8111  * @augments wp.media.view.PriorityList
       
  8112  * @augments wp.media.View
       
  8113  * @augments wp.Backbone.View
       
  8114  * @augments Backbone.View
       
  8115  */
       
  8116 Menu = PriorityList.extend(/** @lends wp.media.view.Menu.prototype */{
       
  8117 	tagName:   'div',
       
  8118 	className: 'media-menu',
       
  8119 	property:  'state',
       
  8120 	ItemView:  MenuItem,
       
  8121 	region:    'menu',
       
  8122 
       
  8123 	attributes: {
       
  8124 		role:               'tablist',
       
  8125 		'aria-orientation': 'horizontal'
       
  8126 	},
       
  8127 
       
  8128 	initialize: function() {
       
  8129 		this._views = {};
       
  8130 
       
  8131 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
       
  8132 		delete this.options.views;
       
  8133 
       
  8134 		if ( ! this.options.silent ) {
       
  8135 			this.render();
       
  8136 		}
       
  8137 
       
  8138 		// Initialize the Focus Manager.
       
  8139 		this.focusManager = new wp.media.view.FocusManager( {
       
  8140 			el:   this.el,
       
  8141 			mode: 'tabsNavigation'
       
  8142 		} );
       
  8143 
       
  8144 		// The menu is always rendered and can be visible or hidden on some frames.
       
  8145 		this.isVisible = true;
       
  8146 	},
       
  8147 
       
  8148 	/**
       
  8149 	 * @param {Object} options
       
  8150 	 * @param {string} id
       
  8151 	 * @return {wp.media.View}
       
  8152 	 */
       
  8153 	toView: function( options, id ) {
       
  8154 		options = options || {};
       
  8155 		options[ this.property ] = options[ this.property ] || id;
       
  8156 		return new this.ItemView( options ).render();
       
  8157 	},
       
  8158 
       
  8159 	ready: function() {
       
  8160 		/**
       
  8161 		 * call 'ready' directly on the parent class
       
  8162 		 */
       
  8163 		PriorityList.prototype.ready.apply( this, arguments );
       
  8164 		this.visibility();
       
  8165 
       
  8166 		// Set up aria tabs initial attributes.
       
  8167 		this.focusManager.setupAriaTabs();
       
  8168 	},
       
  8169 
       
  8170 	set: function() {
       
  8171 		/**
       
  8172 		 * call 'set' directly on the parent class
       
  8173 		 */
       
  8174 		PriorityList.prototype.set.apply( this, arguments );
       
  8175 		this.visibility();
       
  8176 	},
       
  8177 
       
  8178 	unset: function() {
       
  8179 		/**
       
  8180 		 * call 'unset' directly on the parent class
       
  8181 		 */
       
  8182 		PriorityList.prototype.unset.apply( this, arguments );
       
  8183 		this.visibility();
       
  8184 	},
       
  8185 
       
  8186 	visibility: function() {
       
  8187 		var region = this.region,
       
  8188 			view = this.controller[ region ].get(),
       
  8189 			views = this.views.get(),
       
  8190 			hide = ! views || views.length < 2;
       
  8191 
       
  8192 		if ( this === view ) {
       
  8193 			// Flag this menu as hidden or visible.
       
  8194 			this.isVisible = ! hide;
       
  8195 			// Set or remove a CSS class to hide the menu.
       
  8196 			this.controller.$el.toggleClass( 'hide-' + region, hide );
       
  8197 		}
       
  8198 	},
       
  8199 	/**
       
  8200 	 * @param {string} id
       
  8201 	 */
       
  8202 	select: function( id ) {
       
  8203 		var view = this.get( id );
       
  8204 
       
  8205 		if ( ! view ) {
       
  8206 			return;
       
  8207 		}
       
  8208 
       
  8209 		this.deselect();
       
  8210 		view.$el.addClass('active');
       
  8211 
       
  8212 		// Set up again the aria tabs initial attributes after the menu updates.
       
  8213 		this.focusManager.setupAriaTabs();
       
  8214 	},
       
  8215 
       
  8216 	deselect: function() {
       
  8217 		this.$el.children().removeClass('active');
       
  8218 	},
       
  8219 
       
  8220 	hide: function( id ) {
       
  8221 		var view = this.get( id );
       
  8222 
       
  8223 		if ( ! view ) {
       
  8224 			return;
       
  8225 		}
       
  8226 
       
  8227 		view.$el.addClass('hidden');
       
  8228 	},
       
  8229 
       
  8230 	show: function( id ) {
       
  8231 		var view = this.get( id );
       
  8232 
       
  8233 		if ( ! view ) {
       
  8234 			return;
       
  8235 		}
       
  8236 
       
  8237 		view.$el.removeClass('hidden');
       
  8238 	}
       
  8239 });
       
  8240 
       
  8241 module.exports = Menu;
       
  8242 
       
  8243 
       
  8244 /***/ }),
       
  8245 
       
  8246 /***/ 2621:
       
  8247 /***/ ((module) => {
       
  8248 
       
  8249 var $ = jQuery,
       
  8250 	Modal;
       
  8251 
       
  8252 /**
       
  8253  * wp.media.view.Modal
       
  8254  *
       
  8255  * A modal view, which the media modal uses as its default container.
       
  8256  *
       
  8257  * @memberOf wp.media.view
       
  8258  *
       
  8259  * @class
       
  8260  * @augments wp.media.View
       
  8261  * @augments wp.Backbone.View
       
  8262  * @augments Backbone.View
       
  8263  */
       
  8264 Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
       
  8265 	tagName:  'div',
       
  8266 	template: wp.template('media-modal'),
       
  8267 
       
  8268 	events: {
       
  8269 		'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
       
  8270 		'keydown': 'keydown'
       
  8271 	},
       
  8272 
       
  8273 	clickedOpenerEl: null,
       
  8274 
       
  8275 	initialize: function() {
       
  8276 		_.defaults( this.options, {
       
  8277 			container:      document.body,
       
  8278 			title:          '',
       
  8279 			propagate:      true,
       
  8280 			hasCloseButton: true
       
  8281 		});
       
  8282 
       
  8283 		this.focusManager = new wp.media.view.FocusManager({
       
  8284 			el: this.el
       
  8285 		});
       
  8286 	},
       
  8287 	/**
       
  8288 	 * @return {Object}
       
  8289 	 */
       
  8290 	prepare: function() {
       
  8291 		return {
       
  8292 			title:          this.options.title,
       
  8293 			hasCloseButton: this.options.hasCloseButton
       
  8294 		};
       
  8295 	},
       
  8296 
       
  8297 	/**
       
  8298 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8299 	 */
       
  8300 	attach: function() {
       
  8301 		if ( this.views.attached ) {
       
  8302 			return this;
       
  8303 		}
       
  8304 
       
  8305 		if ( ! this.views.rendered ) {
       
  8306 			this.render();
       
  8307 		}
       
  8308 
       
  8309 		this.$el.appendTo( this.options.container );
       
  8310 
       
  8311 		// Manually mark the view as attached and trigger ready.
       
  8312 		this.views.attached = true;
       
  8313 		this.views.ready();
       
  8314 
       
  8315 		return this.propagate('attach');
       
  8316 	},
       
  8317 
       
  8318 	/**
       
  8319 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8320 	 */
       
  8321 	detach: function() {
       
  8322 		if ( this.$el.is(':visible') ) {
       
  8323 			this.close();
       
  8324 		}
       
  8325 
       
  8326 		this.$el.detach();
       
  8327 		this.views.attached = false;
       
  8328 		return this.propagate('detach');
       
  8329 	},
       
  8330 
       
  8331 	/**
       
  8332 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8333 	 */
       
  8334 	open: function() {
       
  8335 		var $el = this.$el,
       
  8336 			mceEditor;
       
  8337 
       
  8338 		if ( $el.is(':visible') ) {
       
  8339 			return this;
       
  8340 		}
       
  8341 
       
  8342 		this.clickedOpenerEl = document.activeElement;
       
  8343 
       
  8344 		if ( ! this.views.attached ) {
       
  8345 			this.attach();
       
  8346 		}
       
  8347 
       
  8348 		// Disable page scrolling.
       
  8349 		$( 'body' ).addClass( 'modal-open' );
       
  8350 
       
  8351 		$el.show();
       
  8352 
       
  8353 		// Try to close the onscreen keyboard.
       
  8354 		if ( 'ontouchend' in document ) {
       
  8355 			if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor ) && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
       
  8356 				mceEditor.iframeElement.focus();
       
  8357 				mceEditor.iframeElement.blur();
       
  8358 
       
  8359 				setTimeout( function() {
       
  8360 					mceEditor.iframeElement.blur();
       
  8361 				}, 100 );
       
  8362 			}
       
  8363 		}
       
  8364 
       
  8365 		// Set initial focus on the content instead of this view element, to avoid page scrolling.
       
  8366 		this.$( '.media-modal' ).trigger( 'focus' );
       
  8367 
       
  8368 		// Hide the page content from assistive technologies.
       
  8369 		this.focusManager.setAriaHiddenOnBodyChildren( $el );
       
  8370 
       
  8371 		return this.propagate('open');
       
  8372 	},
       
  8373 
       
  8374 	/**
       
  8375 	 * @param {Object} options
       
  8376 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8377 	 */
       
  8378 	close: function( options ) {
       
  8379 		if ( ! this.views.attached || ! this.$el.is(':visible') ) {
       
  8380 			return this;
       
  8381 		}
       
  8382 
       
  8383 		// Pause current audio/video even after closing the modal.
       
  8384 		$( '.mejs-pause button' ).trigger( 'click' );
       
  8385 
       
  8386 		// Enable page scrolling.
       
  8387 		$( 'body' ).removeClass( 'modal-open' );
       
  8388 
       
  8389 		// Hide the modal element by adding display:none.
       
  8390 		this.$el.hide();
       
  8391 
       
  8392 		/*
       
  8393 		 * Make visible again to assistive technologies all body children that
       
  8394 		 * have been made hidden when the modal opened.
       
  8395 		 */
       
  8396 		this.focusManager.removeAriaHiddenFromBodyChildren();
       
  8397 
       
  8398 		// Move focus back in useful location once modal is closed.
       
  8399 		if ( null !== this.clickedOpenerEl ) {
       
  8400 			// Move focus back to the element that opened the modal.
       
  8401 			this.clickedOpenerEl.focus();
       
  8402 		} else {
       
  8403 			// Fallback to the admin page main element.
       
  8404 			$( '#wpbody-content' )
       
  8405 				.attr( 'tabindex', '-1' )
       
  8406 				.trigger( 'focus' );
       
  8407 		}
       
  8408 
       
  8409 		this.propagate('close');
       
  8410 
       
  8411 		if ( options && options.escape ) {
       
  8412 			this.propagate('escape');
       
  8413 		}
       
  8414 
       
  8415 		return this;
       
  8416 	},
       
  8417 	/**
       
  8418 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8419 	 */
       
  8420 	escape: function() {
       
  8421 		return this.close({ escape: true });
       
  8422 	},
       
  8423 	/**
       
  8424 	 * @param {Object} event
       
  8425 	 */
       
  8426 	escapeHandler: function( event ) {
       
  8427 		event.preventDefault();
       
  8428 		this.escape();
       
  8429 	},
       
  8430 
       
  8431 	/**
       
  8432 	 * @param {Array|Object} content Views to register to '.media-modal-content'
       
  8433 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8434 	 */
       
  8435 	content: function( content ) {
       
  8436 		this.views.set( '.media-modal-content', content );
       
  8437 		return this;
       
  8438 	},
       
  8439 
       
  8440 	/**
       
  8441 	 * Triggers a modal event and if the `propagate` option is set,
       
  8442 	 * forwards events to the modal's controller.
       
  8443 	 *
       
  8444 	 * @param {string} id
       
  8445 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8446 	 */
       
  8447 	propagate: function( id ) {
       
  8448 		this.trigger( id );
       
  8449 
       
  8450 		if ( this.options.propagate ) {
       
  8451 			this.controller.trigger( id );
       
  8452 		}
       
  8453 
       
  8454 		return this;
       
  8455 	},
       
  8456 	/**
       
  8457 	 * @param {Object} event
       
  8458 	 */
       
  8459 	keydown: function( event ) {
       
  8460 		// Close the modal when escape is pressed.
       
  8461 		if ( 27 === event.which && this.$el.is(':visible') ) {
       
  8462 			this.escape();
       
  8463 			event.stopImmediatePropagation();
       
  8464 		}
       
  8465 	}
       
  8466 });
       
  8467 
       
  8468 module.exports = Modal;
       
  8469 
       
  8470 
       
  8471 /***/ }),
       
  8472 
       
  8473 /***/ 8815:
       
  8474 /***/ ((module) => {
       
  8475 
       
  8476 /**
       
  8477  * wp.media.view.PriorityList
       
  8478  *
       
  8479  * @memberOf wp.media.view
       
  8480  *
       
  8481  * @class
       
  8482  * @augments wp.media.View
       
  8483  * @augments wp.Backbone.View
       
  8484  * @augments Backbone.View
       
  8485  */
       
  8486 var PriorityList = wp.media.View.extend(/** @lends wp.media.view.PriorityList.prototype */{
       
  8487 	tagName:   'div',
       
  8488 
       
  8489 	initialize: function() {
       
  8490 		this._views = {};
       
  8491 
       
  8492 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
       
  8493 		delete this.options.views;
       
  8494 
       
  8495 		if ( ! this.options.silent ) {
       
  8496 			this.render();
       
  8497 		}
       
  8498 	},
       
  8499 	/**
       
  8500 	 * @param {string} id
       
  8501 	 * @param {wp.media.View|Object} view
       
  8502 	 * @param {Object} options
       
  8503 	 * @return {wp.media.view.PriorityList} Returns itself to allow chaining.
       
  8504 	 */
       
  8505 	set: function( id, view, options ) {
       
  8506 		var priority, views, index;
       
  8507 
       
  8508 		options = options || {};
       
  8509 
       
  8510 		// Accept an object with an `id` : `view` mapping.
       
  8511 		if ( _.isObject( id ) ) {
       
  8512 			_.each( id, function( view, id ) {
       
  8513 				this.set( id, view );
       
  8514 			}, this );
       
  8515 			return this;
       
  8516 		}
       
  8517 
       
  8518 		if ( ! (view instanceof Backbone.View) ) {
       
  8519 			view = this.toView( view, id, options );
       
  8520 		}
       
  8521 		view.controller = view.controller || this.controller;
       
  8522 
       
  8523 		this.unset( id );
       
  8524 
       
  8525 		priority = view.options.priority || 10;
       
  8526 		views = this.views.get() || [];
       
  8527 
       
  8528 		_.find( views, function( existing, i ) {
       
  8529 			if ( existing.options.priority > priority ) {
       
  8530 				index = i;
       
  8531 				return true;
       
  8532 			}
       
  8533 		});
       
  8534 
       
  8535 		this._views[ id ] = view;
       
  8536 		this.views.add( view, {
       
  8537 			at: _.isNumber( index ) ? index : views.length || 0
       
  8538 		});
       
  8539 
       
  8540 		return this;
       
  8541 	},
       
  8542 	/**
       
  8543 	 * @param {string} id
       
  8544 	 * @return {wp.media.View}
       
  8545 	 */
       
  8546 	get: function( id ) {
       
  8547 		return this._views[ id ];
       
  8548 	},
       
  8549 	/**
       
  8550 	 * @param {string} id
       
  8551 	 * @return {wp.media.view.PriorityList}
       
  8552 	 */
       
  8553 	unset: function( id ) {
       
  8554 		var view = this.get( id );
       
  8555 
       
  8556 		if ( view ) {
       
  8557 			view.remove();
       
  8558 		}
       
  8559 
       
  8560 		delete this._views[ id ];
       
  8561 		return this;
       
  8562 	},
       
  8563 	/**
       
  8564 	 * @param {Object} options
       
  8565 	 * @return {wp.media.View}
       
  8566 	 */
       
  8567 	toView: function( options ) {
       
  8568 		return new wp.media.View( options );
       
  8569 	}
       
  8570 });
       
  8571 
       
  8572 module.exports = PriorityList;
       
  8573 
       
  8574 
       
  8575 /***/ }),
       
  8576 
       
  8577 /***/ 6327:
       
  8578 /***/ ((module) => {
       
  8579 
       
  8580 /**
       
  8581  * wp.media.view.RouterItem
       
  8582  *
       
  8583  * @memberOf wp.media.view
       
  8584  *
       
  8585  * @class
       
  8586  * @augments wp.media.view.MenuItem
       
  8587  * @augments wp.media.View
       
  8588  * @augments wp.Backbone.View
       
  8589  * @augments Backbone.View
       
  8590  */
       
  8591 var RouterItem = wp.media.view.MenuItem.extend(/** @lends wp.media.view.RouterItem.prototype */{
       
  8592 	/**
       
  8593 	 * On click handler to activate the content region's corresponding mode.
       
  8594 	 */
       
  8595 	click: function() {
       
  8596 		var contentMode = this.options.contentMode;
       
  8597 		if ( contentMode ) {
       
  8598 			this.controller.content.mode( contentMode );
       
  8599 		}
       
  8600 	}
       
  8601 });
       
  8602 
       
  8603 module.exports = RouterItem;
       
  8604 
       
  8605 
       
  8606 /***/ }),
       
  8607 
       
  8608 /***/ 4783:
       
  8609 /***/ ((module) => {
       
  8610 
       
  8611 var Menu = wp.media.view.Menu,
       
  8612 	Router;
       
  8613 
       
  8614 /**
       
  8615  * wp.media.view.Router
       
  8616  *
       
  8617  * @memberOf wp.media.view
       
  8618  *
       
  8619  * @class
       
  8620  * @augments wp.media.view.Menu
       
  8621  * @augments wp.media.view.PriorityList
       
  8622  * @augments wp.media.View
       
  8623  * @augments wp.Backbone.View
       
  8624  * @augments Backbone.View
       
  8625  */
       
  8626 Router = Menu.extend(/** @lends wp.media.view.Router.prototype */{
       
  8627 	tagName:   'div',
       
  8628 	className: 'media-router',
       
  8629 	property:  'contentMode',
       
  8630 	ItemView:  wp.media.view.RouterItem,
       
  8631 	region:    'router',
       
  8632 
       
  8633 	attributes: {
       
  8634 		role:               'tablist',
       
  8635 		'aria-orientation': 'horizontal'
       
  8636 	},
       
  8637 
       
  8638 	initialize: function() {
       
  8639 		this.controller.on( 'content:render', this.update, this );
       
  8640 		// Call 'initialize' directly on the parent class.
       
  8641 		Menu.prototype.initialize.apply( this, arguments );
       
  8642 	},
       
  8643 
       
  8644 	update: function() {
       
  8645 		var mode = this.controller.content.mode();
       
  8646 		if ( mode ) {
       
  8647 			this.select( mode );
       
  8648 		}
       
  8649 	}
       
  8650 });
       
  8651 
       
  8652 module.exports = Router;
       
  8653 
       
  8654 
       
  8655 /***/ }),
       
  8656 
       
  8657 /***/ 2102:
       
  8658 /***/ ((module) => {
       
  8659 
       
  8660 var Search;
       
  8661 
       
  8662 /**
       
  8663  * wp.media.view.Search
       
  8664  *
       
  8665  * @memberOf wp.media.view
       
  8666  *
       
  8667  * @class
       
  8668  * @augments wp.media.View
       
  8669  * @augments wp.Backbone.View
       
  8670  * @augments Backbone.View
       
  8671  */
       
  8672 Search = wp.media.View.extend(/** @lends wp.media.view.Search.prototype */{
       
  8673 	tagName:   'input',
       
  8674 	className: 'search',
       
  8675 	id:        'media-search-input',
       
  8676 
       
  8677 	attributes: {
       
  8678 		type: 'search'
       
  8679 	},
       
  8680 
       
  8681 	events: {
       
  8682 		'input': 'search'
       
  8683 	},
       
  8684 
       
  8685 	/**
       
  8686 	 * @return {wp.media.view.Search} Returns itself to allow chaining.
       
  8687 	 */
       
  8688 	render: function() {
       
  8689 		this.el.value = this.model.escape('search');
       
  8690 		return this;
       
  8691 	},
       
  8692 
       
  8693 	search: _.debounce( function( event ) {
       
  8694 		var searchTerm = event.target.value.trim();
       
  8695 
       
  8696 		// Trigger the search only after 2 ASCII characters.
       
  8697 		if ( searchTerm && searchTerm.length > 1 ) {
       
  8698 			this.model.set( 'search', searchTerm );
       
  8699 		} else {
       
  8700 			this.model.unset( 'search' );
       
  8701 		}
       
  8702 	}, 500 )
       
  8703 });
       
  8704 
       
  8705 module.exports = Search;
       
  8706 
       
  8707 
       
  8708 /***/ }),
       
  8709 
       
  8710 /***/ 8282:
  9441 /***/ 8282:
  8711 /***/ ((module) => {
  9442 /***/ ((module) => {
  8712 
  9443 
  8713 var _n = wp.i18n._n,
  9444 var _n = wp.i18n._n,
  8714 	sprintf = wp.i18n.sprintf,
  9445 	sprintf = wp.i18n.sprintf,
  8798 module.exports = Selection;
  9529 module.exports = Selection;
  8799 
  9530 
  8800 
  9531 
  8801 /***/ }),
  9532 /***/ }),
  8802 
  9533 
  8803 /***/ 1915:
  9534 /***/ 8291:
  8804 /***/ ((module) => {
  9535 /***/ ((module) => {
  8805 
  9536 
  8806 var View = wp.media.View,
  9537 var $ = jQuery,
  8807 	$ = Backbone.$,
  9538 	UploaderWindow;
  8808 	Settings;
       
  8809 
  9539 
  8810 /**
  9540 /**
  8811  * wp.media.view.Settings
  9541  * wp.media.view.UploaderWindow
       
  9542  *
       
  9543  * An uploader window that allows for dragging and dropping media.
       
  9544  *
       
  9545  * @memberOf wp.media.view
       
  9546  *
       
  9547  * @class
       
  9548  * @augments wp.media.View
       
  9549  * @augments wp.Backbone.View
       
  9550  * @augments Backbone.View
       
  9551  *
       
  9552  * @param {object} [options]                   Options hash passed to the view.
       
  9553  * @param {object} [options.uploader]          Uploader properties.
       
  9554  * @param {jQuery} [options.uploader.browser]
       
  9555  * @param {jQuery} [options.uploader.dropzone] jQuery collection of the dropzone.
       
  9556  * @param {object} [options.uploader.params]
       
  9557  */
       
  9558 UploaderWindow = wp.media.View.extend(/** @lends wp.media.view.UploaderWindow.prototype */{
       
  9559 	tagName:   'div',
       
  9560 	className: 'uploader-window',
       
  9561 	template:  wp.template('uploader-window'),
       
  9562 
       
  9563 	initialize: function() {
       
  9564 		var uploader;
       
  9565 
       
  9566 		this.$browser = $( '<button type="button" class="browser" />' ).hide().appendTo( 'body' );
       
  9567 
       
  9568 		uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
       
  9569 			dropzone:  this.$el,
       
  9570 			browser:   this.$browser,
       
  9571 			params:    {}
       
  9572 		});
       
  9573 
       
  9574 		// Ensure the dropzone is a jQuery collection.
       
  9575 		if ( uploader.dropzone && ! (uploader.dropzone instanceof $) ) {
       
  9576 			uploader.dropzone = $( uploader.dropzone );
       
  9577 		}
       
  9578 
       
  9579 		this.controller.on( 'activate', this.refresh, this );
       
  9580 
       
  9581 		this.controller.on( 'detach', function() {
       
  9582 			this.$browser.remove();
       
  9583 		}, this );
       
  9584 	},
       
  9585 
       
  9586 	refresh: function() {
       
  9587 		if ( this.uploader ) {
       
  9588 			this.uploader.refresh();
       
  9589 		}
       
  9590 	},
       
  9591 
       
  9592 	ready: function() {
       
  9593 		var postId = wp.media.view.settings.post.id,
       
  9594 			dropzone;
       
  9595 
       
  9596 		// If the uploader already exists, bail.
       
  9597 		if ( this.uploader ) {
       
  9598 			return;
       
  9599 		}
       
  9600 
       
  9601 		if ( postId ) {
       
  9602 			this.options.uploader.params.post_id = postId;
       
  9603 		}
       
  9604 		this.uploader = new wp.Uploader( this.options.uploader );
       
  9605 
       
  9606 		dropzone = this.uploader.dropzone;
       
  9607 		dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
       
  9608 		dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
       
  9609 
       
  9610 		$( this.uploader ).on( 'uploader:ready', _.bind( this._ready, this ) );
       
  9611 	},
       
  9612 
       
  9613 	_ready: function() {
       
  9614 		this.controller.trigger( 'uploader:ready' );
       
  9615 	},
       
  9616 
       
  9617 	show: function() {
       
  9618 		var $el = this.$el.show();
       
  9619 
       
  9620 		// Ensure that the animation is triggered by waiting until
       
  9621 		// the transparent element is painted into the DOM.
       
  9622 		_.defer( function() {
       
  9623 			$el.css({ opacity: 1 });
       
  9624 		});
       
  9625 	},
       
  9626 
       
  9627 	hide: function() {
       
  9628 		var $el = this.$el.css({ opacity: 0 });
       
  9629 
       
  9630 		wp.media.transition( $el ).done( function() {
       
  9631 			// Transition end events are subject to race conditions.
       
  9632 			// Make sure that the value is set as intended.
       
  9633 			if ( '0' === $el.css('opacity') ) {
       
  9634 				$el.hide();
       
  9635 			}
       
  9636 		});
       
  9637 
       
  9638 		// https://core.trac.wordpress.org/ticket/27341
       
  9639 		_.delay( function() {
       
  9640 			if ( '0' === $el.css('opacity') && $el.is(':visible') ) {
       
  9641 				$el.hide();
       
  9642 			}
       
  9643 		}, 500 );
       
  9644 	}
       
  9645 });
       
  9646 
       
  9647 module.exports = UploaderWindow;
       
  9648 
       
  9649 
       
  9650 /***/ }),
       
  9651 
       
  9652 /***/ 8612:
       
  9653 /***/ ((module) => {
       
  9654 
       
  9655 var Library = wp.media.controller.Library,
       
  9656 	l10n = wp.media.view.l10n,
       
  9657 	$ = jQuery,
       
  9658 	CollectionEdit;
       
  9659 
       
  9660 /**
       
  9661  * wp.media.controller.CollectionEdit
       
  9662  *
       
  9663  * A state for editing a collection, which is used by audio and video playlists,
       
  9664  * and can be used for other collections.
       
  9665  *
       
  9666  * @memberOf wp.media.controller
       
  9667  *
       
  9668  * @class
       
  9669  * @augments wp.media.controller.Library
       
  9670  * @augments wp.media.controller.State
       
  9671  * @augments Backbone.Model
       
  9672  *
       
  9673  * @param {object}                     [attributes]                      The attributes hash passed to the state.
       
  9674  * @param {string}                     attributes.title                  Title for the state. Displays in the media menu and the frame's title region.
       
  9675  * @param {wp.media.model.Attachments} [attributes.library]              The attachments collection to edit.
       
  9676  *                                                                       If one is not supplied, an empty media.model.Selection collection is created.
       
  9677  * @param {boolean}                    [attributes.multiple=false]       Whether multi-select is enabled.
       
  9678  * @param {string}                     [attributes.content=browse]       Initial mode for the content region.
       
  9679  * @param {string}                     attributes.menu                   Initial mode for the menu region. @todo this needs a better explanation.
       
  9680  * @param {boolean}                    [attributes.searchable=false]     Whether the library is searchable.
       
  9681  * @param {boolean}                    [attributes.sortable=true]        Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  9682  * @param {boolean}                    [attributes.date=true]            Whether to show the date filter in the browser's toolbar.
       
  9683  * @param {boolean}                    [attributes.describe=true]        Whether to offer UI to describe the attachments - e.g. captioning images in a gallery.
       
  9684  * @param {boolean}                    [attributes.dragInfo=true]        Whether to show instructional text about the attachments being sortable.
       
  9685  * @param {boolean}                    [attributes.dragInfoText]         Instructional text about the attachments being sortable.
       
  9686  * @param {int}                        [attributes.idealColumnWidth=170] The ideal column width in pixels for attachments.
       
  9687  * @param {boolean}                    [attributes.editing=false]        Whether the gallery is being created, or editing an existing instance.
       
  9688  * @param {int}                        [attributes.priority=60]          The priority for the state link in the media menu.
       
  9689  * @param {boolean}                    [attributes.syncSelection=false]  Whether the Attachments selection should be persisted from the last state.
       
  9690  *                                                                       Defaults to false for this state, because the library passed in  *is* the selection.
       
  9691  * @param {view}                       [attributes.SettingsView]         The view to edit the collection instance settings (e.g. Playlist settings with "Show tracklist" checkbox).
       
  9692  * @param {view}                       [attributes.AttachmentView]       The single `Attachment` view to be used in the `Attachments`.
       
  9693  *                                                                       If none supplied, defaults to wp.media.view.Attachment.EditLibrary.
       
  9694  * @param {string}                     attributes.type                   The collection's media type. (e.g. 'video').
       
  9695  * @param {string}                     attributes.collectionType         The collection type. (e.g. 'playlist').
       
  9696  */
       
  9697 CollectionEdit = Library.extend(/** @lends wp.media.controller.CollectionEdit.prototype */{
       
  9698 	defaults: {
       
  9699 		multiple:         false,
       
  9700 		sortable:         true,
       
  9701 		date:             false,
       
  9702 		searchable:       false,
       
  9703 		content:          'browse',
       
  9704 		describe:         true,
       
  9705 		dragInfo:         true,
       
  9706 		idealColumnWidth: 170,
       
  9707 		editing:          false,
       
  9708 		priority:         60,
       
  9709 		SettingsView:     false,
       
  9710 		syncSelection:    false
       
  9711 	},
       
  9712 
       
  9713 	/**
       
  9714 	 * @since 3.9.0
       
  9715 	 */
       
  9716 	initialize: function() {
       
  9717 		var collectionType = this.get('collectionType');
       
  9718 
       
  9719 		if ( 'video' === this.get( 'type' ) ) {
       
  9720 			collectionType = 'video-' + collectionType;
       
  9721 		}
       
  9722 
       
  9723 		this.set( 'id', collectionType + '-edit' );
       
  9724 		this.set( 'toolbar', collectionType + '-edit' );
       
  9725 
       
  9726 		// If we haven't been provided a `library`, create a `Selection`.
       
  9727 		if ( ! this.get('library') ) {
       
  9728 			this.set( 'library', new wp.media.model.Selection() );
       
  9729 		}
       
  9730 		// The single `Attachment` view to be used in the `Attachments` view.
       
  9731 		if ( ! this.get('AttachmentView') ) {
       
  9732 			this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );
       
  9733 		}
       
  9734 		Library.prototype.initialize.apply( this, arguments );
       
  9735 	},
       
  9736 
       
  9737 	/**
       
  9738 	 * @since 3.9.0
       
  9739 	 */
       
  9740 	activate: function() {
       
  9741 		var library = this.get('library');
       
  9742 
       
  9743 		// Limit the library to images only.
       
  9744 		library.props.set( 'type', this.get( 'type' ) );
       
  9745 
       
  9746 		// Watch for uploaded attachments.
       
  9747 		this.get('library').observe( wp.Uploader.queue );
       
  9748 
       
  9749 		this.frame.on( 'content:render:browse', this.renderSettings, this );
       
  9750 
       
  9751 		Library.prototype.activate.apply( this, arguments );
       
  9752 	},
       
  9753 
       
  9754 	/**
       
  9755 	 * @since 3.9.0
       
  9756 	 */
       
  9757 	deactivate: function() {
       
  9758 		// Stop watching for uploaded attachments.
       
  9759 		this.get('library').unobserve( wp.Uploader.queue );
       
  9760 
       
  9761 		this.frame.off( 'content:render:browse', this.renderSettings, this );
       
  9762 
       
  9763 		Library.prototype.deactivate.apply( this, arguments );
       
  9764 	},
       
  9765 
       
  9766 	/**
       
  9767 	 * Render the collection embed settings view in the browser sidebar.
       
  9768 	 *
       
  9769 	 * @todo This is against the pattern elsewhere in media. Typically the frame
       
  9770 	 *       is responsible for adding region mode callbacks. Explain.
       
  9771 	 *
       
  9772 	 * @since 3.9.0
       
  9773 	 *
       
  9774 	 * @param {wp.media.view.attachmentsBrowser} The attachments browser view.
       
  9775 	 */
       
  9776 	renderSettings: function( attachmentsBrowserView ) {
       
  9777 		var library = this.get('library'),
       
  9778 			collectionType = this.get('collectionType'),
       
  9779 			dragInfoText = this.get('dragInfoText'),
       
  9780 			SettingsView = this.get('SettingsView'),
       
  9781 			obj = {};
       
  9782 
       
  9783 		if ( ! library || ! attachmentsBrowserView ) {
       
  9784 			return;
       
  9785 		}
       
  9786 
       
  9787 		library[ collectionType ] = library[ collectionType ] || new Backbone.Model();
       
  9788 
       
  9789 		obj[ collectionType ] = new SettingsView({
       
  9790 			controller: this,
       
  9791 			model:      library[ collectionType ],
       
  9792 			priority:   40
       
  9793 		});
       
  9794 
       
  9795 		attachmentsBrowserView.sidebar.set( obj );
       
  9796 
       
  9797 		if ( dragInfoText ) {
       
  9798 			attachmentsBrowserView.toolbar.set( 'dragInfo', new wp.media.View({
       
  9799 				el: $( '<div class="instructions">' + dragInfoText + '</div>' )[0],
       
  9800 				priority: -40
       
  9801 			}) );
       
  9802 		}
       
  9803 
       
  9804 		// Add the 'Reverse order' button to the toolbar.
       
  9805 		attachmentsBrowserView.toolbar.set( 'reverse', {
       
  9806 			text:     l10n.reverseOrder,
       
  9807 			priority: 80,
       
  9808 
       
  9809 			click: function() {
       
  9810 				library.reset( library.toArray().reverse() );
       
  9811 			}
       
  9812 		});
       
  9813 	}
       
  9814 });
       
  9815 
       
  9816 module.exports = CollectionEdit;
       
  9817 
       
  9818 
       
  9819 /***/ }),
       
  9820 
       
  9821 /***/ 8815:
       
  9822 /***/ ((module) => {
       
  9823 
       
  9824 /**
       
  9825  * wp.media.view.PriorityList
  8812  *
  9826  *
  8813  * @memberOf wp.media.view
  9827  * @memberOf wp.media.view
  8814  *
  9828  *
  8815  * @class
  9829  * @class
  8816  * @augments wp.media.View
  9830  * @augments wp.media.View
  8817  * @augments wp.Backbone.View
  9831  * @augments wp.Backbone.View
  8818  * @augments Backbone.View
  9832  * @augments Backbone.View
  8819  */
  9833  */
  8820 Settings = View.extend(/** @lends wp.media.view.Settings.prototype */{
  9834 var PriorityList = wp.media.View.extend(/** @lends wp.media.view.PriorityList.prototype */{
  8821 	events: {
  9835 	tagName:   'div',
  8822 		'click button':    'updateHandler',
       
  8823 		'change input':    'updateHandler',
       
  8824 		'change select':   'updateHandler',
       
  8825 		'change textarea': 'updateHandler'
       
  8826 	},
       
  8827 
  9836 
  8828 	initialize: function() {
  9837 	initialize: function() {
  8829 		this.model = this.model || new Backbone.Model();
  9838 		this._views = {};
  8830 		this.listenTo( this.model, 'change', this.updateChanges );
  9839 
  8831 	},
  9840 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
  8832 
  9841 		delete this.options.views;
  8833 	prepare: function() {
  9842 
  8834 		return _.defaults({
  9843 		if ( ! this.options.silent ) {
  8835 			model: this.model.toJSON()
  9844 			this.render();
  8836 		}, this.options );
  9845 		}
  8837 	},
  9846 	},
  8838 	/**
  9847 	/**
  8839 	 * @return {wp.media.view.Settings} Returns itself to allow chaining.
  9848 	 * @param {string} id
  8840 	 */
  9849 	 * @param {wp.media.View|Object} view
  8841 	render: function() {
  9850 	 * @param {Object} options
  8842 		View.prototype.render.apply( this, arguments );
  9851 	 * @return {wp.media.view.PriorityList} Returns itself to allow chaining.
  8843 		// Select the correct values.
  9852 	 */
  8844 		_( this.model.attributes ).chain().keys().each( this.update, this );
  9853 	set: function( id, view, options ) {
       
  9854 		var priority, views, index;
       
  9855 
       
  9856 		options = options || {};
       
  9857 
       
  9858 		// Accept an object with an `id` : `view` mapping.
       
  9859 		if ( _.isObject( id ) ) {
       
  9860 			_.each( id, function( view, id ) {
       
  9861 				this.set( id, view );
       
  9862 			}, this );
       
  9863 			return this;
       
  9864 		}
       
  9865 
       
  9866 		if ( ! (view instanceof Backbone.View) ) {
       
  9867 			view = this.toView( view, id, options );
       
  9868 		}
       
  9869 		view.controller = view.controller || this.controller;
       
  9870 
       
  9871 		this.unset( id );
       
  9872 
       
  9873 		priority = view.options.priority || 10;
       
  9874 		views = this.views.get() || [];
       
  9875 
       
  9876 		_.find( views, function( existing, i ) {
       
  9877 			if ( existing.options.priority > priority ) {
       
  9878 				index = i;
       
  9879 				return true;
       
  9880 			}
       
  9881 		});
       
  9882 
       
  9883 		this._views[ id ] = view;
       
  9884 		this.views.add( view, {
       
  9885 			at: _.isNumber( index ) ? index : views.length || 0
       
  9886 		});
       
  9887 
  8845 		return this;
  9888 		return this;
  8846 	},
  9889 	},
  8847 	/**
  9890 	/**
  8848 	 * @param {string} key
  9891 	 * @param {string} id
  8849 	 */
  9892 	 * @return {wp.media.View}
  8850 	update: function( key ) {
  9893 	 */
  8851 		var value = this.model.get( key ),
  9894 	get: function( id ) {
  8852 			$setting = this.$('[data-setting="' + key + '"]'),
  9895 		return this._views[ id ];
  8853 			$buttons, $value;
  9896 	},
  8854 
  9897 	/**
  8855 		// Bail if we didn't find a matching setting.
  9898 	 * @param {string} id
  8856 		if ( ! $setting.length ) {
  9899 	 * @return {wp.media.view.PriorityList}
  8857 			return;
  9900 	 */
  8858 		}
  9901 	unset: function( id ) {
  8859 
  9902 		var view = this.get( id );
  8860 		// Attempt to determine how the setting is rendered and update
  9903 
  8861 		// the selected value.
  9904 		if ( view ) {
  8862 
  9905 			view.remove();
  8863 		// Handle dropdowns.
  9906 		}
  8864 		if ( $setting.is('select') ) {
  9907 
  8865 			$value = $setting.find('[value="' + value + '"]');
  9908 		delete this._views[ id ];
  8866 
  9909 		return this;
  8867 			if ( $value.length ) {
  9910 	},
  8868 				$setting.find('option').prop( 'selected', false );
  9911 	/**
  8869 				$value.prop( 'selected', true );
  9912 	 * @param {Object} options
  8870 			} else {
  9913 	 * @return {wp.media.View}
  8871 				// If we can't find the desired value, record what *is* selected.
  9914 	 */
  8872 				this.model.set( key, $setting.find(':selected').val() );
  9915 	toView: function( options ) {
  8873 			}
  9916 		return new wp.media.View( options );
  8874 
       
  8875 		// Handle button groups.
       
  8876 		} else if ( $setting.hasClass('button-group') ) {
       
  8877 			$buttons = $setting.find( 'button' )
       
  8878 				.removeClass( 'active' )
       
  8879 				.attr( 'aria-pressed', 'false' );
       
  8880 			$buttons.filter( '[value="' + value + '"]' )
       
  8881 				.addClass( 'active' )
       
  8882 				.attr( 'aria-pressed', 'true' );
       
  8883 
       
  8884 		// Handle text inputs and textareas.
       
  8885 		} else if ( $setting.is('input[type="text"], textarea') ) {
       
  8886 			if ( ! $setting.is(':focus') ) {
       
  8887 				$setting.val( value );
       
  8888 			}
       
  8889 		// Handle checkboxes.
       
  8890 		} else if ( $setting.is('input[type="checkbox"]') ) {
       
  8891 			$setting.prop( 'checked', !! value && 'false' !== value );
       
  8892 		}
       
  8893 	},
       
  8894 	/**
       
  8895 	 * @param {Object} event
       
  8896 	 */
       
  8897 	updateHandler: function( event ) {
       
  8898 		var $setting = $( event.target ).closest('[data-setting]'),
       
  8899 			value = event.target.value,
       
  8900 			userSetting;
       
  8901 
       
  8902 		event.preventDefault();
       
  8903 
       
  8904 		if ( ! $setting.length ) {
       
  8905 			return;
       
  8906 		}
       
  8907 
       
  8908 		// Use the correct value for checkboxes.
       
  8909 		if ( $setting.is('input[type="checkbox"]') ) {
       
  8910 			value = $setting[0].checked;
       
  8911 		}
       
  8912 
       
  8913 		// Update the corresponding setting.
       
  8914 		this.model.set( $setting.data('setting'), value );
       
  8915 
       
  8916 		// If the setting has a corresponding user setting,
       
  8917 		// update that as well.
       
  8918 		userSetting = $setting.data('userSetting');
       
  8919 		if ( userSetting ) {
       
  8920 			window.setUserSetting( userSetting, value );
       
  8921 		}
       
  8922 	},
       
  8923 
       
  8924 	updateChanges: function( model ) {
       
  8925 		if ( model.hasChanged() ) {
       
  8926 			_( model.changed ).chain().keys().each( this.update, this );
       
  8927 		}
       
  8928 	}
  9917 	}
  8929 });
  9918 });
  8930 
  9919 
  8931 module.exports = Settings;
  9920 module.exports = PriorityList;
  8932 
  9921 
  8933 
  9922 
  8934 /***/ }),
  9923 /***/ }),
  8935 
  9924 
  8936 /***/ 7656:
  9925 /***/ 9013:
  8937 /***/ ((module) => {
  9926 /***/ ((module) => {
  8938 
  9927 
  8939 var Settings = wp.media.view.Settings,
  9928 var MenuItem;
  8940 	AttachmentDisplay;
       
  8941 
  9929 
  8942 /**
  9930 /**
  8943  * wp.media.view.Settings.AttachmentDisplay
  9931  * wp.media.view.MenuItem
  8944  *
       
  8945  * @memberOf wp.media.view.Settings
       
  8946  *
       
  8947  * @class
       
  8948  * @augments wp.media.view.Settings
       
  8949  * @augments wp.media.View
       
  8950  * @augments wp.Backbone.View
       
  8951  * @augments Backbone.View
       
  8952  */
       
  8953 AttachmentDisplay = Settings.extend(/** @lends wp.media.view.Settings.AttachmentDisplay.prototype */{
       
  8954 	className: 'attachment-display-settings',
       
  8955 	template:  wp.template('attachment-display-settings'),
       
  8956 
       
  8957 	initialize: function() {
       
  8958 		var attachment = this.options.attachment;
       
  8959 
       
  8960 		_.defaults( this.options, {
       
  8961 			userSettings: false
       
  8962 		});
       
  8963 		// Call 'initialize' directly on the parent class.
       
  8964 		Settings.prototype.initialize.apply( this, arguments );
       
  8965 		this.listenTo( this.model, 'change:link', this.updateLinkTo );
       
  8966 
       
  8967 		if ( attachment ) {
       
  8968 			attachment.on( 'change:uploading', this.render, this );
       
  8969 		}
       
  8970 	},
       
  8971 
       
  8972 	dispose: function() {
       
  8973 		var attachment = this.options.attachment;
       
  8974 		if ( attachment ) {
       
  8975 			attachment.off( null, null, this );
       
  8976 		}
       
  8977 		/**
       
  8978 		 * call 'dispose' directly on the parent class
       
  8979 		 */
       
  8980 		Settings.prototype.dispose.apply( this, arguments );
       
  8981 	},
       
  8982 	/**
       
  8983 	 * @return {wp.media.view.AttachmentDisplay} Returns itself to allow chaining.
       
  8984 	 */
       
  8985 	render: function() {
       
  8986 		var attachment = this.options.attachment;
       
  8987 		if ( attachment ) {
       
  8988 			_.extend( this.options, {
       
  8989 				sizes: attachment.get('sizes'),
       
  8990 				type:  attachment.get('type')
       
  8991 			});
       
  8992 		}
       
  8993 		/**
       
  8994 		 * call 'render' directly on the parent class
       
  8995 		 */
       
  8996 		Settings.prototype.render.call( this );
       
  8997 		this.updateLinkTo();
       
  8998 		return this;
       
  8999 	},
       
  9000 
       
  9001 	updateLinkTo: function() {
       
  9002 		var linkTo = this.model.get('link'),
       
  9003 			$input = this.$('.link-to-custom'),
       
  9004 			attachment = this.options.attachment;
       
  9005 
       
  9006 		if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
       
  9007 			$input.closest( '.setting' ).addClass( 'hidden' );
       
  9008 			return;
       
  9009 		}
       
  9010 
       
  9011 		if ( attachment ) {
       
  9012 			if ( 'post' === linkTo ) {
       
  9013 				$input.val( attachment.get('link') );
       
  9014 			} else if ( 'file' === linkTo ) {
       
  9015 				$input.val( attachment.get('url') );
       
  9016 			} else if ( ! this.model.get('linkUrl') ) {
       
  9017 				$input.val('http://');
       
  9018 			}
       
  9019 
       
  9020 			$input.prop( 'readonly', 'custom' !== linkTo );
       
  9021 		}
       
  9022 
       
  9023 		$input.closest( '.setting' ).removeClass( 'hidden' );
       
  9024 		if ( $input.length ) {
       
  9025 			$input[0].scrollIntoView();
       
  9026 		}
       
  9027 	}
       
  9028 });
       
  9029 
       
  9030 module.exports = AttachmentDisplay;
       
  9031 
       
  9032 
       
  9033 /***/ }),
       
  9034 
       
  9035 /***/ 7266:
       
  9036 /***/ ((module) => {
       
  9037 
       
  9038 /**
       
  9039  * wp.media.view.Settings.Gallery
       
  9040  *
       
  9041  * @memberOf wp.media.view.Settings
       
  9042  *
       
  9043  * @class
       
  9044  * @augments wp.media.view.Settings
       
  9045  * @augments wp.media.View
       
  9046  * @augments wp.Backbone.View
       
  9047  * @augments Backbone.View
       
  9048  */
       
  9049 var Gallery = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Gallery.prototype */{
       
  9050 	className: 'collection-settings gallery-settings',
       
  9051 	template:  wp.template('gallery-settings')
       
  9052 });
       
  9053 
       
  9054 module.exports = Gallery;
       
  9055 
       
  9056 
       
  9057 /***/ }),
       
  9058 
       
  9059 /***/ 2356:
       
  9060 /***/ ((module) => {
       
  9061 
       
  9062 /**
       
  9063  * wp.media.view.Settings.Playlist
       
  9064  *
       
  9065  * @memberOf wp.media.view.Settings
       
  9066  *
       
  9067  * @class
       
  9068  * @augments wp.media.view.Settings
       
  9069  * @augments wp.media.View
       
  9070  * @augments wp.Backbone.View
       
  9071  * @augments Backbone.View
       
  9072  */
       
  9073 var Playlist = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Playlist.prototype */{
       
  9074 	className: 'collection-settings playlist-settings',
       
  9075 	template:  wp.template('playlist-settings')
       
  9076 });
       
  9077 
       
  9078 module.exports = Playlist;
       
  9079 
       
  9080 
       
  9081 /***/ }),
       
  9082 
       
  9083 /***/ 1992:
       
  9084 /***/ ((module) => {
       
  9085 
       
  9086 /**
       
  9087  * wp.media.view.Sidebar
       
  9088  *
       
  9089  * @memberOf wp.media.view
       
  9090  *
       
  9091  * @class
       
  9092  * @augments wp.media.view.PriorityList
       
  9093  * @augments wp.media.View
       
  9094  * @augments wp.Backbone.View
       
  9095  * @augments Backbone.View
       
  9096  */
       
  9097 var Sidebar = wp.media.view.PriorityList.extend(/** @lends wp.media.view.Sidebar.prototype */{
       
  9098 	className: 'media-sidebar'
       
  9099 });
       
  9100 
       
  9101 module.exports = Sidebar;
       
  9102 
       
  9103 
       
  9104 /***/ }),
       
  9105 
       
  9106 /***/ 443:
       
  9107 /***/ ((module) => {
       
  9108 
       
  9109 var View = wp.media.view,
       
  9110 	SiteIconCropper;
       
  9111 
       
  9112 /**
       
  9113  * wp.media.view.SiteIconCropper
       
  9114  *
       
  9115  * Uses the imgAreaSelect plugin to allow a user to crop a Site Icon.
       
  9116  *
       
  9117  * Takes imgAreaSelect options from
       
  9118  * wp.customize.SiteIconControl.calculateImageSelectOptions.
       
  9119  *
       
  9120  * @memberOf wp.media.view
       
  9121  *
       
  9122  * @class
       
  9123  * @augments wp.media.view.Cropper
       
  9124  * @augments wp.media.View
       
  9125  * @augments wp.Backbone.View
       
  9126  * @augments Backbone.View
       
  9127  */
       
  9128 SiteIconCropper = View.Cropper.extend(/** @lends wp.media.view.SiteIconCropper.prototype */{
       
  9129 	className: 'crop-content site-icon',
       
  9130 
       
  9131 	ready: function () {
       
  9132 		View.Cropper.prototype.ready.apply( this, arguments );
       
  9133 
       
  9134 		this.$( '.crop-image' ).on( 'load', _.bind( this.addSidebar, this ) );
       
  9135 	},
       
  9136 
       
  9137 	addSidebar: function() {
       
  9138 		this.sidebar = new wp.media.view.Sidebar({
       
  9139 			controller: this.controller
       
  9140 		});
       
  9141 
       
  9142 		this.sidebar.set( 'preview', new wp.media.view.SiteIconPreview({
       
  9143 			controller: this.controller,
       
  9144 			attachment: this.options.attachment
       
  9145 		}) );
       
  9146 
       
  9147 		this.controller.cropperView.views.add( this.sidebar );
       
  9148 	}
       
  9149 });
       
  9150 
       
  9151 module.exports = SiteIconCropper;
       
  9152 
       
  9153 
       
  9154 /***/ }),
       
  9155 
       
  9156 /***/ 7810:
       
  9157 /***/ ((module) => {
       
  9158 
       
  9159 var View = wp.media.View,
       
  9160 	$ = jQuery,
       
  9161 	SiteIconPreview;
       
  9162 
       
  9163 /**
       
  9164  * wp.media.view.SiteIconPreview
       
  9165  *
       
  9166  * Shows a preview of the Site Icon as a favicon and app icon while cropping.
       
  9167  *
  9932  *
  9168  * @memberOf wp.media.view
  9933  * @memberOf wp.media.view
  9169  *
  9934  *
  9170  * @class
  9935  * @class
  9171  * @augments wp.media.View
  9936  * @augments wp.media.View
  9172  * @augments wp.Backbone.View
  9937  * @augments wp.Backbone.View
  9173  * @augments Backbone.View
  9938  * @augments Backbone.View
  9174  */
  9939  */
  9175 SiteIconPreview = View.extend(/** @lends wp.media.view.SiteIconPreview.prototype */{
  9940 MenuItem = wp.media.View.extend(/** @lends wp.media.view.MenuItem.prototype */{
  9176 	className: 'site-icon-preview',
  9941 	tagName:   'button',
  9177 	template: wp.template( 'site-icon-preview' ),
  9942 	className: 'media-menu-item',
  9178 
  9943 
  9179 	ready: function() {
  9944 	attributes: {
  9180 		this.controller.imgSelect.setOptions({
  9945 		type: 'button',
  9181 			onInit: this.updatePreview,
  9946 		role: 'tab'
  9182 			onSelectChange: this.updatePreview
  9947 	},
  9183 		});
  9948 
  9184 	},
  9949 	events: {
  9185 
  9950 		'click': '_click'
  9186 	prepare: function() {
  9951 	},
  9187 		return {
  9952 
  9188 			url: this.options.attachment.get( 'url' )
  9953 	/**
  9189 		};
  9954 	 * Allows to override the click event.
  9190 	},
  9955 	 */
  9191 
  9956 	_click: function() {
  9192 	updatePreview: function( img, coords ) {
  9957 		var clickOverride = this.options.click;
  9193 		var rx = 64 / coords.width,
  9958 
  9194 			ry = 64 / coords.height,
  9959 		if ( clickOverride ) {
  9195 			preview_rx = 16 / coords.width,
  9960 			clickOverride.call( this );
  9196 			preview_ry = 16 / coords.height;
  9961 		} else {
  9197 
  9962 			this.click();
  9198 		$( '#preview-app-icon' ).css({
  9963 		}
  9199 			width: Math.round(rx * this.imageWidth ) + 'px',
  9964 	},
  9200 			height: Math.round(ry * this.imageHeight ) + 'px',
  9965 
  9201 			marginLeft: '-' + Math.round(rx * coords.x1) + 'px',
  9966 	click: function() {
  9202 			marginTop: '-' + Math.round(ry * coords.y1) + 'px'
  9967 		var state = this.options.state;
  9203 		});
  9968 
  9204 
  9969 		if ( state ) {
  9205 		$( '#preview-favicon' ).css({
  9970 			this.controller.setState( state );
  9206 			width: Math.round( preview_rx * this.imageWidth ) + 'px',
  9971 			// Toggle the menu visibility in the responsive view.
  9207 			height: Math.round( preview_ry * this.imageHeight ) + 'px',
  9972 			this.views.parent.$el.removeClass( 'visible' ); // @todo Or hide on any click, see below.
  9208 			marginLeft: '-' + Math.round( preview_rx * coords.x1 ) + 'px',
  9973 		}
  9209 			marginTop: '-' + Math.floor( preview_ry* coords.y1 ) + 'px'
  9974 	},
  9210 		});
  9975 
       
  9976 	/**
       
  9977 	 * @return {wp.media.view.MenuItem} returns itself to allow chaining.
       
  9978 	 */
       
  9979 	render: function() {
       
  9980 		var options = this.options,
       
  9981 			menuProperty = options.state || options.contentMode;
       
  9982 
       
  9983 		if ( options.text ) {
       
  9984 			this.$el.text( options.text );
       
  9985 		} else if ( options.html ) {
       
  9986 			this.$el.html( options.html );
       
  9987 		}
       
  9988 
       
  9989 		// Set the menu item ID based on the frame state associated to the menu item.
       
  9990 		this.$el.attr( 'id', 'menu-item-' + menuProperty );
       
  9991 
       
  9992 		return this;
  9211 	}
  9993 	}
  9212 });
  9994 });
  9213 
  9995 
  9214 module.exports = SiteIconPreview;
  9996 module.exports = MenuItem;
  9215 
  9997 
  9216 
  9998 
  9217 /***/ }),
  9999 /***/ }),
  9218 
 10000 
  9219 /***/ 9141:
 10001 /***/ 9141:
  9270 		return this;
 10052 		return this;
  9271 	}
 10053 	}
  9272 });
 10054 });
  9273 
 10055 
  9274 module.exports = Spinner;
 10056 module.exports = Spinner;
  9275 
       
  9276 
       
  9277 /***/ }),
       
  9278 
       
  9279 /***/ 5275:
       
  9280 /***/ ((module) => {
       
  9281 
       
  9282 var View = wp.media.View,
       
  9283 	Toolbar;
       
  9284 
       
  9285 /**
       
  9286  * wp.media.view.Toolbar
       
  9287  *
       
  9288  * A toolbar which consists of a primary and a secondary section. Each sections
       
  9289  * can be filled with views.
       
  9290  *
       
  9291  * @memberOf wp.media.view
       
  9292  *
       
  9293  * @class
       
  9294  * @augments wp.media.View
       
  9295  * @augments wp.Backbone.View
       
  9296  * @augments Backbone.View
       
  9297  */
       
  9298 Toolbar = View.extend(/** @lends wp.media.view.Toolbar.prototype */{
       
  9299 	tagName:   'div',
       
  9300 	className: 'media-toolbar',
       
  9301 
       
  9302 	initialize: function() {
       
  9303 		var state = this.controller.state(),
       
  9304 			selection = this.selection = state.get('selection'),
       
  9305 			library = this.library = state.get('library');
       
  9306 
       
  9307 		this._views = {};
       
  9308 
       
  9309 		// The toolbar is composed of two `PriorityList` views.
       
  9310 		this.primary   = new wp.media.view.PriorityList();
       
  9311 		this.secondary = new wp.media.view.PriorityList();
       
  9312 		this.tertiary  = new wp.media.view.PriorityList();
       
  9313 		this.primary.$el.addClass('media-toolbar-primary search-form');
       
  9314 		this.secondary.$el.addClass('media-toolbar-secondary');
       
  9315 		this.tertiary.$el.addClass('media-bg-overlay');
       
  9316 
       
  9317 		this.views.set([ this.secondary, this.primary, this.tertiary ]);
       
  9318 
       
  9319 		if ( this.options.items ) {
       
  9320 			this.set( this.options.items, { silent: true });
       
  9321 		}
       
  9322 
       
  9323 		if ( ! this.options.silent ) {
       
  9324 			this.render();
       
  9325 		}
       
  9326 
       
  9327 		if ( selection ) {
       
  9328 			selection.on( 'add remove reset', this.refresh, this );
       
  9329 		}
       
  9330 
       
  9331 		if ( library ) {
       
  9332 			library.on( 'add remove reset', this.refresh, this );
       
  9333 		}
       
  9334 	},
       
  9335 	/**
       
  9336 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining
       
  9337 	 */
       
  9338 	dispose: function() {
       
  9339 		if ( this.selection ) {
       
  9340 			this.selection.off( null, null, this );
       
  9341 		}
       
  9342 
       
  9343 		if ( this.library ) {
       
  9344 			this.library.off( null, null, this );
       
  9345 		}
       
  9346 		/**
       
  9347 		 * call 'dispose' directly on the parent class
       
  9348 		 */
       
  9349 		return View.prototype.dispose.apply( this, arguments );
       
  9350 	},
       
  9351 
       
  9352 	ready: function() {
       
  9353 		this.refresh();
       
  9354 	},
       
  9355 
       
  9356 	/**
       
  9357 	 * @param {string} id
       
  9358 	 * @param {Backbone.View|Object} view
       
  9359 	 * @param {Object} [options={}]
       
  9360 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
       
  9361 	 */
       
  9362 	set: function( id, view, options ) {
       
  9363 		var list;
       
  9364 		options = options || {};
       
  9365 
       
  9366 		// Accept an object with an `id` : `view` mapping.
       
  9367 		if ( _.isObject( id ) ) {
       
  9368 			_.each( id, function( view, id ) {
       
  9369 				this.set( id, view, { silent: true });
       
  9370 			}, this );
       
  9371 
       
  9372 		} else {
       
  9373 			if ( ! ( view instanceof Backbone.View ) ) {
       
  9374 				view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
       
  9375 				view = new wp.media.view.Button( view ).render();
       
  9376 			}
       
  9377 
       
  9378 			view.controller = view.controller || this.controller;
       
  9379 
       
  9380 			this._views[ id ] = view;
       
  9381 
       
  9382 			list = view.options.priority < 0 ? 'secondary' : 'primary';
       
  9383 			this[ list ].set( id, view, options );
       
  9384 		}
       
  9385 
       
  9386 		if ( ! options.silent ) {
       
  9387 			this.refresh();
       
  9388 		}
       
  9389 
       
  9390 		return this;
       
  9391 	},
       
  9392 	/**
       
  9393 	 * @param {string} id
       
  9394 	 * @return {wp.media.view.Button}
       
  9395 	 */
       
  9396 	get: function( id ) {
       
  9397 		return this._views[ id ];
       
  9398 	},
       
  9399 	/**
       
  9400 	 * @param {string} id
       
  9401 	 * @param {Object} options
       
  9402 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
       
  9403 	 */
       
  9404 	unset: function( id, options ) {
       
  9405 		delete this._views[ id ];
       
  9406 		this.primary.unset( id, options );
       
  9407 		this.secondary.unset( id, options );
       
  9408 		this.tertiary.unset( id, options );
       
  9409 
       
  9410 		if ( ! options || ! options.silent ) {
       
  9411 			this.refresh();
       
  9412 		}
       
  9413 		return this;
       
  9414 	},
       
  9415 
       
  9416 	refresh: function() {
       
  9417 		var state = this.controller.state(),
       
  9418 			library = state.get('library'),
       
  9419 			selection = state.get('selection');
       
  9420 
       
  9421 		_.each( this._views, function( button ) {
       
  9422 			if ( ! button.model || ! button.options || ! button.options.requires ) {
       
  9423 				return;
       
  9424 			}
       
  9425 
       
  9426 			var requires = button.options.requires,
       
  9427 				disabled = false;
       
  9428 
       
  9429 			// Prevent insertion of attachments if any of them are still uploading.
       
  9430 			if ( selection && selection.models ) {
       
  9431 				disabled = _.some( selection.models, function( attachment ) {
       
  9432 					return attachment.get('uploading') === true;
       
  9433 				});
       
  9434 			}
       
  9435 
       
  9436 			if ( requires.selection && selection && ! selection.length ) {
       
  9437 				disabled = true;
       
  9438 			} else if ( requires.library && library && ! library.length ) {
       
  9439 				disabled = true;
       
  9440 			}
       
  9441 			button.model.set( 'disabled', disabled );
       
  9442 		});
       
  9443 	}
       
  9444 });
       
  9445 
       
  9446 module.exports = Toolbar;
       
  9447 
       
  9448 
       
  9449 /***/ }),
       
  9450 
       
  9451 /***/ 397:
       
  9452 /***/ ((module) => {
       
  9453 
       
  9454 var Select = wp.media.view.Toolbar.Select,
       
  9455 	l10n = wp.media.view.l10n,
       
  9456 	Embed;
       
  9457 
       
  9458 /**
       
  9459  * wp.media.view.Toolbar.Embed
       
  9460  *
       
  9461  * @memberOf wp.media.view.Toolbar
       
  9462  *
       
  9463  * @class
       
  9464  * @augments wp.media.view.Toolbar.Select
       
  9465  * @augments wp.media.view.Toolbar
       
  9466  * @augments wp.media.View
       
  9467  * @augments wp.Backbone.View
       
  9468  * @augments Backbone.View
       
  9469  */
       
  9470 Embed = Select.extend(/** @lends wp.media.view.Toolbar.Embed.prototype */{
       
  9471 	initialize: function() {
       
  9472 		_.defaults( this.options, {
       
  9473 			text: l10n.insertIntoPost,
       
  9474 			requires: false
       
  9475 		});
       
  9476 		// Call 'initialize' directly on the parent class.
       
  9477 		Select.prototype.initialize.apply( this, arguments );
       
  9478 	},
       
  9479 
       
  9480 	refresh: function() {
       
  9481 		var url = this.controller.state().props.get('url');
       
  9482 		this.get('select').model.set( 'disabled', ! url || url === 'http://' );
       
  9483 		/**
       
  9484 		 * call 'refresh' directly on the parent class
       
  9485 		 */
       
  9486 		Select.prototype.refresh.apply( this, arguments );
       
  9487 	}
       
  9488 });
       
  9489 
       
  9490 module.exports = Embed;
       
  9491 
 10057 
  9492 
 10058 
  9493 /***/ }),
 10059 /***/ }),
  9494 
 10060 
  9495 /***/ 9458:
 10061 /***/ 9458:
  9567 module.exports = Select;
 10133 module.exports = Select;
  9568 
 10134 
  9569 
 10135 
  9570 /***/ }),
 10136 /***/ }),
  9571 
 10137 
  9572 /***/ 3674:
 10138 /***/ 9660:
  9573 /***/ ((module) => {
 10139 /***/ ((module) => {
  9574 
 10140 
  9575 var View = wp.media.View,
 10141 var Controller = wp.media.controller,
  9576 	l10n = wp.media.view.l10n,
 10142 	CustomizeImageCropper;
  9577 	$ = jQuery,
       
  9578 	EditorUploader;
       
  9579 
 10143 
  9580 /**
 10144 /**
  9581  * Creates a dropzone on WP editor instances (elements with .wp-editor-wrap)
 10145  * A state for cropping an image in the customizer.
  9582  * and relays drag'n'dropped files to a media workflow.
 10146  *
  9583  *
 10147  * @since 4.3.0
  9584  * wp.media.view.EditorUploader
 10148  *
  9585  *
 10149  * @constructs wp.media.controller.CustomizeImageCropper
  9586  * @memberOf wp.media.view
 10150  * @memberOf wp.media.controller
  9587  *
 10151  * @augments wp.media.controller.CustomizeImageCropper.Cropper
  9588  * @class
 10152  * @inheritDoc
  9589  * @augments wp.media.View
       
  9590  * @augments wp.Backbone.View
       
  9591  * @augments Backbone.View
       
  9592  */
 10153  */
  9593 EditorUploader = View.extend(/** @lends wp.media.view.EditorUploader.prototype */{
 10154 CustomizeImageCropper = Controller.Cropper.extend(/** @lends wp.media.controller.CustomizeImageCropper.prototype */{
  9594 	tagName:   'div',
 10155 	/**
  9595 	className: 'uploader-editor',
 10156 	 * Posts the crop details to the admin.
  9596 	template:  wp.template( 'uploader-editor' ),
 10157 	 *
  9597 
 10158 	 * Uses crop measurements when flexible in both directions.
  9598 	localDrag: false,
 10159 	 * Constrains flexible side based on image ratio and size of the fixed side.
  9599 	overContainer: false,
 10160 	 *
  9600 	overDropzone: false,
 10161 	 * @since 4.3.0
  9601 	draggingFile: null,
 10162 	 *
  9602 
 10163 	 * @param {Object} attachment The attachment to crop.
  9603 	/**
 10164 	 *
  9604 	 * Bind drag'n'drop events to callbacks.
 10165 	 * @return {$.promise} A jQuery promise that represents the crop image request.
  9605 	 */
 10166 	 */
  9606 	initialize: function() {
 10167 	doCrop: function( attachment ) {
  9607 		this.initialized = false;
 10168 		var cropDetails = attachment.get( 'cropDetails' ),
  9608 
 10169 			control = this.get( 'control' ),
  9609 		// Bail if not enabled or UA does not support drag'n'drop or File API.
 10170 			ratio = cropDetails.width / cropDetails.height;
  9610 		if ( ! window.tinyMCEPreInit || ! window.tinyMCEPreInit.dragDropUpload || ! this.browserSupport() ) {
 10171 
  9611 			return this;
 10172 		// Use crop measurements when flexible in both directions.
  9612 		}
 10173 		if ( control.params.flex_width && control.params.flex_height ) {
  9613 
 10174 			cropDetails.dst_width  = cropDetails.width;
  9614 		this.$document = $(document);
 10175 			cropDetails.dst_height = cropDetails.height;
  9615 		this.dropzones = [];
 10176 
  9616 		this.files = [];
 10177 		// Constrain flexible side based on image ratio and size of the fixed side.
  9617 
       
  9618 		this.$document.on( 'drop', '.uploader-editor', _.bind( this.drop, this ) );
       
  9619 		this.$document.on( 'dragover', '.uploader-editor', _.bind( this.dropzoneDragover, this ) );
       
  9620 		this.$document.on( 'dragleave', '.uploader-editor', _.bind( this.dropzoneDragleave, this ) );
       
  9621 		this.$document.on( 'click', '.uploader-editor', _.bind( this.click, this ) );
       
  9622 
       
  9623 		this.$document.on( 'dragover', _.bind( this.containerDragover, this ) );
       
  9624 		this.$document.on( 'dragleave', _.bind( this.containerDragleave, this ) );
       
  9625 
       
  9626 		this.$document.on( 'dragstart dragend drop', _.bind( function( event ) {
       
  9627 			this.localDrag = event.type === 'dragstart';
       
  9628 
       
  9629 			if ( event.type === 'drop' ) {
       
  9630 				this.containerDragleave();
       
  9631 			}
       
  9632 		}, this ) );
       
  9633 
       
  9634 		this.initialized = true;
       
  9635 		return this;
       
  9636 	},
       
  9637 
       
  9638 	/**
       
  9639 	 * Check browser support for drag'n'drop.
       
  9640 	 *
       
  9641 	 * @return {boolean}
       
  9642 	 */
       
  9643 	browserSupport: function() {
       
  9644 		var supports = false, div = document.createElement('div');
       
  9645 
       
  9646 		supports = ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div );
       
  9647 		supports = supports && !! ( window.File && window.FileList && window.FileReader );
       
  9648 		return supports;
       
  9649 	},
       
  9650 
       
  9651 	isDraggingFile: function( event ) {
       
  9652 		if ( this.draggingFile !== null ) {
       
  9653 			return this.draggingFile;
       
  9654 		}
       
  9655 
       
  9656 		if ( _.isUndefined( event.originalEvent ) || _.isUndefined( event.originalEvent.dataTransfer ) ) {
       
  9657 			return false;
       
  9658 		}
       
  9659 
       
  9660 		this.draggingFile = _.indexOf( event.originalEvent.dataTransfer.types, 'Files' ) > -1 &&
       
  9661 			_.indexOf( event.originalEvent.dataTransfer.types, 'text/plain' ) === -1;
       
  9662 
       
  9663 		return this.draggingFile;
       
  9664 	},
       
  9665 
       
  9666 	refresh: function( e ) {
       
  9667 		var dropzone_id;
       
  9668 		for ( dropzone_id in this.dropzones ) {
       
  9669 			// Hide the dropzones only if dragging has left the screen.
       
  9670 			this.dropzones[ dropzone_id ].toggle( this.overContainer || this.overDropzone );
       
  9671 		}
       
  9672 
       
  9673 		if ( ! _.isUndefined( e ) ) {
       
  9674 			$( e.target ).closest( '.uploader-editor' ).toggleClass( 'droppable', this.overDropzone );
       
  9675 		}
       
  9676 
       
  9677 		if ( ! this.overContainer && ! this.overDropzone ) {
       
  9678 			this.draggingFile = null;
       
  9679 		}
       
  9680 
       
  9681 		return this;
       
  9682 	},
       
  9683 
       
  9684 	render: function() {
       
  9685 		if ( ! this.initialized ) {
       
  9686 			return this;
       
  9687 		}
       
  9688 
       
  9689 		View.prototype.render.apply( this, arguments );
       
  9690 		$( '.wp-editor-wrap' ).each( _.bind( this.attach, this ) );
       
  9691 		return this;
       
  9692 	},
       
  9693 
       
  9694 	attach: function( index, editor ) {
       
  9695 		// Attach a dropzone to an editor.
       
  9696 		var dropzone = this.$el.clone();
       
  9697 		this.dropzones.push( dropzone );
       
  9698 		$( editor ).append( dropzone );
       
  9699 		return this;
       
  9700 	},
       
  9701 
       
  9702 	/**
       
  9703 	 * When a file is dropped on the editor uploader, open up an editor media workflow
       
  9704 	 * and upload the file immediately.
       
  9705 	 *
       
  9706 	 * @param {jQuery.Event} event The 'drop' event.
       
  9707 	 */
       
  9708 	drop: function( event ) {
       
  9709 		var $wrap, uploadView;
       
  9710 
       
  9711 		this.containerDragleave( event );
       
  9712 		this.dropzoneDragleave( event );
       
  9713 
       
  9714 		this.files = event.originalEvent.dataTransfer.files;
       
  9715 		if ( this.files.length < 1 ) {
       
  9716 			return;
       
  9717 		}
       
  9718 
       
  9719 		// Set the active editor to the drop target.
       
  9720 		$wrap = $( event.target ).parents( '.wp-editor-wrap' );
       
  9721 		if ( $wrap.length > 0 && $wrap[0].id ) {
       
  9722 			window.wpActiveEditor = $wrap[0].id.slice( 3, -5 );
       
  9723 		}
       
  9724 
       
  9725 		if ( ! this.workflow ) {
       
  9726 			this.workflow = wp.media.editor.open( window.wpActiveEditor, {
       
  9727 				frame:    'post',
       
  9728 				state:    'insert',
       
  9729 				title:    l10n.addMedia,
       
  9730 				multiple: true
       
  9731 			});
       
  9732 
       
  9733 			uploadView = this.workflow.uploader;
       
  9734 
       
  9735 			if ( uploadView.uploader && uploadView.uploader.ready ) {
       
  9736 				this.addFiles.apply( this );
       
  9737 			} else {
       
  9738 				this.workflow.on( 'uploader:ready', this.addFiles, this );
       
  9739 			}
       
  9740 		} else {
 10178 		} else {
  9741 			this.workflow.state().reset();
 10179 			cropDetails.dst_width  = control.params.flex_width  ? control.params.height * ratio : control.params.width;
  9742 			this.addFiles.apply( this );
 10180 			cropDetails.dst_height = control.params.flex_height ? control.params.width  / ratio : control.params.height;
  9743 			this.workflow.open();
 10181 		}
  9744 		}
 10182 
  9745 
 10183 		return wp.ajax.post( 'crop-image', {
  9746 		return false;
 10184 			wp_customize: 'on',
  9747 	},
 10185 			nonce: attachment.get( 'nonces' ).edit,
  9748 
 10186 			id: attachment.get( 'id' ),
  9749 	/**
 10187 			context: control.id,
  9750 	 * Add the files to the uploader.
 10188 			cropDetails: cropDetails
  9751 	 */
 10189 		} );
  9752 	addFiles: function() {
       
  9753 		if ( this.files.length ) {
       
  9754 			this.workflow.uploader.uploader.uploader.addFile( _.toArray( this.files ) );
       
  9755 			this.files = [];
       
  9756 		}
       
  9757 		return this;
       
  9758 	},
       
  9759 
       
  9760 	containerDragover: function( event ) {
       
  9761 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
       
  9762 			return;
       
  9763 		}
       
  9764 
       
  9765 		this.overContainer = true;
       
  9766 		this.refresh();
       
  9767 	},
       
  9768 
       
  9769 	containerDragleave: function() {
       
  9770 		this.overContainer = false;
       
  9771 
       
  9772 		// Throttle dragleave because it's called when bouncing from some elements to others.
       
  9773 		_.delay( _.bind( this.refresh, this ), 50 );
       
  9774 	},
       
  9775 
       
  9776 	dropzoneDragover: function( event ) {
       
  9777 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
       
  9778 			return;
       
  9779 		}
       
  9780 
       
  9781 		this.overDropzone = true;
       
  9782 		this.refresh( event );
       
  9783 		return false;
       
  9784 	},
       
  9785 
       
  9786 	dropzoneDragleave: function( e ) {
       
  9787 		this.overDropzone = false;
       
  9788 		_.delay( _.bind( this.refresh, this, e ), 50 );
       
  9789 	},
       
  9790 
       
  9791 	click: function( e ) {
       
  9792 		// In the rare case where the dropzone gets stuck, hide it on click.
       
  9793 		this.containerDragleave( e );
       
  9794 		this.dropzoneDragleave( e );
       
  9795 		this.localDrag = false;
       
  9796 	}
 10190 	}
  9797 });
 10191 });
  9798 
 10192 
  9799 module.exports = EditorUploader;
 10193 module.exports = CustomizeImageCropper;
  9800 
 10194 
  9801 
 10195 
  9802 /***/ }),
 10196 /***/ }),
  9803 
 10197 
  9804 /***/ 1753:
 10198 /***/ 9875:
  9805 /***/ ((module) => {
 10199 /***/ ((module) => {
  9806 
 10200 
  9807 var View = wp.media.View,
       
  9808 	UploaderInline;
       
  9809 
       
  9810 /**
 10201 /**
  9811  * wp.media.view.UploaderInline
 10202  * wp.media.controller.Region
  9812  *
 10203  *
  9813  * The inline uploader that shows up in the 'Upload Files' tab.
 10204  * A region is a persistent application layout area.
  9814  *
 10205  *
  9815  * @memberOf wp.media.view
 10206  * A region assumes one mode at any time, and can be switched to another.
       
 10207  *
       
 10208  * When mode changes, events are triggered on the region's parent view.
       
 10209  * The parent view will listen to specific events and fill the region with an
       
 10210  * appropriate view depending on mode. For example, a frame listens for the
       
 10211  * 'browse' mode t be activated on the 'content' view and then fills the region
       
 10212  * with an AttachmentsBrowser view.
       
 10213  *
       
 10214  * @memberOf wp.media.controller
  9816  *
 10215  *
  9817  * @class
 10216  * @class
  9818  * @augments wp.media.View
 10217  *
  9819  * @augments wp.Backbone.View
 10218  * @param {Object}        options          Options hash for the region.
  9820  * @augments Backbone.View
 10219  * @param {string}        options.id       Unique identifier for the region.
       
 10220  * @param {Backbone.View} options.view     A parent view the region exists within.
       
 10221  * @param {string}        options.selector jQuery selector for the region within the parent view.
  9821  */
 10222  */
  9822 UploaderInline = View.extend(/** @lends wp.media.view.UploaderInline.prototype */{
 10223 var Region = function( options ) {
  9823 	tagName:   'div',
 10224 	_.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
  9824 	className: 'uploader-inline',
 10225 };
  9825 	template:  wp.template('uploader-inline'),
 10226 
  9826 
 10227 // Use Backbone's self-propagating `extend` inheritance method.
  9827 	events: {
 10228 Region.extend = Backbone.Model.extend;
  9828 		'click .close': 'hide'
 10229 
  9829 	},
 10230 _.extend( Region.prototype,/** @lends wp.media.controller.Region.prototype */{
  9830 
 10231 	/**
  9831 	initialize: function() {
 10232 	 * Activate a mode.
  9832 		_.defaults( this.options, {
 10233 	 *
  9833 			message: '',
 10234 	 * @since 3.5.0
  9834 			status:  true,
 10235 	 *
  9835 			canClose: false
 10236 	 * @param {string} mode
  9836 		});
 10237 	 *
  9837 
 10238 	 * @fires Region#activate
  9838 		if ( ! this.options.$browser && this.controller.uploader ) {
 10239 	 * @fires Region#deactivate
  9839 			this.options.$browser = this.controller.uploader.$browser;
 10240 	 *
  9840 		}
 10241 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
  9841 
 10242 	 */
  9842 		if ( _.isUndefined( this.options.postId ) ) {
 10243 	mode: function( mode ) {
  9843 			this.options.postId = wp.media.view.settings.post.id;
 10244 		if ( ! mode ) {
  9844 		}
 10245 			return this._mode;
  9845 
 10246 		}
  9846 		if ( this.options.status ) {
 10247 		// Bail if we're trying to change to the current mode.
  9847 			this.views.set( '.upload-inline-status', new wp.media.view.UploaderStatus({
 10248 		if ( mode === this._mode ) {
  9848 				controller: this.controller
 10249 			return this;
  9849 			}) );
 10250 		}
  9850 		}
 10251 
  9851 	},
 10252 		/**
  9852 
 10253 		 * Region mode deactivation event.
  9853 	prepare: function() {
 10254 		 *
  9854 		var suggestedWidth = this.controller.state().get('suggestedWidth'),
 10255 		 * @event wp.media.controller.Region#deactivate
  9855 			suggestedHeight = this.controller.state().get('suggestedHeight'),
       
  9856 			data = {};
       
  9857 
       
  9858 		data.message = this.options.message;
       
  9859 		data.canClose = this.options.canClose;
       
  9860 
       
  9861 		if ( suggestedWidth && suggestedHeight ) {
       
  9862 			data.suggestedWidth = suggestedWidth;
       
  9863 			data.suggestedHeight = suggestedHeight;
       
  9864 		}
       
  9865 
       
  9866 		return data;
       
  9867 	},
       
  9868 	/**
       
  9869 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
       
  9870 	 */
       
  9871 	dispose: function() {
       
  9872 		if ( this.disposing ) {
       
  9873 			/**
       
  9874 			 * call 'dispose' directly on the parent class
       
  9875 			 */
       
  9876 			return View.prototype.dispose.apply( this, arguments );
       
  9877 		}
       
  9878 
       
  9879 		/*
       
  9880 		 * Run remove on `dispose`, so we can be sure to refresh the
       
  9881 		 * uploader with a view-less DOM. Track whether we're disposing
       
  9882 		 * so we don't trigger an infinite loop.
       
  9883 		 */
 10256 		 */
  9884 		this.disposing = true;
 10257 		this.trigger('deactivate');
  9885 		return this.remove();
 10258 
  9886 	},
 10259 		this._mode = mode;
  9887 	/**
 10260 		this.render( mode );
  9888 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
 10261 
  9889 	 */
       
  9890 	remove: function() {
       
  9891 		/**
 10262 		/**
  9892 		 * call 'remove' directly on the parent class
 10263 		 * Region mode activation event.
       
 10264 		 *
       
 10265 		 * @event wp.media.controller.Region#activate
  9893 		 */
 10266 		 */
  9894 		var result = View.prototype.remove.apply( this, arguments );
 10267 		this.trigger('activate');
  9895 
       
  9896 		_.defer( _.bind( this.refresh, this ) );
       
  9897 		return result;
       
  9898 	},
       
  9899 
       
  9900 	refresh: function() {
       
  9901 		var uploader = this.controller.uploader;
       
  9902 
       
  9903 		if ( uploader ) {
       
  9904 			uploader.refresh();
       
  9905 		}
       
  9906 	},
       
  9907 	/**
       
  9908 	 * @return {wp.media.view.UploaderInline}
       
  9909 	 */
       
  9910 	ready: function() {
       
  9911 		var $browser = this.options.$browser,
       
  9912 			$placeholder;
       
  9913 
       
  9914 		if ( this.controller.uploader ) {
       
  9915 			$placeholder = this.$('.browser');
       
  9916 
       
  9917 			// Check if we've already replaced the placeholder.
       
  9918 			if ( $placeholder[0] === $browser[0] ) {
       
  9919 				return;
       
  9920 			}
       
  9921 
       
  9922 			$browser.detach().text( $placeholder.text() );
       
  9923 			$browser[0].className = $placeholder[0].className;
       
  9924 			$browser[0].setAttribute( 'aria-labelledby', $browser[0].id + ' ' + $placeholder[0].getAttribute('aria-labelledby') );
       
  9925 			$placeholder.replaceWith( $browser.show() );
       
  9926 		}
       
  9927 
       
  9928 		this.refresh();
       
  9929 		return this;
 10268 		return this;
  9930 	},
 10269 	},
  9931 	show: function() {
 10270 	/**
  9932 		this.$el.removeClass( 'hidden' );
 10271 	 * Render a mode.
  9933 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
 10272 	 *
  9934 			this.controller.$uploaderToggler.attr( 'aria-expanded', 'true' );
 10273 	 * @since 3.5.0
  9935 		}
 10274 	 *
  9936 	},
 10275 	 * @param {string} mode
  9937 	hide: function() {
 10276 	 *
  9938 		this.$el.addClass( 'hidden' );
 10277 	 * @fires Region#create
  9939 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
 10278 	 * @fires Region#render
  9940 			this.controller.$uploaderToggler
 10279 	 *
  9941 				.attr( 'aria-expanded', 'false' )
 10280 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
  9942 				// Move focus back to the toggle button when closing the uploader.
 10281 	 */
  9943 				.trigger( 'focus' );
 10282 	render: function( mode ) {
  9944 		}
 10283 		// If the mode isn't active, activate it.
  9945 	}
 10284 		if ( mode && mode !== this._mode ) {
  9946 
 10285 			return this.mode( mode );
  9947 });
 10286 		}
  9948 
 10287 
  9949 module.exports = UploaderInline;
 10288 		var set = { view: null },
  9950 
 10289 			view;
  9951 
 10290 
  9952 /***/ }),
       
  9953 
       
  9954 /***/ 6442:
       
  9955 /***/ ((module) => {
       
  9956 
       
  9957 /**
       
  9958  * wp.media.view.UploaderStatusError
       
  9959  *
       
  9960  * @memberOf wp.media.view
       
  9961  *
       
  9962  * @class
       
  9963  * @augments wp.media.View
       
  9964  * @augments wp.Backbone.View
       
  9965  * @augments Backbone.View
       
  9966  */
       
  9967 var UploaderStatusError = wp.media.View.extend(/** @lends wp.media.view.UploaderStatusError.prototype */{
       
  9968 	className: 'upload-error',
       
  9969 	template:  wp.template('uploader-status-error')
       
  9970 });
       
  9971 
       
  9972 module.exports = UploaderStatusError;
       
  9973 
       
  9974 
       
  9975 /***/ }),
       
  9976 
       
  9977 /***/ 8197:
       
  9978 /***/ ((module) => {
       
  9979 
       
  9980 var View = wp.media.View,
       
  9981 	UploaderStatus;
       
  9982 
       
  9983 /**
       
  9984  * wp.media.view.UploaderStatus
       
  9985  *
       
  9986  * An uploader status for on-going uploads.
       
  9987  *
       
  9988  * @memberOf wp.media.view
       
  9989  *
       
  9990  * @class
       
  9991  * @augments wp.media.View
       
  9992  * @augments wp.Backbone.View
       
  9993  * @augments Backbone.View
       
  9994  */
       
  9995 UploaderStatus = View.extend(/** @lends wp.media.view.UploaderStatus.prototype */{
       
  9996 	className: 'media-uploader-status',
       
  9997 	template:  wp.template('uploader-status'),
       
  9998 
       
  9999 	events: {
       
 10000 		'click .upload-dismiss-errors': 'dismiss'
       
 10001 	},
       
 10002 
       
 10003 	initialize: function() {
       
 10004 		this.queue = wp.Uploader.queue;
       
 10005 		this.queue.on( 'add remove reset', this.visibility, this );
       
 10006 		this.queue.on( 'add remove reset change:percent', this.progress, this );
       
 10007 		this.queue.on( 'add remove reset change:uploading', this.info, this );
       
 10008 
       
 10009 		this.errors = wp.Uploader.errors;
       
 10010 		this.errors.reset();
       
 10011 		this.errors.on( 'add remove reset', this.visibility, this );
       
 10012 		this.errors.on( 'add', this.error, this );
       
 10013 	},
       
 10014 	/**
       
 10015 	 * @return {wp.media.view.UploaderStatus}
       
 10016 	 */
       
 10017 	dispose: function() {
       
 10018 		wp.Uploader.queue.off( null, null, this );
       
 10019 		/**
 10291 		/**
 10020 		 * call 'dispose' directly on the parent class
 10292 		 * Create region view event.
       
 10293 		 *
       
 10294 		 * Region view creation takes place in an event callback on the frame.
       
 10295 		 *
       
 10296 		 * @event wp.media.controller.Region#create
       
 10297 		 * @type {object}
       
 10298 		 * @property {object} view
 10021 		 */
 10299 		 */
 10022 		View.prototype.dispose.apply( this, arguments );
 10300 		this.trigger( 'create', set );
       
 10301 		view = set.view;
       
 10302 
       
 10303 		/**
       
 10304 		 * Render region view event.
       
 10305 		 *
       
 10306 		 * Region view creation takes place in an event callback on the frame.
       
 10307 		 *
       
 10308 		 * @event wp.media.controller.Region#render
       
 10309 		 * @type {object}
       
 10310 		 */
       
 10311 		this.trigger( 'render', view );
       
 10312 		if ( view ) {
       
 10313 			this.set( view );
       
 10314 		}
 10023 		return this;
 10315 		return this;
 10024 	},
 10316 	},
 10025 
 10317 
 10026 	visibility: function() {
 10318 	/**
 10027 		this.$el.toggleClass( 'uploading', !! this.queue.length );
 10319 	 * Get the region's view.
 10028 		this.$el.toggleClass( 'errors', !! this.errors.length );
 10320 	 *
 10029 		this.$el.toggle( !! this.queue.length || !! this.errors.length );
 10321 	 * @since 3.5.0
 10030 	},
 10322 	 *
 10031 
 10323 	 * @return {wp.media.View}
 10032 	ready: function() {
 10324 	 */
 10033 		_.each({
 10325 	get: function() {
 10034 			'$bar':      '.media-progress-bar div',
 10326 		return this.view.views.first( this.selector );
 10035 			'$index':    '.upload-index',
 10327 	},
 10036 			'$total':    '.upload-total',
 10328 
 10037 			'$filename': '.upload-filename'
 10329 	/**
 10038 		}, function( selector, key ) {
 10330 	 * Set the region's view as a subview of the frame.
 10039 			this[ key ] = this.$( selector );
 10331 	 *
 10040 		}, this );
 10332 	 * @since 3.5.0
 10041 
 10333 	 *
 10042 		this.visibility();
 10334 	 * @param {Array|Object} views
 10043 		this.progress();
 10335 	 * @param {Object} [options={}]
 10044 		this.info();
 10336 	 * @return {wp.Backbone.Subviews} Subviews is returned to allow chaining.
 10045 	},
 10337 	 */
 10046 
 10338 	set: function( views, options ) {
 10047 	progress: function() {
 10339 		if ( options ) {
 10048 		var queue = this.queue,
 10340 			options.add = false;
 10049 			$bar = this.$bar;
 10341 		}
 10050 
 10342 		return this.view.views.set( this.selector, views, options );
 10051 		if ( ! $bar || ! queue.length ) {
 10343 	},
       
 10344 
       
 10345 	/**
       
 10346 	 * Trigger regional view events on the frame.
       
 10347 	 *
       
 10348 	 * @since 3.5.0
       
 10349 	 *
       
 10350 	 * @param {string} event
       
 10351 	 * @return {undefined|wp.media.controller.Region} Returns itself to allow chaining.
       
 10352 	 */
       
 10353 	trigger: function( event ) {
       
 10354 		var base, args;
       
 10355 
       
 10356 		if ( ! this._mode ) {
 10052 			return;
 10357 			return;
 10053 		}
 10358 		}
 10054 
 10359 
 10055 		$bar.width( ( queue.reduce( function( memo, attachment ) {
 10360 		args = _.toArray( arguments );
 10056 			if ( ! attachment.get('uploading') ) {
 10361 		base = this.id + ':' + event;
 10057 				return memo + 100;
 10362 
 10058 			}
 10363 		// Trigger `{this.id}:{event}:{this._mode}` event on the frame.
 10059 
 10364 		args[0] = base + ':' + this._mode;
 10060 			var percent = attachment.get('percent');
 10365 		this.view.trigger.apply( this.view, args );
 10061 			return memo + ( _.isNumber( percent ) ? percent : 100 );
 10366 
 10062 		}, 0 ) / queue.length ) + '%' );
 10367 		// Trigger `{this.id}:{event}` event on the frame.
 10063 	},
 10368 		args[0] = base;
 10064 
 10369 		this.view.trigger.apply( this.view, args );
 10065 	info: function() {
 10370 		return this;
 10066 		var queue = this.queue,
       
 10067 			index = 0, active;
       
 10068 
       
 10069 		if ( ! queue.length ) {
       
 10070 			return;
       
 10071 		}
       
 10072 
       
 10073 		active = this.queue.find( function( attachment, i ) {
       
 10074 			index = i;
       
 10075 			return attachment.get('uploading');
       
 10076 		});
       
 10077 
       
 10078 		if ( this.$index && this.$total && this.$filename ) {
       
 10079 			this.$index.text( index + 1 );
       
 10080 			this.$total.text( queue.length );
       
 10081 			this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
       
 10082 		}
       
 10083 	},
       
 10084 	/**
       
 10085 	 * @param {string} filename
       
 10086 	 * @return {string}
       
 10087 	 */
       
 10088 	filename: function( filename ) {
       
 10089 		return _.escape( filename );
       
 10090 	},
       
 10091 	/**
       
 10092 	 * @param {Backbone.Model} error
       
 10093 	 */
       
 10094 	error: function( error ) {
       
 10095 		var statusError = new wp.media.view.UploaderStatusError( {
       
 10096 			filename: this.filename( error.get( 'file' ).name ),
       
 10097 			message:  error.get( 'message' )
       
 10098 		} );
       
 10099 
       
 10100 		var buttonClose = this.$el.find( 'button' );
       
 10101 
       
 10102 		// Can show additional info here while retrying to create image sub-sizes.
       
 10103 		this.views.add( '.upload-errors', statusError, { at: 0 } );
       
 10104 		_.delay( function() {
       
 10105 			buttonClose.trigger( 'focus' );
       
 10106 			wp.a11y.speak( error.get( 'message' ), 'assertive' );
       
 10107 		}, 1000 );
       
 10108 	},
       
 10109 
       
 10110 	dismiss: function() {
       
 10111 		var errors = this.views.get('.upload-errors');
       
 10112 
       
 10113 		if ( errors ) {
       
 10114 			_.invoke( errors, 'remove' );
       
 10115 		}
       
 10116 		wp.Uploader.errors.reset();
       
 10117 		// Move focus to the modal after the dismiss button gets removed from the DOM.
       
 10118 		if ( this.controller.modal ) {
       
 10119 			this.controller.modal.focusManager.focus();
       
 10120 		}
       
 10121 	}
 10371 	}
 10122 });
 10372 });
 10123 
 10373 
 10124 module.exports = UploaderStatus;
 10374 module.exports = Region;
 10125 
       
 10126 
       
 10127 /***/ }),
       
 10128 
       
 10129 /***/ 8291:
       
 10130 /***/ ((module) => {
       
 10131 
       
 10132 var $ = jQuery,
       
 10133 	UploaderWindow;
       
 10134 
       
 10135 /**
       
 10136  * wp.media.view.UploaderWindow
       
 10137  *
       
 10138  * An uploader window that allows for dragging and dropping media.
       
 10139  *
       
 10140  * @memberOf wp.media.view
       
 10141  *
       
 10142  * @class
       
 10143  * @augments wp.media.View
       
 10144  * @augments wp.Backbone.View
       
 10145  * @augments Backbone.View
       
 10146  *
       
 10147  * @param {object} [options]                   Options hash passed to the view.
       
 10148  * @param {object} [options.uploader]          Uploader properties.
       
 10149  * @param {jQuery} [options.uploader.browser]
       
 10150  * @param {jQuery} [options.uploader.dropzone] jQuery collection of the dropzone.
       
 10151  * @param {object} [options.uploader.params]
       
 10152  */
       
 10153 UploaderWindow = wp.media.View.extend(/** @lends wp.media.view.UploaderWindow.prototype */{
       
 10154 	tagName:   'div',
       
 10155 	className: 'uploader-window',
       
 10156 	template:  wp.template('uploader-window'),
       
 10157 
       
 10158 	initialize: function() {
       
 10159 		var uploader;
       
 10160 
       
 10161 		this.$browser = $( '<button type="button" class="browser" />' ).hide().appendTo( 'body' );
       
 10162 
       
 10163 		uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
       
 10164 			dropzone:  this.$el,
       
 10165 			browser:   this.$browser,
       
 10166 			params:    {}
       
 10167 		});
       
 10168 
       
 10169 		// Ensure the dropzone is a jQuery collection.
       
 10170 		if ( uploader.dropzone && ! (uploader.dropzone instanceof $) ) {
       
 10171 			uploader.dropzone = $( uploader.dropzone );
       
 10172 		}
       
 10173 
       
 10174 		this.controller.on( 'activate', this.refresh, this );
       
 10175 
       
 10176 		this.controller.on( 'detach', function() {
       
 10177 			this.$browser.remove();
       
 10178 		}, this );
       
 10179 	},
       
 10180 
       
 10181 	refresh: function() {
       
 10182 		if ( this.uploader ) {
       
 10183 			this.uploader.refresh();
       
 10184 		}
       
 10185 	},
       
 10186 
       
 10187 	ready: function() {
       
 10188 		var postId = wp.media.view.settings.post.id,
       
 10189 			dropzone;
       
 10190 
       
 10191 		// If the uploader already exists, bail.
       
 10192 		if ( this.uploader ) {
       
 10193 			return;
       
 10194 		}
       
 10195 
       
 10196 		if ( postId ) {
       
 10197 			this.options.uploader.params.post_id = postId;
       
 10198 		}
       
 10199 		this.uploader = new wp.Uploader( this.options.uploader );
       
 10200 
       
 10201 		dropzone = this.uploader.dropzone;
       
 10202 		dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
       
 10203 		dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
       
 10204 
       
 10205 		$( this.uploader ).on( 'uploader:ready', _.bind( this._ready, this ) );
       
 10206 	},
       
 10207 
       
 10208 	_ready: function() {
       
 10209 		this.controller.trigger( 'uploader:ready' );
       
 10210 	},
       
 10211 
       
 10212 	show: function() {
       
 10213 		var $el = this.$el.show();
       
 10214 
       
 10215 		// Ensure that the animation is triggered by waiting until
       
 10216 		// the transparent element is painted into the DOM.
       
 10217 		_.defer( function() {
       
 10218 			$el.css({ opacity: 1 });
       
 10219 		});
       
 10220 	},
       
 10221 
       
 10222 	hide: function() {
       
 10223 		var $el = this.$el.css({ opacity: 0 });
       
 10224 
       
 10225 		wp.media.transition( $el ).done( function() {
       
 10226 			// Transition end events are subject to race conditions.
       
 10227 			// Make sure that the value is set as intended.
       
 10228 			if ( '0' === $el.css('opacity') ) {
       
 10229 				$el.hide();
       
 10230 			}
       
 10231 		});
       
 10232 
       
 10233 		// https://core.trac.wordpress.org/ticket/27341
       
 10234 		_.delay( function() {
       
 10235 			if ( '0' === $el.css('opacity') && $el.is(':visible') ) {
       
 10236 				$el.hide();
       
 10237 			}
       
 10238 		}, 500 );
       
 10239 	}
       
 10240 });
       
 10241 
       
 10242 module.exports = UploaderWindow;
       
 10243 
       
 10244 
       
 10245 /***/ }),
       
 10246 
       
 10247 /***/ 4747:
       
 10248 /***/ ((module) => {
       
 10249 
       
 10250 /**
       
 10251  * wp.media.View
       
 10252  *
       
 10253  * The base view class for media.
       
 10254  *
       
 10255  * Undelegating events, removing events from the model, and
       
 10256  * removing events from the controller mirror the code for
       
 10257  * `Backbone.View.dispose` in Backbone 0.9.8 development.
       
 10258  *
       
 10259  * This behavior has since been removed, and should not be used
       
 10260  * outside of the media manager.
       
 10261  *
       
 10262  * @memberOf wp.media
       
 10263  *
       
 10264  * @class
       
 10265  * @augments wp.Backbone.View
       
 10266  * @augments Backbone.View
       
 10267  */
       
 10268 var View = wp.Backbone.View.extend(/** @lends wp.media.View.prototype */{
       
 10269 	constructor: function( options ) {
       
 10270 		if ( options && options.controller ) {
       
 10271 			this.controller = options.controller;
       
 10272 		}
       
 10273 		wp.Backbone.View.apply( this, arguments );
       
 10274 	},
       
 10275 	/**
       
 10276 	 * @todo The internal comment mentions this might have been a stop-gap
       
 10277 	 *       before Backbone 0.9.8 came out. Figure out if Backbone core takes
       
 10278 	 *       care of this in Backbone.View now.
       
 10279 	 *
       
 10280 	 * @return {wp.media.View} Returns itself to allow chaining.
       
 10281 	 */
       
 10282 	dispose: function() {
       
 10283 		/*
       
 10284 		 * Undelegating events, removing events from the model, and
       
 10285 		 * removing events from the controller mirror the code for
       
 10286 		 * `Backbone.View.dispose` in Backbone 0.9.8 development.
       
 10287 		 */
       
 10288 		this.undelegateEvents();
       
 10289 
       
 10290 		if ( this.model && this.model.off ) {
       
 10291 			this.model.off( null, null, this );
       
 10292 		}
       
 10293 
       
 10294 		if ( this.collection && this.collection.off ) {
       
 10295 			this.collection.off( null, null, this );
       
 10296 		}
       
 10297 
       
 10298 		// Unbind controller events.
       
 10299 		if ( this.controller && this.controller.off ) {
       
 10300 			this.controller.off( null, null, this );
       
 10301 		}
       
 10302 
       
 10303 		return this;
       
 10304 	},
       
 10305 	/**
       
 10306 	 * @return {wp.media.View} Returns itself to allow chaining.
       
 10307 	 */
       
 10308 	remove: function() {
       
 10309 		this.dispose();
       
 10310 		/**
       
 10311 		 * call 'remove' directly on the parent class
       
 10312 		 */
       
 10313 		return wp.Backbone.View.prototype.remove.apply( this, arguments );
       
 10314 	}
       
 10315 });
       
 10316 
       
 10317 module.exports = View;
       
 10318 
 10375 
 10319 
 10376 
 10320 /***/ })
 10377 /***/ })
 10321 
 10378 
 10322 /******/ 	});
 10379 /******/ 	});
 10344 /******/ 		// Return the exports of the module
 10401 /******/ 		// Return the exports of the module
 10345 /******/ 		return module.exports;
 10402 /******/ 		return module.exports;
 10346 /******/ 	}
 10403 /******/ 	}
 10347 /******/ 	
 10404 /******/ 	
 10348 /************************************************************************/
 10405 /************************************************************************/
 10349 var __webpack_exports__ = {};
       
 10350 // This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
       
 10351 (() => {
       
 10352 /**
 10406 /**
 10353  * @output wp-includes/js/media-views.js
 10407  * @output wp-includes/js/media-views.js
 10354  */
 10408  */
 10355 
 10409 
 10356 var media = wp.media,
 10410 var media = wp.media,
 10502 media.view.SiteIconPreview = __webpack_require__( 7810 );
 10556 media.view.SiteIconPreview = __webpack_require__( 7810 );
 10503 media.view.EditImage = __webpack_require__( 6126 );
 10557 media.view.EditImage = __webpack_require__( 6126 );
 10504 media.view.Spinner = __webpack_require__( 9141 );
 10558 media.view.Spinner = __webpack_require__( 9141 );
 10505 media.view.Heading = __webpack_require__( 170 );
 10559 media.view.Heading = __webpack_require__( 170 );
 10506 
 10560 
 10507 })();
       
 10508 
       
 10509 /******/ })()
 10561 /******/ })()
 10510 ;
 10562 ;