wp/wp-includes/js/media-views.js
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
    79 /******/ 	// __webpack_public_path__
    79 /******/ 	// __webpack_public_path__
    80 /******/ 	__webpack_require__.p = "";
    80 /******/ 	__webpack_require__.p = "";
    81 /******/
    81 /******/
    82 /******/
    82 /******/
    83 /******/ 	// Load entry module and return exports
    83 /******/ 	// Load entry module and return exports
    84 /******/ 	return __webpack_require__(__webpack_require__.s = 29);
    84 /******/ 	return __webpack_require__(__webpack_require__.s = 3);
    85 /******/ })
    85 /******/ })
    86 /************************************************************************/
    86 /************************************************************************/
    87 /******/ (Array(29).concat([
    87 /******/ ({
    88 /* 29 */
    88 
    89 /***/ (function(module, exports, __webpack_require__) {
    89 /***/ "+B8m":
    90 
    90 /***/ (function(module, exports) {
    91 module.exports = __webpack_require__(30);
    91 
    92 
    92 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
    93 
    93 	EmbedImage;
    94 /***/ }),
       
    95 /* 30 */
       
    96 /***/ (function(module, exports, __webpack_require__) {
       
    97 
    94 
    98 /**
    95 /**
    99  * @output wp-includes/js/media-views.js
    96  * wp.media.view.EmbedImage
       
    97  *
       
    98  * @memberOf wp.media.view
       
    99  *
       
   100  * @class
       
   101  * @augments wp.media.view.Settings.AttachmentDisplay
       
   102  * @augments wp.media.view.Settings
       
   103  * @augments wp.media.View
       
   104  * @augments wp.Backbone.View
       
   105  * @augments Backbone.View
   100  */
   106  */
   101 
   107 EmbedImage = AttachmentDisplay.extend(/** @lends wp.media.view.EmbedImage.prototype */{
   102 var media = wp.media,
   108 	className: 'embed-media-settings',
   103 	$ = jQuery,
   109 	template:  wp.template('embed-image-settings'),
   104 	l10n;
   110 
   105 
   111 	initialize: function() {
   106 media.isTouchDevice = ( 'ontouchend' in document );
       
   107 
       
   108 // Link any localized strings.
       
   109 l10n = media.view.l10n = window._wpMediaViewsL10n || {};
       
   110 
       
   111 // Link any settings.
       
   112 media.view.settings = l10n.settings || {};
       
   113 delete l10n.settings;
       
   114 
       
   115 // Copy the `post` setting over to the model settings.
       
   116 media.model.settings.post = media.view.settings.post;
       
   117 
       
   118 // Check if the browser supports CSS 3.0 transitions.
       
   119 $.support.transition = (function(){
       
   120 	var style = document.documentElement.style,
       
   121 		transitions = {
       
   122 			WebkitTransition: 'webkitTransitionEnd',
       
   123 			MozTransition:    'transitionend',
       
   124 			OTransition:      'oTransitionEnd otransitionend',
       
   125 			transition:       'transitionend'
       
   126 		}, transition;
       
   127 
       
   128 	transition = _.find( _.keys( transitions ), function( transition ) {
       
   129 		return ! _.isUndefined( style[ transition ] );
       
   130 	});
       
   131 
       
   132 	return transition && {
       
   133 		end: transitions[ transition ]
       
   134 	};
       
   135 }());
       
   136 
       
   137 /**
       
   138  * A shared event bus used to provide events into
       
   139  * the media workflows that 3rd-party devs can use to hook
       
   140  * in.
       
   141  */
       
   142 media.events = _.extend( {}, Backbone.Events );
       
   143 
       
   144 /**
       
   145  * Makes it easier to bind events using transitions.
       
   146  *
       
   147  * @param {string} selector
       
   148  * @param {number} sensitivity
       
   149  * @return {Promise}
       
   150  */
       
   151 media.transition = function( selector, sensitivity ) {
       
   152 	var deferred = $.Deferred();
       
   153 
       
   154 	sensitivity = sensitivity || 2000;
       
   155 
       
   156 	if ( $.support.transition ) {
       
   157 		if ( ! (selector instanceof $) ) {
       
   158 			selector = $( selector );
       
   159 		}
       
   160 
       
   161 		// Resolve the deferred when the first element finishes animating.
       
   162 		selector.first().one( $.support.transition.end, deferred.resolve );
       
   163 
       
   164 		// Just in case the event doesn't trigger, fire a callback.
       
   165 		_.delay( deferred.resolve, sensitivity );
       
   166 
       
   167 	// Otherwise, execute on the spot.
       
   168 	} else {
       
   169 		deferred.resolve();
       
   170 	}
       
   171 
       
   172 	return deferred.promise();
       
   173 };
       
   174 
       
   175 media.controller.Region = __webpack_require__( 31 );
       
   176 media.controller.StateMachine = __webpack_require__( 32 );
       
   177 media.controller.State = __webpack_require__( 33 );
       
   178 
       
   179 media.selectionSync = __webpack_require__( 34 );
       
   180 media.controller.Library = __webpack_require__( 35 );
       
   181 media.controller.ImageDetails = __webpack_require__( 36 );
       
   182 media.controller.GalleryEdit = __webpack_require__( 37 );
       
   183 media.controller.GalleryAdd = __webpack_require__( 38 );
       
   184 media.controller.CollectionEdit = __webpack_require__( 39 );
       
   185 media.controller.CollectionAdd = __webpack_require__( 40 );
       
   186 media.controller.FeaturedImage = __webpack_require__( 41 );
       
   187 media.controller.ReplaceImage = __webpack_require__( 42 );
       
   188 media.controller.EditImage = __webpack_require__( 43 );
       
   189 media.controller.MediaLibrary = __webpack_require__( 44 );
       
   190 media.controller.Embed = __webpack_require__( 45 );
       
   191 media.controller.Cropper = __webpack_require__( 46 );
       
   192 media.controller.CustomizeImageCropper = __webpack_require__( 47 );
       
   193 media.controller.SiteIconCropper = __webpack_require__( 48 );
       
   194 
       
   195 media.View = __webpack_require__( 49 );
       
   196 media.view.Frame = __webpack_require__( 50 );
       
   197 media.view.MediaFrame = __webpack_require__( 51 );
       
   198 media.view.MediaFrame.Select = __webpack_require__( 52 );
       
   199 media.view.MediaFrame.Post = __webpack_require__( 53 );
       
   200 media.view.MediaFrame.ImageDetails = __webpack_require__( 54 );
       
   201 media.view.Modal = __webpack_require__( 55 );
       
   202 media.view.FocusManager = __webpack_require__( 56 );
       
   203 media.view.UploaderWindow = __webpack_require__( 57 );
       
   204 media.view.EditorUploader = __webpack_require__( 58 );
       
   205 media.view.UploaderInline = __webpack_require__( 59 );
       
   206 media.view.UploaderStatus = __webpack_require__( 60 );
       
   207 media.view.UploaderStatusError = __webpack_require__( 61 );
       
   208 media.view.Toolbar = __webpack_require__( 62 );
       
   209 media.view.Toolbar.Select = __webpack_require__( 63 );
       
   210 media.view.Toolbar.Embed = __webpack_require__( 64 );
       
   211 media.view.Button = __webpack_require__( 65 );
       
   212 media.view.ButtonGroup = __webpack_require__( 66 );
       
   213 media.view.PriorityList = __webpack_require__( 67 );
       
   214 media.view.MenuItem = __webpack_require__( 68 );
       
   215 media.view.Menu = __webpack_require__( 69 );
       
   216 media.view.RouterItem = __webpack_require__( 70 );
       
   217 media.view.Router = __webpack_require__( 71 );
       
   218 media.view.Sidebar = __webpack_require__( 72 );
       
   219 media.view.Attachment = __webpack_require__( 73 );
       
   220 media.view.Attachment.Library = __webpack_require__( 74 );
       
   221 media.view.Attachment.EditLibrary = __webpack_require__( 75 );
       
   222 media.view.Attachments = __webpack_require__( 76 );
       
   223 media.view.Search = __webpack_require__( 77 );
       
   224 media.view.AttachmentFilters = __webpack_require__( 78 );
       
   225 media.view.DateFilter = __webpack_require__( 79 );
       
   226 media.view.AttachmentFilters.Uploaded = __webpack_require__( 80 );
       
   227 media.view.AttachmentFilters.All = __webpack_require__( 81 );
       
   228 media.view.AttachmentsBrowser = __webpack_require__( 82 );
       
   229 media.view.Selection = __webpack_require__( 83 );
       
   230 media.view.Attachment.Selection = __webpack_require__( 84 );
       
   231 media.view.Attachments.Selection = __webpack_require__( 85 );
       
   232 media.view.Attachment.EditSelection = __webpack_require__( 86 );
       
   233 media.view.Settings = __webpack_require__( 87 );
       
   234 media.view.Settings.AttachmentDisplay = __webpack_require__( 88 );
       
   235 media.view.Settings.Gallery = __webpack_require__( 89 );
       
   236 media.view.Settings.Playlist = __webpack_require__( 90 );
       
   237 media.view.Attachment.Details = __webpack_require__( 91 );
       
   238 media.view.AttachmentCompat = __webpack_require__( 92 );
       
   239 media.view.Iframe = __webpack_require__( 93 );
       
   240 media.view.Embed = __webpack_require__( 94 );
       
   241 media.view.Label = __webpack_require__( 95 );
       
   242 media.view.EmbedUrl = __webpack_require__( 96 );
       
   243 media.view.EmbedLink = __webpack_require__( 97 );
       
   244 media.view.EmbedImage = __webpack_require__( 98 );
       
   245 media.view.ImageDetails = __webpack_require__( 99 );
       
   246 media.view.Cropper = __webpack_require__( 100 );
       
   247 media.view.SiteIconCropper = __webpack_require__( 101 );
       
   248 media.view.SiteIconPreview = __webpack_require__( 102 );
       
   249 media.view.EditImage = __webpack_require__( 103 );
       
   250 media.view.Spinner = __webpack_require__( 104 );
       
   251 media.view.Heading = __webpack_require__( 105 );
       
   252 
       
   253 
       
   254 /***/ }),
       
   255 /* 31 */
       
   256 /***/ (function(module, exports) {
       
   257 
       
   258 /**
       
   259  * wp.media.controller.Region
       
   260  *
       
   261  * A region is a persistent application layout area.
       
   262  *
       
   263  * A region assumes one mode at any time, and can be switched to another.
       
   264  *
       
   265  * When mode changes, events are triggered on the region's parent view.
       
   266  * The parent view will listen to specific events and fill the region with an
       
   267  * appropriate view depending on mode. For example, a frame listens for the
       
   268  * 'browse' mode t be activated on the 'content' view and then fills the region
       
   269  * with an AttachmentsBrowser view.
       
   270  *
       
   271  * @memberOf wp.media.controller
       
   272  *
       
   273  * @class
       
   274  *
       
   275  * @param {Object}        options          Options hash for the region.
       
   276  * @param {string}        options.id       Unique identifier for the region.
       
   277  * @param {Backbone.View} options.view     A parent view the region exists within.
       
   278  * @param {string}        options.selector jQuery selector for the region within the parent view.
       
   279  */
       
   280 var Region = function( options ) {
       
   281 	_.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
       
   282 };
       
   283 
       
   284 // Use Backbone's self-propagating `extend` inheritance method.
       
   285 Region.extend = Backbone.Model.extend;
       
   286 
       
   287 _.extend( Region.prototype,/** @lends wp.media.controller.Region.prototype */{
       
   288 	/**
       
   289 	 * Activate a mode.
       
   290 	 *
       
   291 	 * @since 3.5.0
       
   292 	 *
       
   293 	 * @param {string} mode
       
   294 	 *
       
   295 	 * @fires Region#activate
       
   296 	 * @fires Region#deactivate
       
   297 	 *
       
   298 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
       
   299 	 */
       
   300 	mode: function( mode ) {
       
   301 		if ( ! mode ) {
       
   302 			return this._mode;
       
   303 		}
       
   304 		// Bail if we're trying to change to the current mode.
       
   305 		if ( mode === this._mode ) {
       
   306 			return this;
       
   307 		}
       
   308 
       
   309 		/**
   112 		/**
   310 		 * Region mode deactivation event.
   113 		 * Call `initialize` directly on parent class with passed arguments
   311 		 *
       
   312 		 * @event wp.media.controller.Region#deactivate
       
   313 		 */
   114 		 */
   314 		this.trigger('deactivate');
   115 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
   315 
   116 		this.listenTo( this.model, 'change:url', this.updateImage );
   316 		this._mode = mode;
   117 	},
   317 		this.render( mode );
   118 
   318 
   119 	updateImage: function() {
   319 		/**
   120 		this.$('img').attr( 'src', this.model.get('url') );
   320 		 * Region mode activation event.
       
   321 		 *
       
   322 		 * @event wp.media.controller.Region#activate
       
   323 		 */
       
   324 		this.trigger('activate');
       
   325 		return this;
       
   326 	},
       
   327 	/**
       
   328 	 * Render a mode.
       
   329 	 *
       
   330 	 * @since 3.5.0
       
   331 	 *
       
   332 	 * @param {string} mode
       
   333 	 *
       
   334 	 * @fires Region#create
       
   335 	 * @fires Region#render
       
   336 	 *
       
   337 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
       
   338 	 */
       
   339 	render: function( mode ) {
       
   340 		// If the mode isn't active, activate it.
       
   341 		if ( mode && mode !== this._mode ) {
       
   342 			return this.mode( mode );
       
   343 		}
       
   344 
       
   345 		var set = { view: null },
       
   346 			view;
       
   347 
       
   348 		/**
       
   349 		 * Create region view event.
       
   350 		 *
       
   351 		 * Region view creation takes place in an event callback on the frame.
       
   352 		 *
       
   353 		 * @event wp.media.controller.Region#create
       
   354 		 * @type {object}
       
   355 		 * @property {object} view
       
   356 		 */
       
   357 		this.trigger( 'create', set );
       
   358 		view = set.view;
       
   359 
       
   360 		/**
       
   361 		 * Render region view event.
       
   362 		 *
       
   363 		 * Region view creation takes place in an event callback on the frame.
       
   364 		 *
       
   365 		 * @event wp.media.controller.Region#render
       
   366 		 * @type {object}
       
   367 		 */
       
   368 		this.trigger( 'render', view );
       
   369 		if ( view ) {
       
   370 			this.set( view );
       
   371 		}
       
   372 		return this;
       
   373 	},
       
   374 
       
   375 	/**
       
   376 	 * Get the region's view.
       
   377 	 *
       
   378 	 * @since 3.5.0
       
   379 	 *
       
   380 	 * @return {wp.media.View}
       
   381 	 */
       
   382 	get: function() {
       
   383 		return this.view.views.first( this.selector );
       
   384 	},
       
   385 
       
   386 	/**
       
   387 	 * Set the region's view as a subview of the frame.
       
   388 	 *
       
   389 	 * @since 3.5.0
       
   390 	 *
       
   391 	 * @param {Array|Object} views
       
   392 	 * @param {Object} [options={}]
       
   393 	 * @return {wp.Backbone.Subviews} Subviews is returned to allow chaining.
       
   394 	 */
       
   395 	set: function( views, options ) {
       
   396 		if ( options ) {
       
   397 			options.add = false;
       
   398 		}
       
   399 		return this.view.views.set( this.selector, views, options );
       
   400 	},
       
   401 
       
   402 	/**
       
   403 	 * Trigger regional view events on the frame.
       
   404 	 *
       
   405 	 * @since 3.5.0
       
   406 	 *
       
   407 	 * @param {string} event
       
   408 	 * @return {undefined|wp.media.controller.Region} Returns itself to allow chaining.
       
   409 	 */
       
   410 	trigger: function( event ) {
       
   411 		var base, args;
       
   412 
       
   413 		if ( ! this._mode ) {
       
   414 			return;
       
   415 		}
       
   416 
       
   417 		args = _.toArray( arguments );
       
   418 		base = this.id + ':' + event;
       
   419 
       
   420 		// Trigger `{this.id}:{event}:{this._mode}` event on the frame.
       
   421 		args[0] = base + ':' + this._mode;
       
   422 		this.view.trigger.apply( this.view, args );
       
   423 
       
   424 		// Trigger `{this.id}:{event}` event on the frame.
       
   425 		args[0] = base;
       
   426 		this.view.trigger.apply( this.view, args );
       
   427 		return this;
       
   428 	}
   121 	}
   429 });
   122 });
   430 
   123 
   431 module.exports = Region;
   124 module.exports = EmbedImage;
   432 
   125 
   433 
   126 
   434 /***/ }),
   127 /***/ }),
   435 /* 32 */
   128 
       
   129 /***/ "+mQJ":
   436 /***/ (function(module, exports) {
   130 /***/ (function(module, exports) {
   437 
   131 
       
   132 var View = wp.media.View,
       
   133 	$ = jQuery,
       
   134 	l10n = wp.media.view.l10n,
       
   135 	EmbedUrl;
       
   136 
   438 /**
   137 /**
   439  * wp.media.controller.StateMachine
   138  * wp.media.view.EmbedUrl
   440  *
   139  *
   441  * A state machine keeps track of state. It is in one state at a time,
   140  * @memberOf wp.media.view
   442  * and can change from one state to another.
       
   443  *
       
   444  * States are stored as models in a Backbone collection.
       
   445  *
       
   446  * @memberOf wp.media.controller
       
   447  *
       
   448  * @since 3.5.0
       
   449  *
   141  *
   450  * @class
   142  * @class
   451  * @augments Backbone.Model
   143  * @augments wp.media.View
   452  * @mixin
   144  * @augments wp.Backbone.View
   453  * @mixes Backbone.Events
   145  * @augments Backbone.View
   454  */
   146  */
   455 var StateMachine = function() {
   147 EmbedUrl = View.extend(/** @lends wp.media.view.EmbedUrl.prototype */{
   456 	return {
   148 	tagName:   'span',
   457 		// Use Backbone's self-propagating `extend` inheritance method.
   149 	className: 'embed-url',
   458 		extend: Backbone.Model.extend
   150 
   459 	};
   151 	events: {
   460 };
   152 		'input': 'url'
   461 
   153 	},
   462 _.extend( StateMachine.prototype, Backbone.Events,/** @lends wp.media.controller.StateMachine.prototype */{
   154 
   463 	/**
   155 	initialize: function() {
   464 	 * Fetch a state.
   156 		this.$input = $( '<input id="embed-url-field" type="url" />' )
   465 	 *
   157 			.attr( 'aria-label', l10n.insertFromUrlTitle )
   466 	 * If no `id` is provided, returns the active state.
   158 			.val( this.model.get('url') );
   467 	 *
   159 		this.input = this.$input[0];
   468 	 * Implicitly creates states.
   160 
   469 	 *
   161 		this.spinner = $('<span class="spinner" />')[0];
   470 	 * Ensure that the `states` collection exists so the `StateMachine`
   162 		this.$el.append([ this.input, this.spinner ]);
   471 	 * can be used as a mixin.
   163 
   472 	 *
   164 		this.listenTo( this.model, 'change:url', this.render );
   473 	 * @since 3.5.0
   165 
   474 	 *
   166 		if ( this.model.get( 'url' ) ) {
   475 	 * @param {string} id
   167 			_.delay( _.bind( function () {
   476 	 * @return {wp.media.controller.State} Returns a State model from
   168 				this.model.trigger( 'change:url' );
   477 	 *                                     the StateMachine collection.
   169 			}, this ), 500 );
   478 	 */
   170 		}
   479 	state: function( id ) {
   171 	},
   480 		this.states = this.states || new Backbone.Collection();
   172 	/**
   481 
   173 	 * @return {wp.media.view.EmbedUrl} Returns itself to allow chaining.
   482 		// Default to the active state.
   174 	 */
   483 		id = id || this._state;
   175 	render: function() {
   484 
   176 		var $input = this.$input;
   485 		if ( id && ! this.states.get( id ) ) {
   177 
   486 			this.states.add({ id: id });
   178 		if ( $input.is(':focus') ) {
   487 		}
   179 			return;
   488 		return this.states.get( id );
   180 		}
   489 	},
   181 
   490 
   182 		this.input.value = this.model.get('url') || 'http://';
   491 	/**
   183 		/**
   492 	 * Sets the active state.
   184 		 * Call `render` directly on parent class with passed arguments
   493 	 *
   185 		 */
   494 	 * Bail if we're trying to select the current state, if we haven't
   186 		View.prototype.render.apply( this, arguments );
   495 	 * created the `states` collection, or are trying to select a state
       
   496 	 * that does not exist.
       
   497 	 *
       
   498 	 * @since 3.5.0
       
   499 	 *
       
   500 	 * @param {string} id
       
   501 	 *
       
   502 	 * @fires wp.media.controller.State#deactivate
       
   503 	 * @fires wp.media.controller.State#activate
       
   504 	 *
       
   505 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
   506 	 */
       
   507 	setState: function( id ) {
       
   508 		var previous = this.state();
       
   509 
       
   510 		if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) {
       
   511 			return this;
       
   512 		}
       
   513 
       
   514 		if ( previous ) {
       
   515 			previous.trigger('deactivate');
       
   516 			this._lastState = previous.id;
       
   517 		}
       
   518 
       
   519 		this._state = id;
       
   520 		this.state().trigger('activate');
       
   521 
       
   522 		return this;
   187 		return this;
   523 	},
   188 	},
   524 
   189 
   525 	/**
   190 	url: function( event ) {
   526 	 * Returns the previous active state.
   191 		var url = event.target.value || '';
   527 	 *
   192 		this.model.set( 'url', url.trim() );
   528 	 * Call the `state()` method with no parameters to retrieve the current
       
   529 	 * active state.
       
   530 	 *
       
   531 	 * @since 3.5.0
       
   532 	 *
       
   533 	 * @return {wp.media.controller.State} Returns a State model from
       
   534 	 *                                     the StateMachine collection.
       
   535 	 */
       
   536 	lastState: function() {
       
   537 		if ( this._lastState ) {
       
   538 			return this.state( this._lastState );
       
   539 		}
       
   540 	}
   193 	}
   541 });
   194 });
   542 
   195 
   543 // Map all event binding and triggering on a StateMachine to its `states` collection.
   196 module.exports = EmbedUrl;
   544 _.each([ 'on', 'off', 'trigger' ], function( method ) {
       
   545 	/**
       
   546 	 * @function on
       
   547 	 * @memberOf wp.media.controller.StateMachine
       
   548 	 * @instance
       
   549 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
   550 	 */
       
   551 	/**
       
   552 	 * @function off
       
   553 	 * @memberOf wp.media.controller.StateMachine
       
   554 	 * @instance
       
   555 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
   556 	 */
       
   557 	/**
       
   558 	 * @function trigger
       
   559 	 * @memberOf wp.media.controller.StateMachine
       
   560 	 * @instance
       
   561 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
   562 	 */
       
   563 	StateMachine.prototype[ method ] = function() {
       
   564 		// Ensure that the `states` collection exists so the `StateMachine`
       
   565 		// can be used as a mixin.
       
   566 		this.states = this.states || new Backbone.Collection();
       
   567 		// Forward the method to the `states` collection.
       
   568 		this.states[ method ].apply( this.states, arguments );
       
   569 		return this;
       
   570 	};
       
   571 });
       
   572 
       
   573 module.exports = StateMachine;
       
   574 
   197 
   575 
   198 
   576 /***/ }),
   199 /***/ }),
   577 /* 33 */
   200 
       
   201 /***/ "04Ix":
   578 /***/ (function(module, exports) {
   202 /***/ (function(module, exports) {
   579 
   203 
       
   204 var _n = wp.i18n._n,
       
   205 	sprintf = wp.i18n.sprintf,
       
   206 	Selection;
       
   207 
   580 /**
   208 /**
   581  * wp.media.controller.State
   209  * wp.media.view.Selection
   582  *
   210  *
   583  * A state is a step in a workflow that when set will trigger the controllers
   211  * @memberOf wp.media.view
   584  * for the regions to be updated as specified in the frame.
       
   585  *
       
   586  * A state has an event-driven lifecycle:
       
   587  *
       
   588  *     'ready'      triggers when a state is added to a state machine's collection.
       
   589  *     'activate'   triggers when a state is activated by a state machine.
       
   590  *     'deactivate' triggers when a state is deactivated by a state machine.
       
   591  *     'reset'      is not triggered automatically. It should be invoked by the
       
   592  *                  proper controller to reset the state to its default.
       
   593  *
       
   594  * @memberOf wp.media.controller
       
   595  *
   212  *
   596  * @class
   213  * @class
   597  * @augments Backbone.Model
   214  * @augments wp.media.View
       
   215  * @augments wp.Backbone.View
       
   216  * @augments Backbone.View
   598  */
   217  */
   599 var State = Backbone.Model.extend(/** @lends wp.media.controller.State.prototype */{
   218 Selection = wp.media.View.extend(/** @lends wp.media.view.Selection.prototype */{
   600 	/**
   219 	tagName:   'div',
   601 	 * Constructor.
   220 	className: 'media-selection',
   602 	 *
   221 	template:  wp.template('media-selection'),
   603 	 * @since 3.5.0
   222 
   604 	 */
   223 	events: {
   605 	constructor: function() {
   224 		'click .edit-selection':  'edit',
   606 		this.on( 'activate', this._preActivate, this );
   225 		'click .clear-selection': 'clear'
   607 		this.on( 'activate', this.activate, this );
   226 	},
   608 		this.on( 'activate', this._postActivate, this );
   227 
   609 		this.on( 'deactivate', this._deactivate, this );
   228 	initialize: function() {
   610 		this.on( 'deactivate', this.deactivate, this );
   229 		_.defaults( this.options, {
   611 		this.on( 'reset', this.reset, this );
   230 			editable:  false,
   612 		this.on( 'ready', this._ready, this );
   231 			clearable: true
   613 		this.on( 'ready', this.ready, this );
   232 		});
       
   233 
   614 		/**
   234 		/**
   615 		 * Call parent constructor with passed arguments
   235 		 * @member {wp.media.view.Attachments.Selection}
   616 		 */
   236 		 */
   617 		Backbone.Model.apply( this, arguments );
   237 		this.attachments = new wp.media.view.Attachments.Selection({
   618 		this.on( 'change:menu', this._updateMenu, this );
   238 			controller: this.controller,
   619 	},
   239 			collection: this.collection,
   620 	/**
   240 			selection:  this.collection,
   621 	 * Ready event callback.
   241 			model:      new Backbone.Model()
   622 	 *
   242 		});
   623 	 * @abstract
   243 
   624 	 * @since 3.5.0
   244 		this.views.set( '.selection-view', this.attachments );
   625 	 */
   245 		this.collection.on( 'add remove reset', this.refresh, this );
   626 	ready: function() {},
   246 		this.controller.on( 'content:activate', this.refresh, this );
   627 
   247 	},
   628 	/**
   248 
   629 	 * Activate event callback.
   249 	ready: function() {
   630 	 *
   250 		this.refresh();
   631 	 * @abstract
   251 	},
   632 	 * @since 3.5.0
   252 
   633 	 */
   253 	refresh: function() {
   634 	activate: function() {},
   254 		// If the selection hasn't been rendered, bail.
   635 
   255 		if ( ! this.$el.children().length ) {
   636 	/**
       
   637 	 * Deactivate event callback.
       
   638 	 *
       
   639 	 * @abstract
       
   640 	 * @since 3.5.0
       
   641 	 */
       
   642 	deactivate: function() {},
       
   643 
       
   644 	/**
       
   645 	 * Reset event callback.
       
   646 	 *
       
   647 	 * @abstract
       
   648 	 * @since 3.5.0
       
   649 	 */
       
   650 	reset: function() {},
       
   651 
       
   652 	/**
       
   653 	 * @since 3.5.0
       
   654 	 * @access private
       
   655 	 */
       
   656 	_ready: function() {
       
   657 		this._updateMenu();
       
   658 	},
       
   659 
       
   660 	/**
       
   661 	 * @since 3.5.0
       
   662 	 * @access private
       
   663 	*/
       
   664 	_preActivate: function() {
       
   665 		this.active = true;
       
   666 	},
       
   667 
       
   668 	/**
       
   669 	 * @since 3.5.0
       
   670 	 * @access private
       
   671 	 */
       
   672 	_postActivate: function() {
       
   673 		this.on( 'change:menu', this._menu, this );
       
   674 		this.on( 'change:titleMode', this._title, this );
       
   675 		this.on( 'change:content', this._content, this );
       
   676 		this.on( 'change:toolbar', this._toolbar, this );
       
   677 
       
   678 		this.frame.on( 'title:render:default', this._renderTitle, this );
       
   679 
       
   680 		this._title();
       
   681 		this._menu();
       
   682 		this._toolbar();
       
   683 		this._content();
       
   684 		this._router();
       
   685 	},
       
   686 
       
   687 	/**
       
   688 	 * @since 3.5.0
       
   689 	 * @access private
       
   690 	 */
       
   691 	_deactivate: function() {
       
   692 		this.active = false;
       
   693 
       
   694 		this.frame.off( 'title:render:default', this._renderTitle, this );
       
   695 
       
   696 		this.off( 'change:menu', this._menu, this );
       
   697 		this.off( 'change:titleMode', this._title, this );
       
   698 		this.off( 'change:content', this._content, this );
       
   699 		this.off( 'change:toolbar', this._toolbar, this );
       
   700 	},
       
   701 
       
   702 	/**
       
   703 	 * @since 3.5.0
       
   704 	 * @access private
       
   705 	 */
       
   706 	_title: function() {
       
   707 		this.frame.title.render( this.get('titleMode') || 'default' );
       
   708 	},
       
   709 
       
   710 	/**
       
   711 	 * @since 3.5.0
       
   712 	 * @access private
       
   713 	 */
       
   714 	_renderTitle: function( view ) {
       
   715 		view.$el.text( this.get('title') || '' );
       
   716 	},
       
   717 
       
   718 	/**
       
   719 	 * @since 3.5.0
       
   720 	 * @access private
       
   721 	 */
       
   722 	_router: function() {
       
   723 		var router = this.frame.router,
       
   724 			mode = this.get('router'),
       
   725 			view;
       
   726 
       
   727 		this.frame.$el.toggleClass( 'hide-router', ! mode );
       
   728 		if ( ! mode ) {
       
   729 			return;
   256 			return;
   730 		}
   257 		}
   731 
   258 
   732 		this.frame.router.render( mode );
   259 		var collection = this.collection,
   733 
   260 			editing = 'edit-selection' === this.controller.content.mode();
   734 		view = router.get();
   261 
   735 		if ( view && view.select ) {
   262 		// If nothing is selected, display nothing.
   736 			view.select( this.frame.content.mode() );
   263 		this.$el.toggleClass( 'empty', ! collection.length );
   737 		}
   264 		this.$el.toggleClass( 'one', 1 === collection.length );
   738 	},
   265 		this.$el.toggleClass( 'editing', editing );
   739 
   266 
   740 	/**
   267 		this.$( '.count' ).text(
   741 	 * @since 3.5.0
   268 			/* translators: %s: Number of selected media attachments. */
   742 	 * @access private
   269 			sprintf( _n( '%s item selected', '%s items selected', collection.length ), collection.length )
   743 	 */
   270 		);
   744 	_menu: function() {
   271 	},
   745 		var menu = this.frame.menu,
   272 
   746 			mode = this.get('menu'),
   273 	edit: function( event ) {
   747 			view;
   274 		event.preventDefault();
   748 
   275 		if ( this.options.editable ) {
   749 		this.frame.$el.toggleClass( 'hide-menu', ! mode );
   276 			this.options.editable.call( this, this.collection );
   750 		if ( ! mode ) {
   277 		}
   751 			return;
   278 	},
   752 		}
   279 
   753 
   280 	clear: function( event ) {
   754 		menu.mode( mode );
   281 		event.preventDefault();
   755 
   282 		this.collection.reset();
   756 		view = menu.get();
   283 
   757 		if ( view && view.select ) {
   284 		// Move focus to the modal.
   758 			view.select( this.id );
   285 		this.controller.modal.focusManager.focus();
   759 		}
       
   760 	},
       
   761 
       
   762 	/**
       
   763 	 * @since 3.5.0
       
   764 	 * @access private
       
   765 	 */
       
   766 	_updateMenu: function() {
       
   767 		var previous = this.previous('menu'),
       
   768 			menu = this.get('menu');
       
   769 
       
   770 		if ( previous ) {
       
   771 			this.frame.off( 'menu:render:' + previous, this._renderMenu, this );
       
   772 		}
       
   773 
       
   774 		if ( menu ) {
       
   775 			this.frame.on( 'menu:render:' + menu, this._renderMenu, this );
       
   776 		}
       
   777 	},
       
   778 
       
   779 	/**
       
   780 	 * Create a view in the media menu for the state.
       
   781 	 *
       
   782 	 * @since 3.5.0
       
   783 	 * @access private
       
   784 	 *
       
   785 	 * @param {media.view.Menu} view The menu view.
       
   786 	 */
       
   787 	_renderMenu: function( view ) {
       
   788 		var menuItem = this.get('menuItem'),
       
   789 			title = this.get('title'),
       
   790 			priority = this.get('priority');
       
   791 
       
   792 		if ( ! menuItem && title ) {
       
   793 			menuItem = { text: title };
       
   794 
       
   795 			if ( priority ) {
       
   796 				menuItem.priority = priority;
       
   797 			}
       
   798 		}
       
   799 
       
   800 		if ( ! menuItem ) {
       
   801 			return;
       
   802 		}
       
   803 
       
   804 		view.set( this.id, menuItem );
       
   805 	}
   286 	}
   806 });
   287 });
   807 
   288 
   808 _.each(['toolbar','content'], function( region ) {
   289 module.exports = Selection;
   809 	/**
   290 
   810 	 * @access private
   291 
   811 	 */
   292 /***/ }),
   812 	State.prototype[ '_' + region ] = function() {
   293 
   813 		var mode = this.get( region );
   294 /***/ "1S4+":
       
   295 /***/ (function(module, exports) {
       
   296 
       
   297 var $ = jQuery,
       
   298 	AttachmentFilters;
       
   299 
       
   300 /**
       
   301  * wp.media.view.AttachmentFilters
       
   302  *
       
   303  * @memberOf wp.media.view
       
   304  *
       
   305  * @class
       
   306  * @augments wp.media.View
       
   307  * @augments wp.Backbone.View
       
   308  * @augments Backbone.View
       
   309  */
       
   310 AttachmentFilters = wp.media.View.extend(/** @lends wp.media.view.AttachmentFilters.prototype */{
       
   311 	tagName:   'select',
       
   312 	className: 'attachment-filters',
       
   313 	id:        'media-attachment-filters',
       
   314 
       
   315 	events: {
       
   316 		change: 'change'
       
   317 	},
       
   318 
       
   319 	keys: [],
       
   320 
       
   321 	initialize: function() {
       
   322 		this.createFilters();
       
   323 		_.extend( this.filters, this.options.filters );
       
   324 
       
   325 		// Build `<option>` elements.
       
   326 		this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
       
   327 			return {
       
   328 				el: $( '<option></option>' ).val( value ).html( filter.text )[0],
       
   329 				priority: filter.priority || 50
       
   330 			};
       
   331 		}, this ).sortBy('priority').pluck('el').value() );
       
   332 
       
   333 		this.listenTo( this.model, 'change', this.select );
       
   334 		this.select();
       
   335 	},
       
   336 
       
   337 	/**
       
   338 	 * @abstract
       
   339 	 */
       
   340 	createFilters: function() {
       
   341 		this.filters = {};
       
   342 	},
       
   343 
       
   344 	/**
       
   345 	 * When the selected filter changes, update the Attachment Query properties to match.
       
   346 	 */
       
   347 	change: function() {
       
   348 		var filter = this.filters[ this.el.value ];
       
   349 		if ( filter ) {
       
   350 			this.model.set( filter.props );
       
   351 		}
       
   352 	},
       
   353 
       
   354 	select: function() {
       
   355 		var model = this.model,
       
   356 			value = 'all',
       
   357 			props = model.toJSON();
       
   358 
       
   359 		_.find( this.filters, function( filter, id ) {
       
   360 			var equal = _.all( filter.props, function( prop, key ) {
       
   361 				return prop === ( _.isUndefined( props[ key ] ) ? null : props[ key ] );
       
   362 			});
       
   363 
       
   364 			if ( equal ) {
       
   365 				return value = id;
       
   366 			}
       
   367 		});
       
   368 
       
   369 		this.$el.val( value );
       
   370 	}
       
   371 });
       
   372 
       
   373 module.exports = AttachmentFilters;
       
   374 
       
   375 
       
   376 /***/ }),
       
   377 
       
   378 /***/ "2AvB":
       
   379 /***/ (function(module, exports) {
       
   380 
       
   381 var Settings = wp.media.view.Settings,
       
   382 	AttachmentDisplay;
       
   383 
       
   384 /**
       
   385  * wp.media.view.Settings.AttachmentDisplay
       
   386  *
       
   387  * @memberOf wp.media.view.Settings
       
   388  *
       
   389  * @class
       
   390  * @augments wp.media.view.Settings
       
   391  * @augments wp.media.View
       
   392  * @augments wp.Backbone.View
       
   393  * @augments Backbone.View
       
   394  */
       
   395 AttachmentDisplay = Settings.extend(/** @lends wp.media.view.Settings.AttachmentDisplay.prototype */{
       
   396 	className: 'attachment-display-settings',
       
   397 	template:  wp.template('attachment-display-settings'),
       
   398 
       
   399 	initialize: function() {
       
   400 		var attachment = this.options.attachment;
       
   401 
       
   402 		_.defaults( this.options, {
       
   403 			userSettings: false
       
   404 		});
       
   405 		// Call 'initialize' directly on the parent class.
       
   406 		Settings.prototype.initialize.apply( this, arguments );
       
   407 		this.listenTo( this.model, 'change:link', this.updateLinkTo );
       
   408 
       
   409 		if ( attachment ) {
       
   410 			attachment.on( 'change:uploading', this.render, this );
       
   411 		}
       
   412 	},
       
   413 
       
   414 	dispose: function() {
       
   415 		var attachment = this.options.attachment;
       
   416 		if ( attachment ) {
       
   417 			attachment.off( null, null, this );
       
   418 		}
       
   419 		/**
       
   420 		 * call 'dispose' directly on the parent class
       
   421 		 */
       
   422 		Settings.prototype.dispose.apply( this, arguments );
       
   423 	},
       
   424 	/**
       
   425 	 * @return {wp.media.view.AttachmentDisplay} Returns itself to allow chaining.
       
   426 	 */
       
   427 	render: function() {
       
   428 		var attachment = this.options.attachment;
       
   429 		if ( attachment ) {
       
   430 			_.extend( this.options, {
       
   431 				sizes: attachment.get('sizes'),
       
   432 				type:  attachment.get('type')
       
   433 			});
       
   434 		}
       
   435 		/**
       
   436 		 * call 'render' directly on the parent class
       
   437 		 */
       
   438 		Settings.prototype.render.call( this );
       
   439 		this.updateLinkTo();
       
   440 		return this;
       
   441 	},
       
   442 
       
   443 	updateLinkTo: function() {
       
   444 		var linkTo = this.model.get('link'),
       
   445 			$input = this.$('.link-to-custom'),
       
   446 			attachment = this.options.attachment;
       
   447 
       
   448 		if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
       
   449 			$input.closest( '.setting' ).addClass( 'hidden' );
       
   450 			return;
       
   451 		}
       
   452 
       
   453 		if ( attachment ) {
       
   454 			if ( 'post' === linkTo ) {
       
   455 				$input.val( attachment.get('link') );
       
   456 			} else if ( 'file' === linkTo ) {
       
   457 				$input.val( attachment.get('url') );
       
   458 			} else if ( ! this.model.get('linkUrl') ) {
       
   459 				$input.val('http://');
       
   460 			}
       
   461 
       
   462 			$input.prop( 'readonly', 'custom' !== linkTo );
       
   463 		}
       
   464 
       
   465 		$input.closest( '.setting' ).removeClass( 'hidden' );
       
   466 		if ( $input.length ) {
       
   467 			$input[0].scrollIntoView();
       
   468 		}
       
   469 	}
       
   470 });
       
   471 
       
   472 module.exports = AttachmentDisplay;
       
   473 
       
   474 
       
   475 /***/ }),
       
   476 
       
   477 /***/ "2NU8":
       
   478 /***/ (function(module, exports) {
       
   479 
       
   480 var View = wp.media.View,
       
   481 	Toolbar;
       
   482 
       
   483 /**
       
   484  * wp.media.view.Toolbar
       
   485  *
       
   486  * A toolbar which consists of a primary and a secondary section. Each sections
       
   487  * can be filled with views.
       
   488  *
       
   489  * @memberOf wp.media.view
       
   490  *
       
   491  * @class
       
   492  * @augments wp.media.View
       
   493  * @augments wp.Backbone.View
       
   494  * @augments Backbone.View
       
   495  */
       
   496 Toolbar = View.extend(/** @lends wp.media.view.Toolbar.prototype */{
       
   497 	tagName:   'div',
       
   498 	className: 'media-toolbar',
       
   499 
       
   500 	initialize: function() {
       
   501 		var state = this.controller.state(),
       
   502 			selection = this.selection = state.get('selection'),
       
   503 			library = this.library = state.get('library');
       
   504 
       
   505 		this._views = {};
       
   506 
       
   507 		// The toolbar is composed of two `PriorityList` views.
       
   508 		this.primary   = new wp.media.view.PriorityList();
       
   509 		this.secondary = new wp.media.view.PriorityList();
       
   510 		this.primary.$el.addClass('media-toolbar-primary search-form');
       
   511 		this.secondary.$el.addClass('media-toolbar-secondary');
       
   512 
       
   513 		this.views.set([ this.secondary, this.primary ]);
       
   514 
       
   515 		if ( this.options.items ) {
       
   516 			this.set( this.options.items, { silent: true });
       
   517 		}
       
   518 
       
   519 		if ( ! this.options.silent ) {
       
   520 			this.render();
       
   521 		}
       
   522 
       
   523 		if ( selection ) {
       
   524 			selection.on( 'add remove reset', this.refresh, this );
       
   525 		}
       
   526 
       
   527 		if ( library ) {
       
   528 			library.on( 'add remove reset', this.refresh, this );
       
   529 		}
       
   530 	},
       
   531 	/**
       
   532 	 * @return {wp.media.view.Toolbar} Returns itsef to allow chaining
       
   533 	 */
       
   534 	dispose: function() {
       
   535 		if ( this.selection ) {
       
   536 			this.selection.off( null, null, this );
       
   537 		}
       
   538 
       
   539 		if ( this.library ) {
       
   540 			this.library.off( null, null, this );
       
   541 		}
       
   542 		/**
       
   543 		 * call 'dispose' directly on the parent class
       
   544 		 */
       
   545 		return View.prototype.dispose.apply( this, arguments );
       
   546 	},
       
   547 
       
   548 	ready: function() {
       
   549 		this.refresh();
       
   550 	},
       
   551 
       
   552 	/**
       
   553 	 * @param {string} id
       
   554 	 * @param {Backbone.View|Object} view
       
   555 	 * @param {Object} [options={}]
       
   556 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
       
   557 	 */
       
   558 	set: function( id, view, options ) {
       
   559 		var list;
       
   560 		options = options || {};
       
   561 
       
   562 		// Accept an object with an `id` : `view` mapping.
       
   563 		if ( _.isObject( id ) ) {
       
   564 			_.each( id, function( view, id ) {
       
   565 				this.set( id, view, { silent: true });
       
   566 			}, this );
       
   567 
       
   568 		} else {
       
   569 			if ( ! ( view instanceof Backbone.View ) ) {
       
   570 				view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
       
   571 				view = new wp.media.view.Button( view ).render();
       
   572 			}
       
   573 
       
   574 			view.controller = view.controller || this.controller;
       
   575 
       
   576 			this._views[ id ] = view;
       
   577 
       
   578 			list = view.options.priority < 0 ? 'secondary' : 'primary';
       
   579 			this[ list ].set( id, view, options );
       
   580 		}
       
   581 
       
   582 		if ( ! options.silent ) {
       
   583 			this.refresh();
       
   584 		}
       
   585 
       
   586 		return this;
       
   587 	},
       
   588 	/**
       
   589 	 * @param {string} id
       
   590 	 * @return {wp.media.view.Button}
       
   591 	 */
       
   592 	get: function( id ) {
       
   593 		return this._views[ id ];
       
   594 	},
       
   595 	/**
       
   596 	 * @param {string} id
       
   597 	 * @param {Object} options
       
   598 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
       
   599 	 */
       
   600 	unset: function( id, options ) {
       
   601 		delete this._views[ id ];
       
   602 		this.primary.unset( id, options );
       
   603 		this.secondary.unset( id, options );
       
   604 
       
   605 		if ( ! options || ! options.silent ) {
       
   606 			this.refresh();
       
   607 		}
       
   608 		return this;
       
   609 	},
       
   610 
       
   611 	refresh: function() {
       
   612 		var state = this.controller.state(),
       
   613 			library = state.get('library'),
       
   614 			selection = state.get('selection');
       
   615 
       
   616 		_.each( this._views, function( button ) {
       
   617 			if ( ! button.model || ! button.options || ! button.options.requires ) {
       
   618 				return;
       
   619 			}
       
   620 
       
   621 			var requires = button.options.requires,
       
   622 				disabled = false;
       
   623 
       
   624 			// Prevent insertion of attachments if any of them are still uploading.
       
   625 			if ( selection && selection.models ) {
       
   626 				disabled = _.some( selection.models, function( attachment ) {
       
   627 					return attachment.get('uploading') === true;
       
   628 				});
       
   629 			}
       
   630 
       
   631 			if ( requires.selection && selection && ! selection.length ) {
       
   632 				disabled = true;
       
   633 			} else if ( requires.library && library && ! library.length ) {
       
   634 				disabled = true;
       
   635 			}
       
   636 			button.model.set( 'disabled', disabled );
       
   637 		});
       
   638 	}
       
   639 });
       
   640 
       
   641 module.exports = Toolbar;
       
   642 
       
   643 
       
   644 /***/ }),
       
   645 
       
   646 /***/ "2jku":
       
   647 /***/ (function(module, exports) {
       
   648 
       
   649 /**
       
   650  * wp.media.view.Attachment.Library
       
   651  *
       
   652  * @memberOf wp.media.view.Attachment
       
   653  *
       
   654  * @class
       
   655  * @augments wp.media.view.Attachment
       
   656  * @augments wp.media.View
       
   657  * @augments wp.Backbone.View
       
   658  * @augments Backbone.View
       
   659  */
       
   660 var Library = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Library.prototype */{
       
   661 	buttons: {
       
   662 		check: true
       
   663 	}
       
   664 });
       
   665 
       
   666 module.exports = Library;
       
   667 
       
   668 
       
   669 /***/ }),
       
   670 
       
   671 /***/ 3:
       
   672 /***/ (function(module, exports, __webpack_require__) {
       
   673 
       
   674 module.exports = __webpack_require__("tg/Y");
       
   675 
       
   676 
       
   677 /***/ }),
       
   678 
       
   679 /***/ "3nJM":
       
   680 /***/ (function(module, exports) {
       
   681 
       
   682 var $ = jQuery;
       
   683 
       
   684 /**
       
   685  * wp.media.view.FocusManager
       
   686  *
       
   687  * @memberOf wp.media.view
       
   688  *
       
   689  * @class
       
   690  * @augments wp.media.View
       
   691  * @augments wp.Backbone.View
       
   692  * @augments Backbone.View
       
   693  */
       
   694 var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.prototype */{
       
   695 
       
   696 	events: {
       
   697 		'keydown': 'focusManagementMode'
       
   698 	},
       
   699 
       
   700 	/**
       
   701 	 * Initializes the Focus Manager.
       
   702 	 *
       
   703 	 * @param {Object} options The Focus Manager options.
       
   704 	 *
       
   705 	 * @since 5.3.0
       
   706 	 *
       
   707 	 * @return {void}
       
   708 	 */
       
   709 	initialize: function( options ) {
       
   710 		this.mode                    = options.mode || 'constrainTabbing';
       
   711 		this.tabsAutomaticActivation = options.tabsAutomaticActivation || false;
       
   712 	},
       
   713 
       
   714  	/**
       
   715 	 * Determines which focus management mode to use.
       
   716 	 *
       
   717 	 * @since 5.3.0
       
   718 	 *
       
   719 	 * @param {Object} event jQuery event object.
       
   720 	 *
       
   721 	 * @return {void}
       
   722 	 */
       
   723 	focusManagementMode: function( event ) {
       
   724 		if ( this.mode === 'constrainTabbing' ) {
       
   725 			this.constrainTabbing( event );
       
   726 		}
       
   727 
       
   728 		if ( this.mode === 'tabsNavigation' ) {
       
   729 			this.tabsNavigation( event );
       
   730 		}
       
   731 	},
       
   732 
       
   733 	/**
       
   734 	 * Gets all the tabbable elements.
       
   735 	 *
       
   736 	 * @since 5.3.0
       
   737 	 *
       
   738 	 * @return {Object} A jQuery collection of tabbable elements.
       
   739 	 */
       
   740 	getTabbables: function() {
       
   741 		// Skip the file input added by Plupload.
       
   742 		return this.$( ':tabbable' ).not( '.moxie-shim input[type="file"]' );
       
   743 	},
       
   744 
       
   745 	/**
       
   746 	 * Moves focus to the modal dialog.
       
   747 	 *
       
   748 	 * @since 3.5.0
       
   749 	 *
       
   750 	 * @return {void}
       
   751 	 */
       
   752 	focus: function() {
       
   753 		this.$( '.media-modal' ).trigger( 'focus' );
       
   754 	},
       
   755 
       
   756 	/**
       
   757 	 * Constrains navigation with the Tab key within the media view element.
       
   758 	 *
       
   759 	 * @since 4.0.0
       
   760 	 *
       
   761 	 * @param {Object} event A keydown jQuery event.
       
   762 	 *
       
   763 	 * @return {void}
       
   764 	 */
       
   765 	constrainTabbing: function( event ) {
       
   766 		var tabbables;
       
   767 
       
   768 		// Look for the tab key.
       
   769 		if ( 9 !== event.keyCode ) {
       
   770 			return;
       
   771 		}
       
   772 
       
   773 		tabbables = this.getTabbables();
       
   774 
       
   775 		// Keep tab focus within media modal while it's open.
       
   776 		if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
       
   777 			tabbables.first().focus();
       
   778 			return false;
       
   779 		} else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
       
   780 			tabbables.last().focus();
       
   781 			return false;
       
   782 		}
       
   783 	},
       
   784 
       
   785 	/**
       
   786 	 * Hides from assistive technologies all the body children.
       
   787 	 *
       
   788 	 * Sets an `aria-hidden="true"` attribute on all the body children except
       
   789 	 * the provided element and other elements that should not be hidden.
       
   790 	 *
       
   791 	 * The reason why we use `aria-hidden` is that `aria-modal="true"` is buggy
       
   792 	 * in Safari 11.1 and support is spotty in other browsers. Also, `aria-modal="true"`
       
   793 	 * prevents the `wp.a11y.speak()` ARIA live regions to work as they're outside
       
   794 	 * of the modal dialog and get hidden from assistive technologies.
       
   795 	 *
       
   796 	 * @since 5.2.3
       
   797 	 *
       
   798 	 * @param {Object} visibleElement The jQuery object representing the element that should not be hidden.
       
   799 	 *
       
   800 	 * @return {void}
       
   801 	 */
       
   802 	setAriaHiddenOnBodyChildren: function( visibleElement ) {
       
   803 		var bodyChildren,
       
   804 			self = this;
       
   805 
       
   806 		if ( this.isBodyAriaHidden ) {
       
   807 			return;
       
   808 		}
       
   809 
       
   810 		// Get all the body children.
       
   811 		bodyChildren = document.body.children;
       
   812 
       
   813 		// Loop through the body children and hide the ones that should be hidden.
       
   814 		_.each( bodyChildren, function( element ) {
       
   815 			// Don't hide the modal element.
       
   816 			if ( element === visibleElement[0] ) {
       
   817 				return;
       
   818 			}
       
   819 
       
   820 			// Determine the body children to hide.
       
   821 			if ( self.elementShouldBeHidden( element ) ) {
       
   822 				element.setAttribute( 'aria-hidden', 'true' );
       
   823 				// Store the hidden elements.
       
   824 				self.ariaHiddenElements.push( element );
       
   825 			}
       
   826 		} );
       
   827 
       
   828 		this.isBodyAriaHidden = true;
       
   829 	},
       
   830 
       
   831 	/**
       
   832 	 * Unhides from assistive technologies all the body children.
       
   833 	 *
       
   834 	 * Makes visible again to assistive technologies all the body children
       
   835 	 * previously hidden and stored in this.ariaHiddenElements.
       
   836 	 *
       
   837 	 * @since 5.2.3
       
   838 	 *
       
   839 	 * @return {void}
       
   840 	 */
       
   841 	removeAriaHiddenFromBodyChildren: function() {
       
   842 		_.each( this.ariaHiddenElements, function( element ) {
       
   843 			element.removeAttribute( 'aria-hidden' );
       
   844 		} );
       
   845 
       
   846 		this.ariaHiddenElements = [];
       
   847 		this.isBodyAriaHidden   = false;
       
   848 	},
       
   849 
       
   850 	/**
       
   851 	 * Determines if the passed element should not be hidden from assistive technologies.
       
   852 	 *
       
   853 	 * @since 5.2.3
       
   854 	 *
       
   855 	 * @param {Object} element The DOM element that should be checked.
       
   856 	 *
       
   857 	 * @return {boolean} Whether the element should not be hidden from assistive technologies.
       
   858 	 */
       
   859 	elementShouldBeHidden: function( element ) {
       
   860 		var role = element.getAttribute( 'role' ),
       
   861 			liveRegionsRoles = [ 'alert', 'status', 'log', 'marquee', 'timer' ];
       
   862 
       
   863 		/*
       
   864 		 * Don't hide scripts, elements that already have `aria-hidden`, and
       
   865 		 * ARIA live regions.
       
   866 		 */
       
   867 		return ! (
       
   868 			element.tagName === 'SCRIPT' ||
       
   869 			element.hasAttribute( 'aria-hidden' ) ||
       
   870 			element.hasAttribute( 'aria-live' ) ||
       
   871 			liveRegionsRoles.indexOf( role ) !== -1
       
   872 		);
       
   873 	},
       
   874 
       
   875 	/**
       
   876 	 * Whether the body children are hidden from assistive technologies.
       
   877 	 *
       
   878 	 * @since 5.2.3
       
   879 	 */
       
   880 	isBodyAriaHidden: false,
       
   881 
       
   882 	/**
       
   883 	 * Stores an array of DOM elements that should be hidden from assistive
       
   884 	 * technologies, for example when the media modal dialog opens.
       
   885 	 *
       
   886 	 * @since 5.2.3
       
   887 	 */
       
   888 	ariaHiddenElements: [],
       
   889 
       
   890 	/**
       
   891 	 * Holds the jQuery collection of ARIA tabs.
       
   892 	 *
       
   893 	 * @since 5.3.0
       
   894 	 */
       
   895 	tabs: $(),
       
   896 
       
   897 	/**
       
   898 	 * Sets up tabs in an ARIA tabbed interface.
       
   899 	 *
       
   900 	 * @since 5.3.0
       
   901 	 *
       
   902 	 * @param {Object} event jQuery event object.
       
   903 	 *
       
   904 	 * @return {void}
       
   905 	 */
       
   906 	setupAriaTabs: function() {
       
   907 		this.tabs = this.$( '[role="tab"]' );
       
   908 
       
   909 		// Set up initial attributes.
       
   910 		this.tabs.attr( {
       
   911 			'aria-selected': 'false',
       
   912 			tabIndex: '-1'
       
   913 		} );
       
   914 
       
   915 		// Set up attributes on the initially active tab.
       
   916 		this.tabs.filter( '.active' )
       
   917 			.removeAttr( 'tabindex' )
       
   918 			.attr( 'aria-selected', 'true' );
       
   919 	},
       
   920 
       
   921 	/**
       
   922 	 * Enables arrows navigation within the ARIA tabbed interface.
       
   923 	 *
       
   924 	 * @since 5.3.0
       
   925 	 *
       
   926 	 * @param {Object} event jQuery event object.
       
   927 	 *
       
   928 	 * @return {void}
       
   929 	 */
       
   930 	tabsNavigation: function( event ) {
       
   931 		var orientation = 'horizontal',
       
   932 			keys = [ 32, 35, 36, 37, 38, 39, 40 ];
       
   933 
       
   934 		// Return if not Spacebar, End, Home, or Arrow keys.
       
   935 		if ( keys.indexOf( event.which ) === -1 ) {
       
   936 			return;
       
   937 		}
       
   938 
       
   939 		// Determine navigation direction.
       
   940 		if ( this.$el.attr( 'aria-orientation' ) === 'vertical' ) {
       
   941 			orientation = 'vertical';
       
   942 		}
       
   943 
       
   944 		// Make Up and Down arrow keys do nothing with horizontal tabs.
       
   945 		if ( orientation === 'horizontal' && [ 38, 40 ].indexOf( event.which ) !== -1 ) {
       
   946 			return;
       
   947 		}
       
   948 
       
   949 		// Make Left and Right arrow keys do nothing with vertical tabs.
       
   950 		if ( orientation === 'vertical' && [ 37, 39 ].indexOf( event.which ) !== -1 ) {
       
   951 			return;
       
   952 		}
       
   953 
       
   954 		this.switchTabs( event, this.tabs );
       
   955 	},
       
   956 
       
   957 	/**
       
   958 	 * Switches tabs in the ARIA tabbed interface.
       
   959 	 *
       
   960 	 * @since 5.3.0
       
   961 	 *
       
   962 	 * @param {Object} event jQuery event object.
       
   963 	 *
       
   964 	 * @return {void}
       
   965 	 */
       
   966 	switchTabs: function( event ) {
       
   967 		var key   = event.which,
       
   968 			index = this.tabs.index( $( event.target ) ),
       
   969 			newIndex;
       
   970 
       
   971 		switch ( key ) {
       
   972 			// Space bar: Activate current targeted tab.
       
   973 			case 32: {
       
   974 				this.activateTab( this.tabs[ index ] );
       
   975 				break;
       
   976 			}
       
   977 			// End key: Activate last tab.
       
   978 			case 35: {
       
   979 				event.preventDefault();
       
   980 				this.activateTab( this.tabs[ this.tabs.length - 1 ] );
       
   981 				break;
       
   982 			}
       
   983 			// Home key: Activate first tab.
       
   984 			case 36: {
       
   985 				event.preventDefault();
       
   986 				this.activateTab( this.tabs[ 0 ] );
       
   987 				break;
       
   988 			}
       
   989 			// Left and up keys: Activate previous tab.
       
   990 			case 37:
       
   991 			case 38: {
       
   992 				event.preventDefault();
       
   993 				newIndex = ( index - 1 ) < 0 ? this.tabs.length - 1 : index - 1;
       
   994 				this.activateTab( this.tabs[ newIndex ] );
       
   995 				break;
       
   996 			}
       
   997 			// Right and down keys: Activate next tab.
       
   998 			case 39:
       
   999 			case 40: {
       
  1000 				event.preventDefault();
       
  1001 				newIndex = ( index + 1 ) === this.tabs.length ? 0 : index + 1;
       
  1002 				this.activateTab( this.tabs[ newIndex ] );
       
  1003 				break;
       
  1004 			}
       
  1005 		}
       
  1006 	},
       
  1007 
       
  1008 	/**
       
  1009 	 * Sets a single tab to be focusable and semantically selected.
       
  1010 	 *
       
  1011 	 * @since 5.3.0
       
  1012 	 *
       
  1013 	 * @param {Object} tab The tab DOM element.
       
  1014 	 *
       
  1015 	 * @return {void}
       
  1016 	 */
       
  1017 	activateTab: function( tab ) {
       
  1018 		if ( ! tab ) {
       
  1019 			return;
       
  1020 		}
       
  1021 
       
  1022 		// The tab is a DOM element: no need for jQuery methods.
       
  1023 		tab.focus();
       
  1024 
       
  1025 		// Handle automatic activation.
       
  1026 		if ( this.tabsAutomaticActivation ) {
       
  1027 			tab.removeAttribute( 'tabindex' );
       
  1028 			tab.setAttribute( 'aria-selected', 'true' );
       
  1029 			tab.click();
       
  1030 
       
  1031 			return;
       
  1032 		}
       
  1033 
       
  1034 		// Handle manual activation.
       
  1035 		$( tab ).on( 'click', function() {
       
  1036 			tab.removeAttribute( 'tabindex' );
       
  1037 			tab.setAttribute( 'aria-selected', 'true' );
       
  1038 		} );
       
  1039  	}
       
  1040 });
       
  1041 
       
  1042 module.exports = FocusManager;
       
  1043 
       
  1044 
       
  1045 /***/ }),
       
  1046 
       
  1047 /***/ "4jjk":
       
  1048 /***/ (function(module, exports) {
       
  1049 
       
  1050 var l10n = wp.media.view.l10n,
       
  1051 	Uploaded;
       
  1052 
       
  1053 /**
       
  1054  * wp.media.view.AttachmentFilters.Uploaded
       
  1055  *
       
  1056  * @memberOf wp.media.view.AttachmentFilters
       
  1057  *
       
  1058  * @class
       
  1059  * @augments wp.media.view.AttachmentFilters
       
  1060  * @augments wp.media.View
       
  1061  * @augments wp.Backbone.View
       
  1062  * @augments Backbone.View
       
  1063  */
       
  1064 Uploaded = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Uploaded.prototype */{
       
  1065 	createFilters: function() {
       
  1066 		var type = this.model.get('type'),
       
  1067 			types = wp.media.view.settings.mimeTypes,
       
  1068 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0,
       
  1069 			text;
       
  1070 
       
  1071 		if ( types && type ) {
       
  1072 			text = types[ type ];
       
  1073 		}
       
  1074 
       
  1075 		this.filters = {
       
  1076 			all: {
       
  1077 				text:  text || l10n.allMediaItems,
       
  1078 				props: {
       
  1079 					uploadedTo: null,
       
  1080 					orderby: 'date',
       
  1081 					order:   'DESC',
       
  1082 					author:	 null
       
  1083 				},
       
  1084 				priority: 10
       
  1085 			},
       
  1086 
       
  1087 			uploaded: {
       
  1088 				text:  l10n.uploadedToThisPost,
       
  1089 				props: {
       
  1090 					uploadedTo: wp.media.view.settings.post.id,
       
  1091 					orderby: 'menuOrder',
       
  1092 					order:   'ASC',
       
  1093 					author:	 null
       
  1094 				},
       
  1095 				priority: 20
       
  1096 			},
       
  1097 
       
  1098 			unattached: {
       
  1099 				text:  l10n.unattached,
       
  1100 				props: {
       
  1101 					uploadedTo: 0,
       
  1102 					orderby: 'menuOrder',
       
  1103 					order:   'ASC',
       
  1104 					author:	 null
       
  1105 				},
       
  1106 				priority: 50
       
  1107 			}
       
  1108 		};
       
  1109 
       
  1110 		if ( uid ) {
       
  1111 			this.filters.mine = {
       
  1112 				text:  l10n.mine,
       
  1113 				props: {
       
  1114 					orderby: 'date',
       
  1115 					order:   'DESC',
       
  1116 					author:  uid
       
  1117 				},
       
  1118 				priority: 50
       
  1119 			};
       
  1120 		}
       
  1121 	}
       
  1122 });
       
  1123 
       
  1124 module.exports = Uploaded;
       
  1125 
       
  1126 
       
  1127 /***/ }),
       
  1128 
       
  1129 /***/ "4tHu":
       
  1130 /***/ (function(module, exports) {
       
  1131 
       
  1132 var l10n = wp.media.view.l10n,
       
  1133 	EditImage;
       
  1134 
       
  1135 /**
       
  1136  * wp.media.controller.EditImage
       
  1137  *
       
  1138  * A state for editing (cropping, etc.) an image.
       
  1139  *
       
  1140  * @memberOf wp.media.controller
       
  1141  *
       
  1142  * @class
       
  1143  * @augments wp.media.controller.State
       
  1144  * @augments Backbone.Model
       
  1145  *
       
  1146  * @param {object}                    attributes                      The attributes hash passed to the state.
       
  1147  * @param {wp.media.model.Attachment} attributes.model                The attachment.
       
  1148  * @param {string}                    [attributes.id=edit-image]      Unique identifier.
       
  1149  * @param {string}                    [attributes.title=Edit Image]   Title for the state. Displays in the media menu and the frame's title region.
       
  1150  * @param {string}                    [attributes.content=edit-image] Initial mode for the content region.
       
  1151  * @param {string}                    [attributes.toolbar=edit-image] Initial mode for the toolbar region.
       
  1152  * @param {string}                    [attributes.menu=false]         Initial mode for the menu region.
       
  1153  * @param {string}                    [attributes.url]                Unused. @todo Consider removal.
       
  1154  */
       
  1155 EditImage = wp.media.controller.State.extend(/** @lends wp.media.controller.EditImage.prototype */{
       
  1156 	defaults: {
       
  1157 		id:      'edit-image',
       
  1158 		title:   l10n.editImage,
       
  1159 		menu:    false,
       
  1160 		toolbar: 'edit-image',
       
  1161 		content: 'edit-image',
       
  1162 		url:     ''
       
  1163 	},
       
  1164 
       
  1165 	/**
       
  1166 	 * Activates a frame for editing a featured image.
       
  1167 	 *
       
  1168 	 * @since 3.9.0
       
  1169 	 *
       
  1170 	 * @return {void}
       
  1171 	 */
       
  1172 	activate: function() {
       
  1173 		this.frame.on( 'toolbar:render:edit-image', _.bind( this.toolbar, this ) );
       
  1174 	},
       
  1175 
       
  1176 	/**
       
  1177 	 * Deactivates a frame for editing a featured image.
       
  1178 	 *
       
  1179 	 * @since 3.9.0
       
  1180 	 *
       
  1181 	 * @return {void}
       
  1182 	 */
       
  1183 	deactivate: function() {
       
  1184 		this.frame.off( 'toolbar:render:edit-image' );
       
  1185 	},
       
  1186 
       
  1187 	/**
       
  1188 	 * Adds a toolbar with a back button.
       
  1189 	 *
       
  1190 	 * When the back button is pressed it checks whether there is a previous state.
       
  1191 	 * In case there is a previous state it sets that previous state otherwise it
       
  1192 	 * closes the frame.
       
  1193 	 *
       
  1194 	 * @since 3.9.0
       
  1195 	 *
       
  1196 	 * @return {void}
       
  1197 	 */
       
  1198 	toolbar: function() {
       
  1199 		var frame = this.frame,
       
  1200 			lastState = frame.lastState(),
       
  1201 			previous = lastState && lastState.id;
       
  1202 
       
  1203 		frame.toolbar.set( new wp.media.view.Toolbar({
       
  1204 			controller: frame,
       
  1205 			items: {
       
  1206 				back: {
       
  1207 					style: 'primary',
       
  1208 					text:     l10n.back,
       
  1209 					priority: 20,
       
  1210 					click:    function() {
       
  1211 						if ( previous ) {
       
  1212 							frame.setState( previous );
       
  1213 						} else {
       
  1214 							frame.close();
       
  1215 						}
       
  1216 					}
       
  1217 				}
       
  1218 			}
       
  1219 		}) );
       
  1220 	}
       
  1221 });
       
  1222 
       
  1223 module.exports = EditImage;
       
  1224 
       
  1225 
       
  1226 /***/ }),
       
  1227 
       
  1228 /***/ "6B7g":
       
  1229 /***/ (function(module, exports) {
       
  1230 
       
  1231 var Select = wp.media.view.MediaFrame.Select,
       
  1232 	Library = wp.media.controller.Library,
       
  1233 	l10n = wp.media.view.l10n,
       
  1234 	Post;
       
  1235 
       
  1236 /**
       
  1237  * wp.media.view.MediaFrame.Post
       
  1238  *
       
  1239  * The frame for manipulating media on the Edit Post page.
       
  1240  *
       
  1241  * @memberOf wp.media.view.MediaFrame
       
  1242  *
       
  1243  * @class
       
  1244  * @augments wp.media.view.MediaFrame.Select
       
  1245  * @augments wp.media.view.MediaFrame
       
  1246  * @augments wp.media.view.Frame
       
  1247  * @augments wp.media.View
       
  1248  * @augments wp.Backbone.View
       
  1249  * @augments Backbone.View
       
  1250  * @mixes wp.media.controller.StateMachine
       
  1251  */
       
  1252 Post = Select.extend(/** @lends wp.media.view.MediaFrame.Post.prototype */{
       
  1253 	initialize: function() {
       
  1254 		this.counts = {
       
  1255 			audio: {
       
  1256 				count: wp.media.view.settings.attachmentCounts.audio,
       
  1257 				state: 'playlist'
       
  1258 			},
       
  1259 			video: {
       
  1260 				count: wp.media.view.settings.attachmentCounts.video,
       
  1261 				state: 'video-playlist'
       
  1262 			}
       
  1263 		};
       
  1264 
       
  1265 		_.defaults( this.options, {
       
  1266 			multiple:  true,
       
  1267 			editing:   false,
       
  1268 			state:    'insert',
       
  1269 			metadata:  {}
       
  1270 		});
       
  1271 
       
  1272 		// Call 'initialize' directly on the parent class.
       
  1273 		Select.prototype.initialize.apply( this, arguments );
       
  1274 		this.createIframeStates();
       
  1275 
       
  1276 	},
       
  1277 
       
  1278 	/**
       
  1279 	 * Create the default states.
       
  1280 	 */
       
  1281 	createStates: function() {
       
  1282 		var options = this.options;
       
  1283 
       
  1284 		this.states.add([
       
  1285 			// Main states.
       
  1286 			new Library({
       
  1287 				id:         'insert',
       
  1288 				title:      l10n.insertMediaTitle,
       
  1289 				priority:   20,
       
  1290 				toolbar:    'main-insert',
       
  1291 				filterable: 'all',
       
  1292 				library:    wp.media.query( options.library ),
       
  1293 				multiple:   options.multiple ? 'reset' : false,
       
  1294 				editable:   true,
       
  1295 
       
  1296 				// If the user isn't allowed to edit fields,
       
  1297 				// can they still edit it locally?
       
  1298 				allowLocalEdits: true,
       
  1299 
       
  1300 				// Show the attachment display settings.
       
  1301 				displaySettings: true,
       
  1302 				// Update user settings when users adjust the
       
  1303 				// attachment display settings.
       
  1304 				displayUserSettings: true
       
  1305 			}),
       
  1306 
       
  1307 			new Library({
       
  1308 				id:         'gallery',
       
  1309 				title:      l10n.createGalleryTitle,
       
  1310 				priority:   40,
       
  1311 				toolbar:    'main-gallery',
       
  1312 				filterable: 'uploaded',
       
  1313 				multiple:   'add',
       
  1314 				editable:   false,
       
  1315 
       
  1316 				library:  wp.media.query( _.defaults({
       
  1317 					type: 'image'
       
  1318 				}, options.library ) )
       
  1319 			}),
       
  1320 
       
  1321 			// Embed states.
       
  1322 			new wp.media.controller.Embed( { metadata: options.metadata } ),
       
  1323 
       
  1324 			new wp.media.controller.EditImage( { model: options.editImage } ),
       
  1325 
       
  1326 			// Gallery states.
       
  1327 			new wp.media.controller.GalleryEdit({
       
  1328 				library: options.selection,
       
  1329 				editing: options.editing,
       
  1330 				menu:    'gallery'
       
  1331 			}),
       
  1332 
       
  1333 			new wp.media.controller.GalleryAdd(),
       
  1334 
       
  1335 			new Library({
       
  1336 				id:         'playlist',
       
  1337 				title:      l10n.createPlaylistTitle,
       
  1338 				priority:   60,
       
  1339 				toolbar:    'main-playlist',
       
  1340 				filterable: 'uploaded',
       
  1341 				multiple:   'add',
       
  1342 				editable:   false,
       
  1343 
       
  1344 				library:  wp.media.query( _.defaults({
       
  1345 					type: 'audio'
       
  1346 				}, options.library ) )
       
  1347 			}),
       
  1348 
       
  1349 			// Playlist states.
       
  1350 			new wp.media.controller.CollectionEdit({
       
  1351 				type: 'audio',
       
  1352 				collectionType: 'playlist',
       
  1353 				title:          l10n.editPlaylistTitle,
       
  1354 				SettingsView:   wp.media.view.Settings.Playlist,
       
  1355 				library:        options.selection,
       
  1356 				editing:        options.editing,
       
  1357 				menu:           'playlist',
       
  1358 				dragInfoText:   l10n.playlistDragInfo,
       
  1359 				dragInfo:       false
       
  1360 			}),
       
  1361 
       
  1362 			new wp.media.controller.CollectionAdd({
       
  1363 				type: 'audio',
       
  1364 				collectionType: 'playlist',
       
  1365 				title: l10n.addToPlaylistTitle
       
  1366 			}),
       
  1367 
       
  1368 			new Library({
       
  1369 				id:         'video-playlist',
       
  1370 				title:      l10n.createVideoPlaylistTitle,
       
  1371 				priority:   60,
       
  1372 				toolbar:    'main-video-playlist',
       
  1373 				filterable: 'uploaded',
       
  1374 				multiple:   'add',
       
  1375 				editable:   false,
       
  1376 
       
  1377 				library:  wp.media.query( _.defaults({
       
  1378 					type: 'video'
       
  1379 				}, options.library ) )
       
  1380 			}),
       
  1381 
       
  1382 			new wp.media.controller.CollectionEdit({
       
  1383 				type: 'video',
       
  1384 				collectionType: 'playlist',
       
  1385 				title:          l10n.editVideoPlaylistTitle,
       
  1386 				SettingsView:   wp.media.view.Settings.Playlist,
       
  1387 				library:        options.selection,
       
  1388 				editing:        options.editing,
       
  1389 				menu:           'video-playlist',
       
  1390 				dragInfoText:   l10n.videoPlaylistDragInfo,
       
  1391 				dragInfo:       false
       
  1392 			}),
       
  1393 
       
  1394 			new wp.media.controller.CollectionAdd({
       
  1395 				type: 'video',
       
  1396 				collectionType: 'playlist',
       
  1397 				title: l10n.addToVideoPlaylistTitle
       
  1398 			})
       
  1399 		]);
       
  1400 
       
  1401 		if ( wp.media.view.settings.post.featuredImageId ) {
       
  1402 			this.states.add( new wp.media.controller.FeaturedImage() );
       
  1403 		}
       
  1404 	},
       
  1405 
       
  1406 	bindHandlers: function() {
       
  1407 		var handlers, checkCounts;
       
  1408 
       
  1409 		Select.prototype.bindHandlers.apply( this, arguments );
       
  1410 
       
  1411 		this.on( 'activate', this.activate, this );
       
  1412 
       
  1413 		// Only bother checking media type counts if one of the counts is zero.
       
  1414 		checkCounts = _.find( this.counts, function( type ) {
       
  1415 			return type.count === 0;
       
  1416 		} );
       
  1417 
       
  1418 		if ( typeof checkCounts !== 'undefined' ) {
       
  1419 			this.listenTo( wp.media.model.Attachments.all, 'change:type', this.mediaTypeCounts );
       
  1420 		}
       
  1421 
       
  1422 		this.on( 'menu:create:gallery', this.createMenu, this );
       
  1423 		this.on( 'menu:create:playlist', this.createMenu, this );
       
  1424 		this.on( 'menu:create:video-playlist', this.createMenu, this );
       
  1425 		this.on( 'toolbar:create:main-insert', this.createToolbar, this );
       
  1426 		this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
       
  1427 		this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
       
  1428 		this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
       
  1429 		this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
       
  1430 		this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
       
  1431 
       
  1432 		handlers = {
       
  1433 			menu: {
       
  1434 				'default': 'mainMenu',
       
  1435 				'gallery': 'galleryMenu',
       
  1436 				'playlist': 'playlistMenu',
       
  1437 				'video-playlist': 'videoPlaylistMenu'
       
  1438 			},
       
  1439 
       
  1440 			content: {
       
  1441 				'embed':          'embedContent',
       
  1442 				'edit-image':     'editImageContent',
       
  1443 				'edit-selection': 'editSelectionContent'
       
  1444 			},
       
  1445 
       
  1446 			toolbar: {
       
  1447 				'main-insert':      'mainInsertToolbar',
       
  1448 				'main-gallery':     'mainGalleryToolbar',
       
  1449 				'gallery-edit':     'galleryEditToolbar',
       
  1450 				'gallery-add':      'galleryAddToolbar',
       
  1451 				'main-playlist':	'mainPlaylistToolbar',
       
  1452 				'playlist-edit':	'playlistEditToolbar',
       
  1453 				'playlist-add':		'playlistAddToolbar',
       
  1454 				'main-video-playlist': 'mainVideoPlaylistToolbar',
       
  1455 				'video-playlist-edit': 'videoPlaylistEditToolbar',
       
  1456 				'video-playlist-add': 'videoPlaylistAddToolbar'
       
  1457 			}
       
  1458 		};
       
  1459 
       
  1460 		_.each( handlers, function( regionHandlers, region ) {
       
  1461 			_.each( regionHandlers, function( callback, handler ) {
       
  1462 				this.on( region + ':render:' + handler, this[ callback ], this );
       
  1463 			}, this );
       
  1464 		}, this );
       
  1465 	},
       
  1466 
       
  1467 	activate: function() {
       
  1468 		// Hide menu items for states tied to particular media types if there are no items.
       
  1469 		_.each( this.counts, function( type ) {
       
  1470 			if ( type.count < 1 ) {
       
  1471 				this.menuItemVisibility( type.state, 'hide' );
       
  1472 			}
       
  1473 		}, this );
       
  1474 	},
       
  1475 
       
  1476 	mediaTypeCounts: function( model, attr ) {
       
  1477 		if ( typeof this.counts[ attr ] !== 'undefined' && this.counts[ attr ].count < 1 ) {
       
  1478 			this.counts[ attr ].count++;
       
  1479 			this.menuItemVisibility( this.counts[ attr ].state, 'show' );
       
  1480 		}
       
  1481 	},
       
  1482 
       
  1483 	// Menus.
       
  1484 	/**
       
  1485 	 * @param {wp.Backbone.View} view
       
  1486 	 */
       
  1487 	mainMenu: function( view ) {
       
  1488 		view.set({
       
  1489 			'library-separator': new wp.media.View({
       
  1490 				className:  'separator',
       
  1491 				priority:   100,
       
  1492 				attributes: {
       
  1493 					role: 'presentation'
       
  1494 				}
       
  1495 			})
       
  1496 		});
       
  1497 	},
       
  1498 
       
  1499 	menuItemVisibility: function( state, visibility ) {
       
  1500 		var menu = this.menu.get();
       
  1501 		if ( visibility === 'hide' ) {
       
  1502 			menu.hide( state );
       
  1503 		} else if ( visibility === 'show' ) {
       
  1504 			menu.show( state );
       
  1505 		}
       
  1506 	},
       
  1507 	/**
       
  1508 	 * @param {wp.Backbone.View} view
       
  1509 	 */
       
  1510 	galleryMenu: function( view ) {
       
  1511 		var lastState = this.lastState(),
       
  1512 			previous = lastState && lastState.id,
       
  1513 			frame = this;
       
  1514 
       
  1515 		view.set({
       
  1516 			cancel: {
       
  1517 				text:     l10n.cancelGalleryTitle,
       
  1518 				priority: 20,
       
  1519 				click:    function() {
       
  1520 					if ( previous ) {
       
  1521 						frame.setState( previous );
       
  1522 					} else {
       
  1523 						frame.close();
       
  1524 					}
       
  1525 
       
  1526 					// Move focus to the modal after canceling a Gallery.
       
  1527 					this.controller.modal.focusManager.focus();
       
  1528 				}
       
  1529 			},
       
  1530 			separateCancel: new wp.media.View({
       
  1531 				className: 'separator',
       
  1532 				priority: 40
       
  1533 			})
       
  1534 		});
       
  1535 	},
       
  1536 
       
  1537 	playlistMenu: function( view ) {
       
  1538 		var lastState = this.lastState(),
       
  1539 			previous = lastState && lastState.id,
       
  1540 			frame = this;
       
  1541 
       
  1542 		view.set({
       
  1543 			cancel: {
       
  1544 				text:     l10n.cancelPlaylistTitle,
       
  1545 				priority: 20,
       
  1546 				click:    function() {
       
  1547 					if ( previous ) {
       
  1548 						frame.setState( previous );
       
  1549 					} else {
       
  1550 						frame.close();
       
  1551 					}
       
  1552 
       
  1553 					// Move focus to the modal after canceling an Audio Playlist.
       
  1554 					this.controller.modal.focusManager.focus();
       
  1555 				}
       
  1556 			},
       
  1557 			separateCancel: new wp.media.View({
       
  1558 				className: 'separator',
       
  1559 				priority: 40
       
  1560 			})
       
  1561 		});
       
  1562 	},
       
  1563 
       
  1564 	videoPlaylistMenu: function( view ) {
       
  1565 		var lastState = this.lastState(),
       
  1566 			previous = lastState && lastState.id,
       
  1567 			frame = this;
       
  1568 
       
  1569 		view.set({
       
  1570 			cancel: {
       
  1571 				text:     l10n.cancelVideoPlaylistTitle,
       
  1572 				priority: 20,
       
  1573 				click:    function() {
       
  1574 					if ( previous ) {
       
  1575 						frame.setState( previous );
       
  1576 					} else {
       
  1577 						frame.close();
       
  1578 					}
       
  1579 
       
  1580 					// Move focus to the modal after canceling a Video Playlist.
       
  1581 					this.controller.modal.focusManager.focus();
       
  1582 				}
       
  1583 			},
       
  1584 			separateCancel: new wp.media.View({
       
  1585 				className: 'separator',
       
  1586 				priority: 40
       
  1587 			})
       
  1588 		});
       
  1589 	},
       
  1590 
       
  1591 	// Content.
       
  1592 	embedContent: function() {
       
  1593 		var view = new wp.media.view.Embed({
       
  1594 			controller: this,
       
  1595 			model:      this.state()
       
  1596 		}).render();
       
  1597 
       
  1598 		this.content.set( view );
       
  1599 	},
       
  1600 
       
  1601 	editSelectionContent: function() {
       
  1602 		var state = this.state(),
       
  1603 			selection = state.get('selection'),
       
  1604 			view;
       
  1605 
       
  1606 		view = new wp.media.view.AttachmentsBrowser({
       
  1607 			controller: this,
       
  1608 			collection: selection,
       
  1609 			selection:  selection,
       
  1610 			model:      state,
       
  1611 			sortable:   true,
       
  1612 			search:     false,
       
  1613 			date:       false,
       
  1614 			dragInfo:   true,
       
  1615 
       
  1616 			AttachmentView: wp.media.view.Attachments.EditSelection
       
  1617 		}).render();
       
  1618 
       
  1619 		view.toolbar.set( 'backToLibrary', {
       
  1620 			text:     l10n.returnToLibrary,
       
  1621 			priority: -100,
       
  1622 
       
  1623 			click: function() {
       
  1624 				this.controller.content.mode('browse');
       
  1625 				// Move focus to the modal when jumping back from Edit Selection to Add Media view.
       
  1626 				this.controller.modal.focusManager.focus();
       
  1627 			}
       
  1628 		});
       
  1629 
       
  1630 		// Browse our library of attachments.
       
  1631 		this.content.set( view );
       
  1632 
       
  1633 		// Trigger the controller to set focus.
       
  1634 		this.trigger( 'edit:selection', this );
       
  1635 	},
       
  1636 
       
  1637 	editImageContent: function() {
       
  1638 		var image = this.state().get('image'),
       
  1639 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
       
  1640 
       
  1641 		this.content.set( view );
       
  1642 
       
  1643 		// After creating the wrapper view, load the actual editor via an Ajax call.
       
  1644 		view.loadEditor();
       
  1645 
       
  1646 	},
       
  1647 
       
  1648 	// Toolbars.
       
  1649 
       
  1650 	/**
       
  1651 	 * @param {wp.Backbone.View} view
       
  1652 	 */
       
  1653 	selectionStatusToolbar: function( view ) {
       
  1654 		var editable = this.state().get('editable');
       
  1655 
       
  1656 		view.set( 'selection', new wp.media.view.Selection({
       
  1657 			controller: this,
       
  1658 			collection: this.state().get('selection'),
       
  1659 			priority:   -40,
       
  1660 
       
  1661 			// If the selection is editable, pass the callback to
       
  1662 			// switch the content mode.
       
  1663 			editable: editable && function() {
       
  1664 				this.controller.content.mode('edit-selection');
       
  1665 			}
       
  1666 		}).render() );
       
  1667 	},
       
  1668 
       
  1669 	/**
       
  1670 	 * @param {wp.Backbone.View} view
       
  1671 	 */
       
  1672 	mainInsertToolbar: function( view ) {
       
  1673 		var controller = this;
       
  1674 
       
  1675 		this.selectionStatusToolbar( view );
       
  1676 
       
  1677 		view.set( 'insert', {
       
  1678 			style:    'primary',
       
  1679 			priority: 80,
       
  1680 			text:     l10n.insertIntoPost,
       
  1681 			requires: { selection: true },
       
  1682 
       
  1683 			/**
       
  1684 			 * @ignore
       
  1685 			 *
       
  1686 			 * @fires wp.media.controller.State#insert
       
  1687 			 */
       
  1688 			click: function() {
       
  1689 				var state = controller.state(),
       
  1690 					selection = state.get('selection');
       
  1691 
       
  1692 				controller.close();
       
  1693 				state.trigger( 'insert', selection ).reset();
       
  1694 			}
       
  1695 		});
       
  1696 	},
       
  1697 
       
  1698 	/**
       
  1699 	 * @param {wp.Backbone.View} view
       
  1700 	 */
       
  1701 	mainGalleryToolbar: function( view ) {
       
  1702 		var controller = this;
       
  1703 
       
  1704 		this.selectionStatusToolbar( view );
       
  1705 
       
  1706 		view.set( 'gallery', {
       
  1707 			style:    'primary',
       
  1708 			text:     l10n.createNewGallery,
       
  1709 			priority: 60,
       
  1710 			requires: { selection: true },
       
  1711 
       
  1712 			click: function() {
       
  1713 				var selection = controller.state().get('selection'),
       
  1714 					edit = controller.state('gallery-edit'),
       
  1715 					models = selection.where({ type: 'image' });
       
  1716 
       
  1717 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  1718 					props:    selection.props.toJSON(),
       
  1719 					multiple: true
       
  1720 				}) );
       
  1721 
       
  1722 				// Jump to Edit Gallery view.
       
  1723 				this.controller.setState( 'gallery-edit' );
       
  1724 
       
  1725 				// Move focus to the modal after jumping to Edit Gallery view.
       
  1726 				this.controller.modal.focusManager.focus();
       
  1727 			}
       
  1728 		});
       
  1729 	},
       
  1730 
       
  1731 	mainPlaylistToolbar: function( view ) {
       
  1732 		var controller = this;
       
  1733 
       
  1734 		this.selectionStatusToolbar( view );
       
  1735 
       
  1736 		view.set( 'playlist', {
       
  1737 			style:    'primary',
       
  1738 			text:     l10n.createNewPlaylist,
       
  1739 			priority: 100,
       
  1740 			requires: { selection: true },
       
  1741 
       
  1742 			click: function() {
       
  1743 				var selection = controller.state().get('selection'),
       
  1744 					edit = controller.state('playlist-edit'),
       
  1745 					models = selection.where({ type: 'audio' });
       
  1746 
       
  1747 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  1748 					props:    selection.props.toJSON(),
       
  1749 					multiple: true
       
  1750 				}) );
       
  1751 
       
  1752 				// Jump to Edit Audio Playlist view.
       
  1753 				this.controller.setState( 'playlist-edit' );
       
  1754 
       
  1755 				// Move focus to the modal after jumping to Edit Audio Playlist view.
       
  1756 				this.controller.modal.focusManager.focus();
       
  1757 			}
       
  1758 		});
       
  1759 	},
       
  1760 
       
  1761 	mainVideoPlaylistToolbar: function( view ) {
       
  1762 		var controller = this;
       
  1763 
       
  1764 		this.selectionStatusToolbar( view );
       
  1765 
       
  1766 		view.set( 'video-playlist', {
       
  1767 			style:    'primary',
       
  1768 			text:     l10n.createNewVideoPlaylist,
       
  1769 			priority: 100,
       
  1770 			requires: { selection: true },
       
  1771 
       
  1772 			click: function() {
       
  1773 				var selection = controller.state().get('selection'),
       
  1774 					edit = controller.state('video-playlist-edit'),
       
  1775 					models = selection.where({ type: 'video' });
       
  1776 
       
  1777 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  1778 					props:    selection.props.toJSON(),
       
  1779 					multiple: true
       
  1780 				}) );
       
  1781 
       
  1782 				// Jump to Edit Video Playlist view.
       
  1783 				this.controller.setState( 'video-playlist-edit' );
       
  1784 
       
  1785 				// Move focus to the modal after jumping to Edit Video Playlist view.
       
  1786 				this.controller.modal.focusManager.focus();
       
  1787 			}
       
  1788 		});
       
  1789 	},
       
  1790 
       
  1791 	featuredImageToolbar: function( toolbar ) {
       
  1792 		this.createSelectToolbar( toolbar, {
       
  1793 			text:  l10n.setFeaturedImage,
       
  1794 			state: this.options.state
       
  1795 		});
       
  1796 	},
       
  1797 
       
  1798 	mainEmbedToolbar: function( toolbar ) {
       
  1799 		toolbar.view = new wp.media.view.Toolbar.Embed({
       
  1800 			controller: this
       
  1801 		});
       
  1802 	},
       
  1803 
       
  1804 	galleryEditToolbar: function() {
       
  1805 		var editing = this.state().get('editing');
       
  1806 		this.toolbar.set( new wp.media.view.Toolbar({
       
  1807 			controller: this,
       
  1808 			items: {
       
  1809 				insert: {
       
  1810 					style:    'primary',
       
  1811 					text:     editing ? l10n.updateGallery : l10n.insertGallery,
       
  1812 					priority: 80,
       
  1813 					requires: { library: true },
       
  1814 
       
  1815 					/**
       
  1816 					 * @fires wp.media.controller.State#update
       
  1817 					 */
       
  1818 					click: function() {
       
  1819 						var controller = this.controller,
       
  1820 							state = controller.state();
       
  1821 
       
  1822 						controller.close();
       
  1823 						state.trigger( 'update', state.get('library') );
       
  1824 
       
  1825 						// Restore and reset the default state.
       
  1826 						controller.setState( controller.options.state );
       
  1827 						controller.reset();
       
  1828 					}
       
  1829 				}
       
  1830 			}
       
  1831 		}) );
       
  1832 	},
       
  1833 
       
  1834 	galleryAddToolbar: function() {
       
  1835 		this.toolbar.set( new wp.media.view.Toolbar({
       
  1836 			controller: this,
       
  1837 			items: {
       
  1838 				insert: {
       
  1839 					style:    'primary',
       
  1840 					text:     l10n.addToGallery,
       
  1841 					priority: 80,
       
  1842 					requires: { selection: true },
       
  1843 
       
  1844 					/**
       
  1845 					 * @fires wp.media.controller.State#reset
       
  1846 					 */
       
  1847 					click: function() {
       
  1848 						var controller = this.controller,
       
  1849 							state = controller.state(),
       
  1850 							edit = controller.state('gallery-edit');
       
  1851 
       
  1852 						edit.get('library').add( state.get('selection').models );
       
  1853 						state.trigger('reset');
       
  1854 						controller.setState('gallery-edit');
       
  1855 						// Move focus to the modal when jumping back from Add to Gallery to Edit Gallery view.
       
  1856 						this.controller.modal.focusManager.focus();
       
  1857 					}
       
  1858 				}
       
  1859 			}
       
  1860 		}) );
       
  1861 	},
       
  1862 
       
  1863 	playlistEditToolbar: function() {
       
  1864 		var editing = this.state().get('editing');
       
  1865 		this.toolbar.set( new wp.media.view.Toolbar({
       
  1866 			controller: this,
       
  1867 			items: {
       
  1868 				insert: {
       
  1869 					style:    'primary',
       
  1870 					text:     editing ? l10n.updatePlaylist : l10n.insertPlaylist,
       
  1871 					priority: 80,
       
  1872 					requires: { library: true },
       
  1873 
       
  1874 					/**
       
  1875 					 * @fires wp.media.controller.State#update
       
  1876 					 */
       
  1877 					click: function() {
       
  1878 						var controller = this.controller,
       
  1879 							state = controller.state();
       
  1880 
       
  1881 						controller.close();
       
  1882 						state.trigger( 'update', state.get('library') );
       
  1883 
       
  1884 						// Restore and reset the default state.
       
  1885 						controller.setState( controller.options.state );
       
  1886 						controller.reset();
       
  1887 					}
       
  1888 				}
       
  1889 			}
       
  1890 		}) );
       
  1891 	},
       
  1892 
       
  1893 	playlistAddToolbar: function() {
       
  1894 		this.toolbar.set( new wp.media.view.Toolbar({
       
  1895 			controller: this,
       
  1896 			items: {
       
  1897 				insert: {
       
  1898 					style:    'primary',
       
  1899 					text:     l10n.addToPlaylist,
       
  1900 					priority: 80,
       
  1901 					requires: { selection: true },
       
  1902 
       
  1903 					/**
       
  1904 					 * @fires wp.media.controller.State#reset
       
  1905 					 */
       
  1906 					click: function() {
       
  1907 						var controller = this.controller,
       
  1908 							state = controller.state(),
       
  1909 							edit = controller.state('playlist-edit');
       
  1910 
       
  1911 						edit.get('library').add( state.get('selection').models );
       
  1912 						state.trigger('reset');
       
  1913 						controller.setState('playlist-edit');
       
  1914 						// Move focus to the modal when jumping back from Add to Audio Playlist to Edit Audio Playlist view.
       
  1915 						this.controller.modal.focusManager.focus();
       
  1916 					}
       
  1917 				}
       
  1918 			}
       
  1919 		}) );
       
  1920 	},
       
  1921 
       
  1922 	videoPlaylistEditToolbar: function() {
       
  1923 		var editing = this.state().get('editing');
       
  1924 		this.toolbar.set( new wp.media.view.Toolbar({
       
  1925 			controller: this,
       
  1926 			items: {
       
  1927 				insert: {
       
  1928 					style:    'primary',
       
  1929 					text:     editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
       
  1930 					priority: 140,
       
  1931 					requires: { library: true },
       
  1932 
       
  1933 					click: function() {
       
  1934 						var controller = this.controller,
       
  1935 							state = controller.state(),
       
  1936 							library = state.get('library');
       
  1937 
       
  1938 						library.type = 'video';
       
  1939 
       
  1940 						controller.close();
       
  1941 						state.trigger( 'update', library );
       
  1942 
       
  1943 						// Restore and reset the default state.
       
  1944 						controller.setState( controller.options.state );
       
  1945 						controller.reset();
       
  1946 					}
       
  1947 				}
       
  1948 			}
       
  1949 		}) );
       
  1950 	},
       
  1951 
       
  1952 	videoPlaylistAddToolbar: function() {
       
  1953 		this.toolbar.set( new wp.media.view.Toolbar({
       
  1954 			controller: this,
       
  1955 			items: {
       
  1956 				insert: {
       
  1957 					style:    'primary',
       
  1958 					text:     l10n.addToVideoPlaylist,
       
  1959 					priority: 140,
       
  1960 					requires: { selection: true },
       
  1961 
       
  1962 					click: function() {
       
  1963 						var controller = this.controller,
       
  1964 							state = controller.state(),
       
  1965 							edit = controller.state('video-playlist-edit');
       
  1966 
       
  1967 						edit.get('library').add( state.get('selection').models );
       
  1968 						state.trigger('reset');
       
  1969 						controller.setState('video-playlist-edit');
       
  1970 						// Move focus to the modal when jumping back from Add to Video Playlist to Edit Video Playlist view.
       
  1971 						this.controller.modal.focusManager.focus();
       
  1972 					}
       
  1973 				}
       
  1974 			}
       
  1975 		}) );
       
  1976 	}
       
  1977 });
       
  1978 
       
  1979 module.exports = Post;
       
  1980 
       
  1981 
       
  1982 /***/ }),
       
  1983 
       
  1984 /***/ "72mI":
       
  1985 /***/ (function(module, exports) {
       
  1986 
       
  1987 var View = wp.media.View,
       
  1988 	mediaTrash = wp.media.view.settings.mediaTrash,
       
  1989 	l10n = wp.media.view.l10n,
       
  1990 	$ = jQuery,
       
  1991 	AttachmentsBrowser,
       
  1992 	infiniteScrolling = wp.media.view.settings.infiniteScrolling,
       
  1993 	__ = wp.i18n.__,
       
  1994 	sprintf = wp.i18n.sprintf;
       
  1995 
       
  1996 /**
       
  1997  * wp.media.view.AttachmentsBrowser
       
  1998  *
       
  1999  * @memberOf wp.media.view
       
  2000  *
       
  2001  * @class
       
  2002  * @augments wp.media.View
       
  2003  * @augments wp.Backbone.View
       
  2004  * @augments Backbone.View
       
  2005  *
       
  2006  * @param {object}         [options]               The options hash passed to the view.
       
  2007  * @param {boolean|string} [options.filters=false] Which filters to show in the browser's toolbar.
       
  2008  *                                                 Accepts 'uploaded' and 'all'.
       
  2009  * @param {boolean}        [options.search=true]   Whether to show the search interface in the
       
  2010  *                                                 browser's toolbar.
       
  2011  * @param {boolean}        [options.date=true]     Whether to show the date filter in the
       
  2012  *                                                 browser's toolbar.
       
  2013  * @param {boolean}        [options.display=false] Whether to show the attachments display settings
       
  2014  *                                                 view in the sidebar.
       
  2015  * @param {boolean|string} [options.sidebar=true]  Whether to create a sidebar for the browser.
       
  2016  *                                                 Accepts true, false, and 'errors'.
       
  2017  */
       
  2018 AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.prototype */{
       
  2019 	tagName:   'div',
       
  2020 	className: 'attachments-browser',
       
  2021 
       
  2022 	initialize: function() {
       
  2023 		_.defaults( this.options, {
       
  2024 			filters: false,
       
  2025 			search:  true,
       
  2026 			date:    true,
       
  2027 			display: false,
       
  2028 			sidebar: true,
       
  2029 			AttachmentView: wp.media.view.Attachment.Library
       
  2030 		});
       
  2031 
       
  2032 		this.controller.on( 'toggle:upload:attachment', this.toggleUploader, this );
       
  2033 		this.controller.on( 'edit:selection', this.editSelection );
       
  2034 
       
  2035 		// In the Media Library, the sidebar is used to display errors before the attachments grid.
       
  2036 		if ( this.options.sidebar && 'errors' === this.options.sidebar ) {
       
  2037 			this.createSidebar();
       
  2038 		}
       
  2039 
       
  2040 		/*
       
  2041 		 * In the grid mode (the Media Library), place the Inline Uploader before
       
  2042 		 * other sections so that the visual order and the DOM order match. This way,
       
  2043 		 * the Inline Uploader in the Media Library is right after the "Add New"
       
  2044 		 * button, see ticket #37188.
       
  2045 		 */
       
  2046 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  2047 			this.createUploader();
       
  2048 
       
  2049 			/*
       
  2050 			 * Create a multi-purpose toolbar. Used as main toolbar in the Media Library
       
  2051 			 * and also for other things, for example the "Drag and drop to reorder" and
       
  2052 			 * "Suggested dimensions" info in the media modal.
       
  2053 			 */
       
  2054 			this.createToolbar();
       
  2055 		} else {
       
  2056 			this.createToolbar();
       
  2057 			this.createUploader();
       
  2058 		}
       
  2059 
       
  2060 		// Add a heading before the attachments list.
       
  2061 		this.createAttachmentsHeading();
       
  2062 
       
  2063 		// Create the attachments wrapper view.
       
  2064 		this.createAttachmentsWrapperView();
       
  2065 
       
  2066 		if ( ! infiniteScrolling ) {
       
  2067 			this.$el.addClass( 'has-load-more' );
       
  2068 			this.createLoadMoreView();
       
  2069 		}
       
  2070 
       
  2071 		// For accessibility reasons, place the normal sidebar after the attachments, see ticket #36909.
       
  2072 		if ( this.options.sidebar && 'errors' !== this.options.sidebar ) {
       
  2073 			this.createSidebar();
       
  2074 		}
       
  2075 
       
  2076 		this.updateContent();
       
  2077 
       
  2078 		if ( ! infiniteScrolling ) {
       
  2079 			this.updateLoadMoreView();
       
  2080 		}
       
  2081 
       
  2082 		if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
       
  2083 			this.$el.addClass( 'hide-sidebar' );
       
  2084 
       
  2085 			if ( 'errors' === this.options.sidebar ) {
       
  2086 				this.$el.addClass( 'sidebar-for-errors' );
       
  2087 			}
       
  2088 		}
       
  2089 
       
  2090 		this.collection.on( 'add remove reset', this.updateContent, this );
       
  2091 
       
  2092 		if ( ! infiniteScrolling ) {
       
  2093 			this.collection.on( 'add remove reset', this.updateLoadMoreView, this );
       
  2094 		}
       
  2095 
       
  2096 		// The non-cached or cached attachments query has completed.
       
  2097 		this.collection.on( 'attachments:received', this.announceSearchResults, this );
       
  2098 	},
       
  2099 
       
  2100 	/**
       
  2101 	 * Updates the `wp.a11y.speak()` ARIA live region with a message to communicate
       
  2102 	 * the number of search results to screen reader users. This function is
       
  2103 	 * debounced because the collection updates multiple times.
       
  2104 	 *
       
  2105 	 * @since 5.3.0
       
  2106 	 *
       
  2107 	 * @return {void}
       
  2108 	 */
       
  2109 	announceSearchResults: _.debounce( function() {
       
  2110 		var count,
       
  2111 			/* translators: Accessibility text. %d: Number of attachments found in a search. */
       
  2112 			mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Click load more for more results.' );
       
  2113 
       
  2114 		if ( infiniteScrolling ) {
       
  2115 			/* translators: Accessibility text. %d: Number of attachments found in a search. */
       
  2116 			mediaFoundHasMoreResultsMessage = __( 'Number of media items displayed: %d. Scroll the page for more results.' );
       
  2117 		}
       
  2118 
       
  2119 		if ( this.collection.mirroring.args.s ) {
       
  2120 			count = this.collection.length;
       
  2121 
       
  2122 			if ( 0 === count ) {
       
  2123 				wp.a11y.speak( l10n.noMediaTryNewSearch );
       
  2124 				return;
       
  2125 			}
       
  2126 
       
  2127 			if ( this.collection.hasMore() ) {
       
  2128 				wp.a11y.speak( mediaFoundHasMoreResultsMessage.replace( '%d', count ) );
       
  2129 				return;
       
  2130 			}
       
  2131 
       
  2132 			wp.a11y.speak( l10n.mediaFound.replace( '%d', count ) );
       
  2133 		}
       
  2134 	}, 200 ),
       
  2135 
       
  2136 	editSelection: function( modal ) {
       
  2137 		// When editing a selection, move focus to the "Go to library" button.
       
  2138 		modal.$( '.media-button-backToLibrary' ).focus();
       
  2139 	},
       
  2140 
       
  2141 	/**
       
  2142 	 * @return {wp.media.view.AttachmentsBrowser} Returns itself to allow chaining.
       
  2143 	 */
       
  2144 	dispose: function() {
       
  2145 		this.options.selection.off( null, null, this );
       
  2146 		View.prototype.dispose.apply( this, arguments );
       
  2147 		return this;
       
  2148 	},
       
  2149 
       
  2150 	createToolbar: function() {
       
  2151 		var LibraryViewSwitcher, Filters, toolbarOptions,
       
  2152 			showFilterByType = -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] );
       
  2153 
       
  2154 		toolbarOptions = {
       
  2155 			controller: this.controller
       
  2156 		};
       
  2157 
       
  2158 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  2159 			toolbarOptions.className = 'media-toolbar wp-filter';
       
  2160 		}
       
  2161 
       
  2162 		/**
       
  2163 		* @member {wp.media.view.Toolbar}
       
  2164 		*/
       
  2165 		this.toolbar = new wp.media.view.Toolbar( toolbarOptions );
       
  2166 
       
  2167 		this.views.add( this.toolbar );
       
  2168 
       
  2169 		this.toolbar.set( 'spinner', new wp.media.view.Spinner({
       
  2170 			priority: -20
       
  2171 		}) );
       
  2172 
       
  2173 		if ( showFilterByType || this.options.date ) {
       
  2174 			/*
       
  2175 			 * Create a h2 heading before the select elements that filter attachments.
       
  2176 			 * This heading is visible in the modal and visually hidden in the grid.
       
  2177 			 */
       
  2178 			this.toolbar.set( 'filters-heading', new wp.media.view.Heading( {
       
  2179 				priority:   -100,
       
  2180 				text:       l10n.filterAttachments,
       
  2181 				level:      'h2',
       
  2182 				className:  'media-attachments-filter-heading'
       
  2183 			}).render() );
       
  2184 		}
       
  2185 
       
  2186 		if ( showFilterByType ) {
       
  2187 			// "Filters" is a <select>, a visually hidden label element needs to be rendered before.
       
  2188 			this.toolbar.set( 'filtersLabel', new wp.media.view.Label({
       
  2189 				value: l10n.filterByType,
       
  2190 				attributes: {
       
  2191 					'for':  'media-attachment-filters'
       
  2192 				},
       
  2193 				priority:   -80
       
  2194 			}).render() );
       
  2195 
       
  2196 			if ( 'uploaded' === this.options.filters ) {
       
  2197 				this.toolbar.set( 'filters', new wp.media.view.AttachmentFilters.Uploaded({
       
  2198 					controller: this.controller,
       
  2199 					model:      this.collection.props,
       
  2200 					priority:   -80
       
  2201 				}).render() );
       
  2202 			} else {
       
  2203 				Filters = new wp.media.view.AttachmentFilters.All({
       
  2204 					controller: this.controller,
       
  2205 					model:      this.collection.props,
       
  2206 					priority:   -80
       
  2207 				});
       
  2208 
       
  2209 				this.toolbar.set( 'filters', Filters.render() );
       
  2210 			}
       
  2211 		}
       
  2212 
       
  2213 		/*
       
  2214 		 * Feels odd to bring the global media library switcher into the Attachment browser view.
       
  2215 		 * Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
       
  2216 		 * which the controller can tap into and add this view?
       
  2217 		 */
       
  2218 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  2219 			LibraryViewSwitcher = View.extend({
       
  2220 				className: 'view-switch media-grid-view-switch',
       
  2221 				template: wp.template( 'media-library-view-switcher')
       
  2222 			});
       
  2223 
       
  2224 			this.toolbar.set( 'libraryViewSwitcher', new LibraryViewSwitcher({
       
  2225 				controller: this.controller,
       
  2226 				priority: -90
       
  2227 			}).render() );
       
  2228 
       
  2229 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
       
  2230 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
       
  2231 				value: l10n.filterByDate,
       
  2232 				attributes: {
       
  2233 					'for': 'media-attachment-date-filters'
       
  2234 				},
       
  2235 				priority: -75
       
  2236 			}).render() );
       
  2237 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
       
  2238 				controller: this.controller,
       
  2239 				model:      this.collection.props,
       
  2240 				priority: -75
       
  2241 			}).render() );
       
  2242 
       
  2243 			// BulkSelection is a <div> with subviews, including screen reader text.
       
  2244 			this.toolbar.set( 'selectModeToggleButton', new wp.media.view.SelectModeToggleButton({
       
  2245 				text: l10n.bulkSelect,
       
  2246 				controller: this.controller,
       
  2247 				priority: -70
       
  2248 			}).render() );
       
  2249 
       
  2250 			this.toolbar.set( 'deleteSelectedButton', new wp.media.view.DeleteSelectedButton({
       
  2251 				filters: Filters,
       
  2252 				style: 'primary',
       
  2253 				disabled: true,
       
  2254 				text: mediaTrash ? l10n.trashSelected : l10n.deletePermanently,
       
  2255 				controller: this.controller,
       
  2256 				priority: -80,
       
  2257 				click: function() {
       
  2258 					var changed = [], removed = [],
       
  2259 						selection = this.controller.state().get( 'selection' ),
       
  2260 						library = this.controller.state().get( 'library' );
       
  2261 
       
  2262 					if ( ! selection.length ) {
       
  2263 						return;
       
  2264 					}
       
  2265 
       
  2266 					if ( ! mediaTrash && ! window.confirm( l10n.warnBulkDelete ) ) {
       
  2267 						return;
       
  2268 					}
       
  2269 
       
  2270 					if ( mediaTrash &&
       
  2271 						'trash' !== selection.at( 0 ).get( 'status' ) &&
       
  2272 						! window.confirm( l10n.warnBulkTrash ) ) {
       
  2273 
       
  2274 						return;
       
  2275 					}
       
  2276 
       
  2277 					selection.each( function( model ) {
       
  2278 						if ( ! model.get( 'nonces' )['delete'] ) {
       
  2279 							removed.push( model );
       
  2280 							return;
       
  2281 						}
       
  2282 
       
  2283 						if ( mediaTrash && 'trash' === model.get( 'status' ) ) {
       
  2284 							model.set( 'status', 'inherit' );
       
  2285 							changed.push( model.save() );
       
  2286 							removed.push( model );
       
  2287 						} else if ( mediaTrash ) {
       
  2288 							model.set( 'status', 'trash' );
       
  2289 							changed.push( model.save() );
       
  2290 							removed.push( model );
       
  2291 						} else {
       
  2292 							model.destroy({wait: true});
       
  2293 						}
       
  2294 					} );
       
  2295 
       
  2296 					if ( changed.length ) {
       
  2297 						selection.remove( removed );
       
  2298 
       
  2299 						$.when.apply( null, changed ).then( _.bind( function() {
       
  2300 							library._requery( true );
       
  2301 							this.controller.trigger( 'selection:action:done' );
       
  2302 						}, this ) );
       
  2303 					} else {
       
  2304 						this.controller.trigger( 'selection:action:done' );
       
  2305 					}
       
  2306 				}
       
  2307 			}).render() );
       
  2308 
       
  2309 			if ( mediaTrash ) {
       
  2310 				this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
       
  2311 					filters: Filters,
       
  2312 					style: 'link button-link-delete',
       
  2313 					disabled: true,
       
  2314 					text: l10n.deletePermanently,
       
  2315 					controller: this.controller,
       
  2316 					priority: -55,
       
  2317 					click: function() {
       
  2318 						var removed = [],
       
  2319 							destroy = [],
       
  2320 							selection = this.controller.state().get( 'selection' );
       
  2321 
       
  2322 						if ( ! selection.length || ! window.confirm( l10n.warnBulkDelete ) ) {
       
  2323 							return;
       
  2324 						}
       
  2325 
       
  2326 						selection.each( function( model ) {
       
  2327 							if ( ! model.get( 'nonces' )['delete'] ) {
       
  2328 								removed.push( model );
       
  2329 								return;
       
  2330 							}
       
  2331 
       
  2332 							destroy.push( model );
       
  2333 						} );
       
  2334 
       
  2335 						if ( removed.length ) {
       
  2336 							selection.remove( removed );
       
  2337 						}
       
  2338 
       
  2339 						if ( destroy.length ) {
       
  2340 							$.when.apply( null, destroy.map( function (item) {
       
  2341 								return item.destroy();
       
  2342 							} ) ).then( _.bind( function() {
       
  2343 								this.controller.trigger( 'selection:action:done' );
       
  2344 							}, this ) );
       
  2345 						}
       
  2346 					}
       
  2347 				}).render() );
       
  2348 			}
       
  2349 
       
  2350 		} else if ( this.options.date ) {
       
  2351 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
       
  2352 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
       
  2353 				value: l10n.filterByDate,
       
  2354 				attributes: {
       
  2355 					'for': 'media-attachment-date-filters'
       
  2356 				},
       
  2357 				priority: -75
       
  2358 			}).render() );
       
  2359 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
       
  2360 				controller: this.controller,
       
  2361 				model:      this.collection.props,
       
  2362 				priority: -75
       
  2363 			}).render() );
       
  2364 		}
       
  2365 
       
  2366 		if ( this.options.search ) {
       
  2367 			// Search is an input, a visually hidden label element needs to be rendered before.
       
  2368 			this.toolbar.set( 'searchLabel', new wp.media.view.Label({
       
  2369 				value: l10n.searchLabel,
       
  2370 				className: 'media-search-input-label',
       
  2371 				attributes: {
       
  2372 					'for': 'media-search-input'
       
  2373 				},
       
  2374 				priority:   60
       
  2375 			}).render() );
       
  2376 			this.toolbar.set( 'search', new wp.media.view.Search({
       
  2377 				controller: this.controller,
       
  2378 				model:      this.collection.props,
       
  2379 				priority:   60
       
  2380 			}).render() );
       
  2381 		}
       
  2382 
       
  2383 		if ( this.options.dragInfo ) {
       
  2384 			this.toolbar.set( 'dragInfo', new View({
       
  2385 				el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
       
  2386 				priority: -40
       
  2387 			}) );
       
  2388 		}
       
  2389 
       
  2390 		if ( this.options.suggestedWidth && this.options.suggestedHeight ) {
       
  2391 			this.toolbar.set( 'suggestedDimensions', new View({
       
  2392 				el: $( '<div class="instructions">' + l10n.suggestedDimensions.replace( '%1$s', this.options.suggestedWidth ).replace( '%2$s', this.options.suggestedHeight ) + '</div>' )[0],
       
  2393 				priority: -40
       
  2394 			}) );
       
  2395 		}
       
  2396 	},
       
  2397 
       
  2398 	updateContent: function() {
       
  2399 		var view = this,
       
  2400 			noItemsView;
       
  2401 
       
  2402 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  2403 			// Usually the media library.
       
  2404 			noItemsView = view.attachmentsNoResults;
       
  2405 		} else {
       
  2406 			// Usually the media modal.
       
  2407 			noItemsView = view.uploader;
       
  2408 		}
       
  2409 
       
  2410 		if ( ! this.collection.length ) {
       
  2411 			this.toolbar.get( 'spinner' ).show();
       
  2412 			this.dfd = this.collection.more().done( function() {
       
  2413 				if ( ! view.collection.length ) {
       
  2414 					noItemsView.$el.removeClass( 'hidden' );
       
  2415 				} else {
       
  2416 					noItemsView.$el.addClass( 'hidden' );
       
  2417 				}
       
  2418 				view.toolbar.get( 'spinner' ).hide();
       
  2419 			} );
       
  2420 		} else {
       
  2421 			noItemsView.$el.addClass( 'hidden' );
       
  2422 			view.toolbar.get( 'spinner' ).hide();
       
  2423 		}
       
  2424 	},
       
  2425 
       
  2426 	createUploader: function() {
       
  2427 		this.uploader = new wp.media.view.UploaderInline({
       
  2428 			controller: this.controller,
       
  2429 			status:     false,
       
  2430 			message:    this.controller.isModeActive( 'grid' ) ? '' : l10n.noItemsFound,
       
  2431 			canClose:   this.controller.isModeActive( 'grid' )
       
  2432 		});
       
  2433 
       
  2434 		this.uploader.$el.addClass( 'hidden' );
       
  2435 		this.views.add( this.uploader );
       
  2436 	},
       
  2437 
       
  2438 	toggleUploader: function() {
       
  2439 		if ( this.uploader.$el.hasClass( 'hidden' ) ) {
       
  2440 			this.uploader.show();
       
  2441 		} else {
       
  2442 			this.uploader.hide();
       
  2443 		}
       
  2444 	},
       
  2445 
       
  2446 	/**
       
  2447 	 * Creates the Attachments wrapper view.
       
  2448 	 *
       
  2449 	 * @since 5.8.0
       
  2450 	 *
       
  2451 	 * @return {void}
       
  2452 	 */
       
  2453 	createAttachmentsWrapperView: function() {
       
  2454 		this.attachmentsWrapper = new wp.media.View( {
       
  2455 			className: 'attachments-wrapper'
       
  2456 		} );
       
  2457 
       
  2458 		// Create the list of attachments.
       
  2459 		this.views.add( this.attachmentsWrapper );
       
  2460 		this.createAttachments();
       
  2461 	},
       
  2462 
       
  2463 	createAttachments: function() {
       
  2464 		this.attachments = new wp.media.view.Attachments({
       
  2465 			controller:           this.controller,
       
  2466 			collection:           this.collection,
       
  2467 			selection:            this.options.selection,
       
  2468 			model:                this.model,
       
  2469 			sortable:             this.options.sortable,
       
  2470 			scrollElement:        this.options.scrollElement,
       
  2471 			idealColumnWidth:     this.options.idealColumnWidth,
       
  2472 
       
  2473 			// The single `Attachment` view to be used in the `Attachments` view.
       
  2474 			AttachmentView: this.options.AttachmentView
       
  2475 		});
       
  2476 
       
  2477 		// Add keydown listener to the instance of the Attachments view.
       
  2478 		this.controller.on( 'attachment:keydown:arrow',     _.bind( this.attachments.arrowEvent, this.attachments ) );
       
  2479 		this.controller.on( 'attachment:details:shift-tab', _.bind( this.attachments.restoreFocus, this.attachments ) );
       
  2480 
       
  2481 		this.views.add( '.attachments-wrapper', this.attachments );
       
  2482 
       
  2483 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  2484 			this.attachmentsNoResults = new View({
       
  2485 				controller: this.controller,
       
  2486 				tagName: 'p'
       
  2487 			});
       
  2488 
       
  2489 			this.attachmentsNoResults.$el.addClass( 'hidden no-media' );
       
  2490 			this.attachmentsNoResults.$el.html( l10n.noMedia );
       
  2491 
       
  2492 			this.views.add( this.attachmentsNoResults );
       
  2493 		}
       
  2494 	},
       
  2495 
       
  2496 	/**
       
  2497 	 * Creates the load more button and attachments counter view.
       
  2498 	 *
       
  2499 	 * @since 5.8.0
       
  2500 	 *
       
  2501 	 * @return {void}
       
  2502 	 */
       
  2503 	createLoadMoreView: function() {
       
  2504 		var view = this;
       
  2505 
       
  2506 		this.loadMoreWrapper = new View( {
       
  2507 			controller: this.controller,
       
  2508 			className: 'load-more-wrapper'
       
  2509 		} );
       
  2510 
       
  2511 		this.loadMoreCount = new View( {
       
  2512 			controller: this.controller,
       
  2513 			tagName: 'p',
       
  2514 			className: 'load-more-count hidden'
       
  2515 		} );
       
  2516 
       
  2517 		this.loadMoreButton = new wp.media.view.Button( {
       
  2518 			text: __( 'Load more' ),
       
  2519 			className: 'load-more hidden',
       
  2520 			style: 'primary',
       
  2521 			size: '',
       
  2522 			click: function() {
       
  2523 				view.loadMoreAttachments();
       
  2524 			}
       
  2525 		} );
       
  2526 
       
  2527 		this.loadMoreSpinner = new wp.media.view.Spinner();
       
  2528 
       
  2529 		this.loadMoreJumpToFirst = new wp.media.view.Button( {
       
  2530 			text: __( 'Jump to first loaded item' ),
       
  2531 			className: 'load-more-jump hidden',
       
  2532 			size: '',
       
  2533 			click: function() {
       
  2534 				view.jumpToFirstAddedItem();
       
  2535 			}
       
  2536 		} );
       
  2537 
       
  2538 		this.views.add( '.attachments-wrapper', this.loadMoreWrapper );
       
  2539 		this.views.add( '.load-more-wrapper', this.loadMoreSpinner );
       
  2540 		this.views.add( '.load-more-wrapper', this.loadMoreCount );
       
  2541 		this.views.add( '.load-more-wrapper', this.loadMoreButton );
       
  2542 		this.views.add( '.load-more-wrapper', this.loadMoreJumpToFirst );
       
  2543 	},
       
  2544 
       
  2545 	/**
       
  2546 	 * Updates the Load More view. This function is debounced because the
       
  2547 	 * collection updates multiple times at the add, remove, and reset events.
       
  2548 	 * We need it to run only once, after all attachments are added or removed.
       
  2549 	 *
       
  2550 	 * @since 5.8.0
       
  2551 	 *
       
  2552 	 * @return {void}
       
  2553 	 */
       
  2554 	updateLoadMoreView: _.debounce( function() {
       
  2555 		// Ensure the load more view elements are initially hidden at each update.
       
  2556 		this.loadMoreButton.$el.addClass( 'hidden' );
       
  2557 		this.loadMoreCount.$el.addClass( 'hidden' );
       
  2558 		this.loadMoreJumpToFirst.$el.addClass( 'hidden' ).prop( 'disabled', true );
       
  2559 
       
  2560 		if ( ! this.collection.getTotalAttachments() ) {
       
  2561 			return;
       
  2562 		}
       
  2563 
       
  2564 		if ( this.collection.length ) {
       
  2565 			this.loadMoreCount.$el.text(
       
  2566 				/* translators: 1: Number of displayed attachments, 2: Number of total attachments. */
       
  2567 				sprintf(
       
  2568 					__( 'Showing %1$s of %2$s media items' ),
       
  2569 					this.collection.length,
       
  2570 					this.collection.getTotalAttachments()
       
  2571 				)
       
  2572 			);
       
  2573 
       
  2574 			this.loadMoreCount.$el.removeClass( 'hidden' );
       
  2575 		}
       
  2576 
       
  2577 		/*
       
  2578 		 * Notice that while the collection updates multiple times hasMore() may
       
  2579 		 * return true when it's actually not true.
       
  2580 		 */
       
  2581 		if ( this.collection.hasMore() ) {
       
  2582 			this.loadMoreButton.$el.removeClass( 'hidden' );
       
  2583 		}
       
  2584 
       
  2585 		// Find the media item to move focus to. The jQuery `eq()` index is zero-based.
       
  2586 		this.firstAddedMediaItem = this.$el.find( '.attachment' ).eq( this.firstAddedMediaItemIndex );
       
  2587 
       
  2588 		// If there's a media item to move focus to, make the "Jump to" button available.
       
  2589 		if ( this.firstAddedMediaItem.length ) {
       
  2590 			this.firstAddedMediaItem.addClass( 'new-media' );
       
  2591 			this.loadMoreJumpToFirst.$el.removeClass( 'hidden' ).prop( 'disabled', false );
       
  2592 		}
       
  2593 
       
  2594 		// If there are new items added, but no more to be added, move focus to Jump button.
       
  2595 		if ( this.firstAddedMediaItem.length && ! this.collection.hasMore() ) {
       
  2596 			this.loadMoreJumpToFirst.$el.trigger( 'focus' );
       
  2597 		}
       
  2598 	}, 10 ),
       
  2599 
       
  2600 	/**
       
  2601 	 * Loads more attachments.
       
  2602 	 *
       
  2603 	 * @since 5.8.0
       
  2604 	 *
       
  2605 	 * @return {void}
       
  2606 	 */
       
  2607 	loadMoreAttachments: function() {
       
  2608 		var view = this;
       
  2609 
       
  2610 		if ( ! this.collection.hasMore() ) {
       
  2611 			return;
       
  2612 		}
       
  2613 
       
  2614 		/*
       
  2615 		 * The collection index is zero-based while the length counts the actual
       
  2616 		 * amount of items. Thus the length is equivalent to the position of the
       
  2617 		 * first added item.
       
  2618 		 */
       
  2619 		this.firstAddedMediaItemIndex = this.collection.length;
       
  2620 
       
  2621 		this.$el.addClass( 'more-loaded' );
       
  2622 		this.collection.each( function( attachment ) {
       
  2623 			var attach_id = attachment.attributes.id;
       
  2624 			$( '[data-id="' + attach_id + '"]' ).addClass( 'found-media' );
       
  2625 		});
       
  2626 
       
  2627 		view.loadMoreSpinner.show();
       
  2628 		this.collection.once( 'attachments:received', function() {
       
  2629 			view.loadMoreSpinner.hide();
       
  2630 		} );
       
  2631 		this.collection.more();
       
  2632 	},
       
  2633 
       
  2634 	/**
       
  2635 	 * Moves focus to the first new added item.	.
       
  2636 	 *
       
  2637 	 * @since 5.8.0
       
  2638 	 *
       
  2639 	 * @return {void}
       
  2640 	 */
       
  2641 	jumpToFirstAddedItem: function() {
       
  2642 		// Set focus on first added item.
       
  2643 		this.firstAddedMediaItem.focus();
       
  2644 	},
       
  2645 
       
  2646 	createAttachmentsHeading: function() {
       
  2647 		this.attachmentsHeading = new wp.media.view.Heading( {
       
  2648 			text: l10n.attachmentsList,
       
  2649 			level: 'h2',
       
  2650 			className: 'media-views-heading screen-reader-text'
       
  2651 		} );
       
  2652 		this.views.add( this.attachmentsHeading );
       
  2653 	},
       
  2654 
       
  2655 	createSidebar: function() {
       
  2656 		var options = this.options,
       
  2657 			selection = options.selection,
       
  2658 			sidebar = this.sidebar = new wp.media.view.Sidebar({
       
  2659 				controller: this.controller
       
  2660 			});
       
  2661 
       
  2662 		this.views.add( sidebar );
       
  2663 
       
  2664 		if ( this.controller.uploader ) {
       
  2665 			sidebar.set( 'uploads', new wp.media.view.UploaderStatus({
       
  2666 				controller: this.controller,
       
  2667 				priority:   40
       
  2668 			}) );
       
  2669 		}
       
  2670 
       
  2671 		selection.on( 'selection:single', this.createSingle, this );
       
  2672 		selection.on( 'selection:unsingle', this.disposeSingle, this );
       
  2673 
       
  2674 		if ( selection.single() ) {
       
  2675 			this.createSingle();
       
  2676 		}
       
  2677 	},
       
  2678 
       
  2679 	createSingle: function() {
       
  2680 		var sidebar = this.sidebar,
       
  2681 			single = this.options.selection.single();
       
  2682 
       
  2683 		sidebar.set( 'details', new wp.media.view.Attachment.Details({
       
  2684 			controller: this.controller,
       
  2685 			model:      single,
       
  2686 			priority:   80
       
  2687 		}) );
       
  2688 
       
  2689 		sidebar.set( 'compat', new wp.media.view.AttachmentCompat({
       
  2690 			controller: this.controller,
       
  2691 			model:      single,
       
  2692 			priority:   120
       
  2693 		}) );
       
  2694 
       
  2695 		if ( this.options.display ) {
       
  2696 			sidebar.set( 'display', new wp.media.view.Settings.AttachmentDisplay({
       
  2697 				controller:   this.controller,
       
  2698 				model:        this.model.display( single ),
       
  2699 				attachment:   single,
       
  2700 				priority:     160,
       
  2701 				userSettings: this.model.get('displayUserSettings')
       
  2702 			}) );
       
  2703 		}
       
  2704 
       
  2705 		// Show the sidebar on mobile.
       
  2706 		if ( this.model.id === 'insert' ) {
       
  2707 			sidebar.$el.addClass( 'visible' );
       
  2708 		}
       
  2709 	},
       
  2710 
       
  2711 	disposeSingle: function() {
       
  2712 		var sidebar = this.sidebar;
       
  2713 		sidebar.unset('details');
       
  2714 		sidebar.unset('compat');
       
  2715 		sidebar.unset('display');
       
  2716 		// Hide the sidebar on mobile.
       
  2717 		sidebar.$el.removeClass( 'visible' );
       
  2718 	}
       
  2719 });
       
  2720 
       
  2721 module.exports = AttachmentsBrowser;
       
  2722 
       
  2723 
       
  2724 /***/ }),
       
  2725 
       
  2726 /***/ "76BF":
       
  2727 /***/ (function(module, exports) {
       
  2728 
       
  2729 /**
       
  2730  * wp.media.view.Settings.Playlist
       
  2731  *
       
  2732  * @memberOf wp.media.view.Settings
       
  2733  *
       
  2734  * @class
       
  2735  * @augments wp.media.view.Settings
       
  2736  * @augments wp.media.View
       
  2737  * @augments wp.Backbone.View
       
  2738  * @augments Backbone.View
       
  2739  */
       
  2740 var Playlist = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Playlist.prototype */{
       
  2741 	className: 'collection-settings playlist-settings',
       
  2742 	template:  wp.template('playlist-settings')
       
  2743 });
       
  2744 
       
  2745 module.exports = Playlist;
       
  2746 
       
  2747 
       
  2748 /***/ }),
       
  2749 
       
  2750 /***/ "7Bpz":
       
  2751 /***/ (function(module, exports) {
       
  2752 
       
  2753 var View = wp.media.View,
       
  2754 	UploaderInline;
       
  2755 
       
  2756 /**
       
  2757  * wp.media.view.UploaderInline
       
  2758  *
       
  2759  * The inline uploader that shows up in the 'Upload Files' tab.
       
  2760  *
       
  2761  * @memberOf wp.media.view
       
  2762  *
       
  2763  * @class
       
  2764  * @augments wp.media.View
       
  2765  * @augments wp.Backbone.View
       
  2766  * @augments Backbone.View
       
  2767  */
       
  2768 UploaderInline = View.extend(/** @lends wp.media.view.UploaderInline.prototype */{
       
  2769 	tagName:   'div',
       
  2770 	className: 'uploader-inline',
       
  2771 	template:  wp.template('uploader-inline'),
       
  2772 
       
  2773 	events: {
       
  2774 		'click .close': 'hide'
       
  2775 	},
       
  2776 
       
  2777 	initialize: function() {
       
  2778 		_.defaults( this.options, {
       
  2779 			message: '',
       
  2780 			status:  true,
       
  2781 			canClose: false
       
  2782 		});
       
  2783 
       
  2784 		if ( ! this.options.$browser && this.controller.uploader ) {
       
  2785 			this.options.$browser = this.controller.uploader.$browser;
       
  2786 		}
       
  2787 
       
  2788 		if ( _.isUndefined( this.options.postId ) ) {
       
  2789 			this.options.postId = wp.media.view.settings.post.id;
       
  2790 		}
       
  2791 
       
  2792 		if ( this.options.status ) {
       
  2793 			this.views.set( '.upload-inline-status', new wp.media.view.UploaderStatus({
       
  2794 				controller: this.controller
       
  2795 			}) );
       
  2796 		}
       
  2797 	},
       
  2798 
       
  2799 	prepare: function() {
       
  2800 		var suggestedWidth = this.controller.state().get('suggestedWidth'),
       
  2801 			suggestedHeight = this.controller.state().get('suggestedHeight'),
       
  2802 			data = {};
       
  2803 
       
  2804 		data.message = this.options.message;
       
  2805 		data.canClose = this.options.canClose;
       
  2806 
       
  2807 		if ( suggestedWidth && suggestedHeight ) {
       
  2808 			data.suggestedWidth = suggestedWidth;
       
  2809 			data.suggestedHeight = suggestedHeight;
       
  2810 		}
       
  2811 
       
  2812 		return data;
       
  2813 	},
       
  2814 	/**
       
  2815 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
       
  2816 	 */
       
  2817 	dispose: function() {
       
  2818 		if ( this.disposing ) {
       
  2819 			/**
       
  2820 			 * call 'dispose' directly on the parent class
       
  2821 			 */
       
  2822 			return View.prototype.dispose.apply( this, arguments );
       
  2823 		}
       
  2824 
       
  2825 		/*
       
  2826 		 * Run remove on `dispose`, so we can be sure to refresh the
       
  2827 		 * uploader with a view-less DOM. Track whether we're disposing
       
  2828 		 * so we don't trigger an infinite loop.
       
  2829 		 */
       
  2830 		this.disposing = true;
       
  2831 		return this.remove();
       
  2832 	},
       
  2833 	/**
       
  2834 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
       
  2835 	 */
       
  2836 	remove: function() {
       
  2837 		/**
       
  2838 		 * call 'remove' directly on the parent class
       
  2839 		 */
       
  2840 		var result = View.prototype.remove.apply( this, arguments );
       
  2841 
       
  2842 		_.defer( _.bind( this.refresh, this ) );
       
  2843 		return result;
       
  2844 	},
       
  2845 
       
  2846 	refresh: function() {
       
  2847 		var uploader = this.controller.uploader;
       
  2848 
       
  2849 		if ( uploader ) {
       
  2850 			uploader.refresh();
       
  2851 		}
       
  2852 	},
       
  2853 	/**
       
  2854 	 * @return {wp.media.view.UploaderInline}
       
  2855 	 */
       
  2856 	ready: function() {
       
  2857 		var $browser = this.options.$browser,
       
  2858 			$placeholder;
       
  2859 
       
  2860 		if ( this.controller.uploader ) {
       
  2861 			$placeholder = this.$('.browser');
       
  2862 
       
  2863 			// Check if we've already replaced the placeholder.
       
  2864 			if ( $placeholder[0] === $browser[0] ) {
       
  2865 				return;
       
  2866 			}
       
  2867 
       
  2868 			$browser.detach().text( $placeholder.text() );
       
  2869 			$browser[0].className = $placeholder[0].className;
       
  2870 			$browser[0].setAttribute( 'aria-labelledby', $browser[0].id + ' ' + $placeholder[0].getAttribute('aria-labelledby') );
       
  2871 			$placeholder.replaceWith( $browser.show() );
       
  2872 		}
       
  2873 
       
  2874 		this.refresh();
       
  2875 		return this;
       
  2876 	},
       
  2877 	show: function() {
       
  2878 		this.$el.removeClass( 'hidden' );
       
  2879 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
       
  2880 			this.controller.$uploaderToggler.attr( 'aria-expanded', 'true' );
       
  2881 		}
       
  2882 	},
       
  2883 	hide: function() {
       
  2884 		this.$el.addClass( 'hidden' );
       
  2885 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
       
  2886 			this.controller.$uploaderToggler
       
  2887 				.attr( 'aria-expanded', 'false' )
       
  2888 				// Move focus back to the toggle button when closing the uploader.
       
  2889 				.trigger( 'focus' );
       
  2890 		}
       
  2891 	}
       
  2892 
       
  2893 });
       
  2894 
       
  2895 module.exports = UploaderInline;
       
  2896 
       
  2897 
       
  2898 /***/ }),
       
  2899 
       
  2900 /***/ "99yY":
       
  2901 /***/ (function(module, exports) {
       
  2902 
       
  2903 var Library = wp.media.controller.Library,
       
  2904 	l10n = wp.media.view.l10n,
       
  2905 	GalleryEdit;
       
  2906 
       
  2907 /**
       
  2908  * wp.media.controller.GalleryEdit
       
  2909  *
       
  2910  * A state for editing a gallery's images and settings.
       
  2911  *
       
  2912  * @since 3.5.0
       
  2913  *
       
  2914  * @class
       
  2915  * @augments wp.media.controller.Library
       
  2916  * @augments wp.media.controller.State
       
  2917  * @augments Backbone.Model
       
  2918  *
       
  2919  * @memberOf wp.media.controller
       
  2920  *
       
  2921  * @param {Object}                     [attributes]                       The attributes hash passed to the state.
       
  2922  * @param {string}                     [attributes.id=gallery-edit]       Unique identifier.
       
  2923  * @param {string}                     [attributes.title=Edit Gallery]    Title for the state. Displays in the frame's title region.
       
  2924  * @param {wp.media.model.Attachments} [attributes.library]               The collection of attachments in the gallery.
       
  2925  *                                                                        If one is not supplied, an empty media.model.Selection collection is created.
       
  2926  * @param {boolean}                    [attributes.multiple=false]        Whether multi-select is enabled.
       
  2927  * @param {boolean}                    [attributes.searchable=false]      Whether the library is searchable.
       
  2928  * @param {boolean}                    [attributes.sortable=true]         Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  2929  * @param {boolean}                    [attributes.date=true]             Whether to show the date filter in the browser's toolbar.
       
  2930  * @param {string|false}               [attributes.content=browse]        Initial mode for the content region.
       
  2931  * @param {string|false}               [attributes.toolbar=image-details] Initial mode for the toolbar region.
       
  2932  * @param {boolean}                    [attributes.describe=true]         Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
       
  2933  * @param {boolean}                    [attributes.displaySettings=true]  Whether to show the attachment display settings interface.
       
  2934  * @param {boolean}                    [attributes.dragInfo=true]         Whether to show instructional text about the attachments being sortable.
       
  2935  * @param {number}                     [attributes.idealColumnWidth=170]  The ideal column width in pixels for attachments.
       
  2936  * @param {boolean}                    [attributes.editing=false]         Whether the gallery is being created, or editing an existing instance.
       
  2937  * @param {number}                     [attributes.priority=60]           The priority for the state link in the media menu.
       
  2938  * @param {boolean}                    [attributes.syncSelection=false]   Whether the Attachments selection should be persisted from the last state.
       
  2939  *                                                                        Defaults to false for this state, because the library passed in  *is* the selection.
       
  2940  * @param {view}                       [attributes.AttachmentView]        The single `Attachment` view to be used in the `Attachments`.
       
  2941  *                                                                        If none supplied, defaults to wp.media.view.Attachment.EditLibrary.
       
  2942  */
       
  2943 GalleryEdit = Library.extend(/** @lends wp.media.controller.GalleryEdit.prototype */{
       
  2944 	defaults: {
       
  2945 		id:               'gallery-edit',
       
  2946 		title:            l10n.editGalleryTitle,
       
  2947 		multiple:         false,
       
  2948 		searchable:       false,
       
  2949 		sortable:         true,
       
  2950 		date:             false,
       
  2951 		display:          false,
       
  2952 		content:          'browse',
       
  2953 		toolbar:          'gallery-edit',
       
  2954 		describe:         true,
       
  2955 		displaySettings:  true,
       
  2956 		dragInfo:         true,
       
  2957 		idealColumnWidth: 170,
       
  2958 		editing:          false,
       
  2959 		priority:         60,
       
  2960 		syncSelection:    false
       
  2961 	},
       
  2962 
       
  2963 	/**
       
  2964 	 * Initializes the library.
       
  2965 	 *
       
  2966 	 * Creates a selection if a library isn't supplied and creates an attachment
       
  2967 	 * view if no attachment view is supplied.
       
  2968 	 *
       
  2969 	 * @since 3.5.0
       
  2970 	 *
       
  2971 	 * @return {void}
       
  2972 	 */
       
  2973 	initialize: function() {
       
  2974 		// If we haven't been provided a `library`, create a `Selection`.
       
  2975 		if ( ! this.get('library') ) {
       
  2976 			this.set( 'library', new wp.media.model.Selection() );
       
  2977 		}
       
  2978 
       
  2979 		// The single `Attachment` view to be used in the `Attachments` view.
       
  2980 		if ( ! this.get('AttachmentView') ) {
       
  2981 			this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );
       
  2982 		}
       
  2983 
       
  2984 		Library.prototype.initialize.apply( this, arguments );
       
  2985 	},
       
  2986 
       
  2987 	/**
       
  2988 	 * Activates the library.
       
  2989 	 *
       
  2990 	 * Limits the library to images, watches for uploaded attachments. Watches for
       
  2991 	 * the browse event on the frame and binds it to gallerySettings.
       
  2992 	 *
       
  2993 	 * @since 3.5.0
       
  2994 	 *
       
  2995 	 * @return {void}
       
  2996 	 */
       
  2997 	activate: function() {
       
  2998 		var library = this.get('library');
       
  2999 
       
  3000 		// Limit the library to images only.
       
  3001 		library.props.set( 'type', 'image' );
       
  3002 
       
  3003 		// Watch for uploaded attachments.
       
  3004 		this.get('library').observe( wp.Uploader.queue );
       
  3005 
       
  3006 		this.frame.on( 'content:render:browse', this.gallerySettings, this );
       
  3007 
       
  3008 		Library.prototype.activate.apply( this, arguments );
       
  3009 	},
       
  3010 
       
  3011 	/**
       
  3012 	 * Deactivates the library.
       
  3013 	 *
       
  3014 	 * Stops watching for uploaded attachments and browse events.
       
  3015 	 *
       
  3016 	 * @since 3.5.0
       
  3017 	 *
       
  3018 	 * @return {void}
       
  3019 	 */
       
  3020 	deactivate: function() {
       
  3021 		// Stop watching for uploaded attachments.
       
  3022 		this.get('library').unobserve( wp.Uploader.queue );
       
  3023 
       
  3024 		this.frame.off( 'content:render:browse', this.gallerySettings, this );
       
  3025 
       
  3026 		Library.prototype.deactivate.apply( this, arguments );
       
  3027 	},
       
  3028 
       
  3029 	/**
       
  3030 	 * Adds the gallery settings to the sidebar and adds a reverse button to the
       
  3031 	 * toolbar.
       
  3032 	 *
       
  3033 	 * @since 3.5.0
       
  3034 	 *
       
  3035 	 * @param {wp.media.view.Frame} browser The file browser.
       
  3036 	 *
       
  3037 	 * @return {void}
       
  3038 	 */
       
  3039 	gallerySettings: function( browser ) {
       
  3040 		if ( ! this.get('displaySettings') ) {
       
  3041 			return;
       
  3042 		}
       
  3043 
       
  3044 		var library = this.get('library');
       
  3045 
       
  3046 		if ( ! library || ! browser ) {
       
  3047 			return;
       
  3048 		}
       
  3049 
       
  3050 		library.gallery = library.gallery || new Backbone.Model();
       
  3051 
       
  3052 		browser.sidebar.set({
       
  3053 			gallery: new wp.media.view.Settings.Gallery({
       
  3054 				controller: this,
       
  3055 				model:      library.gallery,
       
  3056 				priority:   40
       
  3057 			})
       
  3058 		});
       
  3059 
       
  3060 		browser.toolbar.set( 'reverse', {
       
  3061 			text:     l10n.reverseOrder,
       
  3062 			priority: 80,
       
  3063 
       
  3064 			click: function() {
       
  3065 				library.reset( library.toArray().reverse() );
       
  3066 			}
       
  3067 		});
       
  3068 	}
       
  3069 });
       
  3070 
       
  3071 module.exports = GalleryEdit;
       
  3072 
       
  3073 
       
  3074 /***/ }),
       
  3075 
       
  3076 /***/ "9ARG":
       
  3077 /***/ (function(module, exports) {
       
  3078 
       
  3079 /**
       
  3080  * wp.media.view.Sidebar
       
  3081  *
       
  3082  * @memberOf wp.media.view
       
  3083  *
       
  3084  * @class
       
  3085  * @augments wp.media.view.PriorityList
       
  3086  * @augments wp.media.View
       
  3087  * @augments wp.Backbone.View
       
  3088  * @augments Backbone.View
       
  3089  */
       
  3090 var Sidebar = wp.media.view.PriorityList.extend(/** @lends wp.media.view.Sidebar.prototype */{
       
  3091 	className: 'media-sidebar'
       
  3092 });
       
  3093 
       
  3094 module.exports = Sidebar;
       
  3095 
       
  3096 
       
  3097 /***/ }),
       
  3098 
       
  3099 /***/ "Bbnu":
       
  3100 /***/ (function(module, exports) {
       
  3101 
       
  3102 /**
       
  3103  * wp.media.View
       
  3104  *
       
  3105  * The base view class for media.
       
  3106  *
       
  3107  * Undelegating events, removing events from the model, and
       
  3108  * removing events from the controller mirror the code for
       
  3109  * `Backbone.View.dispose` in Backbone 0.9.8 development.
       
  3110  *
       
  3111  * This behavior has since been removed, and should not be used
       
  3112  * outside of the media manager.
       
  3113  *
       
  3114  * @memberOf wp.media
       
  3115  *
       
  3116  * @class
       
  3117  * @augments wp.Backbone.View
       
  3118  * @augments Backbone.View
       
  3119  */
       
  3120 var View = wp.Backbone.View.extend(/** @lends wp.media.View.prototype */{
       
  3121 	constructor: function( options ) {
       
  3122 		if ( options && options.controller ) {
       
  3123 			this.controller = options.controller;
       
  3124 		}
       
  3125 		wp.Backbone.View.apply( this, arguments );
       
  3126 	},
       
  3127 	/**
       
  3128 	 * @todo The internal comment mentions this might have been a stop-gap
       
  3129 	 *       before Backbone 0.9.8 came out. Figure out if Backbone core takes
       
  3130 	 *       care of this in Backbone.View now.
       
  3131 	 *
       
  3132 	 * @return {wp.media.View} Returns itself to allow chaining.
       
  3133 	 */
       
  3134 	dispose: function() {
       
  3135 		/*
       
  3136 		 * Undelegating events, removing events from the model, and
       
  3137 		 * removing events from the controller mirror the code for
       
  3138 		 * `Backbone.View.dispose` in Backbone 0.9.8 development.
       
  3139 		 */
       
  3140 		this.undelegateEvents();
       
  3141 
       
  3142 		if ( this.model && this.model.off ) {
       
  3143 			this.model.off( null, null, this );
       
  3144 		}
       
  3145 
       
  3146 		if ( this.collection && this.collection.off ) {
       
  3147 			this.collection.off( null, null, this );
       
  3148 		}
       
  3149 
       
  3150 		// Unbind controller events.
       
  3151 		if ( this.controller && this.controller.off ) {
       
  3152 			this.controller.off( null, null, this );
       
  3153 		}
       
  3154 
       
  3155 		return this;
       
  3156 	},
       
  3157 	/**
       
  3158 	 * @return {wp.media.View} Returns itself to allow chaining.
       
  3159 	 */
       
  3160 	remove: function() {
       
  3161 		this.dispose();
       
  3162 		/**
       
  3163 		 * call 'remove' directly on the parent class
       
  3164 		 */
       
  3165 		return wp.Backbone.View.prototype.remove.apply( this, arguments );
       
  3166 	}
       
  3167 });
       
  3168 
       
  3169 module.exports = View;
       
  3170 
       
  3171 
       
  3172 /***/ }),
       
  3173 
       
  3174 /***/ "EVvK":
       
  3175 /***/ (function(module, exports) {
       
  3176 
       
  3177 var Menu = wp.media.view.Menu,
       
  3178 	Router;
       
  3179 
       
  3180 /**
       
  3181  * wp.media.view.Router
       
  3182  *
       
  3183  * @memberOf wp.media.view
       
  3184  *
       
  3185  * @class
       
  3186  * @augments wp.media.view.Menu
       
  3187  * @augments wp.media.view.PriorityList
       
  3188  * @augments wp.media.View
       
  3189  * @augments wp.Backbone.View
       
  3190  * @augments Backbone.View
       
  3191  */
       
  3192 Router = Menu.extend(/** @lends wp.media.view.Router.prototype */{
       
  3193 	tagName:   'div',
       
  3194 	className: 'media-router',
       
  3195 	property:  'contentMode',
       
  3196 	ItemView:  wp.media.view.RouterItem,
       
  3197 	region:    'router',
       
  3198 
       
  3199 	attributes: {
       
  3200 		role:               'tablist',
       
  3201 		'aria-orientation': 'horizontal'
       
  3202 	},
       
  3203 
       
  3204 	initialize: function() {
       
  3205 		this.controller.on( 'content:render', this.update, this );
       
  3206 		// Call 'initialize' directly on the parent class.
       
  3207 		Menu.prototype.initialize.apply( this, arguments );
       
  3208 	},
       
  3209 
       
  3210 	update: function() {
       
  3211 		var mode = this.controller.content.mode();
   814 		if ( mode ) {
  3212 		if ( mode ) {
   815 			this.frame[ region ].render( mode );
  3213 			this.select( mode );
   816 		}
  3214 		}
   817 	};
  3215 	}
   818 });
  3216 });
   819 
  3217 
   820 module.exports = State;
  3218 module.exports = Router;
   821 
  3219 
   822 
  3220 
   823 /***/ }),
  3221 /***/ }),
   824 /* 34 */
  3222 
       
  3223 /***/ "EvXF":
   825 /***/ (function(module, exports) {
  3224 /***/ (function(module, exports) {
   826 
  3225 
   827 /**
  3226 /**
   828  * wp.media.selectionSync
  3227  * wp.media.view.Attachment.EditLibrary
   829  *
  3228  *
   830  * Sync an attachments selection in a state with another state.
  3229  * @memberOf wp.media.view.Attachment
   831  *
  3230  *
   832  * Allows for selecting multiple images in the Add Media workflow, and then
  3231  * @class
   833  * switching to the Insert Gallery workflow while preserving the attachments selection.
  3232  * @augments wp.media.view.Attachment
   834  *
  3233  * @augments wp.media.View
   835  * @memberOf wp.media
  3234  * @augments wp.Backbone.View
   836  *
  3235  * @augments Backbone.View
   837  * @mixin
       
   838  */
  3236  */
   839 var selectionSync = {
  3237 var EditLibrary = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.EditLibrary.prototype */{
   840 	/**
  3238 	buttons: {
   841 	 * @since 3.5.0
  3239 		close: true
   842 	 */
       
   843 	syncSelection: function() {
       
   844 		var selection = this.get('selection'),
       
   845 			manager = this.frame._selection;
       
   846 
       
   847 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
       
   848 			return;
       
   849 		}
       
   850 
       
   851 		/*
       
   852 		 * If the selection supports multiple items, validate the stored
       
   853 		 * attachments based on the new selection's conditions. Record
       
   854 		 * the attachments that are not included; we'll maintain a
       
   855 		 * reference to those. Other attachments are considered in flux.
       
   856 		 */
       
   857 		if ( selection.multiple ) {
       
   858 			selection.reset( [], { silent: true });
       
   859 			selection.validateAll( manager.attachments );
       
   860 			manager.difference = _.difference( manager.attachments.models, selection.models );
       
   861 		}
       
   862 
       
   863 		// Sync the selection's single item with the master.
       
   864 		selection.single( manager.single );
       
   865 	},
       
   866 
       
   867 	/**
       
   868 	 * Record the currently active attachments, which is a combination
       
   869 	 * of the selection's attachments and the set of selected
       
   870 	 * attachments that this specific selection considered invalid.
       
   871 	 * Reset the difference and record the single attachment.
       
   872 	 *
       
   873 	 * @since 3.5.0
       
   874 	 */
       
   875 	recordSelection: function() {
       
   876 		var selection = this.get('selection'),
       
   877 			manager = this.frame._selection;
       
   878 
       
   879 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
       
   880 			return;
       
   881 		}
       
   882 
       
   883 		if ( selection.multiple ) {
       
   884 			manager.attachments.reset( selection.toArray().concat( manager.difference ) );
       
   885 			manager.difference = [];
       
   886 		} else {
       
   887 			manager.attachments.add( selection.toArray() );
       
   888 		}
       
   889 
       
   890 		manager.single = selection._single;
       
   891 	}
  3240 	}
   892 };
  3241 });
   893 
  3242 
   894 module.exports = selectionSync;
  3243 module.exports = EditLibrary;
   895 
  3244 
   896 
  3245 
   897 /***/ }),
  3246 /***/ }),
   898 /* 35 */
  3247 
       
  3248 /***/ "F/kE":
   899 /***/ (function(module, exports) {
  3249 /***/ (function(module, exports) {
   900 
  3250 
   901 var l10n = wp.media.view.l10n,
  3251 var l10n = wp.media.view.l10n,
   902 	getUserSetting = window.getUserSetting,
  3252 	getUserSetting = window.getUserSetting,
   903 	setUserSetting = window.setUserSetting,
  3253 	setUserSetting = window.setUserSetting,
  1194 
  3544 
  1195 module.exports = Library;
  3545 module.exports = Library;
  1196 
  3546 
  1197 
  3547 
  1198 /***/ }),
  3548 /***/ }),
  1199 /* 36 */
  3549 
       
  3550 /***/ "GXJ6":
       
  3551 /***/ (function(module, exports) {
       
  3552 
       
  3553 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
       
  3554 	$ = jQuery,
       
  3555 	ImageDetails;
       
  3556 
       
  3557 /**
       
  3558  * wp.media.view.ImageDetails
       
  3559  *
       
  3560  * @memberOf wp.media.view
       
  3561  *
       
  3562  * @class
       
  3563  * @augments wp.media.view.Settings.AttachmentDisplay
       
  3564  * @augments wp.media.view.Settings
       
  3565  * @augments wp.media.View
       
  3566  * @augments wp.Backbone.View
       
  3567  * @augments Backbone.View
       
  3568  */
       
  3569 ImageDetails = AttachmentDisplay.extend(/** @lends wp.media.view.ImageDetails.prototype */{
       
  3570 	className: 'image-details',
       
  3571 	template:  wp.template('image-details'),
       
  3572 	events: _.defaults( AttachmentDisplay.prototype.events, {
       
  3573 		'click .edit-attachment': 'editAttachment',
       
  3574 		'click .replace-attachment': 'replaceAttachment',
       
  3575 		'click .advanced-toggle': 'onToggleAdvanced',
       
  3576 		'change [data-setting="customWidth"]': 'onCustomSize',
       
  3577 		'change [data-setting="customHeight"]': 'onCustomSize',
       
  3578 		'keyup [data-setting="customWidth"]': 'onCustomSize',
       
  3579 		'keyup [data-setting="customHeight"]': 'onCustomSize'
       
  3580 	} ),
       
  3581 	initialize: function() {
       
  3582 		// Used in AttachmentDisplay.prototype.updateLinkTo.
       
  3583 		this.options.attachment = this.model.attachment;
       
  3584 		this.listenTo( this.model, 'change:url', this.updateUrl );
       
  3585 		this.listenTo( this.model, 'change:link', this.toggleLinkSettings );
       
  3586 		this.listenTo( this.model, 'change:size', this.toggleCustomSize );
       
  3587 
       
  3588 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
       
  3589 	},
       
  3590 
       
  3591 	prepare: function() {
       
  3592 		var attachment = false;
       
  3593 
       
  3594 		if ( this.model.attachment ) {
       
  3595 			attachment = this.model.attachment.toJSON();
       
  3596 		}
       
  3597 		return _.defaults({
       
  3598 			model: this.model.toJSON(),
       
  3599 			attachment: attachment
       
  3600 		}, this.options );
       
  3601 	},
       
  3602 
       
  3603 	render: function() {
       
  3604 		var args = arguments;
       
  3605 
       
  3606 		if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
       
  3607 			this.model.dfd
       
  3608 				.done( _.bind( function() {
       
  3609 					AttachmentDisplay.prototype.render.apply( this, args );
       
  3610 					this.postRender();
       
  3611 				}, this ) )
       
  3612 				.fail( _.bind( function() {
       
  3613 					this.model.attachment = false;
       
  3614 					AttachmentDisplay.prototype.render.apply( this, args );
       
  3615 					this.postRender();
       
  3616 				}, this ) );
       
  3617 		} else {
       
  3618 			AttachmentDisplay.prototype.render.apply( this, arguments );
       
  3619 			this.postRender();
       
  3620 		}
       
  3621 
       
  3622 		return this;
       
  3623 	},
       
  3624 
       
  3625 	postRender: function() {
       
  3626 		setTimeout( _.bind( this.scrollToTop, this ), 10 );
       
  3627 		this.toggleLinkSettings();
       
  3628 		if ( window.getUserSetting( 'advImgDetails' ) === 'show' ) {
       
  3629 			this.toggleAdvanced( true );
       
  3630 		}
       
  3631 		this.trigger( 'post-render' );
       
  3632 	},
       
  3633 
       
  3634 	scrollToTop: function() {
       
  3635 		this.$( '.embed-media-settings' ).scrollTop( 0 );
       
  3636 	},
       
  3637 
       
  3638 	updateUrl: function() {
       
  3639 		this.$( '.image img' ).attr( 'src', this.model.get( 'url' ) );
       
  3640 		this.$( '.url' ).val( this.model.get( 'url' ) );
       
  3641 	},
       
  3642 
       
  3643 	toggleLinkSettings: function() {
       
  3644 		if ( this.model.get( 'link' ) === 'none' ) {
       
  3645 			this.$( '.link-settings' ).addClass('hidden');
       
  3646 		} else {
       
  3647 			this.$( '.link-settings' ).removeClass('hidden');
       
  3648 		}
       
  3649 	},
       
  3650 
       
  3651 	toggleCustomSize: function() {
       
  3652 		if ( this.model.get( 'size' ) !== 'custom' ) {
       
  3653 			this.$( '.custom-size' ).addClass('hidden');
       
  3654 		} else {
       
  3655 			this.$( '.custom-size' ).removeClass('hidden');
       
  3656 		}
       
  3657 	},
       
  3658 
       
  3659 	onCustomSize: function( event ) {
       
  3660 		var dimension = $( event.target ).data('setting'),
       
  3661 			num = $( event.target ).val(),
       
  3662 			value;
       
  3663 
       
  3664 		// Ignore bogus input.
       
  3665 		if ( ! /^\d+/.test( num ) || parseInt( num, 10 ) < 1 ) {
       
  3666 			event.preventDefault();
       
  3667 			return;
       
  3668 		}
       
  3669 
       
  3670 		if ( dimension === 'customWidth' ) {
       
  3671 			value = Math.round( 1 / this.model.get( 'aspectRatio' ) * num );
       
  3672 			this.model.set( 'customHeight', value, { silent: true } );
       
  3673 			this.$( '[data-setting="customHeight"]' ).val( value );
       
  3674 		} else {
       
  3675 			value = Math.round( this.model.get( 'aspectRatio' ) * num );
       
  3676 			this.model.set( 'customWidth', value, { silent: true  } );
       
  3677 			this.$( '[data-setting="customWidth"]' ).val( value );
       
  3678 		}
       
  3679 	},
       
  3680 
       
  3681 	onToggleAdvanced: function( event ) {
       
  3682 		event.preventDefault();
       
  3683 		this.toggleAdvanced();
       
  3684 	},
       
  3685 
       
  3686 	toggleAdvanced: function( show ) {
       
  3687 		var $advanced = this.$el.find( '.advanced-section' ),
       
  3688 			mode;
       
  3689 
       
  3690 		if ( $advanced.hasClass('advanced-visible') || show === false ) {
       
  3691 			$advanced.removeClass('advanced-visible');
       
  3692 			$advanced.find('.advanced-settings').addClass('hidden');
       
  3693 			mode = 'hide';
       
  3694 		} else {
       
  3695 			$advanced.addClass('advanced-visible');
       
  3696 			$advanced.find('.advanced-settings').removeClass('hidden');
       
  3697 			mode = 'show';
       
  3698 		}
       
  3699 
       
  3700 		window.setUserSetting( 'advImgDetails', mode );
       
  3701 	},
       
  3702 
       
  3703 	editAttachment: function( event ) {
       
  3704 		var editState = this.controller.states.get( 'edit-image' );
       
  3705 
       
  3706 		if ( window.imageEdit && editState ) {
       
  3707 			event.preventDefault();
       
  3708 			editState.set( 'image', this.model.attachment );
       
  3709 			this.controller.setState( 'edit-image' );
       
  3710 		}
       
  3711 	},
       
  3712 
       
  3713 	replaceAttachment: function( event ) {
       
  3714 		event.preventDefault();
       
  3715 		this.controller.setState( 'replace-image' );
       
  3716 	}
       
  3717 });
       
  3718 
       
  3719 module.exports = ImageDetails;
       
  3720 
       
  3721 
       
  3722 /***/ }),
       
  3723 
       
  3724 /***/ "GXkx":
       
  3725 /***/ (function(module, exports) {
       
  3726 
       
  3727 var View = wp.media.View,
       
  3728 	l10n = wp.media.view.l10n,
       
  3729 	$ = jQuery,
       
  3730 	EditorUploader;
       
  3731 
       
  3732 /**
       
  3733  * Creates a dropzone on WP editor instances (elements with .wp-editor-wrap)
       
  3734  * and relays drag'n'dropped files to a media workflow.
       
  3735  *
       
  3736  * wp.media.view.EditorUploader
       
  3737  *
       
  3738  * @memberOf wp.media.view
       
  3739  *
       
  3740  * @class
       
  3741  * @augments wp.media.View
       
  3742  * @augments wp.Backbone.View
       
  3743  * @augments Backbone.View
       
  3744  */
       
  3745 EditorUploader = View.extend(/** @lends wp.media.view.EditorUploader.prototype */{
       
  3746 	tagName:   'div',
       
  3747 	className: 'uploader-editor',
       
  3748 	template:  wp.template( 'uploader-editor' ),
       
  3749 
       
  3750 	localDrag: false,
       
  3751 	overContainer: false,
       
  3752 	overDropzone: false,
       
  3753 	draggingFile: null,
       
  3754 
       
  3755 	/**
       
  3756 	 * Bind drag'n'drop events to callbacks.
       
  3757 	 */
       
  3758 	initialize: function() {
       
  3759 		this.initialized = false;
       
  3760 
       
  3761 		// Bail if not enabled or UA does not support drag'n'drop or File API.
       
  3762 		if ( ! window.tinyMCEPreInit || ! window.tinyMCEPreInit.dragDropUpload || ! this.browserSupport() ) {
       
  3763 			return this;
       
  3764 		}
       
  3765 
       
  3766 		this.$document = $(document);
       
  3767 		this.dropzones = [];
       
  3768 		this.files = [];
       
  3769 
       
  3770 		this.$document.on( 'drop', '.uploader-editor', _.bind( this.drop, this ) );
       
  3771 		this.$document.on( 'dragover', '.uploader-editor', _.bind( this.dropzoneDragover, this ) );
       
  3772 		this.$document.on( 'dragleave', '.uploader-editor', _.bind( this.dropzoneDragleave, this ) );
       
  3773 		this.$document.on( 'click', '.uploader-editor', _.bind( this.click, this ) );
       
  3774 
       
  3775 		this.$document.on( 'dragover', _.bind( this.containerDragover, this ) );
       
  3776 		this.$document.on( 'dragleave', _.bind( this.containerDragleave, this ) );
       
  3777 
       
  3778 		this.$document.on( 'dragstart dragend drop', _.bind( function( event ) {
       
  3779 			this.localDrag = event.type === 'dragstart';
       
  3780 
       
  3781 			if ( event.type === 'drop' ) {
       
  3782 				this.containerDragleave();
       
  3783 			}
       
  3784 		}, this ) );
       
  3785 
       
  3786 		this.initialized = true;
       
  3787 		return this;
       
  3788 	},
       
  3789 
       
  3790 	/**
       
  3791 	 * Check browser support for drag'n'drop.
       
  3792 	 *
       
  3793 	 * @return {boolean}
       
  3794 	 */
       
  3795 	browserSupport: function() {
       
  3796 		var supports = false, div = document.createElement('div');
       
  3797 
       
  3798 		supports = ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div );
       
  3799 		supports = supports && !! ( window.File && window.FileList && window.FileReader );
       
  3800 		return supports;
       
  3801 	},
       
  3802 
       
  3803 	isDraggingFile: function( event ) {
       
  3804 		if ( this.draggingFile !== null ) {
       
  3805 			return this.draggingFile;
       
  3806 		}
       
  3807 
       
  3808 		if ( _.isUndefined( event.originalEvent ) || _.isUndefined( event.originalEvent.dataTransfer ) ) {
       
  3809 			return false;
       
  3810 		}
       
  3811 
       
  3812 		this.draggingFile = _.indexOf( event.originalEvent.dataTransfer.types, 'Files' ) > -1 &&
       
  3813 			_.indexOf( event.originalEvent.dataTransfer.types, 'text/plain' ) === -1;
       
  3814 
       
  3815 		return this.draggingFile;
       
  3816 	},
       
  3817 
       
  3818 	refresh: function( e ) {
       
  3819 		var dropzone_id;
       
  3820 		for ( dropzone_id in this.dropzones ) {
       
  3821 			// Hide the dropzones only if dragging has left the screen.
       
  3822 			this.dropzones[ dropzone_id ].toggle( this.overContainer || this.overDropzone );
       
  3823 		}
       
  3824 
       
  3825 		if ( ! _.isUndefined( e ) ) {
       
  3826 			$( e.target ).closest( '.uploader-editor' ).toggleClass( 'droppable', this.overDropzone );
       
  3827 		}
       
  3828 
       
  3829 		if ( ! this.overContainer && ! this.overDropzone ) {
       
  3830 			this.draggingFile = null;
       
  3831 		}
       
  3832 
       
  3833 		return this;
       
  3834 	},
       
  3835 
       
  3836 	render: function() {
       
  3837 		if ( ! this.initialized ) {
       
  3838 			return this;
       
  3839 		}
       
  3840 
       
  3841 		View.prototype.render.apply( this, arguments );
       
  3842 		$( '.wp-editor-wrap' ).each( _.bind( this.attach, this ) );
       
  3843 		return this;
       
  3844 	},
       
  3845 
       
  3846 	attach: function( index, editor ) {
       
  3847 		// Attach a dropzone to an editor.
       
  3848 		var dropzone = this.$el.clone();
       
  3849 		this.dropzones.push( dropzone );
       
  3850 		$( editor ).append( dropzone );
       
  3851 		return this;
       
  3852 	},
       
  3853 
       
  3854 	/**
       
  3855 	 * When a file is dropped on the editor uploader, open up an editor media workflow
       
  3856 	 * and upload the file immediately.
       
  3857 	 *
       
  3858 	 * @param {jQuery.Event} event The 'drop' event.
       
  3859 	 */
       
  3860 	drop: function( event ) {
       
  3861 		var $wrap, uploadView;
       
  3862 
       
  3863 		this.containerDragleave( event );
       
  3864 		this.dropzoneDragleave( event );
       
  3865 
       
  3866 		this.files = event.originalEvent.dataTransfer.files;
       
  3867 		if ( this.files.length < 1 ) {
       
  3868 			return;
       
  3869 		}
       
  3870 
       
  3871 		// Set the active editor to the drop target.
       
  3872 		$wrap = $( event.target ).parents( '.wp-editor-wrap' );
       
  3873 		if ( $wrap.length > 0 && $wrap[0].id ) {
       
  3874 			window.wpActiveEditor = $wrap[0].id.slice( 3, -5 );
       
  3875 		}
       
  3876 
       
  3877 		if ( ! this.workflow ) {
       
  3878 			this.workflow = wp.media.editor.open( window.wpActiveEditor, {
       
  3879 				frame:    'post',
       
  3880 				state:    'insert',
       
  3881 				title:    l10n.addMedia,
       
  3882 				multiple: true
       
  3883 			});
       
  3884 
       
  3885 			uploadView = this.workflow.uploader;
       
  3886 
       
  3887 			if ( uploadView.uploader && uploadView.uploader.ready ) {
       
  3888 				this.addFiles.apply( this );
       
  3889 			} else {
       
  3890 				this.workflow.on( 'uploader:ready', this.addFiles, this );
       
  3891 			}
       
  3892 		} else {
       
  3893 			this.workflow.state().reset();
       
  3894 			this.addFiles.apply( this );
       
  3895 			this.workflow.open();
       
  3896 		}
       
  3897 
       
  3898 		return false;
       
  3899 	},
       
  3900 
       
  3901 	/**
       
  3902 	 * Add the files to the uploader.
       
  3903 	 */
       
  3904 	addFiles: function() {
       
  3905 		if ( this.files.length ) {
       
  3906 			this.workflow.uploader.uploader.uploader.addFile( _.toArray( this.files ) );
       
  3907 			this.files = [];
       
  3908 		}
       
  3909 		return this;
       
  3910 	},
       
  3911 
       
  3912 	containerDragover: function( event ) {
       
  3913 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
       
  3914 			return;
       
  3915 		}
       
  3916 
       
  3917 		this.overContainer = true;
       
  3918 		this.refresh();
       
  3919 	},
       
  3920 
       
  3921 	containerDragleave: function() {
       
  3922 		this.overContainer = false;
       
  3923 
       
  3924 		// Throttle dragleave because it's called when bouncing from some elements to others.
       
  3925 		_.delay( _.bind( this.refresh, this ), 50 );
       
  3926 	},
       
  3927 
       
  3928 	dropzoneDragover: function( event ) {
       
  3929 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
       
  3930 			return;
       
  3931 		}
       
  3932 
       
  3933 		this.overDropzone = true;
       
  3934 		this.refresh( event );
       
  3935 		return false;
       
  3936 	},
       
  3937 
       
  3938 	dropzoneDragleave: function( e ) {
       
  3939 		this.overDropzone = false;
       
  3940 		_.delay( _.bind( this.refresh, this, e ), 50 );
       
  3941 	},
       
  3942 
       
  3943 	click: function( e ) {
       
  3944 		// In the rare case where the dropzone gets stuck, hide it on click.
       
  3945 		this.containerDragleave( e );
       
  3946 		this.dropzoneDragleave( e );
       
  3947 		this.localDrag = false;
       
  3948 	}
       
  3949 });
       
  3950 
       
  3951 module.exports = EditorUploader;
       
  3952 
       
  3953 
       
  3954 /***/ }),
       
  3955 
       
  3956 /***/ "I7TD":
       
  3957 /***/ (function(module, exports) {
       
  3958 
       
  3959 var Attachment = wp.media.model.Attachment,
       
  3960 	Library = wp.media.controller.Library,
       
  3961 	l10n = wp.media.view.l10n,
       
  3962 	FeaturedImage;
       
  3963 
       
  3964 /**
       
  3965  * wp.media.controller.FeaturedImage
       
  3966  *
       
  3967  * A state for selecting a featured image for a post.
       
  3968  *
       
  3969  * @memberOf wp.media.controller
       
  3970  *
       
  3971  * @class
       
  3972  * @augments wp.media.controller.Library
       
  3973  * @augments wp.media.controller.State
       
  3974  * @augments Backbone.Model
       
  3975  *
       
  3976  * @param {object}                     [attributes]                          The attributes hash passed to the state.
       
  3977  * @param {string}                     [attributes.id=featured-image]        Unique identifier.
       
  3978  * @param {string}                     [attributes.title=Set Featured Image] Title for the state. Displays in the media menu and the frame's title region.
       
  3979  * @param {wp.media.model.Attachments} [attributes.library]                  The attachments collection to browse.
       
  3980  *                                                                           If one is not supplied, a collection of all images will be created.
       
  3981  * @param {boolean}                    [attributes.multiple=false]           Whether multi-select is enabled.
       
  3982  * @param {string}                     [attributes.content=upload]           Initial mode for the content region.
       
  3983  *                                                                           Overridden by persistent user setting if 'contentUserSetting' is true.
       
  3984  * @param {string}                     [attributes.menu=default]             Initial mode for the menu region.
       
  3985  * @param {string}                     [attributes.router=browse]            Initial mode for the router region.
       
  3986  * @param {string}                     [attributes.toolbar=featured-image]   Initial mode for the toolbar region.
       
  3987  * @param {int}                        [attributes.priority=60]              The priority for the state link in the media menu.
       
  3988  * @param {boolean}                    [attributes.searchable=true]          Whether the library is searchable.
       
  3989  * @param {boolean|string}             [attributes.filterable=false]         Whether the library is filterable, and if so what filters should be shown.
       
  3990  *                                                                           Accepts 'all', 'uploaded', or 'unattached'.
       
  3991  * @param {boolean}                    [attributes.sortable=true]            Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  3992  * @param {boolean}                    [attributes.autoSelect=true]          Whether an uploaded attachment should be automatically added to the selection.
       
  3993  * @param {boolean}                    [attributes.describe=false]           Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
       
  3994  * @param {boolean}                    [attributes.contentUserSetting=true]  Whether the content region's mode should be set and persisted per user.
       
  3995  * @param {boolean}                    [attributes.syncSelection=true]       Whether the Attachments selection should be persisted from the last state.
       
  3996  */
       
  3997 FeaturedImage = Library.extend(/** @lends wp.media.controller.FeaturedImage.prototype */{
       
  3998 	defaults: _.defaults({
       
  3999 		id:            'featured-image',
       
  4000 		title:         l10n.setFeaturedImageTitle,
       
  4001 		multiple:      false,
       
  4002 		filterable:    'uploaded',
       
  4003 		toolbar:       'featured-image',
       
  4004 		priority:      60,
       
  4005 		syncSelection: true
       
  4006 	}, Library.prototype.defaults ),
       
  4007 
       
  4008 	/**
       
  4009 	 * @since 3.5.0
       
  4010 	 */
       
  4011 	initialize: function() {
       
  4012 		var library, comparator;
       
  4013 
       
  4014 		// If we haven't been provided a `library`, create a `Selection`.
       
  4015 		if ( ! this.get('library') ) {
       
  4016 			this.set( 'library', wp.media.query({ type: 'image' }) );
       
  4017 		}
       
  4018 
       
  4019 		Library.prototype.initialize.apply( this, arguments );
       
  4020 
       
  4021 		library    = this.get('library');
       
  4022 		comparator = library.comparator;
       
  4023 
       
  4024 		// Overload the library's comparator to push items that are not in
       
  4025 		// the mirrored query to the front of the aggregate collection.
       
  4026 		library.comparator = function( a, b ) {
       
  4027 			var aInQuery = !! this.mirroring.get( a.cid ),
       
  4028 				bInQuery = !! this.mirroring.get( b.cid );
       
  4029 
       
  4030 			if ( ! aInQuery && bInQuery ) {
       
  4031 				return -1;
       
  4032 			} else if ( aInQuery && ! bInQuery ) {
       
  4033 				return 1;
       
  4034 			} else {
       
  4035 				return comparator.apply( this, arguments );
       
  4036 			}
       
  4037 		};
       
  4038 
       
  4039 		// Add all items in the selection to the library, so any featured
       
  4040 		// images that are not initially loaded still appear.
       
  4041 		library.observe( this.get('selection') );
       
  4042 	},
       
  4043 
       
  4044 	/**
       
  4045 	 * @since 3.5.0
       
  4046 	 */
       
  4047 	activate: function() {
       
  4048 		this.updateSelection();
       
  4049 		this.frame.on( 'open', this.updateSelection, this );
       
  4050 
       
  4051 		Library.prototype.activate.apply( this, arguments );
       
  4052 	},
       
  4053 
       
  4054 	/**
       
  4055 	 * @since 3.5.0
       
  4056 	 */
       
  4057 	deactivate: function() {
       
  4058 		this.frame.off( 'open', this.updateSelection, this );
       
  4059 
       
  4060 		Library.prototype.deactivate.apply( this, arguments );
       
  4061 	},
       
  4062 
       
  4063 	/**
       
  4064 	 * @since 3.5.0
       
  4065 	 */
       
  4066 	updateSelection: function() {
       
  4067 		var selection = this.get('selection'),
       
  4068 			id = wp.media.view.settings.post.featuredImageId,
       
  4069 			attachment;
       
  4070 
       
  4071 		if ( '' !== id && -1 !== id ) {
       
  4072 			attachment = Attachment.get( id );
       
  4073 			attachment.fetch();
       
  4074 		}
       
  4075 
       
  4076 		selection.reset( attachment ? [ attachment ] : [] );
       
  4077 	}
       
  4078 });
       
  4079 
       
  4080 module.exports = FeaturedImage;
       
  4081 
       
  4082 
       
  4083 /***/ }),
       
  4084 
       
  4085 /***/ "IgEq":
       
  4086 /***/ (function(module, exports) {
       
  4087 
       
  4088 var Toolbar = wp.media.view.Toolbar,
       
  4089 	l10n = wp.media.view.l10n,
       
  4090 	Select;
       
  4091 
       
  4092 /**
       
  4093  * wp.media.view.Toolbar.Select
       
  4094  *
       
  4095  * @memberOf wp.media.view.Toolbar
       
  4096  *
       
  4097  * @class
       
  4098  * @augments wp.media.view.Toolbar
       
  4099  * @augments wp.media.View
       
  4100  * @augments wp.Backbone.View
       
  4101  * @augments Backbone.View
       
  4102  */
       
  4103 Select = Toolbar.extend(/** @lends wp.media.view.Toolbar.Select.prototype */{
       
  4104 	initialize: function() {
       
  4105 		var options = this.options;
       
  4106 
       
  4107 		_.bindAll( this, 'clickSelect' );
       
  4108 
       
  4109 		_.defaults( options, {
       
  4110 			event: 'select',
       
  4111 			state: false,
       
  4112 			reset: true,
       
  4113 			close: true,
       
  4114 			text:  l10n.select,
       
  4115 
       
  4116 			// Does the button rely on the selection?
       
  4117 			requires: {
       
  4118 				selection: true
       
  4119 			}
       
  4120 		});
       
  4121 
       
  4122 		options.items = _.defaults( options.items || {}, {
       
  4123 			select: {
       
  4124 				style:    'primary',
       
  4125 				text:     options.text,
       
  4126 				priority: 80,
       
  4127 				click:    this.clickSelect,
       
  4128 				requires: options.requires
       
  4129 			}
       
  4130 		});
       
  4131 		// Call 'initialize' directly on the parent class.
       
  4132 		Toolbar.prototype.initialize.apply( this, arguments );
       
  4133 	},
       
  4134 
       
  4135 	clickSelect: function() {
       
  4136 		var options = this.options,
       
  4137 			controller = this.controller;
       
  4138 
       
  4139 		if ( options.close ) {
       
  4140 			controller.close();
       
  4141 		}
       
  4142 
       
  4143 		if ( options.event ) {
       
  4144 			controller.state().trigger( options.event );
       
  4145 		}
       
  4146 
       
  4147 		if ( options.state ) {
       
  4148 			controller.setState( options.state );
       
  4149 		}
       
  4150 
       
  4151 		if ( options.reset ) {
       
  4152 			controller.reset();
       
  4153 		}
       
  4154 	}
       
  4155 });
       
  4156 
       
  4157 module.exports = Select;
       
  4158 
       
  4159 
       
  4160 /***/ }),
       
  4161 
       
  4162 /***/ "IkWq":
  1200 /***/ (function(module, exports) {
  4163 /***/ (function(module, exports) {
  1201 
  4164 
  1202 var State = wp.media.controller.State,
  4165 var State = wp.media.controller.State,
  1203 	Library = wp.media.controller.Library,
  4166 	Library = wp.media.controller.Library,
  1204 	l10n = wp.media.view.l10n,
  4167 	l10n = wp.media.view.l10n,
  1262 
  4225 
  1263 module.exports = ImageDetails;
  4226 module.exports = ImageDetails;
  1264 
  4227 
  1265 
  4228 
  1266 /***/ }),
  4229 /***/ }),
  1267 /* 37 */
  4230 
       
  4231 /***/ "JecU":
  1268 /***/ (function(module, exports) {
  4232 /***/ (function(module, exports) {
  1269 
  4233 
  1270 var Library = wp.media.controller.Library,
  4234 var $ = jQuery,
  1271 	l10n = wp.media.view.l10n,
  4235 	EmbedLink;
  1272 	GalleryEdit;
       
  1273 
  4236 
  1274 /**
  4237 /**
  1275  * wp.media.controller.GalleryEdit
  4238  * wp.media.view.EmbedLink
  1276  *
  4239  *
  1277  * A state for editing a gallery's images and settings.
  4240  * @memberOf wp.media.view
  1278  *
       
  1279  * @since 3.5.0
       
  1280  *
  4241  *
  1281  * @class
  4242  * @class
  1282  * @augments wp.media.controller.Library
  4243  * @augments wp.media.view.Settings
       
  4244  * @augments wp.media.View
       
  4245  * @augments wp.Backbone.View
       
  4246  * @augments Backbone.View
       
  4247  */
       
  4248 EmbedLink = wp.media.view.Settings.extend(/** @lends wp.media.view.EmbedLink.prototype */{
       
  4249 	className: 'embed-link-settings',
       
  4250 	template:  wp.template('embed-link-settings'),
       
  4251 
       
  4252 	initialize: function() {
       
  4253 		this.listenTo( this.model, 'change:url', this.updateoEmbed );
       
  4254 	},
       
  4255 
       
  4256 	updateoEmbed: _.debounce( function() {
       
  4257 		var url = this.model.get( 'url' );
       
  4258 
       
  4259 		// Clear out previous results.
       
  4260 		this.$('.embed-container').hide().find('.embed-preview').empty();
       
  4261 		this.$( '.setting' ).hide();
       
  4262 
       
  4263 		// Only proceed with embed if the field contains more than 11 characters.
       
  4264 		// Example: http://a.io is 11 chars
       
  4265 		if ( url && ( url.length < 11 || ! url.match(/^http(s)?:\/\//) ) ) {
       
  4266 			return;
       
  4267 		}
       
  4268 
       
  4269 		this.fetch();
       
  4270 	}, wp.media.controller.Embed.sensitivity ),
       
  4271 
       
  4272 	fetch: function() {
       
  4273 		var url = this.model.get( 'url' ), re, youTubeEmbedMatch;
       
  4274 
       
  4275 		// Check if they haven't typed in 500 ms.
       
  4276 		if ( $('#embed-url-field').val() !== url ) {
       
  4277 			return;
       
  4278 		}
       
  4279 
       
  4280 		if ( this.dfd && 'pending' === this.dfd.state() ) {
       
  4281 			this.dfd.abort();
       
  4282 		}
       
  4283 
       
  4284 		// Support YouTube embed urls, since they work once in the editor.
       
  4285 		re = /https?:\/\/www\.youtube\.com\/embed\/([^/]+)/;
       
  4286 		youTubeEmbedMatch = re.exec( url );
       
  4287 		if ( youTubeEmbedMatch ) {
       
  4288 			url = 'https://www.youtube.com/watch?v=' + youTubeEmbedMatch[ 1 ];
       
  4289 		}
       
  4290 
       
  4291 		this.dfd = wp.apiRequest({
       
  4292 			url: wp.media.view.settings.oEmbedProxyUrl,
       
  4293 			data: {
       
  4294 				url: url,
       
  4295 				maxwidth: this.model.get( 'width' ),
       
  4296 				maxheight: this.model.get( 'height' )
       
  4297 			},
       
  4298 			type: 'GET',
       
  4299 			dataType: 'json',
       
  4300 			context: this
       
  4301 		})
       
  4302 			.done( function( response ) {
       
  4303 				this.renderoEmbed( {
       
  4304 					data: {
       
  4305 						body: response.html || ''
       
  4306 					}
       
  4307 				} );
       
  4308 			} )
       
  4309 			.fail( this.renderFail );
       
  4310 	},
       
  4311 
       
  4312 	renderFail: function ( response, status ) {
       
  4313 		if ( 'abort' === status ) {
       
  4314 			return;
       
  4315 		}
       
  4316 		this.$( '.link-text' ).show();
       
  4317 	},
       
  4318 
       
  4319 	renderoEmbed: function( response ) {
       
  4320 		var html = ( response && response.data && response.data.body ) || '';
       
  4321 
       
  4322 		if ( html ) {
       
  4323 			this.$('.embed-container').show().find('.embed-preview').html( html );
       
  4324 		} else {
       
  4325 			this.renderFail();
       
  4326 		}
       
  4327 	}
       
  4328 });
       
  4329 
       
  4330 module.exports = EmbedLink;
       
  4331 
       
  4332 
       
  4333 /***/ }),
       
  4334 
       
  4335 /***/ "Ju2C":
       
  4336 /***/ (function(module, exports) {
       
  4337 
       
  4338 var MenuItem = wp.media.view.MenuItem,
       
  4339 	PriorityList = wp.media.view.PriorityList,
       
  4340 	Menu;
       
  4341 
       
  4342 /**
       
  4343  * wp.media.view.Menu
       
  4344  *
       
  4345  * @memberOf wp.media.view
       
  4346  *
       
  4347  * @class
       
  4348  * @augments wp.media.view.PriorityList
       
  4349  * @augments wp.media.View
       
  4350  * @augments wp.Backbone.View
       
  4351  * @augments Backbone.View
       
  4352  */
       
  4353 Menu = PriorityList.extend(/** @lends wp.media.view.Menu.prototype */{
       
  4354 	tagName:   'div',
       
  4355 	className: 'media-menu',
       
  4356 	property:  'state',
       
  4357 	ItemView:  MenuItem,
       
  4358 	region:    'menu',
       
  4359 
       
  4360 	attributes: {
       
  4361 		role:               'tablist',
       
  4362 		'aria-orientation': 'horizontal'
       
  4363 	},
       
  4364 
       
  4365 	initialize: function() {
       
  4366 		this._views = {};
       
  4367 
       
  4368 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
       
  4369 		delete this.options.views;
       
  4370 
       
  4371 		if ( ! this.options.silent ) {
       
  4372 			this.render();
       
  4373 		}
       
  4374 
       
  4375 		// Initialize the Focus Manager.
       
  4376 		this.focusManager = new wp.media.view.FocusManager( {
       
  4377 			el:   this.el,
       
  4378 			mode: 'tabsNavigation'
       
  4379 		} );
       
  4380 
       
  4381 		// The menu is always rendered and can be visible or hidden on some frames.
       
  4382 		this.isVisible = true;
       
  4383 	},
       
  4384 
       
  4385 	/**
       
  4386 	 * @param {Object} options
       
  4387 	 * @param {string} id
       
  4388 	 * @return {wp.media.View}
       
  4389 	 */
       
  4390 	toView: function( options, id ) {
       
  4391 		options = options || {};
       
  4392 		options[ this.property ] = options[ this.property ] || id;
       
  4393 		return new this.ItemView( options ).render();
       
  4394 	},
       
  4395 
       
  4396 	ready: function() {
       
  4397 		/**
       
  4398 		 * call 'ready' directly on the parent class
       
  4399 		 */
       
  4400 		PriorityList.prototype.ready.apply( this, arguments );
       
  4401 		this.visibility();
       
  4402 
       
  4403 		// Set up aria tabs initial attributes.
       
  4404 		this.focusManager.setupAriaTabs();
       
  4405 	},
       
  4406 
       
  4407 	set: function() {
       
  4408 		/**
       
  4409 		 * call 'set' directly on the parent class
       
  4410 		 */
       
  4411 		PriorityList.prototype.set.apply( this, arguments );
       
  4412 		this.visibility();
       
  4413 	},
       
  4414 
       
  4415 	unset: function() {
       
  4416 		/**
       
  4417 		 * call 'unset' directly on the parent class
       
  4418 		 */
       
  4419 		PriorityList.prototype.unset.apply( this, arguments );
       
  4420 		this.visibility();
       
  4421 	},
       
  4422 
       
  4423 	visibility: function() {
       
  4424 		var region = this.region,
       
  4425 			view = this.controller[ region ].get(),
       
  4426 			views = this.views.get(),
       
  4427 			hide = ! views || views.length < 2;
       
  4428 
       
  4429 		if ( this === view ) {
       
  4430 			// Flag this menu as hidden or visible.
       
  4431 			this.isVisible = ! hide;
       
  4432 			// Set or remove a CSS class to hide the menu.
       
  4433 			this.controller.$el.toggleClass( 'hide-' + region, hide );
       
  4434 		}
       
  4435 	},
       
  4436 	/**
       
  4437 	 * @param {string} id
       
  4438 	 */
       
  4439 	select: function( id ) {
       
  4440 		var view = this.get( id );
       
  4441 
       
  4442 		if ( ! view ) {
       
  4443 			return;
       
  4444 		}
       
  4445 
       
  4446 		this.deselect();
       
  4447 		view.$el.addClass('active');
       
  4448 
       
  4449 		// Set up again the aria tabs initial attributes after the menu updates.
       
  4450 		this.focusManager.setupAriaTabs();
       
  4451 	},
       
  4452 
       
  4453 	deselect: function() {
       
  4454 		this.$el.children().removeClass('active');
       
  4455 	},
       
  4456 
       
  4457 	hide: function( id ) {
       
  4458 		var view = this.get( id );
       
  4459 
       
  4460 		if ( ! view ) {
       
  4461 			return;
       
  4462 		}
       
  4463 
       
  4464 		view.$el.addClass('hidden');
       
  4465 	},
       
  4466 
       
  4467 	show: function( id ) {
       
  4468 		var view = this.get( id );
       
  4469 
       
  4470 		if ( ! view ) {
       
  4471 			return;
       
  4472 		}
       
  4473 
       
  4474 		view.$el.removeClass('hidden');
       
  4475 	}
       
  4476 });
       
  4477 
       
  4478 module.exports = Menu;
       
  4479 
       
  4480 
       
  4481 /***/ }),
       
  4482 
       
  4483 /***/ "KerO":
       
  4484 /***/ (function(module, exports) {
       
  4485 
       
  4486 var l10n = wp.media.view.l10n,
       
  4487 	All;
       
  4488 
       
  4489 /**
       
  4490  * wp.media.view.AttachmentFilters.All
       
  4491  *
       
  4492  * @memberOf wp.media.view.AttachmentFilters
       
  4493  *
       
  4494  * @class
       
  4495  * @augments wp.media.view.AttachmentFilters
       
  4496  * @augments wp.media.View
       
  4497  * @augments wp.Backbone.View
       
  4498  * @augments Backbone.View
       
  4499  */
       
  4500 All = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.All.prototype */{
       
  4501 	createFilters: function() {
       
  4502 		var filters = {},
       
  4503 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0;
       
  4504 
       
  4505 		_.each( wp.media.view.settings.mimeTypes || {}, function( text, key ) {
       
  4506 			filters[ key ] = {
       
  4507 				text: text,
       
  4508 				props: {
       
  4509 					status:  null,
       
  4510 					type:    key,
       
  4511 					uploadedTo: null,
       
  4512 					orderby: 'date',
       
  4513 					order:   'DESC',
       
  4514 					author:  null
       
  4515 				}
       
  4516 			};
       
  4517 		});
       
  4518 
       
  4519 		filters.all = {
       
  4520 			text:  l10n.allMediaItems,
       
  4521 			props: {
       
  4522 				status:  null,
       
  4523 				type:    null,
       
  4524 				uploadedTo: null,
       
  4525 				orderby: 'date',
       
  4526 				order:   'DESC',
       
  4527 				author:  null
       
  4528 			},
       
  4529 			priority: 10
       
  4530 		};
       
  4531 
       
  4532 		if ( wp.media.view.settings.post.id ) {
       
  4533 			filters.uploaded = {
       
  4534 				text:  l10n.uploadedToThisPost,
       
  4535 				props: {
       
  4536 					status:  null,
       
  4537 					type:    null,
       
  4538 					uploadedTo: wp.media.view.settings.post.id,
       
  4539 					orderby: 'menuOrder',
       
  4540 					order:   'ASC',
       
  4541 					author:  null
       
  4542 				},
       
  4543 				priority: 20
       
  4544 			};
       
  4545 		}
       
  4546 
       
  4547 		filters.unattached = {
       
  4548 			text:  l10n.unattached,
       
  4549 			props: {
       
  4550 				status:     null,
       
  4551 				uploadedTo: 0,
       
  4552 				type:       null,
       
  4553 				orderby:    'menuOrder',
       
  4554 				order:      'ASC',
       
  4555 				author:     null
       
  4556 			},
       
  4557 			priority: 50
       
  4558 		};
       
  4559 
       
  4560 		if ( uid ) {
       
  4561 			filters.mine = {
       
  4562 				text:  l10n.mine,
       
  4563 				props: {
       
  4564 					status:		null,
       
  4565 					type:		null,
       
  4566 					uploadedTo:	null,
       
  4567 					orderby:	'date',
       
  4568 					order:		'DESC',
       
  4569 					author:		uid
       
  4570 				},
       
  4571 				priority: 50
       
  4572 			};
       
  4573 		}
       
  4574 
       
  4575 		if ( wp.media.view.settings.mediaTrash &&
       
  4576 			this.controller.isModeActive( 'grid' ) ) {
       
  4577 
       
  4578 			filters.trash = {
       
  4579 				text:  l10n.trash,
       
  4580 				props: {
       
  4581 					uploadedTo: null,
       
  4582 					status:     'trash',
       
  4583 					type:       null,
       
  4584 					orderby:    'date',
       
  4585 					order:      'DESC',
       
  4586 					author:     null
       
  4587 				},
       
  4588 				priority: 50
       
  4589 			};
       
  4590 		}
       
  4591 
       
  4592 		this.filters = filters;
       
  4593 	}
       
  4594 });
       
  4595 
       
  4596 module.exports = All;
       
  4597 
       
  4598 
       
  4599 /***/ }),
       
  4600 
       
  4601 /***/ "LGdN":
       
  4602 /***/ (function(module, exports) {
       
  4603 
       
  4604 /**
       
  4605  * wp.media.view.Frame
       
  4606  *
       
  4607  * A frame is a composite view consisting of one or more regions and one or more
       
  4608  * states.
       
  4609  *
       
  4610  * @memberOf wp.media.view
       
  4611  *
       
  4612  * @see wp.media.controller.State
       
  4613  * @see wp.media.controller.Region
       
  4614  *
       
  4615  * @class
       
  4616  * @augments wp.media.View
       
  4617  * @augments wp.Backbone.View
       
  4618  * @augments Backbone.View
       
  4619  * @mixes wp.media.controller.StateMachine
       
  4620  */
       
  4621 var Frame = wp.media.View.extend(/** @lends wp.media.view.Frame.prototype */{
       
  4622 	initialize: function() {
       
  4623 		_.defaults( this.options, {
       
  4624 			mode: [ 'select' ]
       
  4625 		});
       
  4626 		this._createRegions();
       
  4627 		this._createStates();
       
  4628 		this._createModes();
       
  4629 	},
       
  4630 
       
  4631 	_createRegions: function() {
       
  4632 		// Clone the regions array.
       
  4633 		this.regions = this.regions ? this.regions.slice() : [];
       
  4634 
       
  4635 		// Initialize regions.
       
  4636 		_.each( this.regions, function( region ) {
       
  4637 			this[ region ] = new wp.media.controller.Region({
       
  4638 				view:     this,
       
  4639 				id:       region,
       
  4640 				selector: '.media-frame-' + region
       
  4641 			});
       
  4642 		}, this );
       
  4643 	},
       
  4644 	/**
       
  4645 	 * Create the frame's states.
       
  4646 	 *
       
  4647 	 * @see wp.media.controller.State
       
  4648 	 * @see wp.media.controller.StateMachine
       
  4649 	 *
       
  4650 	 * @fires wp.media.controller.State#ready
       
  4651 	 */
       
  4652 	_createStates: function() {
       
  4653 		// Create the default `states` collection.
       
  4654 		this.states = new Backbone.Collection( null, {
       
  4655 			model: wp.media.controller.State
       
  4656 		});
       
  4657 
       
  4658 		// Ensure states have a reference to the frame.
       
  4659 		this.states.on( 'add', function( model ) {
       
  4660 			model.frame = this;
       
  4661 			model.trigger('ready');
       
  4662 		}, this );
       
  4663 
       
  4664 		if ( this.options.states ) {
       
  4665 			this.states.add( this.options.states );
       
  4666 		}
       
  4667 	},
       
  4668 
       
  4669 	/**
       
  4670 	 * A frame can be in a mode or multiple modes at one time.
       
  4671 	 *
       
  4672 	 * For example, the manage media frame can be in the `Bulk Select` or `Edit` mode.
       
  4673 	 */
       
  4674 	_createModes: function() {
       
  4675 		// Store active "modes" that the frame is in. Unrelated to region modes.
       
  4676 		this.activeModes = new Backbone.Collection();
       
  4677 		this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
       
  4678 
       
  4679 		_.each( this.options.mode, function( mode ) {
       
  4680 			this.activateMode( mode );
       
  4681 		}, this );
       
  4682 	},
       
  4683 	/**
       
  4684 	 * Reset all states on the frame to their defaults.
       
  4685 	 *
       
  4686 	 * @return {wp.media.view.Frame} Returns itself to allow chaining.
       
  4687 	 */
       
  4688 	reset: function() {
       
  4689 		this.states.invoke( 'trigger', 'reset' );
       
  4690 		return this;
       
  4691 	},
       
  4692 	/**
       
  4693 	 * Map activeMode collection events to the frame.
       
  4694 	 */
       
  4695 	triggerModeEvents: function( model, collection, options ) {
       
  4696 		var collectionEvent,
       
  4697 			modeEventMap = {
       
  4698 				add: 'activate',
       
  4699 				remove: 'deactivate'
       
  4700 			},
       
  4701 			eventToTrigger;
       
  4702 		// Probably a better way to do this.
       
  4703 		_.each( options, function( value, key ) {
       
  4704 			if ( value ) {
       
  4705 				collectionEvent = key;
       
  4706 			}
       
  4707 		} );
       
  4708 
       
  4709 		if ( ! _.has( modeEventMap, collectionEvent ) ) {
       
  4710 			return;
       
  4711 		}
       
  4712 
       
  4713 		eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
       
  4714 		this.trigger( eventToTrigger );
       
  4715 	},
       
  4716 	/**
       
  4717 	 * Activate a mode on the frame.
       
  4718 	 *
       
  4719 	 * @param string mode Mode ID.
       
  4720 	 * @return {this} Returns itself to allow chaining.
       
  4721 	 */
       
  4722 	activateMode: function( mode ) {
       
  4723 		// Bail if the mode is already active.
       
  4724 		if ( this.isModeActive( mode ) ) {
       
  4725 			return;
       
  4726 		}
       
  4727 		this.activeModes.add( [ { id: mode } ] );
       
  4728 		// Add a CSS class to the frame so elements can be styled for the mode.
       
  4729 		this.$el.addClass( 'mode-' + mode );
       
  4730 
       
  4731 		return this;
       
  4732 	},
       
  4733 	/**
       
  4734 	 * Deactivate a mode on the frame.
       
  4735 	 *
       
  4736 	 * @param string mode Mode ID.
       
  4737 	 * @return {this} Returns itself to allow chaining.
       
  4738 	 */
       
  4739 	deactivateMode: function( mode ) {
       
  4740 		// Bail if the mode isn't active.
       
  4741 		if ( ! this.isModeActive( mode ) ) {
       
  4742 			return this;
       
  4743 		}
       
  4744 		this.activeModes.remove( this.activeModes.where( { id: mode } ) );
       
  4745 		this.$el.removeClass( 'mode-' + mode );
       
  4746 		/**
       
  4747 		 * Frame mode deactivation event.
       
  4748 		 *
       
  4749 		 * @event wp.media.view.Frame#{mode}:deactivate
       
  4750 		 */
       
  4751 		this.trigger( mode + ':deactivate' );
       
  4752 
       
  4753 		return this;
       
  4754 	},
       
  4755 	/**
       
  4756 	 * Check if a mode is enabled on the frame.
       
  4757 	 *
       
  4758 	 * @param string mode Mode ID.
       
  4759 	 * @return bool
       
  4760 	 */
       
  4761 	isModeActive: function( mode ) {
       
  4762 		return Boolean( this.activeModes.where( { id: mode } ).length );
       
  4763 	}
       
  4764 });
       
  4765 
       
  4766 // Make the `Frame` a `StateMachine`.
       
  4767 _.extend( Frame.prototype, wp.media.controller.StateMachine.prototype );
       
  4768 
       
  4769 module.exports = Frame;
       
  4770 
       
  4771 
       
  4772 /***/ }),
       
  4773 
       
  4774 /***/ "LND6":
       
  4775 /***/ (function(module, exports) {
       
  4776 
       
  4777 var View = wp.media.View,
       
  4778 	AttachmentCompat;
       
  4779 
       
  4780 /**
       
  4781  * wp.media.view.AttachmentCompat
       
  4782  *
       
  4783  * A view to display fields added via the `attachment_fields_to_edit` filter.
       
  4784  *
       
  4785  * @memberOf wp.media.view
       
  4786  *
       
  4787  * @class
       
  4788  * @augments wp.media.View
       
  4789  * @augments wp.Backbone.View
       
  4790  * @augments Backbone.View
       
  4791  */
       
  4792 AttachmentCompat = View.extend(/** @lends wp.media.view.AttachmentCompat.prototype */{
       
  4793 	tagName:   'form',
       
  4794 	className: 'compat-item',
       
  4795 
       
  4796 	events: {
       
  4797 		'submit':          'preventDefault',
       
  4798 		'change input':    'save',
       
  4799 		'change select':   'save',
       
  4800 		'change textarea': 'save'
       
  4801 	},
       
  4802 
       
  4803 	initialize: function() {
       
  4804 		this.listenTo( this.model, 'change:compat', this.render );
       
  4805 	},
       
  4806 	/**
       
  4807 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
       
  4808 	 */
       
  4809 	dispose: function() {
       
  4810 		if ( this.$(':focus').length ) {
       
  4811 			this.save();
       
  4812 		}
       
  4813 		/**
       
  4814 		 * call 'dispose' directly on the parent class
       
  4815 		 */
       
  4816 		return View.prototype.dispose.apply( this, arguments );
       
  4817 	},
       
  4818 	/**
       
  4819 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
       
  4820 	 */
       
  4821 	render: function() {
       
  4822 		var compat = this.model.get('compat');
       
  4823 		if ( ! compat || ! compat.item ) {
       
  4824 			return;
       
  4825 		}
       
  4826 
       
  4827 		this.views.detach();
       
  4828 		this.$el.html( compat.item );
       
  4829 		this.views.render();
       
  4830 		return this;
       
  4831 	},
       
  4832 	/**
       
  4833 	 * @param {Object} event
       
  4834 	 */
       
  4835 	preventDefault: function( event ) {
       
  4836 		event.preventDefault();
       
  4837 	},
       
  4838 	/**
       
  4839 	 * @param {Object} event
       
  4840 	 */
       
  4841 	save: function( event ) {
       
  4842 		var data = {};
       
  4843 
       
  4844 		if ( event ) {
       
  4845 			event.preventDefault();
       
  4846 		}
       
  4847 
       
  4848 		_.each( this.$el.serializeArray(), function( pair ) {
       
  4849 			data[ pair.name ] = pair.value;
       
  4850 		});
       
  4851 
       
  4852 		this.controller.trigger( 'attachment:compat:waiting', ['waiting'] );
       
  4853 		this.model.saveCompat( data ).always( _.bind( this.postSave, this ) );
       
  4854 	},
       
  4855 
       
  4856 	postSave: function() {
       
  4857 		this.controller.trigger( 'attachment:compat:ready', ['ready'] );
       
  4858 	}
       
  4859 });
       
  4860 
       
  4861 module.exports = AttachmentCompat;
       
  4862 
       
  4863 
       
  4864 /***/ }),
       
  4865 
       
  4866 /***/ "LZpE":
       
  4867 /***/ (function(module, exports) {
       
  4868 
       
  4869 /**
       
  4870  * wp.media.view.Button
       
  4871  *
       
  4872  * @memberOf wp.media.view
       
  4873  *
       
  4874  * @class
       
  4875  * @augments wp.media.View
       
  4876  * @augments wp.Backbone.View
       
  4877  * @augments Backbone.View
       
  4878  */
       
  4879 var Button = wp.media.View.extend(/** @lends wp.media.view.Button.prototype */{
       
  4880 	tagName:    'button',
       
  4881 	className:  'media-button',
       
  4882 	attributes: { type: 'button' },
       
  4883 
       
  4884 	events: {
       
  4885 		'click': 'click'
       
  4886 	},
       
  4887 
       
  4888 	defaults: {
       
  4889 		text:     '',
       
  4890 		style:    '',
       
  4891 		size:     'large',
       
  4892 		disabled: false
       
  4893 	},
       
  4894 
       
  4895 	initialize: function() {
       
  4896 		/**
       
  4897 		 * Create a model with the provided `defaults`.
       
  4898 		 *
       
  4899 		 * @member {Backbone.Model}
       
  4900 		 */
       
  4901 		this.model = new Backbone.Model( this.defaults );
       
  4902 
       
  4903 		// If any of the `options` have a key from `defaults`, apply its
       
  4904 		// value to the `model` and remove it from the `options object.
       
  4905 		_.each( this.defaults, function( def, key ) {
       
  4906 			var value = this.options[ key ];
       
  4907 			if ( _.isUndefined( value ) ) {
       
  4908 				return;
       
  4909 			}
       
  4910 
       
  4911 			this.model.set( key, value );
       
  4912 			delete this.options[ key ];
       
  4913 		}, this );
       
  4914 
       
  4915 		this.listenTo( this.model, 'change', this.render );
       
  4916 	},
       
  4917 	/**
       
  4918 	 * @return {wp.media.view.Button} Returns itself to allow chaining.
       
  4919 	 */
       
  4920 	render: function() {
       
  4921 		var classes = [ 'button', this.className ],
       
  4922 			model = this.model.toJSON();
       
  4923 
       
  4924 		if ( model.style ) {
       
  4925 			classes.push( 'button-' + model.style );
       
  4926 		}
       
  4927 
       
  4928 		if ( model.size ) {
       
  4929 			classes.push( 'button-' + model.size );
       
  4930 		}
       
  4931 
       
  4932 		classes = _.uniq( classes.concat( this.options.classes ) );
       
  4933 		this.el.className = classes.join(' ');
       
  4934 
       
  4935 		this.$el.attr( 'disabled', model.disabled );
       
  4936 		this.$el.text( this.model.get('text') );
       
  4937 
       
  4938 		return this;
       
  4939 	},
       
  4940 	/**
       
  4941 	 * @param {Object} event
       
  4942 	 */
       
  4943 	click: function( event ) {
       
  4944 		if ( '#' === this.attributes.href ) {
       
  4945 			event.preventDefault();
       
  4946 		}
       
  4947 
       
  4948 		if ( this.options.click && ! this.model.get('disabled') ) {
       
  4949 			this.options.click.apply( this, arguments );
       
  4950 		}
       
  4951 	}
       
  4952 });
       
  4953 
       
  4954 module.exports = Button;
       
  4955 
       
  4956 
       
  4957 /***/ }),
       
  4958 
       
  4959 /***/ "M+xU":
       
  4960 /***/ (function(module, exports) {
       
  4961 
       
  4962 var l10n = wp.media.view.l10n,
       
  4963 	Cropper;
       
  4964 
       
  4965 /**
       
  4966  * wp.media.controller.Cropper
       
  4967  *
       
  4968  * A class for cropping an image when called from the header media customization panel.
       
  4969  *
       
  4970  * @memberOf wp.media.controller
       
  4971  *
       
  4972  * @class
  1283  * @augments wp.media.controller.State
  4973  * @augments wp.media.controller.State
  1284  * @augments Backbone.Model
  4974  * @augments Backbone.Model
  1285  *
       
  1286  * @memberOf wp.media.controller
       
  1287  *
       
  1288  * @param {Object}                     [attributes]                       The attributes hash passed to the state.
       
  1289  * @param {string}                     [attributes.id=gallery-edit]       Unique identifier.
       
  1290  * @param {string}                     [attributes.title=Edit Gallery]    Title for the state. Displays in the frame's title region.
       
  1291  * @param {wp.media.model.Attachments} [attributes.library]               The collection of attachments in the gallery.
       
  1292  *                                                                        If one is not supplied, an empty media.model.Selection collection is created.
       
  1293  * @param {boolean}                    [attributes.multiple=false]        Whether multi-select is enabled.
       
  1294  * @param {boolean}                    [attributes.searchable=false]      Whether the library is searchable.
       
  1295  * @param {boolean}                    [attributes.sortable=true]         Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  1296  * @param {boolean}                    [attributes.date=true]             Whether to show the date filter in the browser's toolbar.
       
  1297  * @param {string|false}               [attributes.content=browse]        Initial mode for the content region.
       
  1298  * @param {string|false}               [attributes.toolbar=image-details] Initial mode for the toolbar region.
       
  1299  * @param {boolean}                    [attributes.describe=true]         Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
       
  1300  * @param {boolean}                    [attributes.displaySettings=true]  Whether to show the attachment display settings interface.
       
  1301  * @param {boolean}                    [attributes.dragInfo=true]         Whether to show instructional text about the attachments being sortable.
       
  1302  * @param {number}                     [attributes.idealColumnWidth=170]  The ideal column width in pixels for attachments.
       
  1303  * @param {boolean}                    [attributes.editing=false]         Whether the gallery is being created, or editing an existing instance.
       
  1304  * @param {number}                     [attributes.priority=60]           The priority for the state link in the media menu.
       
  1305  * @param {boolean}                    [attributes.syncSelection=false]   Whether the Attachments selection should be persisted from the last state.
       
  1306  *                                                                        Defaults to false for this state, because the library passed in  *is* the selection.
       
  1307  * @param {view}                       [attributes.AttachmentView]        The single `Attachment` view to be used in the `Attachments`.
       
  1308  *                                                                        If none supplied, defaults to wp.media.view.Attachment.EditLibrary.
       
  1309  */
  4975  */
  1310 GalleryEdit = Library.extend(/** @lends wp.media.controller.GalleryEdit.prototype */{
  4976 Cropper = wp.media.controller.State.extend(/** @lends wp.media.controller.Cropper.prototype */{
  1311 	defaults: {
  4977 	defaults: {
  1312 		id:               'gallery-edit',
  4978 		id:          'cropper',
  1313 		title:            l10n.editGalleryTitle,
  4979 		title:       l10n.cropImage,
  1314 		multiple:         false,
  4980 		// Region mode defaults.
  1315 		searchable:       false,
  4981 		toolbar:     'crop',
  1316 		sortable:         true,
  4982 		content:     'crop',
  1317 		date:             false,
  4983 		router:      false,
  1318 		display:          false,
  4984 		canSkipCrop: false,
  1319 		content:          'browse',
  4985 
  1320 		toolbar:          'gallery-edit',
  4986 		// Default doCrop Ajax arguments to allow the Customizer (for example) to inject state.
  1321 		describe:         true,
  4987 		doCropArgs: {}
  1322 		displaySettings:  true,
  4988 	},
  1323 		dragInfo:         true,
  4989 
  1324 		idealColumnWidth: 170,
  4990 	/**
  1325 		editing:          false,
  4991 	 * Shows the crop image window when called from the Add new image button.
  1326 		priority:         60,
  4992 	 *
  1327 		syncSelection:    false
  4993 	 * @since 4.2.0
  1328 	},
       
  1329 
       
  1330 	/**
       
  1331 	 * Initializes the library.
       
  1332 	 *
       
  1333 	 * Creates a selection if a library isn't supplied and creates an attachment
       
  1334 	 * view if no attachment view is supplied.
       
  1335 	 *
       
  1336 	 * @since 3.5.0
       
  1337 	 *
  4994 	 *
  1338 	 * @return {void}
  4995 	 * @return {void}
  1339 	 */
  4996 	 */
  1340 	initialize: function() {
  4997 	activate: function() {
  1341 		// If we haven't been provided a `library`, create a `Selection`.
  4998 		this.frame.on( 'content:create:crop', this.createCropContent, this );
  1342 		if ( ! this.get('library') ) {
  4999 		this.frame.on( 'close', this.removeCropper, this );
  1343 			this.set( 'library', new wp.media.model.Selection() );
  5000 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
  1344 		}
  5001 	},
  1345 
  5002 
  1346 		// The single `Attachment` view to be used in the `Attachments` view.
  5003 	/**
  1347 		if ( ! this.get('AttachmentView') ) {
  5004 	 * Changes the state of the toolbar window to browse mode.
  1348 			this.set( 'AttachmentView', wp.media.view.Attachment.EditLibrary );
  5005 	 *
  1349 		}
  5006 	 * @since 4.2.0
  1350 
       
  1351 		Library.prototype.initialize.apply( this, arguments );
       
  1352 	},
       
  1353 
       
  1354 	/**
       
  1355 	 * Activates the library.
       
  1356 	 *
       
  1357 	 * Limits the library to images, watches for uploaded attachments. Watches for
       
  1358 	 * the browse event on the frame and binds it to gallerySettings.
       
  1359 	 *
       
  1360 	 * @since 3.5.0
       
  1361 	 *
  5007 	 *
  1362 	 * @return {void}
  5008 	 * @return {void}
  1363 	 */
  5009 	 */
  1364 	activate: function() {
  5010 	deactivate: function() {
  1365 		var library = this.get('library');
  5011 		this.frame.toolbar.mode('browse');
  1366 
  5012 	},
  1367 		// Limit the library to images only.
  5013 
  1368 		library.props.set( 'type', 'image' );
  5014 	/**
  1369 
  5015 	 * Creates the crop image window.
  1370 		// Watch for uploaded attachments.
  5016 	 *
  1371 		this.get('library').observe( wp.Uploader.queue );
  5017 	 * Initialized when clicking on the Select and Crop button.
  1372 
  5018 	 *
  1373 		this.frame.on( 'content:render:browse', this.gallerySettings, this );
  5019 	 * @since 4.2.0
  1374 
  5020 	 *
  1375 		Library.prototype.activate.apply( this, arguments );
  5021 	 * @fires crop window
  1376 	},
       
  1377 
       
  1378 	/**
       
  1379 	 * Deactivates the library.
       
  1380 	 *
       
  1381 	 * Stops watching for uploaded attachments and browse events.
       
  1382 	 *
       
  1383 	 * @since 3.5.0
       
  1384 	 *
  5022 	 *
  1385 	 * @return {void}
  5023 	 * @return {void}
  1386 	 */
  5024 	 */
  1387 	deactivate: function() {
  5025 	createCropContent: function() {
  1388 		// Stop watching for uploaded attachments.
  5026 		this.cropperView = new wp.media.view.Cropper({
  1389 		this.get('library').unobserve( wp.Uploader.queue );
  5027 			controller: this,
  1390 
  5028 			attachment: this.get('selection').first()
  1391 		this.frame.off( 'content:render:browse', this.gallerySettings, this );
  5029 		});
  1392 
  5030 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
  1393 		Library.prototype.deactivate.apply( this, arguments );
  5031 		this.frame.content.set(this.cropperView);
  1394 	},
  5032 
  1395 
  5033 	},
  1396 	/**
  5034 
  1397 	 * Adds the gallery settings to the sidebar and adds a reverse button to the
  5035 	/**
  1398 	 * toolbar.
  5036 	 * Removes the image selection and closes the cropping window.
  1399 	 *
  5037 	 *
  1400 	 * @since 3.5.0
  5038 	 * @since 4.2.0
  1401 	 *
       
  1402 	 * @param {wp.media.view.Frame} browser The file browser.
       
  1403 	 *
  5039 	 *
  1404 	 * @return {void}
  5040 	 * @return {void}
  1405 	 */
  5041 	 */
  1406 	gallerySettings: function( browser ) {
  5042 	removeCropper: function() {
  1407 		if ( ! this.get('displaySettings') ) {
  5043 		this.imgSelect.cancelSelection();
  1408 			return;
  5044 		this.imgSelect.setOptions({remove: true});
  1409 		}
  5045 		this.imgSelect.update();
  1410 
  5046 		this.cropperView.remove();
  1411 		var library = this.get('library');
  5047 	},
  1412 
  5048 
  1413 		if ( ! library || ! browser ) {
  5049 	/**
  1414 			return;
  5050 	 * Checks if cropping can be skipped and creates crop toolbar accordingly.
  1415 		}
  5051 	 *
  1416 
  5052 	 * @since 4.2.0
  1417 		library.gallery = library.gallery || new Backbone.Model();
  5053 	 *
  1418 
  5054 	 * @return {void}
  1419 		browser.sidebar.set({
  5055 	 */
  1420 			gallery: new wp.media.view.Settings.Gallery({
  5056 	createCropToolbar: function() {
  1421 				controller: this,
  5057 		var canSkipCrop, toolbarOptions;
  1422 				model:      library.gallery,
  5058 
  1423 				priority:   40
  5059 		canSkipCrop = this.get('canSkipCrop') || false;
  1424 			})
  5060 
  1425 		});
  5061 		toolbarOptions = {
  1426 
  5062 			controller: this.frame,
  1427 		browser.toolbar.set( 'reverse', {
  5063 			items: {
  1428 			text:     l10n.reverseOrder,
  5064 				insert: {
  1429 			priority: 80,
  5065 					style:    'primary',
  1430 
  5066 					text:     l10n.cropImage,
  1431 			click: function() {
  5067 					priority: 80,
  1432 				library.reset( library.toArray().reverse() );
  5068 					requires: { library: false, selection: false },
       
  5069 
       
  5070 					click: function() {
       
  5071 						var controller = this.controller,
       
  5072 							selection;
       
  5073 
       
  5074 						selection = controller.state().get('selection').first();
       
  5075 						selection.set({cropDetails: controller.state().imgSelect.getSelection()});
       
  5076 
       
  5077 						this.$el.text(l10n.cropping);
       
  5078 						this.$el.attr('disabled', true);
       
  5079 
       
  5080 						controller.state().doCrop( selection ).done( function( croppedImage ) {
       
  5081 							controller.trigger('cropped', croppedImage );
       
  5082 							controller.close();
       
  5083 						}).fail( function() {
       
  5084 							controller.trigger('content:error:crop');
       
  5085 						});
       
  5086 					}
       
  5087 				}
  1433 			}
  5088 			}
  1434 		});
  5089 		};
       
  5090 
       
  5091 		if ( canSkipCrop ) {
       
  5092 			_.extend( toolbarOptions.items, {
       
  5093 				skip: {
       
  5094 					style:      'secondary',
       
  5095 					text:       l10n.skipCropping,
       
  5096 					priority:   70,
       
  5097 					requires:   { library: false, selection: false },
       
  5098 					click:      function() {
       
  5099 						var selection = this.controller.state().get('selection').first();
       
  5100 						this.controller.state().cropperView.remove();
       
  5101 						this.controller.trigger('skippedcrop', selection);
       
  5102 						this.controller.close();
       
  5103 					}
       
  5104 				}
       
  5105 			});
       
  5106 		}
       
  5107 
       
  5108 		this.frame.toolbar.set( new wp.media.view.Toolbar(toolbarOptions) );
       
  5109 	},
       
  5110 
       
  5111 	/**
       
  5112 	 * Creates an object with the image attachment and crop properties.
       
  5113 	 *
       
  5114 	 * @since 4.2.0
       
  5115 	 *
       
  5116 	 * @return {$.promise} A jQuery promise with the custom header crop details.
       
  5117 	 */
       
  5118 	doCrop: function( attachment ) {
       
  5119 		return wp.ajax.post( 'custom-header-crop', _.extend(
       
  5120 			{},
       
  5121 			this.defaults.doCropArgs,
       
  5122 			{
       
  5123 				nonce: attachment.get( 'nonces' ).edit,
       
  5124 				id: attachment.get( 'id' ),
       
  5125 				cropDetails: attachment.get( 'cropDetails' )
       
  5126 			}
       
  5127 		) );
  1435 	}
  5128 	}
  1436 });
  5129 });
  1437 
  5130 
  1438 module.exports = GalleryEdit;
  5131 module.exports = Cropper;
  1439 
  5132 
  1440 
  5133 
  1441 /***/ }),
  5134 /***/ }),
  1442 /* 38 */
  5135 
       
  5136 /***/ "M5ZC":
  1443 /***/ (function(module, exports) {
  5137 /***/ (function(module, exports) {
  1444 
  5138 
  1445 var Selection = wp.media.model.Selection,
       
  1446 	Library = wp.media.controller.Library,
       
  1447 	l10n = wp.media.view.l10n,
       
  1448 	GalleryAdd;
       
  1449 
       
  1450 /**
  5139 /**
  1451  * wp.media.controller.GalleryAdd
  5140  * wp.media.controller.State
  1452  *
  5141  *
  1453  * A state for selecting more images to add to a gallery.
  5142  * A state is a step in a workflow that when set will trigger the controllers
  1454  *
  5143  * for the regions to be updated as specified in the frame.
  1455  * @since 3.5.0
  5144  *
       
  5145  * A state has an event-driven lifecycle:
       
  5146  *
       
  5147  *     'ready'      triggers when a state is added to a state machine's collection.
       
  5148  *     'activate'   triggers when a state is activated by a state machine.
       
  5149  *     'deactivate' triggers when a state is deactivated by a state machine.
       
  5150  *     'reset'      is not triggered automatically. It should be invoked by the
       
  5151  *                  proper controller to reset the state to its default.
       
  5152  *
       
  5153  * @memberOf wp.media.controller
  1456  *
  5154  *
  1457  * @class
  5155  * @class
  1458  * @augments wp.media.controller.Library
       
  1459  * @augments wp.media.controller.State
       
  1460  * @augments Backbone.Model
  5156  * @augments Backbone.Model
  1461  *
       
  1462  * @memberof wp.media.controller
       
  1463  *
       
  1464  * @param {Object}                     [attributes]                         The attributes hash passed to the state.
       
  1465  * @param {string}                     [attributes.id=gallery-library]      Unique identifier.
       
  1466  * @param {string}                     [attributes.title=Add to Gallery]    Title for the state. Displays in the frame's title region.
       
  1467  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
       
  1468  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
       
  1469  *                                                                          If one is not supplied, a collection of all images will be created.
       
  1470  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
       
  1471  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
       
  1472  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
       
  1473  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
       
  1474  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
       
  1475  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
       
  1476  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
       
  1477  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
       
  1478  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  1479  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
  1480  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
  1481  * @param {number}                     [attributes.priority=100]            The priority for the state link in the media menu.
       
  1482  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
       
  1483  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
       
  1484  */
  5157  */
  1485 GalleryAdd = Library.extend(/** @lends wp.media.controller.GalleryAdd.prototype */{
  5158 var State = Backbone.Model.extend(/** @lends wp.media.controller.State.prototype */{
  1486 	defaults: _.defaults({
  5159 	/**
  1487 		id:            'gallery-library',
  5160 	 * Constructor.
  1488 		title:         l10n.addToGalleryTitle,
       
  1489 		multiple:      'add',
       
  1490 		filterable:    'uploaded',
       
  1491 		menu:          'gallery',
       
  1492 		toolbar:       'gallery-add',
       
  1493 		priority:      100,
       
  1494 		syncSelection: false
       
  1495 	}, Library.prototype.defaults ),
       
  1496 
       
  1497 	/**
       
  1498 	 * Initializes the library. Creates a library of images if a library isn't supplied.
       
  1499 	 *
  5161 	 *
  1500 	 * @since 3.5.0
  5162 	 * @since 3.5.0
  1501 	 *
  5163 	 */
  1502 	 * @return {void}
  5164 	constructor: function() {
  1503 	 */
  5165 		this.on( 'activate', this._preActivate, this );
  1504 	initialize: function() {
  5166 		this.on( 'activate', this.activate, this );
  1505 		if ( ! this.get('library') ) {
  5167 		this.on( 'activate', this._postActivate, this );
  1506 			this.set( 'library', wp.media.query({ type: 'image' }) );
  5168 		this.on( 'deactivate', this._deactivate, this );
  1507 		}
  5169 		this.on( 'deactivate', this.deactivate, this );
  1508 
  5170 		this.on( 'reset', this.reset, this );
  1509 		Library.prototype.initialize.apply( this, arguments );
  5171 		this.on( 'ready', this._ready, this );
  1510 	},
  5172 		this.on( 'ready', this.ready, this );
  1511 
  5173 		/**
  1512 	/**
  5174 		 * Call parent constructor with passed arguments
  1513 	 * Activates the library.
  5175 		 */
  1514 	 *
  5176 		Backbone.Model.apply( this, arguments );
  1515 	 * Removes all event listeners if in edit mode. Creates a validator to check an attachment.
  5177 		this.on( 'change:menu', this._updateMenu, this );
  1516 	 * Resets library and re-enables event listeners. Activates edit mode. Calls the parent's activate method.
  5178 	},
  1517 	 *
  5179 	/**
       
  5180 	 * Ready event callback.
       
  5181 	 *
       
  5182 	 * @abstract
  1518 	 * @since 3.5.0
  5183 	 * @since 3.5.0
  1519 	 *
  5184 	 */
  1520 	 * @return {void}
  5185 	ready: function() {},
  1521 	 */
  5186 
  1522 	activate: function() {
  5187 	/**
  1523 		var library = this.get('library'),
  5188 	 * Activate event callback.
  1524 			edit    = this.frame.state('gallery-edit').get('library');
  5189 	 *
  1525 
  5190 	 * @abstract
  1526 		if ( this.editLibrary && this.editLibrary !== edit ) {
  5191 	 * @since 3.5.0
  1527 			library.unobserve( this.editLibrary );
  5192 	 */
  1528 		}
  5193 	activate: function() {},
  1529 
  5194 
  1530 		/*
  5195 	/**
  1531 		 * Accept attachments that exist in the original library but
  5196 	 * Deactivate event callback.
  1532 		 * that do not exist in gallery's library yet.
  5197 	 *
  1533 		 */
  5198 	 * @abstract
  1534 		library.validator = function( attachment ) {
  5199 	 * @since 3.5.0
  1535 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
  5200 	 */
  1536 		};
  5201 	deactivate: function() {},
  1537 
  5202 
  1538 		/*
  5203 	/**
  1539 		 * Reset the library to ensure that all attachments are re-added
  5204 	 * Reset event callback.
  1540 		 * to the collection. Do so silently, as calling `observe` will
  5205 	 *
  1541 		 * trigger the `reset` event.
  5206 	 * @abstract
  1542 		 */
  5207 	 * @since 3.5.0
  1543 		library.reset( library.mirroring.models, { silent: true });
  5208 	 */
  1544 		library.observe( edit );
  5209 	reset: function() {},
  1545 		this.editLibrary = edit;
  5210 
  1546 
  5211 	/**
  1547 		Library.prototype.activate.apply( this, arguments );
  5212 	 * @since 3.5.0
       
  5213 	 * @access private
       
  5214 	 */
       
  5215 	_ready: function() {
       
  5216 		this._updateMenu();
       
  5217 	},
       
  5218 
       
  5219 	/**
       
  5220 	 * @since 3.5.0
       
  5221 	 * @access private
       
  5222 	*/
       
  5223 	_preActivate: function() {
       
  5224 		this.active = true;
       
  5225 	},
       
  5226 
       
  5227 	/**
       
  5228 	 * @since 3.5.0
       
  5229 	 * @access private
       
  5230 	 */
       
  5231 	_postActivate: function() {
       
  5232 		this.on( 'change:menu', this._menu, this );
       
  5233 		this.on( 'change:titleMode', this._title, this );
       
  5234 		this.on( 'change:content', this._content, this );
       
  5235 		this.on( 'change:toolbar', this._toolbar, this );
       
  5236 
       
  5237 		this.frame.on( 'title:render:default', this._renderTitle, this );
       
  5238 
       
  5239 		this._title();
       
  5240 		this._menu();
       
  5241 		this._toolbar();
       
  5242 		this._content();
       
  5243 		this._router();
       
  5244 	},
       
  5245 
       
  5246 	/**
       
  5247 	 * @since 3.5.0
       
  5248 	 * @access private
       
  5249 	 */
       
  5250 	_deactivate: function() {
       
  5251 		this.active = false;
       
  5252 
       
  5253 		this.frame.off( 'title:render:default', this._renderTitle, this );
       
  5254 
       
  5255 		this.off( 'change:menu', this._menu, this );
       
  5256 		this.off( 'change:titleMode', this._title, this );
       
  5257 		this.off( 'change:content', this._content, this );
       
  5258 		this.off( 'change:toolbar', this._toolbar, this );
       
  5259 	},
       
  5260 
       
  5261 	/**
       
  5262 	 * @since 3.5.0
       
  5263 	 * @access private
       
  5264 	 */
       
  5265 	_title: function() {
       
  5266 		this.frame.title.render( this.get('titleMode') || 'default' );
       
  5267 	},
       
  5268 
       
  5269 	/**
       
  5270 	 * @since 3.5.0
       
  5271 	 * @access private
       
  5272 	 */
       
  5273 	_renderTitle: function( view ) {
       
  5274 		view.$el.text( this.get('title') || '' );
       
  5275 	},
       
  5276 
       
  5277 	/**
       
  5278 	 * @since 3.5.0
       
  5279 	 * @access private
       
  5280 	 */
       
  5281 	_router: function() {
       
  5282 		var router = this.frame.router,
       
  5283 			mode = this.get('router'),
       
  5284 			view;
       
  5285 
       
  5286 		this.frame.$el.toggleClass( 'hide-router', ! mode );
       
  5287 		if ( ! mode ) {
       
  5288 			return;
       
  5289 		}
       
  5290 
       
  5291 		this.frame.router.render( mode );
       
  5292 
       
  5293 		view = router.get();
       
  5294 		if ( view && view.select ) {
       
  5295 			view.select( this.frame.content.mode() );
       
  5296 		}
       
  5297 	},
       
  5298 
       
  5299 	/**
       
  5300 	 * @since 3.5.0
       
  5301 	 * @access private
       
  5302 	 */
       
  5303 	_menu: function() {
       
  5304 		var menu = this.frame.menu,
       
  5305 			mode = this.get('menu'),
       
  5306 			view;
       
  5307 
       
  5308 		this.frame.$el.toggleClass( 'hide-menu', ! mode );
       
  5309 		if ( ! mode ) {
       
  5310 			return;
       
  5311 		}
       
  5312 
       
  5313 		menu.mode( mode );
       
  5314 
       
  5315 		view = menu.get();
       
  5316 		if ( view && view.select ) {
       
  5317 			view.select( this.id );
       
  5318 		}
       
  5319 	},
       
  5320 
       
  5321 	/**
       
  5322 	 * @since 3.5.0
       
  5323 	 * @access private
       
  5324 	 */
       
  5325 	_updateMenu: function() {
       
  5326 		var previous = this.previous('menu'),
       
  5327 			menu = this.get('menu');
       
  5328 
       
  5329 		if ( previous ) {
       
  5330 			this.frame.off( 'menu:render:' + previous, this._renderMenu, this );
       
  5331 		}
       
  5332 
       
  5333 		if ( menu ) {
       
  5334 			this.frame.on( 'menu:render:' + menu, this._renderMenu, this );
       
  5335 		}
       
  5336 	},
       
  5337 
       
  5338 	/**
       
  5339 	 * Create a view in the media menu for the state.
       
  5340 	 *
       
  5341 	 * @since 3.5.0
       
  5342 	 * @access private
       
  5343 	 *
       
  5344 	 * @param {media.view.Menu} view The menu view.
       
  5345 	 */
       
  5346 	_renderMenu: function( view ) {
       
  5347 		var menuItem = this.get('menuItem'),
       
  5348 			title = this.get('title'),
       
  5349 			priority = this.get('priority');
       
  5350 
       
  5351 		if ( ! menuItem && title ) {
       
  5352 			menuItem = { text: title };
       
  5353 
       
  5354 			if ( priority ) {
       
  5355 				menuItem.priority = priority;
       
  5356 			}
       
  5357 		}
       
  5358 
       
  5359 		if ( ! menuItem ) {
       
  5360 			return;
       
  5361 		}
       
  5362 
       
  5363 		view.set( this.id, menuItem );
  1548 	}
  5364 	}
  1549 });
  5365 });
  1550 
  5366 
  1551 module.exports = GalleryAdd;
  5367 _.each(['toolbar','content'], function( region ) {
       
  5368 	/**
       
  5369 	 * @access private
       
  5370 	 */
       
  5371 	State.prototype[ '_' + region ] = function() {
       
  5372 		var mode = this.get( region );
       
  5373 		if ( mode ) {
       
  5374 			this.frame[ region ].render( mode );
       
  5375 		}
       
  5376 	};
       
  5377 });
       
  5378 
       
  5379 module.exports = State;
  1552 
  5380 
  1553 
  5381 
  1554 /***/ }),
  5382 /***/ }),
  1555 /* 39 */
  5383 
       
  5384 /***/ "Mt+m":
  1556 /***/ (function(module, exports) {
  5385 /***/ (function(module, exports) {
  1557 
  5386 
  1558 var Library = wp.media.controller.Library,
  5387 var Library = wp.media.controller.Library,
  1559 	l10n = wp.media.view.l10n,
  5388 	l10n = wp.media.view.l10n,
  1560 	$ = jQuery,
  5389 	$ = jQuery,
  1718 
  5547 
  1719 module.exports = CollectionEdit;
  5548 module.exports = CollectionEdit;
  1720 
  5549 
  1721 
  5550 
  1722 /***/ }),
  5551 /***/ }),
  1723 /* 40 */
  5552 
       
  5553 /***/ "NguE":
  1724 /***/ (function(module, exports) {
  5554 /***/ (function(module, exports) {
  1725 
  5555 
  1726 var Selection = wp.media.model.Selection,
  5556 var View = wp.media.View,
  1727 	Library = wp.media.controller.Library,
  5557 	UploaderStatus;
  1728 	CollectionAdd;
       
  1729 
  5558 
  1730 /**
  5559 /**
  1731  * wp.media.controller.CollectionAdd
  5560  * wp.media.view.UploaderStatus
  1732  *
  5561  *
  1733  * A state for adding attachments to a collection (e.g. video playlist).
  5562  * An uploader status for on-going uploads.
       
  5563  *
       
  5564  * @memberOf wp.media.view
       
  5565  *
       
  5566  * @class
       
  5567  * @augments wp.media.View
       
  5568  * @augments wp.Backbone.View
       
  5569  * @augments Backbone.View
       
  5570  */
       
  5571 UploaderStatus = View.extend(/** @lends wp.media.view.UploaderStatus.prototype */{
       
  5572 	className: 'media-uploader-status',
       
  5573 	template:  wp.template('uploader-status'),
       
  5574 
       
  5575 	events: {
       
  5576 		'click .upload-dismiss-errors': 'dismiss'
       
  5577 	},
       
  5578 
       
  5579 	initialize: function() {
       
  5580 		this.queue = wp.Uploader.queue;
       
  5581 		this.queue.on( 'add remove reset', this.visibility, this );
       
  5582 		this.queue.on( 'add remove reset change:percent', this.progress, this );
       
  5583 		this.queue.on( 'add remove reset change:uploading', this.info, this );
       
  5584 
       
  5585 		this.errors = wp.Uploader.errors;
       
  5586 		this.errors.reset();
       
  5587 		this.errors.on( 'add remove reset', this.visibility, this );
       
  5588 		this.errors.on( 'add', this.error, this );
       
  5589 	},
       
  5590 	/**
       
  5591 	 * @return {wp.media.view.UploaderStatus}
       
  5592 	 */
       
  5593 	dispose: function() {
       
  5594 		wp.Uploader.queue.off( null, null, this );
       
  5595 		/**
       
  5596 		 * call 'dispose' directly on the parent class
       
  5597 		 */
       
  5598 		View.prototype.dispose.apply( this, arguments );
       
  5599 		return this;
       
  5600 	},
       
  5601 
       
  5602 	visibility: function() {
       
  5603 		this.$el.toggleClass( 'uploading', !! this.queue.length );
       
  5604 		this.$el.toggleClass( 'errors', !! this.errors.length );
       
  5605 		this.$el.toggle( !! this.queue.length || !! this.errors.length );
       
  5606 	},
       
  5607 
       
  5608 	ready: function() {
       
  5609 		_.each({
       
  5610 			'$bar':      '.media-progress-bar div',
       
  5611 			'$index':    '.upload-index',
       
  5612 			'$total':    '.upload-total',
       
  5613 			'$filename': '.upload-filename'
       
  5614 		}, function( selector, key ) {
       
  5615 			this[ key ] = this.$( selector );
       
  5616 		}, this );
       
  5617 
       
  5618 		this.visibility();
       
  5619 		this.progress();
       
  5620 		this.info();
       
  5621 	},
       
  5622 
       
  5623 	progress: function() {
       
  5624 		var queue = this.queue,
       
  5625 			$bar = this.$bar;
       
  5626 
       
  5627 		if ( ! $bar || ! queue.length ) {
       
  5628 			return;
       
  5629 		}
       
  5630 
       
  5631 		$bar.width( ( queue.reduce( function( memo, attachment ) {
       
  5632 			if ( ! attachment.get('uploading') ) {
       
  5633 				return memo + 100;
       
  5634 			}
       
  5635 
       
  5636 			var percent = attachment.get('percent');
       
  5637 			return memo + ( _.isNumber( percent ) ? percent : 100 );
       
  5638 		}, 0 ) / queue.length ) + '%' );
       
  5639 	},
       
  5640 
       
  5641 	info: function() {
       
  5642 		var queue = this.queue,
       
  5643 			index = 0, active;
       
  5644 
       
  5645 		if ( ! queue.length ) {
       
  5646 			return;
       
  5647 		}
       
  5648 
       
  5649 		active = this.queue.find( function( attachment, i ) {
       
  5650 			index = i;
       
  5651 			return attachment.get('uploading');
       
  5652 		});
       
  5653 
       
  5654 		if ( this.$index && this.$total && this.$filename ) {
       
  5655 			this.$index.text( index + 1 );
       
  5656 			this.$total.text( queue.length );
       
  5657 			this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
       
  5658 		}
       
  5659 	},
       
  5660 	/**
       
  5661 	 * @param {string} filename
       
  5662 	 * @return {string}
       
  5663 	 */
       
  5664 	filename: function( filename ) {
       
  5665 		return _.escape( filename );
       
  5666 	},
       
  5667 	/**
       
  5668 	 * @param {Backbone.Model} error
       
  5669 	 */
       
  5670 	error: function( error ) {
       
  5671 		var statusError = new wp.media.view.UploaderStatusError( {
       
  5672 			filename: this.filename( error.get( 'file' ).name ),
       
  5673 			message:  error.get( 'message' )
       
  5674 		} );
       
  5675 
       
  5676 		var buttonClose = this.$el.find( 'button' );
       
  5677 
       
  5678 		// Can show additional info here while retrying to create image sub-sizes.
       
  5679 		this.views.add( '.upload-errors', statusError, { at: 0 } );
       
  5680 		_.delay( function() {
       
  5681 			buttonClose.trigger( 'focus' );
       
  5682 			wp.a11y.speak( error.get( 'message' ), 'assertive' );
       
  5683 		}, 1000 );
       
  5684 	},
       
  5685 
       
  5686 	dismiss: function() {
       
  5687 		var errors = this.views.get('.upload-errors');
       
  5688 
       
  5689 		if ( errors ) {
       
  5690 			_.invoke( errors, 'remove' );
       
  5691 		}
       
  5692 		wp.Uploader.errors.reset();
       
  5693 		// Move focus to the modal after the dismiss button gets removed from the DOM.
       
  5694 		if ( this.controller.modal ) {
       
  5695 			this.controller.modal.focusManager.focus();
       
  5696 		}
       
  5697 	}
       
  5698 });
       
  5699 
       
  5700 module.exports = UploaderStatus;
       
  5701 
       
  5702 
       
  5703 /***/ }),
       
  5704 
       
  5705 /***/ "NjyZ":
       
  5706 /***/ (function(module, exports) {
       
  5707 
       
  5708 /**
       
  5709  * wp.media.view.PriorityList
       
  5710  *
       
  5711  * @memberOf wp.media.view
       
  5712  *
       
  5713  * @class
       
  5714  * @augments wp.media.View
       
  5715  * @augments wp.Backbone.View
       
  5716  * @augments Backbone.View
       
  5717  */
       
  5718 var PriorityList = wp.media.View.extend(/** @lends wp.media.view.PriorityList.prototype */{
       
  5719 	tagName:   'div',
       
  5720 
       
  5721 	initialize: function() {
       
  5722 		this._views = {};
       
  5723 
       
  5724 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
       
  5725 		delete this.options.views;
       
  5726 
       
  5727 		if ( ! this.options.silent ) {
       
  5728 			this.render();
       
  5729 		}
       
  5730 	},
       
  5731 	/**
       
  5732 	 * @param {string} id
       
  5733 	 * @param {wp.media.View|Object} view
       
  5734 	 * @param {Object} options
       
  5735 	 * @return {wp.media.view.PriorityList} Returns itself to allow chaining.
       
  5736 	 */
       
  5737 	set: function( id, view, options ) {
       
  5738 		var priority, views, index;
       
  5739 
       
  5740 		options = options || {};
       
  5741 
       
  5742 		// Accept an object with an `id` : `view` mapping.
       
  5743 		if ( _.isObject( id ) ) {
       
  5744 			_.each( id, function( view, id ) {
       
  5745 				this.set( id, view );
       
  5746 			}, this );
       
  5747 			return this;
       
  5748 		}
       
  5749 
       
  5750 		if ( ! (view instanceof Backbone.View) ) {
       
  5751 			view = this.toView( view, id, options );
       
  5752 		}
       
  5753 		view.controller = view.controller || this.controller;
       
  5754 
       
  5755 		this.unset( id );
       
  5756 
       
  5757 		priority = view.options.priority || 10;
       
  5758 		views = this.views.get() || [];
       
  5759 
       
  5760 		_.find( views, function( existing, i ) {
       
  5761 			if ( existing.options.priority > priority ) {
       
  5762 				index = i;
       
  5763 				return true;
       
  5764 			}
       
  5765 		});
       
  5766 
       
  5767 		this._views[ id ] = view;
       
  5768 		this.views.add( view, {
       
  5769 			at: _.isNumber( index ) ? index : views.length || 0
       
  5770 		});
       
  5771 
       
  5772 		return this;
       
  5773 	},
       
  5774 	/**
       
  5775 	 * @param {string} id
       
  5776 	 * @return {wp.media.View}
       
  5777 	 */
       
  5778 	get: function( id ) {
       
  5779 		return this._views[ id ];
       
  5780 	},
       
  5781 	/**
       
  5782 	 * @param {string} id
       
  5783 	 * @return {wp.media.view.PriorityList}
       
  5784 	 */
       
  5785 	unset: function( id ) {
       
  5786 		var view = this.get( id );
       
  5787 
       
  5788 		if ( view ) {
       
  5789 			view.remove();
       
  5790 		}
       
  5791 
       
  5792 		delete this._views[ id ];
       
  5793 		return this;
       
  5794 	},
       
  5795 	/**
       
  5796 	 * @param {Object} options
       
  5797 	 * @return {wp.media.View}
       
  5798 	 */
       
  5799 	toView: function( options ) {
       
  5800 		return new wp.media.View( options );
       
  5801 	}
       
  5802 });
       
  5803 
       
  5804 module.exports = PriorityList;
       
  5805 
       
  5806 
       
  5807 /***/ }),
       
  5808 
       
  5809 /***/ "P6DV":
       
  5810 /***/ (function(module, exports) {
       
  5811 
       
  5812 /**
       
  5813  * wp.media.view.Attachment.EditSelection
       
  5814  *
       
  5815  * @memberOf wp.media.view.Attachment
       
  5816  *
       
  5817  * @class
       
  5818  * @augments wp.media.view.Attachment.Selection
       
  5819  * @augments wp.media.view.Attachment
       
  5820  * @augments wp.media.View
       
  5821  * @augments wp.Backbone.View
       
  5822  * @augments Backbone.View
       
  5823  */
       
  5824 var EditSelection = wp.media.view.Attachment.Selection.extend(/** @lends wp.media.view.Attachment.EditSelection.prototype */{
       
  5825 	buttons: {
       
  5826 		close: true
       
  5827 	}
       
  5828 });
       
  5829 
       
  5830 module.exports = EditSelection;
       
  5831 
       
  5832 
       
  5833 /***/ }),
       
  5834 
       
  5835 /***/ "PgTd":
       
  5836 /***/ (function(module, exports) {
       
  5837 
       
  5838 /**
       
  5839  * wp.media.selectionSync
       
  5840  *
       
  5841  * Sync an attachments selection in a state with another state.
       
  5842  *
       
  5843  * Allows for selecting multiple images in the Add Media workflow, and then
       
  5844  * switching to the Insert Gallery workflow while preserving the attachments selection.
       
  5845  *
       
  5846  * @memberOf wp.media
       
  5847  *
       
  5848  * @mixin
       
  5849  */
       
  5850 var selectionSync = {
       
  5851 	/**
       
  5852 	 * @since 3.5.0
       
  5853 	 */
       
  5854 	syncSelection: function() {
       
  5855 		var selection = this.get('selection'),
       
  5856 			manager = this.frame._selection;
       
  5857 
       
  5858 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
       
  5859 			return;
       
  5860 		}
       
  5861 
       
  5862 		/*
       
  5863 		 * If the selection supports multiple items, validate the stored
       
  5864 		 * attachments based on the new selection's conditions. Record
       
  5865 		 * the attachments that are not included; we'll maintain a
       
  5866 		 * reference to those. Other attachments are considered in flux.
       
  5867 		 */
       
  5868 		if ( selection.multiple ) {
       
  5869 			selection.reset( [], { silent: true });
       
  5870 			selection.validateAll( manager.attachments );
       
  5871 			manager.difference = _.difference( manager.attachments.models, selection.models );
       
  5872 		}
       
  5873 
       
  5874 		// Sync the selection's single item with the master.
       
  5875 		selection.single( manager.single );
       
  5876 	},
       
  5877 
       
  5878 	/**
       
  5879 	 * Record the currently active attachments, which is a combination
       
  5880 	 * of the selection's attachments and the set of selected
       
  5881 	 * attachments that this specific selection considered invalid.
       
  5882 	 * Reset the difference and record the single attachment.
       
  5883 	 *
       
  5884 	 * @since 3.5.0
       
  5885 	 */
       
  5886 	recordSelection: function() {
       
  5887 		var selection = this.get('selection'),
       
  5888 			manager = this.frame._selection;
       
  5889 
       
  5890 		if ( ! this.get('syncSelection') || ! manager || ! selection ) {
       
  5891 			return;
       
  5892 		}
       
  5893 
       
  5894 		if ( selection.multiple ) {
       
  5895 			manager.attachments.reset( selection.toArray().concat( manager.difference ) );
       
  5896 			manager.difference = [];
       
  5897 		} else {
       
  5898 			manager.attachments.add( selection.toArray() );
       
  5899 		}
       
  5900 
       
  5901 		manager.single = selection._single;
       
  5902 	}
       
  5903 };
       
  5904 
       
  5905 module.exports = selectionSync;
       
  5906 
       
  5907 
       
  5908 /***/ }),
       
  5909 
       
  5910 /***/ "Pt9x":
       
  5911 /***/ (function(module, exports) {
       
  5912 
       
  5913 var Frame = wp.media.view.Frame,
       
  5914 	l10n = wp.media.view.l10n,
       
  5915 	$ = jQuery,
       
  5916 	MediaFrame;
       
  5917 
       
  5918 /**
       
  5919  * wp.media.view.MediaFrame
       
  5920  *
       
  5921  * The frame used to create the media modal.
       
  5922  *
       
  5923  * @memberOf wp.media.view
       
  5924  *
       
  5925  * @class
       
  5926  * @augments wp.media.view.Frame
       
  5927  * @augments wp.media.View
       
  5928  * @augments wp.Backbone.View
       
  5929  * @augments Backbone.View
       
  5930  * @mixes wp.media.controller.StateMachine
       
  5931  */
       
  5932 MediaFrame = Frame.extend(/** @lends wp.media.view.MediaFrame.prototype */{
       
  5933 	className: 'media-frame',
       
  5934 	template:  wp.template('media-frame'),
       
  5935 	regions:   ['menu','title','content','toolbar','router'],
       
  5936 
       
  5937 	events: {
       
  5938 		'click .media-frame-menu-toggle': 'toggleMenu'
       
  5939 	},
       
  5940 
       
  5941 	/**
       
  5942 	 * @constructs
       
  5943 	 */
       
  5944 	initialize: function() {
       
  5945 		Frame.prototype.initialize.apply( this, arguments );
       
  5946 
       
  5947 		_.defaults( this.options, {
       
  5948 			title:    l10n.mediaFrameDefaultTitle,
       
  5949 			modal:    true,
       
  5950 			uploader: true
       
  5951 		});
       
  5952 
       
  5953 		// Ensure core UI is enabled.
       
  5954 		this.$el.addClass('wp-core-ui');
       
  5955 
       
  5956 		// Initialize modal container view.
       
  5957 		if ( this.options.modal ) {
       
  5958 			this.modal = new wp.media.view.Modal({
       
  5959 				controller: this,
       
  5960 				title:      this.options.title
       
  5961 			});
       
  5962 
       
  5963 			this.modal.content( this );
       
  5964 		}
       
  5965 
       
  5966 		// Force the uploader off if the upload limit has been exceeded or
       
  5967 		// if the browser isn't supported.
       
  5968 		if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
       
  5969 			this.options.uploader = false;
       
  5970 		}
       
  5971 
       
  5972 		// Initialize window-wide uploader.
       
  5973 		if ( this.options.uploader ) {
       
  5974 			this.uploader = new wp.media.view.UploaderWindow({
       
  5975 				controller: this,
       
  5976 				uploader: {
       
  5977 					dropzone:  this.modal ? this.modal.$el : this.$el,
       
  5978 					container: this.$el
       
  5979 				}
       
  5980 			});
       
  5981 			this.views.set( '.media-frame-uploader', this.uploader );
       
  5982 		}
       
  5983 
       
  5984 		this.on( 'attach', _.bind( this.views.ready, this.views ), this );
       
  5985 
       
  5986 		// Bind default title creation.
       
  5987 		this.on( 'title:create:default', this.createTitle, this );
       
  5988 		this.title.mode('default');
       
  5989 
       
  5990 		// Bind default menu.
       
  5991 		this.on( 'menu:create:default', this.createMenu, this );
       
  5992 
       
  5993 		// Set the menu ARIA tab panel attributes when the modal opens.
       
  5994 		this.on( 'open', this.setMenuTabPanelAriaAttributes, this );
       
  5995 		// Set the router ARIA tab panel attributes when the modal opens.
       
  5996 		this.on( 'open', this.setRouterTabPanelAriaAttributes, this );
       
  5997 
       
  5998 		// Update the menu ARIA tab panel attributes when the content updates.
       
  5999 		this.on( 'content:render', this.setMenuTabPanelAriaAttributes, this );
       
  6000 		// Update the router ARIA tab panel attributes when the content updates.
       
  6001 		this.on( 'content:render', this.setRouterTabPanelAriaAttributes, this );
       
  6002 	},
       
  6003 
       
  6004 	/**
       
  6005 	 * Sets the attributes to be used on the menu ARIA tab panel.
       
  6006 	 *
       
  6007 	 * @since 5.3.0
       
  6008 	 *
       
  6009 	 * @return {void}
       
  6010 	 */
       
  6011 	setMenuTabPanelAriaAttributes: function() {
       
  6012 		var stateId = this.state().get( 'id' ),
       
  6013 			tabPanelEl = this.$el.find( '.media-frame-tab-panel' ),
       
  6014 			ariaLabelledby;
       
  6015 
       
  6016 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
       
  6017 
       
  6018 		if ( this.state().get( 'menu' ) && this.menuView && this.menuView.isVisible ) {
       
  6019 			ariaLabelledby = 'menu-item-' + stateId;
       
  6020 
       
  6021 			// Set the tab panel attributes only if the tabs are visible.
       
  6022 			tabPanelEl
       
  6023 				.attr( {
       
  6024 					role: 'tabpanel',
       
  6025 					'aria-labelledby': ariaLabelledby,
       
  6026 					tabIndex: '0'
       
  6027 				} );
       
  6028 		}
       
  6029 	},
       
  6030 
       
  6031 	/**
       
  6032 	 * Sets the attributes to be used on the router ARIA tab panel.
       
  6033 	 *
       
  6034 	 * @since 5.3.0
       
  6035 	 *
       
  6036 	 * @return {void}
       
  6037 	 */
       
  6038 	setRouterTabPanelAriaAttributes: function() {
       
  6039 		var tabPanelEl = this.$el.find( '.media-frame-content' ),
       
  6040 			ariaLabelledby;
       
  6041 
       
  6042 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
       
  6043 
       
  6044 		// Set the tab panel attributes only if the tabs are visible.
       
  6045 		if ( this.state().get( 'router' ) && this.routerView && this.routerView.isVisible && this.content._mode ) {
       
  6046 			ariaLabelledby = 'menu-item-' + this.content._mode;
       
  6047 
       
  6048 			tabPanelEl
       
  6049 				.attr( {
       
  6050 					role: 'tabpanel',
       
  6051 					'aria-labelledby': ariaLabelledby,
       
  6052 					tabIndex: '0'
       
  6053 				} );
       
  6054 		}
       
  6055 	},
       
  6056 
       
  6057 	/**
       
  6058 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  6059 	 */
       
  6060 	render: function() {
       
  6061 		// Activate the default state if no active state exists.
       
  6062 		if ( ! this.state() && this.options.state ) {
       
  6063 			this.setState( this.options.state );
       
  6064 		}
       
  6065 		/**
       
  6066 		 * call 'render' directly on the parent class
       
  6067 		 */
       
  6068 		return Frame.prototype.render.apply( this, arguments );
       
  6069 	},
       
  6070 	/**
       
  6071 	 * @param {Object} title
       
  6072 	 * @this wp.media.controller.Region
       
  6073 	 */
       
  6074 	createTitle: function( title ) {
       
  6075 		title.view = new wp.media.View({
       
  6076 			controller: this,
       
  6077 			tagName: 'h1'
       
  6078 		});
       
  6079 	},
       
  6080 	/**
       
  6081 	 * @param {Object} menu
       
  6082 	 * @this wp.media.controller.Region
       
  6083 	 */
       
  6084 	createMenu: function( menu ) {
       
  6085 		menu.view = new wp.media.view.Menu({
       
  6086 			controller: this,
       
  6087 
       
  6088 			attributes: {
       
  6089 				role:               'tablist',
       
  6090 				'aria-orientation': 'vertical'
       
  6091 			}
       
  6092 		});
       
  6093 
       
  6094 		this.menuView = menu.view;
       
  6095 	},
       
  6096 
       
  6097 	toggleMenu: function( event ) {
       
  6098 		var menu = this.$el.find( '.media-menu' );
       
  6099 
       
  6100 		menu.toggleClass( 'visible' );
       
  6101 		$( event.target ).attr( 'aria-expanded', menu.hasClass( 'visible' ) );
       
  6102 	},
       
  6103 
       
  6104 	/**
       
  6105 	 * @param {Object} toolbar
       
  6106 	 * @this wp.media.controller.Region
       
  6107 	 */
       
  6108 	createToolbar: function( toolbar ) {
       
  6109 		toolbar.view = new wp.media.view.Toolbar({
       
  6110 			controller: this
       
  6111 		});
       
  6112 	},
       
  6113 	/**
       
  6114 	 * @param {Object} router
       
  6115 	 * @this wp.media.controller.Region
       
  6116 	 */
       
  6117 	createRouter: function( router ) {
       
  6118 		router.view = new wp.media.view.Router({
       
  6119 			controller: this,
       
  6120 
       
  6121 			attributes: {
       
  6122 				role:               'tablist',
       
  6123 				'aria-orientation': 'horizontal'
       
  6124 			}
       
  6125 		});
       
  6126 
       
  6127 		this.routerView = router.view;
       
  6128 	},
       
  6129 	/**
       
  6130 	 * @param {Object} options
       
  6131 	 */
       
  6132 	createIframeStates: function( options ) {
       
  6133 		var settings = wp.media.view.settings,
       
  6134 			tabs = settings.tabs,
       
  6135 			tabUrl = settings.tabUrl,
       
  6136 			$postId;
       
  6137 
       
  6138 		if ( ! tabs || ! tabUrl ) {
       
  6139 			return;
       
  6140 		}
       
  6141 
       
  6142 		// Add the post ID to the tab URL if it exists.
       
  6143 		$postId = $('#post_ID');
       
  6144 		if ( $postId.length ) {
       
  6145 			tabUrl += '&post_id=' + $postId.val();
       
  6146 		}
       
  6147 
       
  6148 		// Generate the tab states.
       
  6149 		_.each( tabs, function( title, id ) {
       
  6150 			this.state( 'iframe:' + id ).set( _.defaults({
       
  6151 				tab:     id,
       
  6152 				src:     tabUrl + '&tab=' + id,
       
  6153 				title:   title,
       
  6154 				content: 'iframe',
       
  6155 				menu:    'default'
       
  6156 			}, options ) );
       
  6157 		}, this );
       
  6158 
       
  6159 		this.on( 'content:create:iframe', this.iframeContent, this );
       
  6160 		this.on( 'content:deactivate:iframe', this.iframeContentCleanup, this );
       
  6161 		this.on( 'menu:render:default', this.iframeMenu, this );
       
  6162 		this.on( 'open', this.hijackThickbox, this );
       
  6163 		this.on( 'close', this.restoreThickbox, this );
       
  6164 	},
       
  6165 
       
  6166 	/**
       
  6167 	 * @param {Object} content
       
  6168 	 * @this wp.media.controller.Region
       
  6169 	 */
       
  6170 	iframeContent: function( content ) {
       
  6171 		this.$el.addClass('hide-toolbar');
       
  6172 		content.view = new wp.media.view.Iframe({
       
  6173 			controller: this
       
  6174 		});
       
  6175 	},
       
  6176 
       
  6177 	iframeContentCleanup: function() {
       
  6178 		this.$el.removeClass('hide-toolbar');
       
  6179 	},
       
  6180 
       
  6181 	iframeMenu: function( view ) {
       
  6182 		var views = {};
       
  6183 
       
  6184 		if ( ! view ) {
       
  6185 			return;
       
  6186 		}
       
  6187 
       
  6188 		_.each( wp.media.view.settings.tabs, function( title, id ) {
       
  6189 			views[ 'iframe:' + id ] = {
       
  6190 				text: this.state( 'iframe:' + id ).get('title'),
       
  6191 				priority: 200
       
  6192 			};
       
  6193 		}, this );
       
  6194 
       
  6195 		view.set( views );
       
  6196 	},
       
  6197 
       
  6198 	hijackThickbox: function() {
       
  6199 		var frame = this;
       
  6200 
       
  6201 		if ( ! window.tb_remove || this._tb_remove ) {
       
  6202 			return;
       
  6203 		}
       
  6204 
       
  6205 		this._tb_remove = window.tb_remove;
       
  6206 		window.tb_remove = function() {
       
  6207 			frame.close();
       
  6208 			frame.reset();
       
  6209 			frame.setState( frame.options.state );
       
  6210 			frame._tb_remove.call( window );
       
  6211 		};
       
  6212 	},
       
  6213 
       
  6214 	restoreThickbox: function() {
       
  6215 		if ( ! this._tb_remove ) {
       
  6216 			return;
       
  6217 		}
       
  6218 
       
  6219 		window.tb_remove = this._tb_remove;
       
  6220 		delete this._tb_remove;
       
  6221 	}
       
  6222 });
       
  6223 
       
  6224 // Map some of the modal's methods to the frame.
       
  6225 _.each(['open','close','attach','detach','escape'], function( method ) {
       
  6226 	/**
       
  6227 	 * @function open
       
  6228 	 * @memberOf wp.media.view.MediaFrame
       
  6229 	 * @instance
       
  6230 	 *
       
  6231 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  6232 	 */
       
  6233 	/**
       
  6234 	 * @function close
       
  6235 	 * @memberOf wp.media.view.MediaFrame
       
  6236 	 * @instance
       
  6237 	 *
       
  6238 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  6239 	 */
       
  6240 	/**
       
  6241 	 * @function attach
       
  6242 	 * @memberOf wp.media.view.MediaFrame
       
  6243 	 * @instance
       
  6244 	 *
       
  6245 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  6246 	 */
       
  6247 	/**
       
  6248 	 * @function detach
       
  6249 	 * @memberOf wp.media.view.MediaFrame
       
  6250 	 * @instance
       
  6251 	 *
       
  6252 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  6253 	 */
       
  6254 	/**
       
  6255 	 * @function escape
       
  6256 	 * @memberOf wp.media.view.MediaFrame
       
  6257 	 * @instance
       
  6258 	 *
       
  6259 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  6260 	 */
       
  6261 	MediaFrame.prototype[ method ] = function() {
       
  6262 		if ( this.modal ) {
       
  6263 			this.modal[ method ].apply( this.modal, arguments );
       
  6264 		}
       
  6265 		return this;
       
  6266 	};
       
  6267 });
       
  6268 
       
  6269 module.exports = MediaFrame;
       
  6270 
       
  6271 
       
  6272 /***/ }),
       
  6273 
       
  6274 /***/ "Q9T/":
       
  6275 /***/ (function(module, exports) {
       
  6276 
       
  6277 /**
       
  6278  * wp.media.view.RouterItem
       
  6279  *
       
  6280  * @memberOf wp.media.view
       
  6281  *
       
  6282  * @class
       
  6283  * @augments wp.media.view.MenuItem
       
  6284  * @augments wp.media.View
       
  6285  * @augments wp.Backbone.View
       
  6286  * @augments Backbone.View
       
  6287  */
       
  6288 var RouterItem = wp.media.view.MenuItem.extend(/** @lends wp.media.view.RouterItem.prototype */{
       
  6289 	/**
       
  6290 	 * On click handler to activate the content region's corresponding mode.
       
  6291 	 */
       
  6292 	click: function() {
       
  6293 		var contentMode = this.options.contentMode;
       
  6294 		if ( contentMode ) {
       
  6295 			this.controller.content.mode( contentMode );
       
  6296 		}
       
  6297 	}
       
  6298 });
       
  6299 
       
  6300 module.exports = RouterItem;
       
  6301 
       
  6302 
       
  6303 /***/ }),
       
  6304 
       
  6305 /***/ "S4jH":
       
  6306 /***/ (function(module, exports) {
       
  6307 
       
  6308 var $ = jQuery,
       
  6309 	UploaderWindow;
       
  6310 
       
  6311 /**
       
  6312  * wp.media.view.UploaderWindow
       
  6313  *
       
  6314  * An uploader window that allows for dragging and dropping media.
       
  6315  *
       
  6316  * @memberOf wp.media.view
       
  6317  *
       
  6318  * @class
       
  6319  * @augments wp.media.View
       
  6320  * @augments wp.Backbone.View
       
  6321  * @augments Backbone.View
       
  6322  *
       
  6323  * @param {object} [options]                   Options hash passed to the view.
       
  6324  * @param {object} [options.uploader]          Uploader properties.
       
  6325  * @param {jQuery} [options.uploader.browser]
       
  6326  * @param {jQuery} [options.uploader.dropzone] jQuery collection of the dropzone.
       
  6327  * @param {object} [options.uploader.params]
       
  6328  */
       
  6329 UploaderWindow = wp.media.View.extend(/** @lends wp.media.view.UploaderWindow.prototype */{
       
  6330 	tagName:   'div',
       
  6331 	className: 'uploader-window',
       
  6332 	template:  wp.template('uploader-window'),
       
  6333 
       
  6334 	initialize: function() {
       
  6335 		var uploader;
       
  6336 
       
  6337 		this.$browser = $( '<button type="button" class="browser" />' ).hide().appendTo( 'body' );
       
  6338 
       
  6339 		uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
       
  6340 			dropzone:  this.$el,
       
  6341 			browser:   this.$browser,
       
  6342 			params:    {}
       
  6343 		});
       
  6344 
       
  6345 		// Ensure the dropzone is a jQuery collection.
       
  6346 		if ( uploader.dropzone && ! (uploader.dropzone instanceof $) ) {
       
  6347 			uploader.dropzone = $( uploader.dropzone );
       
  6348 		}
       
  6349 
       
  6350 		this.controller.on( 'activate', this.refresh, this );
       
  6351 
       
  6352 		this.controller.on( 'detach', function() {
       
  6353 			this.$browser.remove();
       
  6354 		}, this );
       
  6355 	},
       
  6356 
       
  6357 	refresh: function() {
       
  6358 		if ( this.uploader ) {
       
  6359 			this.uploader.refresh();
       
  6360 		}
       
  6361 	},
       
  6362 
       
  6363 	ready: function() {
       
  6364 		var postId = wp.media.view.settings.post.id,
       
  6365 			dropzone;
       
  6366 
       
  6367 		// If the uploader already exists, bail.
       
  6368 		if ( this.uploader ) {
       
  6369 			return;
       
  6370 		}
       
  6371 
       
  6372 		if ( postId ) {
       
  6373 			this.options.uploader.params.post_id = postId;
       
  6374 		}
       
  6375 		this.uploader = new wp.Uploader( this.options.uploader );
       
  6376 
       
  6377 		dropzone = this.uploader.dropzone;
       
  6378 		dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
       
  6379 		dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
       
  6380 
       
  6381 		$( this.uploader ).on( 'uploader:ready', _.bind( this._ready, this ) );
       
  6382 	},
       
  6383 
       
  6384 	_ready: function() {
       
  6385 		this.controller.trigger( 'uploader:ready' );
       
  6386 	},
       
  6387 
       
  6388 	show: function() {
       
  6389 		var $el = this.$el.show();
       
  6390 
       
  6391 		// Ensure that the animation is triggered by waiting until
       
  6392 		// the transparent element is painted into the DOM.
       
  6393 		_.defer( function() {
       
  6394 			$el.css({ opacity: 1 });
       
  6395 		});
       
  6396 	},
       
  6397 
       
  6398 	hide: function() {
       
  6399 		var $el = this.$el.css({ opacity: 0 });
       
  6400 
       
  6401 		wp.media.transition( $el ).done( function() {
       
  6402 			// Transition end events are subject to race conditions.
       
  6403 			// Make sure that the value is set as intended.
       
  6404 			if ( '0' === $el.css('opacity') ) {
       
  6405 				$el.hide();
       
  6406 			}
       
  6407 		});
       
  6408 
       
  6409 		// https://core.trac.wordpress.org/ticket/27341
       
  6410 		_.delay( function() {
       
  6411 			if ( '0' === $el.css('opacity') && $el.is(':visible') ) {
       
  6412 				$el.hide();
       
  6413 			}
       
  6414 		}, 500 );
       
  6415 	}
       
  6416 });
       
  6417 
       
  6418 module.exports = UploaderWindow;
       
  6419 
       
  6420 
       
  6421 /***/ }),
       
  6422 
       
  6423 /***/ "U3Se":
       
  6424 /***/ (function(module, exports) {
       
  6425 
       
  6426 /**
       
  6427  * wp.media.controller.StateMachine
       
  6428  *
       
  6429  * A state machine keeps track of state. It is in one state at a time,
       
  6430  * and can change from one state to another.
       
  6431  *
       
  6432  * States are stored as models in a Backbone collection.
  1734  *
  6433  *
  1735  * @memberOf wp.media.controller
  6434  * @memberOf wp.media.controller
  1736  *
  6435  *
       
  6436  * @since 3.5.0
       
  6437  *
  1737  * @class
  6438  * @class
  1738  * @augments wp.media.controller.Library
  6439  * @augments Backbone.Model
       
  6440  * @mixin
       
  6441  * @mixes Backbone.Events
       
  6442  */
       
  6443 var StateMachine = function() {
       
  6444 	return {
       
  6445 		// Use Backbone's self-propagating `extend` inheritance method.
       
  6446 		extend: Backbone.Model.extend
       
  6447 	};
       
  6448 };
       
  6449 
       
  6450 _.extend( StateMachine.prototype, Backbone.Events,/** @lends wp.media.controller.StateMachine.prototype */{
       
  6451 	/**
       
  6452 	 * Fetch a state.
       
  6453 	 *
       
  6454 	 * If no `id` is provided, returns the active state.
       
  6455 	 *
       
  6456 	 * Implicitly creates states.
       
  6457 	 *
       
  6458 	 * Ensure that the `states` collection exists so the `StateMachine`
       
  6459 	 * can be used as a mixin.
       
  6460 	 *
       
  6461 	 * @since 3.5.0
       
  6462 	 *
       
  6463 	 * @param {string} id
       
  6464 	 * @return {wp.media.controller.State} Returns a State model from
       
  6465 	 *                                     the StateMachine collection.
       
  6466 	 */
       
  6467 	state: function( id ) {
       
  6468 		this.states = this.states || new Backbone.Collection();
       
  6469 
       
  6470 		// Default to the active state.
       
  6471 		id = id || this._state;
       
  6472 
       
  6473 		if ( id && ! this.states.get( id ) ) {
       
  6474 			this.states.add({ id: id });
       
  6475 		}
       
  6476 		return this.states.get( id );
       
  6477 	},
       
  6478 
       
  6479 	/**
       
  6480 	 * Sets the active state.
       
  6481 	 *
       
  6482 	 * Bail if we're trying to select the current state, if we haven't
       
  6483 	 * created the `states` collection, or are trying to select a state
       
  6484 	 * that does not exist.
       
  6485 	 *
       
  6486 	 * @since 3.5.0
       
  6487 	 *
       
  6488 	 * @param {string} id
       
  6489 	 *
       
  6490 	 * @fires wp.media.controller.State#deactivate
       
  6491 	 * @fires wp.media.controller.State#activate
       
  6492 	 *
       
  6493 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  6494 	 */
       
  6495 	setState: function( id ) {
       
  6496 		var previous = this.state();
       
  6497 
       
  6498 		if ( ( previous && id === previous.id ) || ! this.states || ! this.states.get( id ) ) {
       
  6499 			return this;
       
  6500 		}
       
  6501 
       
  6502 		if ( previous ) {
       
  6503 			previous.trigger('deactivate');
       
  6504 			this._lastState = previous.id;
       
  6505 		}
       
  6506 
       
  6507 		this._state = id;
       
  6508 		this.state().trigger('activate');
       
  6509 
       
  6510 		return this;
       
  6511 	},
       
  6512 
       
  6513 	/**
       
  6514 	 * Returns the previous active state.
       
  6515 	 *
       
  6516 	 * Call the `state()` method with no parameters to retrieve the current
       
  6517 	 * active state.
       
  6518 	 *
       
  6519 	 * @since 3.5.0
       
  6520 	 *
       
  6521 	 * @return {wp.media.controller.State} Returns a State model from
       
  6522 	 *                                     the StateMachine collection.
       
  6523 	 */
       
  6524 	lastState: function() {
       
  6525 		if ( this._lastState ) {
       
  6526 			return this.state( this._lastState );
       
  6527 		}
       
  6528 	}
       
  6529 });
       
  6530 
       
  6531 // Map all event binding and triggering on a StateMachine to its `states` collection.
       
  6532 _.each([ 'on', 'off', 'trigger' ], function( method ) {
       
  6533 	/**
       
  6534 	 * @function on
       
  6535 	 * @memberOf wp.media.controller.StateMachine
       
  6536 	 * @instance
       
  6537 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  6538 	 */
       
  6539 	/**
       
  6540 	 * @function off
       
  6541 	 * @memberOf wp.media.controller.StateMachine
       
  6542 	 * @instance
       
  6543 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  6544 	 */
       
  6545 	/**
       
  6546 	 * @function trigger
       
  6547 	 * @memberOf wp.media.controller.StateMachine
       
  6548 	 * @instance
       
  6549 	 * @return {wp.media.controller.StateMachine} Returns itself to allow chaining.
       
  6550 	 */
       
  6551 	StateMachine.prototype[ method ] = function() {
       
  6552 		// Ensure that the `states` collection exists so the `StateMachine`
       
  6553 		// can be used as a mixin.
       
  6554 		this.states = this.states || new Backbone.Collection();
       
  6555 		// Forward the method to the `states` collection.
       
  6556 		this.states[ method ].apply( this.states, arguments );
       
  6557 		return this;
       
  6558 	};
       
  6559 });
       
  6560 
       
  6561 module.exports = StateMachine;
       
  6562 
       
  6563 
       
  6564 /***/ }),
       
  6565 
       
  6566 /***/ "UmHM":
       
  6567 /***/ (function(module, exports) {
       
  6568 
       
  6569 var View = wp.media.view,
       
  6570 	SiteIconCropper;
       
  6571 
       
  6572 /**
       
  6573  * wp.media.view.SiteIconCropper
       
  6574  *
       
  6575  * Uses the imgAreaSelect plugin to allow a user to crop a Site Icon.
       
  6576  *
       
  6577  * Takes imgAreaSelect options from
       
  6578  * wp.customize.SiteIconControl.calculateImageSelectOptions.
       
  6579  *
       
  6580  * @memberOf wp.media.view
       
  6581  *
       
  6582  * @class
       
  6583  * @augments wp.media.view.Cropper
       
  6584  * @augments wp.media.View
       
  6585  * @augments wp.Backbone.View
       
  6586  * @augments Backbone.View
       
  6587  */
       
  6588 SiteIconCropper = View.Cropper.extend(/** @lends wp.media.view.SiteIconCropper.prototype */{
       
  6589 	className: 'crop-content site-icon',
       
  6590 
       
  6591 	ready: function () {
       
  6592 		View.Cropper.prototype.ready.apply( this, arguments );
       
  6593 
       
  6594 		this.$( '.crop-image' ).on( 'load', _.bind( this.addSidebar, this ) );
       
  6595 	},
       
  6596 
       
  6597 	addSidebar: function() {
       
  6598 		this.sidebar = new wp.media.view.Sidebar({
       
  6599 			controller: this.controller
       
  6600 		});
       
  6601 
       
  6602 		this.sidebar.set( 'preview', new wp.media.view.SiteIconPreview({
       
  6603 			controller: this.controller,
       
  6604 			attachment: this.options.attachment
       
  6605 		}) );
       
  6606 
       
  6607 		this.controller.cropperView.views.add( this.sidebar );
       
  6608 	}
       
  6609 });
       
  6610 
       
  6611 module.exports = SiteIconCropper;
       
  6612 
       
  6613 
       
  6614 /***/ }),
       
  6615 
       
  6616 /***/ "V6sy":
       
  6617 /***/ (function(module, exports) {
       
  6618 
       
  6619 /**
       
  6620  * wp.media.view.Label
       
  6621  *
       
  6622  * @memberOf wp.media.view
       
  6623  *
       
  6624  * @class
       
  6625  * @augments wp.media.View
       
  6626  * @augments wp.Backbone.View
       
  6627  * @augments Backbone.View
       
  6628  */
       
  6629 var Label = wp.media.View.extend(/** @lends wp.media.view.Label.prototype */{
       
  6630 	tagName: 'label',
       
  6631 	className: 'screen-reader-text',
       
  6632 
       
  6633 	initialize: function() {
       
  6634 		this.value = this.options.value;
       
  6635 	},
       
  6636 
       
  6637 	render: function() {
       
  6638 		this.$el.html( this.value );
       
  6639 
       
  6640 		return this;
       
  6641 	}
       
  6642 });
       
  6643 
       
  6644 module.exports = Label;
       
  6645 
       
  6646 
       
  6647 /***/ }),
       
  6648 
       
  6649 /***/ "VIJ9":
       
  6650 /***/ (function(module, exports) {
       
  6651 
       
  6652 var Select = wp.media.view.MediaFrame.Select,
       
  6653 	l10n = wp.media.view.l10n,
       
  6654 	ImageDetails;
       
  6655 
       
  6656 /**
       
  6657  * wp.media.view.MediaFrame.ImageDetails
       
  6658  *
       
  6659  * A media frame for manipulating an image that's already been inserted
       
  6660  * into a post.
       
  6661  *
       
  6662  * @memberOf wp.media.view.MediaFrame
       
  6663  *
       
  6664  * @class
       
  6665  * @augments wp.media.view.MediaFrame.Select
       
  6666  * @augments wp.media.view.MediaFrame
       
  6667  * @augments wp.media.view.Frame
       
  6668  * @augments wp.media.View
       
  6669  * @augments wp.Backbone.View
       
  6670  * @augments Backbone.View
       
  6671  * @mixes wp.media.controller.StateMachine
       
  6672  */
       
  6673 ImageDetails = Select.extend(/** @lends wp.media.view.MediaFrame.ImageDetails.prototype */{
       
  6674 	defaults: {
       
  6675 		id:      'image',
       
  6676 		url:     '',
       
  6677 		menu:    'image-details',
       
  6678 		content: 'image-details',
       
  6679 		toolbar: 'image-details',
       
  6680 		type:    'link',
       
  6681 		title:    l10n.imageDetailsTitle,
       
  6682 		priority: 120
       
  6683 	},
       
  6684 
       
  6685 	initialize: function( options ) {
       
  6686 		this.image = new wp.media.model.PostImage( options.metadata );
       
  6687 		this.options.selection = new wp.media.model.Selection( this.image.attachment, { multiple: false } );
       
  6688 		Select.prototype.initialize.apply( this, arguments );
       
  6689 	},
       
  6690 
       
  6691 	bindHandlers: function() {
       
  6692 		Select.prototype.bindHandlers.apply( this, arguments );
       
  6693 		this.on( 'menu:create:image-details', this.createMenu, this );
       
  6694 		this.on( 'content:create:image-details', this.imageDetailsContent, this );
       
  6695 		this.on( 'content:render:edit-image', this.editImageContent, this );
       
  6696 		this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
       
  6697 		// Override the select toolbar.
       
  6698 		this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
       
  6699 	},
       
  6700 
       
  6701 	createStates: function() {
       
  6702 		this.states.add([
       
  6703 			new wp.media.controller.ImageDetails({
       
  6704 				image: this.image,
       
  6705 				editable: false
       
  6706 			}),
       
  6707 			new wp.media.controller.ReplaceImage({
       
  6708 				id: 'replace-image',
       
  6709 				library: wp.media.query( { type: 'image' } ),
       
  6710 				image: this.image,
       
  6711 				multiple:  false,
       
  6712 				title:     l10n.imageReplaceTitle,
       
  6713 				toolbar: 'replace',
       
  6714 				priority:  80,
       
  6715 				displaySettings: true
       
  6716 			}),
       
  6717 			new wp.media.controller.EditImage( {
       
  6718 				image: this.image,
       
  6719 				selection: this.options.selection
       
  6720 			} )
       
  6721 		]);
       
  6722 	},
       
  6723 
       
  6724 	imageDetailsContent: function( options ) {
       
  6725 		options.view = new wp.media.view.ImageDetails({
       
  6726 			controller: this,
       
  6727 			model: this.state().image,
       
  6728 			attachment: this.state().image.attachment
       
  6729 		});
       
  6730 	},
       
  6731 
       
  6732 	editImageContent: function() {
       
  6733 		var state = this.state(),
       
  6734 			model = state.get('image'),
       
  6735 			view;
       
  6736 
       
  6737 		if ( ! model ) {
       
  6738 			return;
       
  6739 		}
       
  6740 
       
  6741 		view = new wp.media.view.EditImage( { model: model, controller: this } ).render();
       
  6742 
       
  6743 		this.content.set( view );
       
  6744 
       
  6745 		// After bringing in the frame, load the actual editor via an Ajax call.
       
  6746 		view.loadEditor();
       
  6747 
       
  6748 	},
       
  6749 
       
  6750 	renderImageDetailsToolbar: function() {
       
  6751 		this.toolbar.set( new wp.media.view.Toolbar({
       
  6752 			controller: this,
       
  6753 			items: {
       
  6754 				select: {
       
  6755 					style:    'primary',
       
  6756 					text:     l10n.update,
       
  6757 					priority: 80,
       
  6758 
       
  6759 					click: function() {
       
  6760 						var controller = this.controller,
       
  6761 							state = controller.state();
       
  6762 
       
  6763 						controller.close();
       
  6764 
       
  6765 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
       
  6766 						// perhaps wp.html.string to at least to build the <img />.
       
  6767 						state.trigger( 'update', controller.image.toJSON() );
       
  6768 
       
  6769 						// Restore and reset the default state.
       
  6770 						controller.setState( controller.options.state );
       
  6771 						controller.reset();
       
  6772 					}
       
  6773 				}
       
  6774 			}
       
  6775 		}) );
       
  6776 	},
       
  6777 
       
  6778 	renderReplaceImageToolbar: function() {
       
  6779 		var frame = this,
       
  6780 			lastState = frame.lastState(),
       
  6781 			previous = lastState && lastState.id;
       
  6782 
       
  6783 		this.toolbar.set( new wp.media.view.Toolbar({
       
  6784 			controller: this,
       
  6785 			items: {
       
  6786 				back: {
       
  6787 					text:     l10n.back,
       
  6788 					priority: 80,
       
  6789 					click:    function() {
       
  6790 						if ( previous ) {
       
  6791 							frame.setState( previous );
       
  6792 						} else {
       
  6793 							frame.close();
       
  6794 						}
       
  6795 					}
       
  6796 				},
       
  6797 
       
  6798 				replace: {
       
  6799 					style:    'primary',
       
  6800 					text:     l10n.replace,
       
  6801 					priority: 20,
       
  6802 					requires: { selection: true },
       
  6803 
       
  6804 					click: function() {
       
  6805 						var controller = this.controller,
       
  6806 							state = controller.state(),
       
  6807 							selection = state.get( 'selection' ),
       
  6808 							attachment = selection.single();
       
  6809 
       
  6810 						controller.close();
       
  6811 
       
  6812 						controller.image.changeAttachment( attachment, state.display( attachment ) );
       
  6813 
       
  6814 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
       
  6815 						// perhaps wp.html.string to at least to build the <img />.
       
  6816 						state.trigger( 'replace', controller.image.toJSON() );
       
  6817 
       
  6818 						// Restore and reset the default state.
       
  6819 						controller.setState( controller.options.state );
       
  6820 						controller.reset();
       
  6821 					}
       
  6822 				}
       
  6823 			}
       
  6824 		}) );
       
  6825 	}
       
  6826 
       
  6827 });
       
  6828 
       
  6829 module.exports = ImageDetails;
       
  6830 
       
  6831 
       
  6832 /***/ }),
       
  6833 
       
  6834 /***/ "VMHs":
       
  6835 /***/ (function(module, exports) {
       
  6836 
       
  6837 /**
       
  6838  * wp.media.view.Embed
       
  6839  *
       
  6840  * @memberOf wp.media.view
       
  6841  *
       
  6842  * @class
       
  6843  * @augments wp.media.View
       
  6844  * @augments wp.Backbone.View
       
  6845  * @augments Backbone.View
       
  6846  */
       
  6847 var Embed = wp.media.View.extend(/** @lends wp.media.view.Ember.prototype */{
       
  6848 	className: 'media-embed',
       
  6849 
       
  6850 	initialize: function() {
       
  6851 		/**
       
  6852 		 * @member {wp.media.view.EmbedUrl}
       
  6853 		 */
       
  6854 		this.url = new wp.media.view.EmbedUrl({
       
  6855 			controller: this.controller,
       
  6856 			model:      this.model.props
       
  6857 		}).render();
       
  6858 
       
  6859 		this.views.set([ this.url ]);
       
  6860 		this.refresh();
       
  6861 		this.listenTo( this.model, 'change:type', this.refresh );
       
  6862 		this.listenTo( this.model, 'change:loading', this.loading );
       
  6863 	},
       
  6864 
       
  6865 	/**
       
  6866 	 * @param {Object} view
       
  6867 	 */
       
  6868 	settings: function( view ) {
       
  6869 		if ( this._settings ) {
       
  6870 			this._settings.remove();
       
  6871 		}
       
  6872 		this._settings = view;
       
  6873 		this.views.add( view );
       
  6874 	},
       
  6875 
       
  6876 	refresh: function() {
       
  6877 		var type = this.model.get('type'),
       
  6878 			constructor;
       
  6879 
       
  6880 		if ( 'image' === type ) {
       
  6881 			constructor = wp.media.view.EmbedImage;
       
  6882 		} else if ( 'link' === type ) {
       
  6883 			constructor = wp.media.view.EmbedLink;
       
  6884 		} else {
       
  6885 			return;
       
  6886 		}
       
  6887 
       
  6888 		this.settings( new constructor({
       
  6889 			controller: this.controller,
       
  6890 			model:      this.model.props,
       
  6891 			priority:   40
       
  6892 		}) );
       
  6893 	},
       
  6894 
       
  6895 	loading: function() {
       
  6896 		this.$el.toggleClass( 'embed-loading', this.model.get('loading') );
       
  6897 	}
       
  6898 });
       
  6899 
       
  6900 module.exports = Embed;
       
  6901 
       
  6902 
       
  6903 /***/ }),
       
  6904 
       
  6905 /***/ "Vh02":
       
  6906 /***/ (function(module, exports) {
       
  6907 
       
  6908 var View = wp.media.View,
       
  6909 	UploaderStatus = wp.media.view.UploaderStatus,
       
  6910 	l10n = wp.media.view.l10n,
       
  6911 	$ = jQuery,
       
  6912 	Cropper;
       
  6913 
       
  6914 /**
       
  6915  * wp.media.view.Cropper
       
  6916  *
       
  6917  * Uses the imgAreaSelect plugin to allow a user to crop an image.
       
  6918  *
       
  6919  * Takes imgAreaSelect options from
       
  6920  * wp.customize.HeaderControl.calculateImageSelectOptions via
       
  6921  * wp.customize.HeaderControl.openMM.
       
  6922  *
       
  6923  * @memberOf wp.media.view
       
  6924  *
       
  6925  * @class
       
  6926  * @augments wp.media.View
       
  6927  * @augments wp.Backbone.View
       
  6928  * @augments Backbone.View
       
  6929  */
       
  6930 Cropper = View.extend(/** @lends wp.media.view.Cropper.prototype */{
       
  6931 	className: 'crop-content',
       
  6932 	template: wp.template('crop-content'),
       
  6933 	initialize: function() {
       
  6934 		_.bindAll(this, 'onImageLoad');
       
  6935 	},
       
  6936 	ready: function() {
       
  6937 		this.controller.frame.on('content:error:crop', this.onError, this);
       
  6938 		this.$image = this.$el.find('.crop-image');
       
  6939 		this.$image.on('load', this.onImageLoad);
       
  6940 		$(window).on('resize.cropper', _.debounce(this.onImageLoad, 250));
       
  6941 	},
       
  6942 	remove: function() {
       
  6943 		$(window).off('resize.cropper');
       
  6944 		this.$el.remove();
       
  6945 		this.$el.off();
       
  6946 		View.prototype.remove.apply(this, arguments);
       
  6947 	},
       
  6948 	prepare: function() {
       
  6949 		return {
       
  6950 			title: l10n.cropYourImage,
       
  6951 			url: this.options.attachment.get('url')
       
  6952 		};
       
  6953 	},
       
  6954 	onImageLoad: function() {
       
  6955 		var imgOptions = this.controller.get('imgSelectOptions'),
       
  6956 			imgSelect;
       
  6957 
       
  6958 		if (typeof imgOptions === 'function') {
       
  6959 			imgOptions = imgOptions(this.options.attachment, this.controller);
       
  6960 		}
       
  6961 
       
  6962 		imgOptions = _.extend(imgOptions, {
       
  6963 			parent: this.$el,
       
  6964 			onInit: function() {
       
  6965 
       
  6966 				// Store the set ratio.
       
  6967 				var setRatio = imgSelect.getOptions().aspectRatio;
       
  6968 
       
  6969 				// On mousedown, if no ratio is set and the Shift key is down, use a 1:1 ratio.
       
  6970 				this.parent.children().on( 'mousedown touchstart', function( e ) {
       
  6971 
       
  6972 					// If no ratio is set and the shift key is down, use a 1:1 ratio.
       
  6973 					if ( ! setRatio && e.shiftKey ) {
       
  6974 						imgSelect.setOptions( {
       
  6975 							aspectRatio: '1:1'
       
  6976 						} );
       
  6977 					}
       
  6978 				} );
       
  6979 
       
  6980 				this.parent.children().on( 'mouseup touchend', function() {
       
  6981 
       
  6982 					// Restore the set ratio.
       
  6983 					imgSelect.setOptions( {
       
  6984 						aspectRatio: setRatio ? setRatio : false
       
  6985 					} );
       
  6986 				} );
       
  6987 			}
       
  6988 		} );
       
  6989 		this.trigger('image-loaded');
       
  6990 		imgSelect = this.controller.imgSelect = this.$image.imgAreaSelect(imgOptions);
       
  6991 	},
       
  6992 	onError: function() {
       
  6993 		var filename = this.options.attachment.get('filename');
       
  6994 
       
  6995 		this.views.add( '.upload-errors', new wp.media.view.UploaderStatusError({
       
  6996 			filename: UploaderStatus.prototype.filename(filename),
       
  6997 			message: window._wpMediaViewsL10n.cropError
       
  6998 		}), { at: 0 });
       
  6999 	}
       
  7000 });
       
  7001 
       
  7002 module.exports = Cropper;
       
  7003 
       
  7004 
       
  7005 /***/ }),
       
  7006 
       
  7007 /***/ "VkcK":
       
  7008 /***/ (function(module, exports) {
       
  7009 
       
  7010 var l10n = wp.media.view.l10n,
       
  7011 	DateFilter;
       
  7012 
       
  7013 /**
       
  7014  * A filter dropdown for month/dates.
       
  7015  *
       
  7016  * @memberOf wp.media.view.AttachmentFilters
       
  7017  *
       
  7018  * @class
       
  7019  * @augments wp.media.view.AttachmentFilters
       
  7020  * @augments wp.media.View
       
  7021  * @augments wp.Backbone.View
       
  7022  * @augments Backbone.View
       
  7023  */
       
  7024 DateFilter = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Date.prototype */{
       
  7025 	id: 'media-attachment-date-filters',
       
  7026 
       
  7027 	createFilters: function() {
       
  7028 		var filters = {};
       
  7029 		_.each( wp.media.view.settings.months || {}, function( value, index ) {
       
  7030 			filters[ index ] = {
       
  7031 				text: value.text,
       
  7032 				props: {
       
  7033 					year: value.year,
       
  7034 					monthnum: value.month
       
  7035 				}
       
  7036 			};
       
  7037 		});
       
  7038 		filters.all = {
       
  7039 			text:  l10n.allDates,
       
  7040 			props: {
       
  7041 				monthnum: false,
       
  7042 				year:  false
       
  7043 			},
       
  7044 			priority: 10
       
  7045 		};
       
  7046 		this.filters = filters;
       
  7047 	}
       
  7048 });
       
  7049 
       
  7050 module.exports = DateFilter;
       
  7051 
       
  7052 
       
  7053 /***/ }),
       
  7054 
       
  7055 /***/ "W+32":
       
  7056 /***/ (function(module, exports) {
       
  7057 
       
  7058 var Controller = wp.media.controller,
       
  7059 	SiteIconCropper;
       
  7060 
       
  7061 /**
       
  7062  * wp.media.controller.SiteIconCropper
       
  7063  *
       
  7064  * A state for cropping a Site Icon.
       
  7065  *
       
  7066  * @memberOf wp.media.controller
       
  7067  *
       
  7068  * @class
       
  7069  * @augments wp.media.controller.Cropper
  1739  * @augments wp.media.controller.State
  7070  * @augments wp.media.controller.State
  1740  * @augments Backbone.Model
  7071  * @augments Backbone.Model
  1741  *
       
  1742  * @param {object}                     [attributes]                         The attributes hash passed to the state.
       
  1743  * @param {string}                     [attributes.id=library]              Unique identifier.
       
  1744  * @param {string}                     attributes.title                     Title for the state. Displays in the frame's title region.
       
  1745  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
       
  1746  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
       
  1747  *                                                                          If one is not supplied, a collection of attachments of the specified type will be created.
       
  1748  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
       
  1749  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
       
  1750  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
       
  1751  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
       
  1752  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
       
  1753  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
       
  1754  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
       
  1755  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
       
  1756  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  1757  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
  1758  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
  1759  * @param {int}                        [attributes.priority=100]            The priority for the state link in the media menu.
       
  1760  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
       
  1761  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
       
  1762  * @param {string}                     attributes.type                      The collection's media type. (e.g. 'video').
       
  1763  * @param {string}                     attributes.collectionType            The collection type. (e.g. 'playlist').
       
  1764  */
  7072  */
  1765 CollectionAdd = Library.extend(/** @lends wp.media.controller.CollectionAdd.prototype */{
  7073 SiteIconCropper = Controller.Cropper.extend(/** @lends wp.media.controller.SiteIconCropper.prototype */{
  1766 	defaults: _.defaults( {
       
  1767 		// Selection defaults. @see media.model.Selection
       
  1768 		multiple:      'add',
       
  1769 		// Attachments browser defaults. @see media.view.AttachmentsBrowser
       
  1770 		filterable:    'uploaded',
       
  1771 
       
  1772 		priority:      100,
       
  1773 		syncSelection: false
       
  1774 	}, Library.prototype.defaults ),
       
  1775 
       
  1776 	/**
       
  1777 	 * @since 3.9.0
       
  1778 	 */
       
  1779 	initialize: function() {
       
  1780 		var collectionType = this.get('collectionType');
       
  1781 
       
  1782 		if ( 'video' === this.get( 'type' ) ) {
       
  1783 			collectionType = 'video-' + collectionType;
       
  1784 		}
       
  1785 
       
  1786 		this.set( 'id', collectionType + '-library' );
       
  1787 		this.set( 'toolbar', collectionType + '-add' );
       
  1788 		this.set( 'menu', collectionType );
       
  1789 
       
  1790 		// If we haven't been provided a `library`, create a `Selection`.
       
  1791 		if ( ! this.get('library') ) {
       
  1792 			this.set( 'library', wp.media.query({ type: this.get('type') }) );
       
  1793 		}
       
  1794 		Library.prototype.initialize.apply( this, arguments );
       
  1795 	},
       
  1796 
       
  1797 	/**
       
  1798 	 * @since 3.9.0
       
  1799 	 */
       
  1800 	activate: function() {
  7074 	activate: function() {
  1801 		var library = this.get('library'),
  7075 		this.frame.on( 'content:create:crop', this.createCropContent, this );
  1802 			editLibrary = this.get('editLibrary'),
  7076 		this.frame.on( 'close', this.removeCropper, this );
  1803 			edit = this.frame.state( this.get('collectionType') + '-edit' ).get('library');
  7077 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
  1804 
  7078 	},
  1805 		if ( editLibrary && editLibrary !== edit ) {
  7079 
  1806 			library.unobserve( editLibrary );
  7080 	createCropContent: function() {
  1807 		}
  7081 		this.cropperView = new wp.media.view.SiteIconCropper({
  1808 
  7082 			controller: this,
  1809 		// Accepts attachments that exist in the original library and
  7083 			attachment: this.get('selection').first()
  1810 		// that do not exist in gallery's library.
  7084 		});
  1811 		library.validator = function( attachment ) {
  7085 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
  1812 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
  7086 		this.frame.content.set(this.cropperView);
  1813 		};
  7087 
  1814 
  7088 	},
  1815 		/*
  7089 
  1816 		 * Reset the library to ensure that all attachments are re-added
  7090 	doCrop: function( attachment ) {
  1817 		 * to the collection. Do so silently, as calling `observe` will
  7091 		var cropDetails = attachment.get( 'cropDetails' ),
  1818 		 * trigger the `reset` event.
  7092 			control = this.get( 'control' );
  1819 		 */
  7093 
  1820 		library.reset( library.mirroring.models, { silent: true });
  7094 		cropDetails.dst_width  = control.params.width;
  1821 		library.observe( edit );
  7095 		cropDetails.dst_height = control.params.height;
  1822 		this.set('editLibrary', edit);
  7096 
  1823 
  7097 		return wp.ajax.post( 'crop-image', {
  1824 		Library.prototype.activate.apply( this, arguments );
  7098 			nonce: attachment.get( 'nonces' ).edit,
       
  7099 			id: attachment.get( 'id' ),
       
  7100 			context: 'site-icon',
       
  7101 			cropDetails: cropDetails
       
  7102 		} );
  1825 	}
  7103 	}
  1826 });
  7104 });
  1827 
  7105 
  1828 module.exports = CollectionAdd;
  7106 module.exports = SiteIconCropper;
  1829 
  7107 
  1830 
  7108 
  1831 /***/ }),
  7109 /***/ }),
  1832 /* 41 */
  7110 
       
  7111 /***/ "WiNq":
  1833 /***/ (function(module, exports) {
  7112 /***/ (function(module, exports) {
  1834 
  7113 
  1835 var Attachment = wp.media.model.Attachment,
       
  1836 	Library = wp.media.controller.Library,
       
  1837 	l10n = wp.media.view.l10n,
       
  1838 	FeaturedImage;
       
  1839 
       
  1840 /**
  7114 /**
  1841  * wp.media.controller.FeaturedImage
  7115  * wp.media.controller.Region
  1842  *
  7116  *
  1843  * A state for selecting a featured image for a post.
  7117  * A region is a persistent application layout area.
       
  7118  *
       
  7119  * A region assumes one mode at any time, and can be switched to another.
       
  7120  *
       
  7121  * When mode changes, events are triggered on the region's parent view.
       
  7122  * The parent view will listen to specific events and fill the region with an
       
  7123  * appropriate view depending on mode. For example, a frame listens for the
       
  7124  * 'browse' mode t be activated on the 'content' view and then fills the region
       
  7125  * with an AttachmentsBrowser view.
  1844  *
  7126  *
  1845  * @memberOf wp.media.controller
  7127  * @memberOf wp.media.controller
  1846  *
  7128  *
  1847  * @class
  7129  * @class
  1848  * @augments wp.media.controller.Library
  7130  *
  1849  * @augments wp.media.controller.State
  7131  * @param {Object}        options          Options hash for the region.
  1850  * @augments Backbone.Model
  7132  * @param {string}        options.id       Unique identifier for the region.
  1851  *
  7133  * @param {Backbone.View} options.view     A parent view the region exists within.
  1852  * @param {object}                     [attributes]                          The attributes hash passed to the state.
  7134  * @param {string}        options.selector jQuery selector for the region within the parent view.
  1853  * @param {string}                     [attributes.id=featured-image]        Unique identifier.
       
  1854  * @param {string}                     [attributes.title=Set Featured Image] Title for the state. Displays in the media menu and the frame's title region.
       
  1855  * @param {wp.media.model.Attachments} [attributes.library]                  The attachments collection to browse.
       
  1856  *                                                                           If one is not supplied, a collection of all images will be created.
       
  1857  * @param {boolean}                    [attributes.multiple=false]           Whether multi-select is enabled.
       
  1858  * @param {string}                     [attributes.content=upload]           Initial mode for the content region.
       
  1859  *                                                                           Overridden by persistent user setting if 'contentUserSetting' is true.
       
  1860  * @param {string}                     [attributes.menu=default]             Initial mode for the menu region.
       
  1861  * @param {string}                     [attributes.router=browse]            Initial mode for the router region.
       
  1862  * @param {string}                     [attributes.toolbar=featured-image]   Initial mode for the toolbar region.
       
  1863  * @param {int}                        [attributes.priority=60]              The priority for the state link in the media menu.
       
  1864  * @param {boolean}                    [attributes.searchable=true]          Whether the library is searchable.
       
  1865  * @param {boolean|string}             [attributes.filterable=false]         Whether the library is filterable, and if so what filters should be shown.
       
  1866  *                                                                           Accepts 'all', 'uploaded', or 'unattached'.
       
  1867  * @param {boolean}                    [attributes.sortable=true]            Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  1868  * @param {boolean}                    [attributes.autoSelect=true]          Whether an uploaded attachment should be automatically added to the selection.
       
  1869  * @param {boolean}                    [attributes.describe=false]           Whether to offer UI to describe attachments - e.g. captioning images in a gallery.
       
  1870  * @param {boolean}                    [attributes.contentUserSetting=true]  Whether the content region's mode should be set and persisted per user.
       
  1871  * @param {boolean}                    [attributes.syncSelection=true]       Whether the Attachments selection should be persisted from the last state.
       
  1872  */
  7135  */
  1873 FeaturedImage = Library.extend(/** @lends wp.media.controller.FeaturedImage.prototype */{
  7136 var Region = function( options ) {
  1874 	defaults: _.defaults({
  7137 	_.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
  1875 		id:            'featured-image',
  7138 };
  1876 		title:         l10n.setFeaturedImageTitle,
  7139 
  1877 		multiple:      false,
  7140 // Use Backbone's self-propagating `extend` inheritance method.
  1878 		filterable:    'uploaded',
  7141 Region.extend = Backbone.Model.extend;
  1879 		toolbar:       'featured-image',
  7142 
  1880 		priority:      60,
  7143 _.extend( Region.prototype,/** @lends wp.media.controller.Region.prototype */{
  1881 		syncSelection: true
  7144 	/**
  1882 	}, Library.prototype.defaults ),
  7145 	 * Activate a mode.
  1883 
  7146 	 *
  1884 	/**
       
  1885 	 * @since 3.5.0
  7147 	 * @since 3.5.0
  1886 	 */
  7148 	 *
  1887 	initialize: function() {
  7149 	 * @param {string} mode
  1888 		var library, comparator;
  7150 	 *
  1889 
  7151 	 * @fires Region#activate
  1890 		// If we haven't been provided a `library`, create a `Selection`.
  7152 	 * @fires Region#deactivate
  1891 		if ( ! this.get('library') ) {
  7153 	 *
  1892 			this.set( 'library', wp.media.query({ type: 'image' }) );
  7154 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
  1893 		}
  7155 	 */
  1894 
  7156 	mode: function( mode ) {
  1895 		Library.prototype.initialize.apply( this, arguments );
  7157 		if ( ! mode ) {
  1896 
  7158 			return this._mode;
  1897 		library    = this.get('library');
  7159 		}
  1898 		comparator = library.comparator;
  7160 		// Bail if we're trying to change to the current mode.
  1899 
  7161 		if ( mode === this._mode ) {
  1900 		// Overload the library's comparator to push items that are not in
  7162 			return this;
  1901 		// the mirrored query to the front of the aggregate collection.
  7163 		}
  1902 		library.comparator = function( a, b ) {
  7164 
  1903 			var aInQuery = !! this.mirroring.get( a.cid ),
  7165 		/**
  1904 				bInQuery = !! this.mirroring.get( b.cid );
  7166 		 * Region mode deactivation event.
  1905 
  7167 		 *
  1906 			if ( ! aInQuery && bInQuery ) {
  7168 		 * @event wp.media.controller.Region#deactivate
  1907 				return -1;
  7169 		 */
  1908 			} else if ( aInQuery && ! bInQuery ) {
  7170 		this.trigger('deactivate');
  1909 				return 1;
  7171 
  1910 			} else {
  7172 		this._mode = mode;
  1911 				return comparator.apply( this, arguments );
  7173 		this.render( mode );
  1912 			}
  7174 
  1913 		};
  7175 		/**
  1914 
  7176 		 * Region mode activation event.
  1915 		// Add all items in the selection to the library, so any featured
  7177 		 *
  1916 		// images that are not initially loaded still appear.
  7178 		 * @event wp.media.controller.Region#activate
  1917 		library.observe( this.get('selection') );
  7179 		 */
  1918 	},
  7180 		this.trigger('activate');
  1919 
  7181 		return this;
  1920 	/**
  7182 	},
       
  7183 	/**
       
  7184 	 * Render a mode.
       
  7185 	 *
  1921 	 * @since 3.5.0
  7186 	 * @since 3.5.0
  1922 	 */
  7187 	 *
  1923 	activate: function() {
  7188 	 * @param {string} mode
  1924 		this.updateSelection();
  7189 	 *
  1925 		this.frame.on( 'open', this.updateSelection, this );
  7190 	 * @fires Region#create
  1926 
  7191 	 * @fires Region#render
  1927 		Library.prototype.activate.apply( this, arguments );
  7192 	 *
  1928 	},
  7193 	 * @return {wp.media.controller.Region} Returns itself to allow chaining.
  1929 
  7194 	 */
  1930 	/**
  7195 	render: function( mode ) {
       
  7196 		// If the mode isn't active, activate it.
       
  7197 		if ( mode && mode !== this._mode ) {
       
  7198 			return this.mode( mode );
       
  7199 		}
       
  7200 
       
  7201 		var set = { view: null },
       
  7202 			view;
       
  7203 
       
  7204 		/**
       
  7205 		 * Create region view event.
       
  7206 		 *
       
  7207 		 * Region view creation takes place in an event callback on the frame.
       
  7208 		 *
       
  7209 		 * @event wp.media.controller.Region#create
       
  7210 		 * @type {object}
       
  7211 		 * @property {object} view
       
  7212 		 */
       
  7213 		this.trigger( 'create', set );
       
  7214 		view = set.view;
       
  7215 
       
  7216 		/**
       
  7217 		 * Render region view event.
       
  7218 		 *
       
  7219 		 * Region view creation takes place in an event callback on the frame.
       
  7220 		 *
       
  7221 		 * @event wp.media.controller.Region#render
       
  7222 		 * @type {object}
       
  7223 		 */
       
  7224 		this.trigger( 'render', view );
       
  7225 		if ( view ) {
       
  7226 			this.set( view );
       
  7227 		}
       
  7228 		return this;
       
  7229 	},
       
  7230 
       
  7231 	/**
       
  7232 	 * Get the region's view.
       
  7233 	 *
  1931 	 * @since 3.5.0
  7234 	 * @since 3.5.0
  1932 	 */
  7235 	 *
  1933 	deactivate: function() {
  7236 	 * @return {wp.media.View}
  1934 		this.frame.off( 'open', this.updateSelection, this );
  7237 	 */
  1935 
  7238 	get: function() {
  1936 		Library.prototype.deactivate.apply( this, arguments );
  7239 		return this.view.views.first( this.selector );
  1937 	},
  7240 	},
  1938 
  7241 
  1939 	/**
  7242 	/**
       
  7243 	 * Set the region's view as a subview of the frame.
       
  7244 	 *
  1940 	 * @since 3.5.0
  7245 	 * @since 3.5.0
  1941 	 */
  7246 	 *
  1942 	updateSelection: function() {
  7247 	 * @param {Array|Object} views
  1943 		var selection = this.get('selection'),
  7248 	 * @param {Object} [options={}]
  1944 			id = wp.media.view.settings.post.featuredImageId,
  7249 	 * @return {wp.Backbone.Subviews} Subviews is returned to allow chaining.
  1945 			attachment;
  7250 	 */
  1946 
  7251 	set: function( views, options ) {
  1947 		if ( '' !== id && -1 !== id ) {
  7252 		if ( options ) {
  1948 			attachment = Attachment.get( id );
  7253 			options.add = false;
  1949 			attachment.fetch();
  7254 		}
  1950 		}
  7255 		return this.view.views.set( this.selector, views, options );
  1951 
  7256 	},
  1952 		selection.reset( attachment ? [ attachment ] : [] );
  7257 
       
  7258 	/**
       
  7259 	 * Trigger regional view events on the frame.
       
  7260 	 *
       
  7261 	 * @since 3.5.0
       
  7262 	 *
       
  7263 	 * @param {string} event
       
  7264 	 * @return {undefined|wp.media.controller.Region} Returns itself to allow chaining.
       
  7265 	 */
       
  7266 	trigger: function( event ) {
       
  7267 		var base, args;
       
  7268 
       
  7269 		if ( ! this._mode ) {
       
  7270 			return;
       
  7271 		}
       
  7272 
       
  7273 		args = _.toArray( arguments );
       
  7274 		base = this.id + ':' + event;
       
  7275 
       
  7276 		// Trigger `{this.id}:{event}:{this._mode}` event on the frame.
       
  7277 		args[0] = base + ':' + this._mode;
       
  7278 		this.view.trigger.apply( this.view, args );
       
  7279 
       
  7280 		// Trigger `{this.id}:{event}` event on the frame.
       
  7281 		args[0] = base;
       
  7282 		this.view.trigger.apply( this.view, args );
       
  7283 		return this;
  1953 	}
  7284 	}
  1954 });
  7285 });
  1955 
  7286 
  1956 module.exports = FeaturedImage;
  7287 module.exports = Region;
  1957 
  7288 
  1958 
  7289 
  1959 /***/ }),
  7290 /***/ }),
  1960 /* 42 */
  7291 
       
  7292 /***/ "ZeG4":
       
  7293 /***/ (function(module, exports) {
       
  7294 
       
  7295 /**
       
  7296  * wp.media.view.UploaderStatusError
       
  7297  *
       
  7298  * @memberOf wp.media.view
       
  7299  *
       
  7300  * @class
       
  7301  * @augments wp.media.View
       
  7302  * @augments wp.Backbone.View
       
  7303  * @augments Backbone.View
       
  7304  */
       
  7305 var UploaderStatusError = wp.media.View.extend(/** @lends wp.media.view.UploaderStatusError.prototype */{
       
  7306 	className: 'upload-error',
       
  7307 	template:  wp.template('uploader-status-error')
       
  7308 });
       
  7309 
       
  7310 module.exports = UploaderStatusError;
       
  7311 
       
  7312 
       
  7313 /***/ }),
       
  7314 
       
  7315 /***/ "ZgZ7":
       
  7316 /***/ (function(module, exports) {
       
  7317 
       
  7318 var Search;
       
  7319 
       
  7320 /**
       
  7321  * wp.media.view.Search
       
  7322  *
       
  7323  * @memberOf wp.media.view
       
  7324  *
       
  7325  * @class
       
  7326  * @augments wp.media.View
       
  7327  * @augments wp.Backbone.View
       
  7328  * @augments Backbone.View
       
  7329  */
       
  7330 Search = wp.media.View.extend(/** @lends wp.media.view.Search.prototype */{
       
  7331 	tagName:   'input',
       
  7332 	className: 'search',
       
  7333 	id:        'media-search-input',
       
  7334 
       
  7335 	attributes: {
       
  7336 		type: 'search'
       
  7337 	},
       
  7338 
       
  7339 	events: {
       
  7340 		'input': 'search'
       
  7341 	},
       
  7342 
       
  7343 	/**
       
  7344 	 * @return {wp.media.view.Search} Returns itself to allow chaining.
       
  7345 	 */
       
  7346 	render: function() {
       
  7347 		this.el.value = this.model.escape('search');
       
  7348 		return this;
       
  7349 	},
       
  7350 
       
  7351 	search: _.debounce( function( event ) {
       
  7352 		var searchTerm = event.target.value.trim();
       
  7353 
       
  7354 		// Trigger the search only after 2 ASCII characters.
       
  7355 		if ( searchTerm && searchTerm.length > 1 ) {
       
  7356 			this.model.set( 'search', searchTerm );
       
  7357 		} else {
       
  7358 			this.model.unset( 'search' );
       
  7359 		}
       
  7360 	}, 500 )
       
  7361 });
       
  7362 
       
  7363 module.exports = Search;
       
  7364 
       
  7365 
       
  7366 /***/ }),
       
  7367 
       
  7368 /***/ "aBqq":
  1961 /***/ (function(module, exports) {
  7369 /***/ (function(module, exports) {
  1962 
  7370 
  1963 var Library = wp.media.controller.Library,
  7371 var Library = wp.media.controller.Library,
  1964 	l10n = wp.media.view.l10n,
  7372 	l10n = wp.media.view.l10n,
  1965 	ReplaceImage;
  7373 	ReplaceImage;
  2069 
  7477 
  2070 module.exports = ReplaceImage;
  7478 module.exports = ReplaceImage;
  2071 
  7479 
  2072 
  7480 
  2073 /***/ }),
  7481 /***/ }),
  2074 /* 43 */
  7482 
       
  7483 /***/ "cH3P":
  2075 /***/ (function(module, exports) {
  7484 /***/ (function(module, exports) {
  2076 
  7485 
  2077 var l10n = wp.media.view.l10n,
  7486 /**
       
  7487  * wp.media.view.Spinner
       
  7488  *
       
  7489  * Represents a spinner in the Media Library.
       
  7490  *
       
  7491  * @since 3.9.0
       
  7492  *
       
  7493  * @memberOf wp.media.view
       
  7494  *
       
  7495  * @class
       
  7496  * @augments wp.media.View
       
  7497  * @augments wp.Backbone.View
       
  7498  * @augments Backbone.View
       
  7499  */
       
  7500 var Spinner = wp.media.View.extend(/** @lends wp.media.view.Spinner.prototype */{
       
  7501 	tagName:   'span',
       
  7502 	className: 'spinner',
       
  7503 	spinnerTimeout: false,
       
  7504 	delay: 400,
       
  7505 
       
  7506 	/**
       
  7507 	 * Shows the spinner. Delays the visibility by the configured amount.
       
  7508 	 *
       
  7509 	 * @since 3.9.0
       
  7510 	 *
       
  7511 	 * @return {wp.media.view.Spinner} The spinner.
       
  7512 	 */
       
  7513 	show: function() {
       
  7514 		if ( ! this.spinnerTimeout ) {
       
  7515 			this.spinnerTimeout = _.delay(function( $el ) {
       
  7516 				$el.addClass( 'is-active' );
       
  7517 			}, this.delay, this.$el );
       
  7518 		}
       
  7519 
       
  7520 		return this;
       
  7521 	},
       
  7522 
       
  7523 	/**
       
  7524 	 * Hides the spinner.
       
  7525 	 *
       
  7526 	 * @since 3.9.0
       
  7527 	 *
       
  7528 	 * @return {wp.media.view.Spinner} The spinner.
       
  7529 	 */
       
  7530 	hide: function() {
       
  7531 		this.$el.removeClass( 'is-active' );
       
  7532 		this.spinnerTimeout = clearTimeout( this.spinnerTimeout );
       
  7533 
       
  7534 		return this;
       
  7535 	}
       
  7536 });
       
  7537 
       
  7538 module.exports = Spinner;
       
  7539 
       
  7540 
       
  7541 /***/ }),
       
  7542 
       
  7543 /***/ "d3xu":
       
  7544 /***/ (function(module, exports) {
       
  7545 
       
  7546 var View = wp.media.View,
       
  7547 	$ = jQuery,
       
  7548 	SiteIconPreview;
       
  7549 
       
  7550 /**
       
  7551  * wp.media.view.SiteIconPreview
       
  7552  *
       
  7553  * Shows a preview of the Site Icon as a favicon and app icon while cropping.
       
  7554  *
       
  7555  * @memberOf wp.media.view
       
  7556  *
       
  7557  * @class
       
  7558  * @augments wp.media.View
       
  7559  * @augments wp.Backbone.View
       
  7560  * @augments Backbone.View
       
  7561  */
       
  7562 SiteIconPreview = View.extend(/** @lends wp.media.view.SiteIconPreview.prototype */{
       
  7563 	className: 'site-icon-preview',
       
  7564 	template: wp.template( 'site-icon-preview' ),
       
  7565 
       
  7566 	ready: function() {
       
  7567 		this.controller.imgSelect.setOptions({
       
  7568 			onInit: this.updatePreview,
       
  7569 			onSelectChange: this.updatePreview
       
  7570 		});
       
  7571 	},
       
  7572 
       
  7573 	prepare: function() {
       
  7574 		return {
       
  7575 			url: this.options.attachment.get( 'url' )
       
  7576 		};
       
  7577 	},
       
  7578 
       
  7579 	updatePreview: function( img, coords ) {
       
  7580 		var rx = 64 / coords.width,
       
  7581 			ry = 64 / coords.height,
       
  7582 			preview_rx = 16 / coords.width,
       
  7583 			preview_ry = 16 / coords.height;
       
  7584 
       
  7585 		$( '#preview-app-icon' ).css({
       
  7586 			width: Math.round(rx * this.imageWidth ) + 'px',
       
  7587 			height: Math.round(ry * this.imageHeight ) + 'px',
       
  7588 			marginLeft: '-' + Math.round(rx * coords.x1) + 'px',
       
  7589 			marginTop: '-' + Math.round(ry * coords.y1) + 'px'
       
  7590 		});
       
  7591 
       
  7592 		$( '#preview-favicon' ).css({
       
  7593 			width: Math.round( preview_rx * this.imageWidth ) + 'px',
       
  7594 			height: Math.round( preview_ry * this.imageHeight ) + 'px',
       
  7595 			marginLeft: '-' + Math.round( preview_rx * coords.x1 ) + 'px',
       
  7596 			marginTop: '-' + Math.floor( preview_ry* coords.y1 ) + 'px'
       
  7597 		});
       
  7598 	}
       
  7599 });
       
  7600 
       
  7601 module.exports = SiteIconPreview;
       
  7602 
       
  7603 
       
  7604 /***/ }),
       
  7605 
       
  7606 /***/ "dpRc":
       
  7607 /***/ (function(module, exports) {
       
  7608 
       
  7609 var MenuItem;
       
  7610 
       
  7611 /**
       
  7612  * wp.media.view.MenuItem
       
  7613  *
       
  7614  * @memberOf wp.media.view
       
  7615  *
       
  7616  * @class
       
  7617  * @augments wp.media.View
       
  7618  * @augments wp.Backbone.View
       
  7619  * @augments Backbone.View
       
  7620  */
       
  7621 MenuItem = wp.media.View.extend(/** @lends wp.media.view.MenuItem.prototype */{
       
  7622 	tagName:   'button',
       
  7623 	className: 'media-menu-item',
       
  7624 
       
  7625 	attributes: {
       
  7626 		type: 'button',
       
  7627 		role: 'tab'
       
  7628 	},
       
  7629 
       
  7630 	events: {
       
  7631 		'click': '_click'
       
  7632 	},
       
  7633 
       
  7634 	/**
       
  7635 	 * Allows to override the click event.
       
  7636 	 */
       
  7637 	_click: function() {
       
  7638 		var clickOverride = this.options.click;
       
  7639 
       
  7640 		if ( clickOverride ) {
       
  7641 			clickOverride.call( this );
       
  7642 		} else {
       
  7643 			this.click();
       
  7644 		}
       
  7645 	},
       
  7646 
       
  7647 	click: function() {
       
  7648 		var state = this.options.state;
       
  7649 
       
  7650 		if ( state ) {
       
  7651 			this.controller.setState( state );
       
  7652 			// Toggle the menu visibility in the responsive view.
       
  7653 			this.views.parent.$el.removeClass( 'visible' ); // @todo Or hide on any click, see below.
       
  7654 		}
       
  7655 	},
       
  7656 
       
  7657 	/**
       
  7658 	 * @return {wp.media.view.MenuItem} returns itself to allow chaining.
       
  7659 	 */
       
  7660 	render: function() {
       
  7661 		var options = this.options,
       
  7662 			menuProperty = options.state || options.contentMode;
       
  7663 
       
  7664 		if ( options.text ) {
       
  7665 			this.$el.text( options.text );
       
  7666 		} else if ( options.html ) {
       
  7667 			this.$el.html( options.html );
       
  7668 		}
       
  7669 
       
  7670 		// Set the menu item ID based on the frame state associated to the menu item.
       
  7671 		this.$el.attr( 'id', 'menu-item-' + menuProperty );
       
  7672 
       
  7673 		return this;
       
  7674 	}
       
  7675 });
       
  7676 
       
  7677 module.exports = MenuItem;
       
  7678 
       
  7679 
       
  7680 /***/ }),
       
  7681 
       
  7682 /***/ "eqTc":
       
  7683 /***/ (function(module, exports) {
       
  7684 
       
  7685 var Controller = wp.media.controller,
       
  7686 	CustomizeImageCropper;
       
  7687 
       
  7688 /**
       
  7689  * A state for cropping an image in the customizer.
       
  7690  *
       
  7691  * @since 4.3.0
       
  7692  *
       
  7693  * @constructs wp.media.controller.CustomizeImageCropper
       
  7694  * @memberOf wp.media.controller
       
  7695  * @augments wp.media.controller.CustomizeImageCropper.Cropper
       
  7696  * @inheritDoc
       
  7697  */
       
  7698 CustomizeImageCropper = Controller.Cropper.extend(/** @lends wp.media.controller.CustomizeImageCropper.prototype */{
       
  7699 	/**
       
  7700 	 * Posts the crop details to the admin.
       
  7701 	 *
       
  7702 	 * Uses crop measurements when flexible in both directions.
       
  7703 	 * Constrains flexible side based on image ratio and size of the fixed side.
       
  7704 	 *
       
  7705 	 * @since 4.3.0
       
  7706 	 *
       
  7707 	 * @param {Object} attachment The attachment to crop.
       
  7708 	 *
       
  7709 	 * @return {$.promise} A jQuery promise that represents the crop image request.
       
  7710 	 */
       
  7711 	doCrop: function( attachment ) {
       
  7712 		var cropDetails = attachment.get( 'cropDetails' ),
       
  7713 			control = this.get( 'control' ),
       
  7714 			ratio = cropDetails.width / cropDetails.height;
       
  7715 
       
  7716 		// Use crop measurements when flexible in both directions.
       
  7717 		if ( control.params.flex_width && control.params.flex_height ) {
       
  7718 			cropDetails.dst_width  = cropDetails.width;
       
  7719 			cropDetails.dst_height = cropDetails.height;
       
  7720 
       
  7721 		// Constrain flexible side based on image ratio and size of the fixed side.
       
  7722 		} else {
       
  7723 			cropDetails.dst_width  = control.params.flex_width  ? control.params.height * ratio : control.params.width;
       
  7724 			cropDetails.dst_height = control.params.flex_height ? control.params.width  / ratio : control.params.height;
       
  7725 		}
       
  7726 
       
  7727 		return wp.ajax.post( 'crop-image', {
       
  7728 			wp_customize: 'on',
       
  7729 			nonce: attachment.get( 'nonces' ).edit,
       
  7730 			id: attachment.get( 'id' ),
       
  7731 			context: control.id,
       
  7732 			cropDetails: cropDetails
       
  7733 		} );
       
  7734 	}
       
  7735 });
       
  7736 
       
  7737 module.exports = CustomizeImageCropper;
       
  7738 
       
  7739 
       
  7740 /***/ }),
       
  7741 
       
  7742 /***/ "fYN4":
       
  7743 /***/ (function(module, exports) {
       
  7744 
       
  7745 var MediaFrame = wp.media.view.MediaFrame,
       
  7746 	l10n = wp.media.view.l10n,
       
  7747 	Select;
       
  7748 
       
  7749 /**
       
  7750  * wp.media.view.MediaFrame.Select
       
  7751  *
       
  7752  * A frame for selecting an item or items from the media library.
       
  7753  *
       
  7754  * @memberOf wp.media.view.MediaFrame
       
  7755  *
       
  7756  * @class
       
  7757  * @augments wp.media.view.MediaFrame
       
  7758  * @augments wp.media.view.Frame
       
  7759  * @augments wp.media.View
       
  7760  * @augments wp.Backbone.View
       
  7761  * @augments Backbone.View
       
  7762  * @mixes wp.media.controller.StateMachine
       
  7763  */
       
  7764 Select = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Select.prototype */{
       
  7765 	initialize: function() {
       
  7766 		// Call 'initialize' directly on the parent class.
       
  7767 		MediaFrame.prototype.initialize.apply( this, arguments );
       
  7768 
       
  7769 		_.defaults( this.options, {
       
  7770 			selection: [],
       
  7771 			library:   {},
       
  7772 			multiple:  false,
       
  7773 			state:    'library'
       
  7774 		});
       
  7775 
       
  7776 		this.createSelection();
       
  7777 		this.createStates();
       
  7778 		this.bindHandlers();
       
  7779 	},
       
  7780 
       
  7781 	/**
       
  7782 	 * Attach a selection collection to the frame.
       
  7783 	 *
       
  7784 	 * A selection is a collection of attachments used for a specific purpose
       
  7785 	 * by a media frame. e.g. Selecting an attachment (or many) to insert into
       
  7786 	 * post content.
       
  7787 	 *
       
  7788 	 * @see media.model.Selection
       
  7789 	 */
       
  7790 	createSelection: function() {
       
  7791 		var selection = this.options.selection;
       
  7792 
       
  7793 		if ( ! (selection instanceof wp.media.model.Selection) ) {
       
  7794 			this.options.selection = new wp.media.model.Selection( selection, {
       
  7795 				multiple: this.options.multiple
       
  7796 			});
       
  7797 		}
       
  7798 
       
  7799 		this._selection = {
       
  7800 			attachments: new wp.media.model.Attachments(),
       
  7801 			difference: []
       
  7802 		};
       
  7803 	},
       
  7804 
       
  7805 	editImageContent: function() {
       
  7806 		var image = this.state().get('image'),
       
  7807 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
       
  7808 
       
  7809 		this.content.set( view );
       
  7810 
       
  7811 		// After creating the wrapper view, load the actual editor via an Ajax call.
       
  7812 		view.loadEditor();
       
  7813 	},
       
  7814 
       
  7815 	/**
       
  7816 	 * Create the default states on the frame.
       
  7817 	 */
       
  7818 	createStates: function() {
       
  7819 		var options = this.options;
       
  7820 
       
  7821 		if ( this.options.states ) {
       
  7822 			return;
       
  7823 		}
       
  7824 
       
  7825 		// Add the default states.
       
  7826 		this.states.add([
       
  7827 			// Main states.
       
  7828 			new wp.media.controller.Library({
       
  7829 				library:   wp.media.query( options.library ),
       
  7830 				multiple:  options.multiple,
       
  7831 				title:     options.title,
       
  7832 				priority:  20
       
  7833 			}),
       
  7834 			new wp.media.controller.EditImage( { model: options.editImage } )
       
  7835 		]);
       
  7836 	},
       
  7837 
       
  7838 	/**
       
  7839 	 * Bind region mode event callbacks.
       
  7840 	 *
       
  7841 	 * @see media.controller.Region.render
       
  7842 	 */
       
  7843 	bindHandlers: function() {
       
  7844 		this.on( 'router:create:browse', this.createRouter, this );
       
  7845 		this.on( 'router:render:browse', this.browseRouter, this );
       
  7846 		this.on( 'content:create:browse', this.browseContent, this );
       
  7847 		this.on( 'content:render:upload', this.uploadContent, this );
       
  7848 		this.on( 'toolbar:create:select', this.createSelectToolbar, this );
       
  7849 		this.on( 'content:render:edit-image', this.editImageContent, this );
       
  7850 	},
       
  7851 
       
  7852 	/**
       
  7853 	 * Render callback for the router region in the `browse` mode.
       
  7854 	 *
       
  7855 	 * @param {wp.media.view.Router} routerView
       
  7856 	 */
       
  7857 	browseRouter: function( routerView ) {
       
  7858 		routerView.set({
       
  7859 			upload: {
       
  7860 				text:     l10n.uploadFilesTitle,
       
  7861 				priority: 20
       
  7862 			},
       
  7863 			browse: {
       
  7864 				text:     l10n.mediaLibraryTitle,
       
  7865 				priority: 40
       
  7866 			}
       
  7867 		});
       
  7868 	},
       
  7869 
       
  7870 	/**
       
  7871 	 * Render callback for the content region in the `browse` mode.
       
  7872 	 *
       
  7873 	 * @param {wp.media.controller.Region} contentRegion
       
  7874 	 */
       
  7875 	browseContent: function( contentRegion ) {
       
  7876 		var state = this.state();
       
  7877 
       
  7878 		this.$el.removeClass('hide-toolbar');
       
  7879 
       
  7880 		// Browse our library of attachments.
       
  7881 		contentRegion.view = new wp.media.view.AttachmentsBrowser({
       
  7882 			controller: this,
       
  7883 			collection: state.get('library'),
       
  7884 			selection:  state.get('selection'),
       
  7885 			model:      state,
       
  7886 			sortable:   state.get('sortable'),
       
  7887 			search:     state.get('searchable'),
       
  7888 			filters:    state.get('filterable'),
       
  7889 			date:       state.get('date'),
       
  7890 			display:    state.has('display') ? state.get('display') : state.get('displaySettings'),
       
  7891 			dragInfo:   state.get('dragInfo'),
       
  7892 
       
  7893 			idealColumnWidth: state.get('idealColumnWidth'),
       
  7894 			suggestedWidth:   state.get('suggestedWidth'),
       
  7895 			suggestedHeight:  state.get('suggestedHeight'),
       
  7896 
       
  7897 			AttachmentView: state.get('AttachmentView')
       
  7898 		});
       
  7899 	},
       
  7900 
       
  7901 	/**
       
  7902 	 * Render callback for the content region in the `upload` mode.
       
  7903 	 */
       
  7904 	uploadContent: function() {
       
  7905 		this.$el.removeClass( 'hide-toolbar' );
       
  7906 		this.content.set( new wp.media.view.UploaderInline({
       
  7907 			controller: this
       
  7908 		}) );
       
  7909 	},
       
  7910 
       
  7911 	/**
       
  7912 	 * Toolbars
       
  7913 	 *
       
  7914 	 * @param {Object} toolbar
       
  7915 	 * @param {Object} [options={}]
       
  7916 	 * @this wp.media.controller.Region
       
  7917 	 */
       
  7918 	createSelectToolbar: function( toolbar, options ) {
       
  7919 		options = options || this.options.button || {};
       
  7920 		options.controller = this;
       
  7921 
       
  7922 		toolbar.view = new wp.media.view.Toolbar.Select( options );
       
  7923 	}
       
  7924 });
       
  7925 
       
  7926 module.exports = Select;
       
  7927 
       
  7928 
       
  7929 /***/ }),
       
  7930 
       
  7931 /***/ "gOpb":
       
  7932 /***/ (function(module, exports) {
       
  7933 
       
  7934 var $ = jQuery,
       
  7935 	Modal;
       
  7936 
       
  7937 /**
       
  7938  * wp.media.view.Modal
       
  7939  *
       
  7940  * A modal view, which the media modal uses as its default container.
       
  7941  *
       
  7942  * @memberOf wp.media.view
       
  7943  *
       
  7944  * @class
       
  7945  * @augments wp.media.View
       
  7946  * @augments wp.Backbone.View
       
  7947  * @augments Backbone.View
       
  7948  */
       
  7949 Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
       
  7950 	tagName:  'div',
       
  7951 	template: wp.template('media-modal'),
       
  7952 
       
  7953 	events: {
       
  7954 		'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
       
  7955 		'keydown': 'keydown'
       
  7956 	},
       
  7957 
       
  7958 	clickedOpenerEl: null,
       
  7959 
       
  7960 	initialize: function() {
       
  7961 		_.defaults( this.options, {
       
  7962 			container:      document.body,
       
  7963 			title:          '',
       
  7964 			propagate:      true,
       
  7965 			hasCloseButton: true
       
  7966 		});
       
  7967 
       
  7968 		this.focusManager = new wp.media.view.FocusManager({
       
  7969 			el: this.el
       
  7970 		});
       
  7971 	},
       
  7972 	/**
       
  7973 	 * @return {Object}
       
  7974 	 */
       
  7975 	prepare: function() {
       
  7976 		return {
       
  7977 			title:          this.options.title,
       
  7978 			hasCloseButton: this.options.hasCloseButton
       
  7979 		};
       
  7980 	},
       
  7981 
       
  7982 	/**
       
  7983 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  7984 	 */
       
  7985 	attach: function() {
       
  7986 		if ( this.views.attached ) {
       
  7987 			return this;
       
  7988 		}
       
  7989 
       
  7990 		if ( ! this.views.rendered ) {
       
  7991 			this.render();
       
  7992 		}
       
  7993 
       
  7994 		this.$el.appendTo( this.options.container );
       
  7995 
       
  7996 		// Manually mark the view as attached and trigger ready.
       
  7997 		this.views.attached = true;
       
  7998 		this.views.ready();
       
  7999 
       
  8000 		return this.propagate('attach');
       
  8001 	},
       
  8002 
       
  8003 	/**
       
  8004 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8005 	 */
       
  8006 	detach: function() {
       
  8007 		if ( this.$el.is(':visible') ) {
       
  8008 			this.close();
       
  8009 		}
       
  8010 
       
  8011 		this.$el.detach();
       
  8012 		this.views.attached = false;
       
  8013 		return this.propagate('detach');
       
  8014 	},
       
  8015 
       
  8016 	/**
       
  8017 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8018 	 */
       
  8019 	open: function() {
       
  8020 		var $el = this.$el,
       
  8021 			mceEditor;
       
  8022 
       
  8023 		if ( $el.is(':visible') ) {
       
  8024 			return this;
       
  8025 		}
       
  8026 
       
  8027 		this.clickedOpenerEl = document.activeElement;
       
  8028 
       
  8029 		if ( ! this.views.attached ) {
       
  8030 			this.attach();
       
  8031 		}
       
  8032 
       
  8033 		// Disable page scrolling.
       
  8034 		$( 'body' ).addClass( 'modal-open' );
       
  8035 
       
  8036 		$el.show();
       
  8037 
       
  8038 		// Try to close the onscreen keyboard.
       
  8039 		if ( 'ontouchend' in document ) {
       
  8040 			if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor ) && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
       
  8041 				mceEditor.iframeElement.focus();
       
  8042 				mceEditor.iframeElement.blur();
       
  8043 
       
  8044 				setTimeout( function() {
       
  8045 					mceEditor.iframeElement.blur();
       
  8046 				}, 100 );
       
  8047 			}
       
  8048 		}
       
  8049 
       
  8050 		// Set initial focus on the content instead of this view element, to avoid page scrolling.
       
  8051 		this.$( '.media-modal' ).trigger( 'focus' );
       
  8052 
       
  8053 		// Hide the page content from assistive technologies.
       
  8054 		this.focusManager.setAriaHiddenOnBodyChildren( $el );
       
  8055 
       
  8056 		return this.propagate('open');
       
  8057 	},
       
  8058 
       
  8059 	/**
       
  8060 	 * @param {Object} options
       
  8061 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8062 	 */
       
  8063 	close: function( options ) {
       
  8064 		if ( ! this.views.attached || ! this.$el.is(':visible') ) {
       
  8065 			return this;
       
  8066 		}
       
  8067 
       
  8068 		// Pause current audio/video even after closing the modal.
       
  8069 		$( '.mejs-pause button' ).trigger( 'click' );
       
  8070 
       
  8071 		// Enable page scrolling.
       
  8072 		$( 'body' ).removeClass( 'modal-open' );
       
  8073 
       
  8074 		// Hide modal and remove restricted media modal tab focus once it's closed.
       
  8075 		this.$el.hide().off( 'keydown' );
       
  8076 
       
  8077 		/*
       
  8078 		 * Make visible again to assistive technologies all body children that
       
  8079 		 * have been made hidden when the modal opened.
       
  8080 		 */
       
  8081 		this.focusManager.removeAriaHiddenFromBodyChildren();
       
  8082 
       
  8083 		// Move focus back in useful location once modal is closed.
       
  8084 		if ( null !== this.clickedOpenerEl ) {
       
  8085 			// Move focus back to the element that opened the modal.
       
  8086 			this.clickedOpenerEl.focus();
       
  8087 		} else {
       
  8088 			// Fallback to the admin page main element.
       
  8089 			$( '#wpbody-content' )
       
  8090 				.attr( 'tabindex', '-1' )
       
  8091 				.trigger( 'focus' );
       
  8092 		}
       
  8093 
       
  8094 		this.propagate('close');
       
  8095 
       
  8096 		if ( options && options.escape ) {
       
  8097 			this.propagate('escape');
       
  8098 		}
       
  8099 
       
  8100 		return this;
       
  8101 	},
       
  8102 	/**
       
  8103 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8104 	 */
       
  8105 	escape: function() {
       
  8106 		return this.close({ escape: true });
       
  8107 	},
       
  8108 	/**
       
  8109 	 * @param {Object} event
       
  8110 	 */
       
  8111 	escapeHandler: function( event ) {
       
  8112 		event.preventDefault();
       
  8113 		this.escape();
       
  8114 	},
       
  8115 
       
  8116 	/**
       
  8117 	 * @param {Array|Object} content Views to register to '.media-modal-content'
       
  8118 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8119 	 */
       
  8120 	content: function( content ) {
       
  8121 		this.views.set( '.media-modal-content', content );
       
  8122 		return this;
       
  8123 	},
       
  8124 
       
  8125 	/**
       
  8126 	 * Triggers a modal event and if the `propagate` option is set,
       
  8127 	 * forwards events to the modal's controller.
       
  8128 	 *
       
  8129 	 * @param {string} id
       
  8130 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  8131 	 */
       
  8132 	propagate: function( id ) {
       
  8133 		this.trigger( id );
       
  8134 
       
  8135 		if ( this.options.propagate ) {
       
  8136 			this.controller.trigger( id );
       
  8137 		}
       
  8138 
       
  8139 		return this;
       
  8140 	},
       
  8141 	/**
       
  8142 	 * @param {Object} event
       
  8143 	 */
       
  8144 	keydown: function( event ) {
       
  8145 		// Close the modal when escape is pressed.
       
  8146 		if ( 27 === event.which && this.$el.is(':visible') ) {
       
  8147 			this.escape();
       
  8148 			event.stopImmediatePropagation();
       
  8149 		}
       
  8150 	}
       
  8151 });
       
  8152 
       
  8153 module.exports = Modal;
       
  8154 
       
  8155 
       
  8156 /***/ }),
       
  8157 
       
  8158 /***/ "ibOK":
       
  8159 /***/ (function(module, exports) {
       
  8160 
       
  8161 var View = wp.media.View,
  2078 	EditImage;
  8162 	EditImage;
  2079 
  8163 
  2080 /**
  8164 /**
  2081  * wp.media.controller.EditImage
  8165  * wp.media.view.EditImage
  2082  *
  8166  *
  2083  * A state for editing (cropping, etc.) an image.
  8167  * @memberOf wp.media.view
       
  8168  *
       
  8169  * @class
       
  8170  * @augments wp.media.View
       
  8171  * @augments wp.Backbone.View
       
  8172  * @augments Backbone.View
       
  8173  */
       
  8174 EditImage = View.extend(/** @lends wp.media.view.EditImage.prototype */{
       
  8175 	className: 'image-editor',
       
  8176 	template: wp.template('image-editor'),
       
  8177 
       
  8178 	initialize: function( options ) {
       
  8179 		this.editor = window.imageEdit;
       
  8180 		this.controller = options.controller;
       
  8181 		View.prototype.initialize.apply( this, arguments );
       
  8182 	},
       
  8183 
       
  8184 	prepare: function() {
       
  8185 		return this.model.toJSON();
       
  8186 	},
       
  8187 
       
  8188 	loadEditor: function() {
       
  8189 		this.editor.open( this.model.get( 'id' ), this.model.get( 'nonces' ).edit, this );
       
  8190 	},
       
  8191 
       
  8192 	back: function() {
       
  8193 		var lastState = this.controller.lastState();
       
  8194 		this.controller.setState( lastState );
       
  8195 	},
       
  8196 
       
  8197 	refresh: function() {
       
  8198 		this.model.fetch();
       
  8199 	},
       
  8200 
       
  8201 	save: function() {
       
  8202 		var lastState = this.controller.lastState();
       
  8203 
       
  8204 		this.model.fetch().done( _.bind( function() {
       
  8205 			this.controller.setState( lastState );
       
  8206 		}, this ) );
       
  8207 	}
       
  8208 
       
  8209 });
       
  8210 
       
  8211 module.exports = EditImage;
       
  8212 
       
  8213 
       
  8214 /***/ }),
       
  8215 
       
  8216 /***/ "iipZ":
       
  8217 /***/ (function(module, exports) {
       
  8218 
       
  8219 var Selection = wp.media.model.Selection,
       
  8220 	Library = wp.media.controller.Library,
       
  8221 	CollectionAdd;
       
  8222 
       
  8223 /**
       
  8224  * wp.media.controller.CollectionAdd
       
  8225  *
       
  8226  * A state for adding attachments to a collection (e.g. video playlist).
  2084  *
  8227  *
  2085  * @memberOf wp.media.controller
  8228  * @memberOf wp.media.controller
  2086  *
  8229  *
  2087  * @class
  8230  * @class
       
  8231  * @augments wp.media.controller.Library
  2088  * @augments wp.media.controller.State
  8232  * @augments wp.media.controller.State
  2089  * @augments Backbone.Model
  8233  * @augments Backbone.Model
  2090  *
  8234  *
  2091  * @param {object}                    attributes                      The attributes hash passed to the state.
  8235  * @param {object}                     [attributes]                         The attributes hash passed to the state.
  2092  * @param {wp.media.model.Attachment} attributes.model                The attachment.
  8236  * @param {string}                     [attributes.id=library]              Unique identifier.
  2093  * @param {string}                    [attributes.id=edit-image]      Unique identifier.
  8237  * @param {string}                     attributes.title                     Title for the state. Displays in the frame's title region.
  2094  * @param {string}                    [attributes.title=Edit Image]   Title for the state. Displays in the media menu and the frame's title region.
  8238  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
  2095  * @param {string}                    [attributes.content=edit-image] Initial mode for the content region.
  8239  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
  2096  * @param {string}                    [attributes.toolbar=edit-image] Initial mode for the toolbar region.
  8240  *                                                                          If one is not supplied, a collection of attachments of the specified type will be created.
  2097  * @param {string}                    [attributes.menu=false]         Initial mode for the menu region.
  8241  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
  2098  * @param {string}                    [attributes.url]                Unused. @todo Consider removal.
  8242  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
       
  8243  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
       
  8244  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
       
  8245  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
       
  8246  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
       
  8247  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
       
  8248  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
       
  8249  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  8250  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
  8251  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
  8252  * @param {int}                        [attributes.priority=100]            The priority for the state link in the media menu.
       
  8253  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
       
  8254  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
       
  8255  * @param {string}                     attributes.type                      The collection's media type. (e.g. 'video').
       
  8256  * @param {string}                     attributes.collectionType            The collection type. (e.g. 'playlist').
  2099  */
  8257  */
  2100 EditImage = wp.media.controller.State.extend(/** @lends wp.media.controller.EditImage.prototype */{
  8258 CollectionAdd = Library.extend(/** @lends wp.media.controller.CollectionAdd.prototype */{
  2101 	defaults: {
  8259 	defaults: _.defaults( {
  2102 		id:      'edit-image',
  8260 		// Selection defaults. @see media.model.Selection
  2103 		title:   l10n.editImage,
  8261 		multiple:      'add',
  2104 		menu:    false,
  8262 		// Attachments browser defaults. @see media.view.AttachmentsBrowser
  2105 		toolbar: 'edit-image',
  8263 		filterable:    'uploaded',
  2106 		content: 'edit-image',
  8264 
  2107 		url:     ''
  8265 		priority:      100,
  2108 	},
  8266 		syncSelection: false
  2109 
  8267 	}, Library.prototype.defaults ),
  2110 	/**
  8268 
  2111 	 * Activates a frame for editing a featured image.
  8269 	/**
  2112 	 *
       
  2113 	 * @since 3.9.0
  8270 	 * @since 3.9.0
  2114 	 *
  8271 	 */
  2115 	 * @return {void}
  8272 	initialize: function() {
       
  8273 		var collectionType = this.get('collectionType');
       
  8274 
       
  8275 		if ( 'video' === this.get( 'type' ) ) {
       
  8276 			collectionType = 'video-' + collectionType;
       
  8277 		}
       
  8278 
       
  8279 		this.set( 'id', collectionType + '-library' );
       
  8280 		this.set( 'toolbar', collectionType + '-add' );
       
  8281 		this.set( 'menu', collectionType );
       
  8282 
       
  8283 		// If we haven't been provided a `library`, create a `Selection`.
       
  8284 		if ( ! this.get('library') ) {
       
  8285 			this.set( 'library', wp.media.query({ type: this.get('type') }) );
       
  8286 		}
       
  8287 		Library.prototype.initialize.apply( this, arguments );
       
  8288 	},
       
  8289 
       
  8290 	/**
       
  8291 	 * @since 3.9.0
  2116 	 */
  8292 	 */
  2117 	activate: function() {
  8293 	activate: function() {
  2118 		this.frame.on( 'toolbar:render:edit-image', _.bind( this.toolbar, this ) );
  8294 		var library = this.get('library'),
  2119 	},
  8295 			editLibrary = this.get('editLibrary'),
  2120 
  8296 			edit = this.frame.state( this.get('collectionType') + '-edit' ).get('library');
  2121 	/**
  8297 
  2122 	 * Deactivates a frame for editing a featured image.
  8298 		if ( editLibrary && editLibrary !== edit ) {
  2123 	 *
  8299 			library.unobserve( editLibrary );
  2124 	 * @since 3.9.0
  8300 		}
  2125 	 *
  8301 
  2126 	 * @return {void}
  8302 		// Accepts attachments that exist in the original library and
  2127 	 */
  8303 		// that do not exist in gallery's library.
  2128 	deactivate: function() {
  8304 		library.validator = function( attachment ) {
  2129 		this.frame.off( 'toolbar:render:edit-image' );
  8305 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
  2130 	},
  8306 		};
  2131 
  8307 
  2132 	/**
  8308 		/*
  2133 	 * Adds a toolbar with a back button.
  8309 		 * Reset the library to ensure that all attachments are re-added
  2134 	 *
  8310 		 * to the collection. Do so silently, as calling `observe` will
  2135 	 * When the back button is pressed it checks whether there is a previous state.
  8311 		 * trigger the `reset` event.
  2136 	 * In case there is a previous state it sets that previous state otherwise it
  8312 		 */
  2137 	 * closes the frame.
  8313 		library.reset( library.mirroring.models, { silent: true });
  2138 	 *
  8314 		library.observe( edit );
  2139 	 * @since 3.9.0
  8315 		this.set('editLibrary', edit);
  2140 	 *
  8316 
  2141 	 * @return {void}
  8317 		Library.prototype.activate.apply( this, arguments );
  2142 	 */
       
  2143 	toolbar: function() {
       
  2144 		var frame = this.frame,
       
  2145 			lastState = frame.lastState(),
       
  2146 			previous = lastState && lastState.id;
       
  2147 
       
  2148 		frame.toolbar.set( new wp.media.view.Toolbar({
       
  2149 			controller: frame,
       
  2150 			items: {
       
  2151 				back: {
       
  2152 					style: 'primary',
       
  2153 					text:     l10n.back,
       
  2154 					priority: 20,
       
  2155 					click:    function() {
       
  2156 						if ( previous ) {
       
  2157 							frame.setState( previous );
       
  2158 						} else {
       
  2159 							frame.close();
       
  2160 						}
       
  2161 					}
       
  2162 				}
       
  2163 			}
       
  2164 		}) );
       
  2165 	}
  8318 	}
  2166 });
  8319 });
  2167 
  8320 
  2168 module.exports = EditImage;
  8321 module.exports = CollectionAdd;
  2169 
  8322 
  2170 
  8323 
  2171 /***/ }),
  8324 /***/ }),
  2172 /* 44 */
  8325 
       
  8326 /***/ "iupV":
       
  8327 /***/ (function(module, exports) {
       
  8328 
       
  8329 /* global ClipboardJS */
       
  8330 var Attachment = wp.media.view.Attachment,
       
  8331 	l10n = wp.media.view.l10n,
       
  8332 	$ = jQuery,
       
  8333 	Details,
       
  8334 	__ = wp.i18n.__;
       
  8335 
       
  8336 Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototype */{
       
  8337 	tagName:   'div',
       
  8338 	className: 'attachment-details',
       
  8339 	template:  wp.template('attachment-details'),
       
  8340 
       
  8341 	/*
       
  8342 	 * Reset all the attributes inherited from Attachment including role=checkbox,
       
  8343 	 * tabindex, etc., as they are inappropriate for this view. See #47458 and [30483] / #30390.
       
  8344 	 */
       
  8345 	attributes: {},
       
  8346 
       
  8347 	events: {
       
  8348 		'change [data-setting]':          'updateSetting',
       
  8349 		'change [data-setting] input':    'updateSetting',
       
  8350 		'change [data-setting] select':   'updateSetting',
       
  8351 		'change [data-setting] textarea': 'updateSetting',
       
  8352 		'click .delete-attachment':       'deleteAttachment',
       
  8353 		'click .trash-attachment':        'trashAttachment',
       
  8354 		'click .untrash-attachment':      'untrashAttachment',
       
  8355 		'click .edit-attachment':         'editAttachment',
       
  8356 		'keydown':                        'toggleSelectionHandler'
       
  8357 	},
       
  8358 
       
  8359 	/**
       
  8360 	 * Copies the attachment URL to the clipboard.
       
  8361 	 *
       
  8362 	 * @since 5.5.0
       
  8363 	 *
       
  8364 	 * @param {MouseEvent} event A click event.
       
  8365 	 *
       
  8366 	 * @return {void}
       
  8367 	 */
       
  8368 	 copyAttachmentDetailsURLClipboard: function() {
       
  8369 		var clipboard = new ClipboardJS( '.copy-attachment-url' ),
       
  8370 			successTimeout;
       
  8371 
       
  8372 		clipboard.on( 'success', function( event ) {
       
  8373 			var triggerElement = $( event.trigger ),
       
  8374 				successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
       
  8375 
       
  8376 			// Clear the selection and move focus back to the trigger.
       
  8377 			event.clearSelection();
       
  8378 			// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
       
  8379 			triggerElement.trigger( 'focus' );
       
  8380 
       
  8381 			// Show success visual feedback.
       
  8382 			clearTimeout( successTimeout );
       
  8383 			successElement.removeClass( 'hidden' );
       
  8384 
       
  8385 			// Hide success visual feedback after 3 seconds since last success.
       
  8386 			successTimeout = setTimeout( function() {
       
  8387 				successElement.addClass( 'hidden' );
       
  8388 			}, 3000 );
       
  8389 
       
  8390 			// Handle success audible feedback.
       
  8391 			wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
       
  8392 		} );
       
  8393 	 },
       
  8394 
       
  8395 	/**
       
  8396 	 * Shows the details of an attachment.
       
  8397 	 *
       
  8398 	 * @since 3.5.0
       
  8399 	 *
       
  8400 	 * @constructs wp.media.view.Attachment.Details
       
  8401 	 * @augments wp.media.view.Attachment
       
  8402 	 *
       
  8403 	 * @return {void}
       
  8404 	 */
       
  8405 	initialize: function() {
       
  8406 		this.options = _.defaults( this.options, {
       
  8407 			rerenderOnModelChange: false
       
  8408 		});
       
  8409 
       
  8410 		// Call 'initialize' directly on the parent class.
       
  8411 		Attachment.prototype.initialize.apply( this, arguments );
       
  8412 
       
  8413 		this.copyAttachmentDetailsURLClipboard();
       
  8414 	},
       
  8415 
       
  8416 	/**
       
  8417 	 * Gets the focusable elements to move focus to.
       
  8418 	 *
       
  8419 	 * @since 5.3.0
       
  8420 	 */
       
  8421 	getFocusableElements: function() {
       
  8422 		var editedAttachment = $( 'li[data-id="' + this.model.id + '"]' );
       
  8423 
       
  8424 		this.previousAttachment = editedAttachment.prev();
       
  8425 		this.nextAttachment = editedAttachment.next();
       
  8426 	},
       
  8427 
       
  8428 	/**
       
  8429 	 * Moves focus to the previous or next attachment in the grid.
       
  8430 	 * Fallbacks to the upload button or media frame when there are no attachments.
       
  8431 	 *
       
  8432 	 * @since 5.3.0
       
  8433 	 */
       
  8434 	moveFocus: function() {
       
  8435 		if ( this.previousAttachment.length ) {
       
  8436 			this.previousAttachment.trigger( 'focus' );
       
  8437 			return;
       
  8438 		}
       
  8439 
       
  8440 		if ( this.nextAttachment.length ) {
       
  8441 			this.nextAttachment.trigger( 'focus' );
       
  8442 			return;
       
  8443 		}
       
  8444 
       
  8445 		// Fallback: move focus to the "Select Files" button in the media modal.
       
  8446 		if ( this.controller.uploader && this.controller.uploader.$browser ) {
       
  8447 			this.controller.uploader.$browser.trigger( 'focus' );
       
  8448 			return;
       
  8449 		}
       
  8450 
       
  8451 		// Last fallback.
       
  8452 		this.moveFocusToLastFallback();
       
  8453 	},
       
  8454 
       
  8455 	/**
       
  8456 	 * Moves focus to the media frame as last fallback.
       
  8457 	 *
       
  8458 	 * @since 5.3.0
       
  8459 	 */
       
  8460 	moveFocusToLastFallback: function() {
       
  8461 		// Last fallback: make the frame focusable and move focus to it.
       
  8462 		$( '.media-frame' )
       
  8463 			.attr( 'tabindex', '-1' )
       
  8464 			.trigger( 'focus' );
       
  8465 	},
       
  8466 
       
  8467 	/**
       
  8468 	 * Deletes an attachment.
       
  8469 	 *
       
  8470 	 * Deletes an attachment after asking for confirmation. After deletion,
       
  8471 	 * keeps focus in the modal.
       
  8472 	 *
       
  8473 	 * @since 3.5.0
       
  8474 	 *
       
  8475 	 * @param {MouseEvent} event A click event.
       
  8476 	 *
       
  8477 	 * @return {void}
       
  8478 	 */
       
  8479 	deleteAttachment: function( event ) {
       
  8480 		event.preventDefault();
       
  8481 
       
  8482 		this.getFocusableElements();
       
  8483 
       
  8484 		if ( window.confirm( l10n.warnDelete ) ) {
       
  8485 			this.model.destroy();
       
  8486 			this.moveFocus();
       
  8487 		}
       
  8488 	},
       
  8489 
       
  8490 	/**
       
  8491 	 * Sets the Trash state on an attachment, or destroys the model itself.
       
  8492 	 *
       
  8493 	 * If the mediaTrash setting is set to true, trashes the attachment.
       
  8494 	 * Otherwise, the model itself is destroyed.
       
  8495 	 *
       
  8496 	 * @since 3.9.0
       
  8497 	 *
       
  8498 	 * @param {MouseEvent} event A click event.
       
  8499 	 *
       
  8500 	 * @return {void}
       
  8501 	 */
       
  8502 	trashAttachment: function( event ) {
       
  8503 		var library = this.controller.library,
       
  8504 			self = this;
       
  8505 		event.preventDefault();
       
  8506 
       
  8507 		this.getFocusableElements();
       
  8508 
       
  8509 		// When in the Media Library and the Media Trash is enabled.
       
  8510 		if ( wp.media.view.settings.mediaTrash &&
       
  8511 			'edit-metadata' === this.controller.content.mode() ) {
       
  8512 
       
  8513 			this.model.set( 'status', 'trash' );
       
  8514 			this.model.save().done( function() {
       
  8515 				library._requery( true );
       
  8516 				/*
       
  8517 				 * @todo We need to move focus back to the previous, next, or first
       
  8518 				 * attachment but the library gets re-queried and refreshed.
       
  8519 				 * Thus, the references to the previous attachments are lost.
       
  8520 				 * We need an alternate method.
       
  8521 				 */
       
  8522 				self.moveFocusToLastFallback();
       
  8523 			} );
       
  8524 		} else {
       
  8525 			this.model.destroy();
       
  8526 			this.moveFocus();
       
  8527 		}
       
  8528 	},
       
  8529 
       
  8530 	/**
       
  8531 	 * Untrashes an attachment.
       
  8532 	 *
       
  8533 	 * @since 4.0.0
       
  8534 	 *
       
  8535 	 * @param {MouseEvent} event A click event.
       
  8536 	 *
       
  8537 	 * @return {void}
       
  8538 	 */
       
  8539 	untrashAttachment: function( event ) {
       
  8540 		var library = this.controller.library;
       
  8541 		event.preventDefault();
       
  8542 
       
  8543 		this.model.set( 'status', 'inherit' );
       
  8544 		this.model.save().done( function() {
       
  8545 			library._requery( true );
       
  8546 		} );
       
  8547 	},
       
  8548 
       
  8549 	/**
       
  8550 	 * Opens the edit page for a specific attachment.
       
  8551 	 *
       
  8552 	 * @since 3.5.0
       
  8553 	 *
       
  8554 	 * @param {MouseEvent} event A click event.
       
  8555 	 *
       
  8556 	 * @return {void}
       
  8557 	 */
       
  8558 	editAttachment: function( event ) {
       
  8559 		var editState = this.controller.states.get( 'edit-image' );
       
  8560 		if ( window.imageEdit && editState ) {
       
  8561 			event.preventDefault();
       
  8562 
       
  8563 			editState.set( 'image', this.model );
       
  8564 			this.controller.setState( 'edit-image' );
       
  8565 		} else {
       
  8566 			this.$el.addClass('needs-refresh');
       
  8567 		}
       
  8568 	},
       
  8569 
       
  8570 	/**
       
  8571 	 * Triggers an event on the controller when reverse tabbing (shift+tab).
       
  8572 	 *
       
  8573 	 * This event can be used to make sure to move the focus correctly.
       
  8574 	 *
       
  8575 	 * @since 4.0.0
       
  8576 	 *
       
  8577 	 * @fires wp.media.controller.MediaLibrary#attachment:details:shift-tab
       
  8578 	 * @fires wp.media.controller.MediaLibrary#attachment:keydown:arrow
       
  8579 	 *
       
  8580 	 * @param {KeyboardEvent} event A keyboard event.
       
  8581 	 *
       
  8582 	 * @return {boolean|void} Returns false or undefined.
       
  8583 	 */
       
  8584 	toggleSelectionHandler: function( event ) {
       
  8585 		if ( 'keydown' === event.type && 9 === event.keyCode && event.shiftKey && event.target === this.$( ':tabbable' ).get( 0 ) ) {
       
  8586 			this.controller.trigger( 'attachment:details:shift-tab', event );
       
  8587 			return false;
       
  8588 		}
       
  8589 	},
       
  8590 
       
  8591 	render: function() {
       
  8592 		Attachment.prototype.render.apply( this, arguments );
       
  8593 
       
  8594 		wp.media.mixin.removeAllPlayers();
       
  8595 		this.$( 'audio, video' ).each( function (i, elem) {
       
  8596 			var el = wp.media.view.MediaDetails.prepareSrc( elem );
       
  8597 			new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings );
       
  8598 		} );
       
  8599 	}
       
  8600 });
       
  8601 
       
  8602 module.exports = Details;
       
  8603 
       
  8604 
       
  8605 /***/ }),
       
  8606 
       
  8607 /***/ "l2j4":
       
  8608 /***/ (function(module, exports) {
       
  8609 
       
  8610 /**
       
  8611  * wp.media.view.Heading
       
  8612  *
       
  8613  * A reusable heading component for the media library
       
  8614  *
       
  8615  * Used to add accessibility friendly headers in the media library/modal.
       
  8616  *
       
  8617  * @class
       
  8618  * @augments wp.media.View
       
  8619  * @augments wp.Backbone.View
       
  8620  * @augments Backbone.View
       
  8621  */
       
  8622 var Heading = wp.media.View.extend( {
       
  8623 	tagName: function() {
       
  8624 		return this.options.level || 'h1';
       
  8625 	},
       
  8626 	className: 'media-views-heading',
       
  8627 
       
  8628 	initialize: function() {
       
  8629 
       
  8630 		if ( this.options.className ) {
       
  8631 			this.$el.addClass( this.options.className );
       
  8632 		}
       
  8633 
       
  8634 		this.text = this.options.text;
       
  8635 	},
       
  8636 
       
  8637 	render: function() {
       
  8638 		this.$el.html( this.text );
       
  8639 		return this;
       
  8640 	}
       
  8641 } );
       
  8642 
       
  8643 module.exports = Heading;
       
  8644 
       
  8645 
       
  8646 /***/ }),
       
  8647 
       
  8648 /***/ "mVaH":
  2173 /***/ (function(module, exports) {
  8649 /***/ (function(module, exports) {
  2174 
  8650 
  2175 /**
  8651 /**
  2176  * wp.media.controller.MediaLibrary
  8652  * wp.media.controller.MediaLibrary
  2177  *
  8653  *
  2223 
  8699 
  2224 module.exports = MediaLibrary;
  8700 module.exports = MediaLibrary;
  2225 
  8701 
  2226 
  8702 
  2227 /***/ }),
  8703 /***/ }),
  2228 /* 45 */
  8704 
       
  8705 /***/ "ng6N":
       
  8706 /***/ (function(module, exports) {
       
  8707 
       
  8708 var Selection = wp.media.model.Selection,
       
  8709 	Library = wp.media.controller.Library,
       
  8710 	l10n = wp.media.view.l10n,
       
  8711 	GalleryAdd;
       
  8712 
       
  8713 /**
       
  8714  * wp.media.controller.GalleryAdd
       
  8715  *
       
  8716  * A state for selecting more images to add to a gallery.
       
  8717  *
       
  8718  * @since 3.5.0
       
  8719  *
       
  8720  * @class
       
  8721  * @augments wp.media.controller.Library
       
  8722  * @augments wp.media.controller.State
       
  8723  * @augments Backbone.Model
       
  8724  *
       
  8725  * @memberof wp.media.controller
       
  8726  *
       
  8727  * @param {Object}                     [attributes]                         The attributes hash passed to the state.
       
  8728  * @param {string}                     [attributes.id=gallery-library]      Unique identifier.
       
  8729  * @param {string}                     [attributes.title=Add to Gallery]    Title for the state. Displays in the frame's title region.
       
  8730  * @param {boolean}                    [attributes.multiple=add]            Whether multi-select is enabled. @todo 'add' doesn't seem do anything special, and gets used as a boolean.
       
  8731  * @param {wp.media.model.Attachments} [attributes.library]                 The attachments collection to browse.
       
  8732  *                                                                          If one is not supplied, a collection of all images will be created.
       
  8733  * @param {boolean|string}             [attributes.filterable=uploaded]     Whether the library is filterable, and if so what filters should be shown.
       
  8734  *                                                                          Accepts 'all', 'uploaded', or 'unattached'.
       
  8735  * @param {string}                     [attributes.menu=gallery]            Initial mode for the menu region.
       
  8736  * @param {string}                     [attributes.content=upload]          Initial mode for the content region.
       
  8737  *                                                                          Overridden by persistent user setting if 'contentUserSetting' is true.
       
  8738  * @param {string}                     [attributes.router=browse]           Initial mode for the router region.
       
  8739  * @param {string}                     [attributes.toolbar=gallery-add]     Initial mode for the toolbar region.
       
  8740  * @param {boolean}                    [attributes.searchable=true]         Whether the library is searchable.
       
  8741  * @param {boolean}                    [attributes.sortable=true]           Whether the Attachments should be sortable. Depends on the orderby property being set to menuOrder on the attachments collection.
       
  8742  * @param {boolean}                    [attributes.autoSelect=true]         Whether an uploaded attachment should be automatically added to the selection.
       
  8743  * @param {boolean}                    [attributes.contentUserSetting=true] Whether the content region's mode should be set and persisted per user.
       
  8744  * @param {number}                     [attributes.priority=100]            The priority for the state link in the media menu.
       
  8745  * @param {boolean}                    [attributes.syncSelection=false]     Whether the Attachments selection should be persisted from the last state.
       
  8746  *                                                                          Defaults to false because for this state, because the library of the Edit Gallery state is the selection.
       
  8747  */
       
  8748 GalleryAdd = Library.extend(/** @lends wp.media.controller.GalleryAdd.prototype */{
       
  8749 	defaults: _.defaults({
       
  8750 		id:            'gallery-library',
       
  8751 		title:         l10n.addToGalleryTitle,
       
  8752 		multiple:      'add',
       
  8753 		filterable:    'uploaded',
       
  8754 		menu:          'gallery',
       
  8755 		toolbar:       'gallery-add',
       
  8756 		priority:      100,
       
  8757 		syncSelection: false
       
  8758 	}, Library.prototype.defaults ),
       
  8759 
       
  8760 	/**
       
  8761 	 * Initializes the library. Creates a library of images if a library isn't supplied.
       
  8762 	 *
       
  8763 	 * @since 3.5.0
       
  8764 	 *
       
  8765 	 * @return {void}
       
  8766 	 */
       
  8767 	initialize: function() {
       
  8768 		if ( ! this.get('library') ) {
       
  8769 			this.set( 'library', wp.media.query({ type: 'image' }) );
       
  8770 		}
       
  8771 
       
  8772 		Library.prototype.initialize.apply( this, arguments );
       
  8773 	},
       
  8774 
       
  8775 	/**
       
  8776 	 * Activates the library.
       
  8777 	 *
       
  8778 	 * Removes all event listeners if in edit mode. Creates a validator to check an attachment.
       
  8779 	 * Resets library and re-enables event listeners. Activates edit mode. Calls the parent's activate method.
       
  8780 	 *
       
  8781 	 * @since 3.5.0
       
  8782 	 *
       
  8783 	 * @return {void}
       
  8784 	 */
       
  8785 	activate: function() {
       
  8786 		var library = this.get('library'),
       
  8787 			edit    = this.frame.state('gallery-edit').get('library');
       
  8788 
       
  8789 		if ( this.editLibrary && this.editLibrary !== edit ) {
       
  8790 			library.unobserve( this.editLibrary );
       
  8791 		}
       
  8792 
       
  8793 		/*
       
  8794 		 * Accept attachments that exist in the original library but
       
  8795 		 * that do not exist in gallery's library yet.
       
  8796 		 */
       
  8797 		library.validator = function( attachment ) {
       
  8798 			return !! this.mirroring.get( attachment.cid ) && ! edit.get( attachment.cid ) && Selection.prototype.validator.apply( this, arguments );
       
  8799 		};
       
  8800 
       
  8801 		/*
       
  8802 		 * Reset the library to ensure that all attachments are re-added
       
  8803 		 * to the collection. Do so silently, as calling `observe` will
       
  8804 		 * trigger the `reset` event.
       
  8805 		 */
       
  8806 		library.reset( library.mirroring.models, { silent: true });
       
  8807 		library.observe( edit );
       
  8808 		this.editLibrary = edit;
       
  8809 
       
  8810 		Library.prototype.activate.apply( this, arguments );
       
  8811 	}
       
  8812 });
       
  8813 
       
  8814 module.exports = GalleryAdd;
       
  8815 
       
  8816 
       
  8817 /***/ }),
       
  8818 
       
  8819 /***/ "nwwF":
       
  8820 /***/ (function(module, exports) {
       
  8821 
       
  8822 var View = wp.media.View,
       
  8823 	$ = Backbone.$,
       
  8824 	Settings;
       
  8825 
       
  8826 /**
       
  8827  * wp.media.view.Settings
       
  8828  *
       
  8829  * @memberOf wp.media.view
       
  8830  *
       
  8831  * @class
       
  8832  * @augments wp.media.View
       
  8833  * @augments wp.Backbone.View
       
  8834  * @augments Backbone.View
       
  8835  */
       
  8836 Settings = View.extend(/** @lends wp.media.view.Settings.prototype */{
       
  8837 	events: {
       
  8838 		'click button':    'updateHandler',
       
  8839 		'change input':    'updateHandler',
       
  8840 		'change select':   'updateHandler',
       
  8841 		'change textarea': 'updateHandler'
       
  8842 	},
       
  8843 
       
  8844 	initialize: function() {
       
  8845 		this.model = this.model || new Backbone.Model();
       
  8846 		this.listenTo( this.model, 'change', this.updateChanges );
       
  8847 	},
       
  8848 
       
  8849 	prepare: function() {
       
  8850 		return _.defaults({
       
  8851 			model: this.model.toJSON()
       
  8852 		}, this.options );
       
  8853 	},
       
  8854 	/**
       
  8855 	 * @return {wp.media.view.Settings} Returns itself to allow chaining.
       
  8856 	 */
       
  8857 	render: function() {
       
  8858 		View.prototype.render.apply( this, arguments );
       
  8859 		// Select the correct values.
       
  8860 		_( this.model.attributes ).chain().keys().each( this.update, this );
       
  8861 		return this;
       
  8862 	},
       
  8863 	/**
       
  8864 	 * @param {string} key
       
  8865 	 */
       
  8866 	update: function( key ) {
       
  8867 		var value = this.model.get( key ),
       
  8868 			$setting = this.$('[data-setting="' + key + '"]'),
       
  8869 			$buttons, $value;
       
  8870 
       
  8871 		// Bail if we didn't find a matching setting.
       
  8872 		if ( ! $setting.length ) {
       
  8873 			return;
       
  8874 		}
       
  8875 
       
  8876 		// Attempt to determine how the setting is rendered and update
       
  8877 		// the selected value.
       
  8878 
       
  8879 		// Handle dropdowns.
       
  8880 		if ( $setting.is('select') ) {
       
  8881 			$value = $setting.find('[value="' + value + '"]');
       
  8882 
       
  8883 			if ( $value.length ) {
       
  8884 				$setting.find('option').prop( 'selected', false );
       
  8885 				$value.prop( 'selected', true );
       
  8886 			} else {
       
  8887 				// If we can't find the desired value, record what *is* selected.
       
  8888 				this.model.set( key, $setting.find(':selected').val() );
       
  8889 			}
       
  8890 
       
  8891 		// Handle button groups.
       
  8892 		} else if ( $setting.hasClass('button-group') ) {
       
  8893 			$buttons = $setting.find( 'button' )
       
  8894 				.removeClass( 'active' )
       
  8895 				.attr( 'aria-pressed', 'false' );
       
  8896 			$buttons.filter( '[value="' + value + '"]' )
       
  8897 				.addClass( 'active' )
       
  8898 				.attr( 'aria-pressed', 'true' );
       
  8899 
       
  8900 		// Handle text inputs and textareas.
       
  8901 		} else if ( $setting.is('input[type="text"], textarea') ) {
       
  8902 			if ( ! $setting.is(':focus') ) {
       
  8903 				$setting.val( value );
       
  8904 			}
       
  8905 		// Handle checkboxes.
       
  8906 		} else if ( $setting.is('input[type="checkbox"]') ) {
       
  8907 			$setting.prop( 'checked', !! value && 'false' !== value );
       
  8908 		}
       
  8909 	},
       
  8910 	/**
       
  8911 	 * @param {Object} event
       
  8912 	 */
       
  8913 	updateHandler: function( event ) {
       
  8914 		var $setting = $( event.target ).closest('[data-setting]'),
       
  8915 			value = event.target.value,
       
  8916 			userSetting;
       
  8917 
       
  8918 		event.preventDefault();
       
  8919 
       
  8920 		if ( ! $setting.length ) {
       
  8921 			return;
       
  8922 		}
       
  8923 
       
  8924 		// Use the correct value for checkboxes.
       
  8925 		if ( $setting.is('input[type="checkbox"]') ) {
       
  8926 			value = $setting[0].checked;
       
  8927 		}
       
  8928 
       
  8929 		// Update the corresponding setting.
       
  8930 		this.model.set( $setting.data('setting'), value );
       
  8931 
       
  8932 		// If the setting has a corresponding user setting,
       
  8933 		// update that as well.
       
  8934 		userSetting = $setting.data('userSetting');
       
  8935 		if ( userSetting ) {
       
  8936 			window.setUserSetting( userSetting, value );
       
  8937 		}
       
  8938 	},
       
  8939 
       
  8940 	updateChanges: function( model ) {
       
  8941 		if ( model.hasChanged() ) {
       
  8942 			_( model.changed ).chain().keys().each( this.update, this );
       
  8943 		}
       
  8944 	}
       
  8945 });
       
  8946 
       
  8947 module.exports = Settings;
       
  8948 
       
  8949 
       
  8950 /***/ }),
       
  8951 
       
  8952 /***/ "ojD6":
       
  8953 /***/ (function(module, exports) {
       
  8954 
       
  8955 var View = wp.media.View,
       
  8956 	$ = jQuery,
       
  8957 	Attachments,
       
  8958 	infiniteScrolling = wp.media.view.settings.infiniteScrolling;
       
  8959 
       
  8960 Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{
       
  8961 	tagName:   'ul',
       
  8962 	className: 'attachments',
       
  8963 
       
  8964 	attributes: {
       
  8965 		tabIndex: -1
       
  8966 	},
       
  8967 
       
  8968 	/**
       
  8969 	 * Represents the overview of attachments in the Media Library.
       
  8970 	 *
       
  8971 	 * The constructor binds events to the collection this view represents when
       
  8972 	 * adding or removing attachments or resetting the entire collection.
       
  8973 	 *
       
  8974 	 * @since 3.5.0
       
  8975 	 *
       
  8976 	 * @constructs
       
  8977 	 * @memberof wp.media.view
       
  8978 	 *
       
  8979 	 * @augments wp.media.View
       
  8980 	 *
       
  8981 	 * @listens collection:add
       
  8982 	 * @listens collection:remove
       
  8983 	 * @listens collection:reset
       
  8984 	 * @listens controller:library:selection:add
       
  8985 	 * @listens scrollElement:scroll
       
  8986 	 * @listens this:ready
       
  8987 	 * @listens controller:open
       
  8988 	 */
       
  8989 	initialize: function() {
       
  8990 		this.el.id = _.uniqueId('__attachments-view-');
       
  8991 
       
  8992 		/**
       
  8993 		 * @since 5.8.0 Added the `infiniteScrolling` parameter.
       
  8994 		 *
       
  8995 		 * @param infiniteScrolling  Whether to enable infinite scrolling or use
       
  8996 		 *                           the default "load more" button.
       
  8997 		 * @param refreshSensitivity The time in milliseconds to throttle the scroll
       
  8998 		 *                           handler.
       
  8999 		 * @param refreshThreshold   The amount of pixels that should be scrolled before
       
  9000 		 *                           loading more attachments from the server.
       
  9001 		 * @param AttachmentView     The view class to be used for models in the
       
  9002 		 *                           collection.
       
  9003 		 * @param sortable           A jQuery sortable options object
       
  9004 		 *                           ( http://api.jqueryui.com/sortable/ ).
       
  9005 		 * @param resize             A boolean indicating whether or not to listen to
       
  9006 		 *                           resize events.
       
  9007 		 * @param idealColumnWidth   The width in pixels which a column should have when
       
  9008 		 *                           calculating the total number of columns.
       
  9009 		 */
       
  9010 		_.defaults( this.options, {
       
  9011 			infiniteScrolling:  infiniteScrolling || false,
       
  9012 			refreshSensitivity: wp.media.isTouchDevice ? 300 : 200,
       
  9013 			refreshThreshold:   3,
       
  9014 			AttachmentView:     wp.media.view.Attachment,
       
  9015 			sortable:           false,
       
  9016 			resize:             true,
       
  9017 			idealColumnWidth:   $( window ).width() < 640 ? 135 : 150
       
  9018 		});
       
  9019 
       
  9020 		this._viewsByCid = {};
       
  9021 		this.$window = $( window );
       
  9022 		this.resizeEvent = 'resize.media-modal-columns';
       
  9023 
       
  9024 		this.collection.on( 'add', function( attachment ) {
       
  9025 			this.views.add( this.createAttachmentView( attachment ), {
       
  9026 				at: this.collection.indexOf( attachment )
       
  9027 			});
       
  9028 		}, this );
       
  9029 
       
  9030 		/*
       
  9031 		 * Find the view to be removed, delete it and call the remove function to clear
       
  9032 		 * any set event handlers.
       
  9033 		 */
       
  9034 		this.collection.on( 'remove', function( attachment ) {
       
  9035 			var view = this._viewsByCid[ attachment.cid ];
       
  9036 			delete this._viewsByCid[ attachment.cid ];
       
  9037 
       
  9038 			if ( view ) {
       
  9039 				view.remove();
       
  9040 			}
       
  9041 		}, this );
       
  9042 
       
  9043 		this.collection.on( 'reset', this.render, this );
       
  9044 
       
  9045 		this.controller.on( 'library:selection:add', this.attachmentFocus, this );
       
  9046 
       
  9047 		if ( this.options.infiniteScrolling ) {
       
  9048 			// Throttle the scroll handler and bind this.
       
  9049 			this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
       
  9050 
       
  9051 			this.options.scrollElement = this.options.scrollElement || this.el;
       
  9052 			$( this.options.scrollElement ).on( 'scroll', this.scroll );
       
  9053 		}
       
  9054 
       
  9055 		this.initSortable();
       
  9056 
       
  9057 		_.bindAll( this, 'setColumns' );
       
  9058 
       
  9059 		if ( this.options.resize ) {
       
  9060 			this.on( 'ready', this.bindEvents );
       
  9061 			this.controller.on( 'open', this.setColumns );
       
  9062 
       
  9063 			/*
       
  9064 			 * Call this.setColumns() after this view has been rendered in the
       
  9065 			 * DOM so attachments get proper width applied.
       
  9066 			 */
       
  9067 			_.defer( this.setColumns, this );
       
  9068 		}
       
  9069 	},
       
  9070 
       
  9071 	/**
       
  9072 	 * Listens to the resizeEvent on the window.
       
  9073 	 *
       
  9074 	 * Adjusts the amount of columns accordingly. First removes any existing event
       
  9075 	 * handlers to prevent duplicate listeners.
       
  9076 	 *
       
  9077 	 * @since 4.0.0
       
  9078 	 *
       
  9079 	 * @listens window:resize
       
  9080 	 *
       
  9081 	 * @return {void}
       
  9082 	 */
       
  9083 	bindEvents: function() {
       
  9084 		this.$window.off( this.resizeEvent ).on( this.resizeEvent, _.debounce( this.setColumns, 50 ) );
       
  9085 	},
       
  9086 
       
  9087 	/**
       
  9088 	 * Focuses the first item in the collection.
       
  9089 	 *
       
  9090 	 * @since 4.0.0
       
  9091 	 *
       
  9092 	 * @return {void}
       
  9093 	 */
       
  9094 	attachmentFocus: function() {
       
  9095 		/*
       
  9096 		 * @todo When uploading new attachments, this tries to move focus to
       
  9097 		 * the attachments grid. Actually, a progress bar gets initially displayed
       
  9098 		 * and then updated when uploading completes, so focus is lost.
       
  9099 		 * Additionally: this view is used for both the attachments list and
       
  9100 		 * the list of selected attachments in the bottom media toolbar. Thus, when
       
  9101 		 * uploading attachments, it is called twice and returns two different `this`.
       
  9102 		 * `this.columns` is truthy within the modal.
       
  9103 		 */
       
  9104 		if ( this.columns ) {
       
  9105 			// Move focus to the grid list within the modal.
       
  9106 			this.$el.focus();
       
  9107 		}
       
  9108 	},
       
  9109 
       
  9110 	/**
       
  9111 	 * Restores focus to the selected item in the collection.
       
  9112 	 *
       
  9113 	 * Moves focus back to the first selected attachment in the grid. Used when
       
  9114 	 * tabbing backwards from the attachment details sidebar.
       
  9115 	 * See media.view.AttachmentsBrowser.
       
  9116 	 *
       
  9117 	 * @since 4.0.0
       
  9118 	 *
       
  9119 	 * @return {void}
       
  9120 	 */
       
  9121 	restoreFocus: function() {
       
  9122 		this.$( 'li.selected:first' ).focus();
       
  9123 	},
       
  9124 
       
  9125 	/**
       
  9126 	 * Handles events for arrow key presses.
       
  9127 	 *
       
  9128 	 * Focuses the attachment in the direction of the used arrow key if it exists.
       
  9129 	 *
       
  9130 	 * @since 4.0.0
       
  9131 	 *
       
  9132 	 * @param {KeyboardEvent} event The keyboard event that triggered this function.
       
  9133 	 *
       
  9134 	 * @return {void}
       
  9135 	 */
       
  9136 	arrowEvent: function( event ) {
       
  9137 		var attachments = this.$el.children( 'li' ),
       
  9138 			perRow = this.columns,
       
  9139 			index = attachments.filter( ':focus' ).index(),
       
  9140 			row = ( index + 1 ) <= perRow ? 1 : Math.ceil( ( index + 1 ) / perRow );
       
  9141 
       
  9142 		if ( index === -1 ) {
       
  9143 			return;
       
  9144 		}
       
  9145 
       
  9146 		// Left arrow = 37.
       
  9147 		if ( 37 === event.keyCode ) {
       
  9148 			if ( 0 === index ) {
       
  9149 				return;
       
  9150 			}
       
  9151 			attachments.eq( index - 1 ).focus();
       
  9152 		}
       
  9153 
       
  9154 		// Up arrow = 38.
       
  9155 		if ( 38 === event.keyCode ) {
       
  9156 			if ( 1 === row ) {
       
  9157 				return;
       
  9158 			}
       
  9159 			attachments.eq( index - perRow ).focus();
       
  9160 		}
       
  9161 
       
  9162 		// Right arrow = 39.
       
  9163 		if ( 39 === event.keyCode ) {
       
  9164 			if ( attachments.length === index ) {
       
  9165 				return;
       
  9166 			}
       
  9167 			attachments.eq( index + 1 ).focus();
       
  9168 		}
       
  9169 
       
  9170 		// Down arrow = 40.
       
  9171 		if ( 40 === event.keyCode ) {
       
  9172 			if ( Math.ceil( attachments.length / perRow ) === row ) {
       
  9173 				return;
       
  9174 			}
       
  9175 			attachments.eq( index + perRow ).focus();
       
  9176 		}
       
  9177 	},
       
  9178 
       
  9179 	/**
       
  9180 	 * Clears any set event handlers.
       
  9181 	 *
       
  9182 	 * @since 3.5.0
       
  9183 	 *
       
  9184 	 * @return {void}
       
  9185 	 */
       
  9186 	dispose: function() {
       
  9187 		this.collection.props.off( null, null, this );
       
  9188 		if ( this.options.resize ) {
       
  9189 			this.$window.off( this.resizeEvent );
       
  9190 		}
       
  9191 
       
  9192 		// Call 'dispose' directly on the parent class.
       
  9193 		View.prototype.dispose.apply( this, arguments );
       
  9194 	},
       
  9195 
       
  9196 	/**
       
  9197 	 * Calculates the amount of columns.
       
  9198 	 *
       
  9199 	 * Calculates the amount of columns and sets it on the data-columns attribute
       
  9200 	 * of .media-frame-content.
       
  9201 	 *
       
  9202 	 * @since 4.0.0
       
  9203 	 *
       
  9204 	 * @return {void}
       
  9205 	 */
       
  9206 	setColumns: function() {
       
  9207 		var prev = this.columns,
       
  9208 			width = this.$el.width();
       
  9209 
       
  9210 		if ( width ) {
       
  9211 			this.columns = Math.min( Math.round( width / this.options.idealColumnWidth ), 12 ) || 1;
       
  9212 
       
  9213 			if ( ! prev || prev !== this.columns ) {
       
  9214 				this.$el.closest( '.media-frame-content' ).attr( 'data-columns', this.columns );
       
  9215 			}
       
  9216 		}
       
  9217 	},
       
  9218 
       
  9219 	/**
       
  9220 	 * Initializes jQuery sortable on the attachment list.
       
  9221 	 *
       
  9222 	 * Fails gracefully if jQuery sortable doesn't exist or isn't passed
       
  9223 	 * in the options.
       
  9224 	 *
       
  9225 	 * @since 3.5.0
       
  9226 	 *
       
  9227 	 * @fires collection:reset
       
  9228 	 *
       
  9229 	 * @return {void}
       
  9230 	 */
       
  9231 	initSortable: function() {
       
  9232 		var collection = this.collection;
       
  9233 
       
  9234 		if ( ! this.options.sortable || ! $.fn.sortable ) {
       
  9235 			return;
       
  9236 		}
       
  9237 
       
  9238 		this.$el.sortable( _.extend({
       
  9239 			// If the `collection` has a `comparator`, disable sorting.
       
  9240 			disabled: !! collection.comparator,
       
  9241 
       
  9242 			/*
       
  9243 			 * Change the position of the attachment as soon as the mouse pointer
       
  9244 			 * overlaps a thumbnail.
       
  9245 			 */
       
  9246 			tolerance: 'pointer',
       
  9247 
       
  9248 			// Record the initial `index` of the dragged model.
       
  9249 			start: function( event, ui ) {
       
  9250 				ui.item.data('sortableIndexStart', ui.item.index());
       
  9251 			},
       
  9252 
       
  9253 			/*
       
  9254 			 * Update the model's index in the collection. Do so silently, as the view
       
  9255 			 * is already accurate.
       
  9256 			 */
       
  9257 			update: function( event, ui ) {
       
  9258 				var model = collection.at( ui.item.data('sortableIndexStart') ),
       
  9259 					comparator = collection.comparator;
       
  9260 
       
  9261 				// Temporarily disable the comparator to prevent `add`
       
  9262 				// from re-sorting.
       
  9263 				delete collection.comparator;
       
  9264 
       
  9265 				// Silently shift the model to its new index.
       
  9266 				collection.remove( model, {
       
  9267 					silent: true
       
  9268 				});
       
  9269 				collection.add( model, {
       
  9270 					silent: true,
       
  9271 					at:     ui.item.index()
       
  9272 				});
       
  9273 
       
  9274 				// Restore the comparator.
       
  9275 				collection.comparator = comparator;
       
  9276 
       
  9277 				// Fire the `reset` event to ensure other collections sync.
       
  9278 				collection.trigger( 'reset', collection );
       
  9279 
       
  9280 				// If the collection is sorted by menu order, update the menu order.
       
  9281 				collection.saveMenuOrder();
       
  9282 			}
       
  9283 		}, this.options.sortable ) );
       
  9284 
       
  9285 		/*
       
  9286 		 * If the `orderby` property is changed on the `collection`,
       
  9287 		 * check to see if we have a `comparator`. If so, disable sorting.
       
  9288 		 */
       
  9289 		collection.props.on( 'change:orderby', function() {
       
  9290 			this.$el.sortable( 'option', 'disabled', !! collection.comparator );
       
  9291 		}, this );
       
  9292 
       
  9293 		this.collection.props.on( 'change:orderby', this.refreshSortable, this );
       
  9294 		this.refreshSortable();
       
  9295 	},
       
  9296 
       
  9297 	/**
       
  9298 	 * Disables jQuery sortable if collection has a comparator or collection.orderby
       
  9299 	 * equals menuOrder.
       
  9300 	 *
       
  9301 	 * @since 3.5.0
       
  9302 	 *
       
  9303 	 * @return {void}
       
  9304 	 */
       
  9305 	refreshSortable: function() {
       
  9306 		if ( ! this.options.sortable || ! $.fn.sortable ) {
       
  9307 			return;
       
  9308 		}
       
  9309 
       
  9310 		var collection = this.collection,
       
  9311 			orderby = collection.props.get('orderby'),
       
  9312 			enabled = 'menuOrder' === orderby || ! collection.comparator;
       
  9313 
       
  9314 		this.$el.sortable( 'option', 'disabled', ! enabled );
       
  9315 	},
       
  9316 
       
  9317 	/**
       
  9318 	 * Creates a new view for an attachment and adds it to _viewsByCid.
       
  9319 	 *
       
  9320 	 * @since 3.5.0
       
  9321 	 *
       
  9322 	 * @param {wp.media.model.Attachment} attachment
       
  9323 	 *
       
  9324 	 * @return {wp.media.View} The created view.
       
  9325 	 */
       
  9326 	createAttachmentView: function( attachment ) {
       
  9327 		var view = new this.options.AttachmentView({
       
  9328 			controller:           this.controller,
       
  9329 			model:                attachment,
       
  9330 			collection:           this.collection,
       
  9331 			selection:            this.options.selection
       
  9332 		});
       
  9333 
       
  9334 		return this._viewsByCid[ attachment.cid ] = view;
       
  9335 	},
       
  9336 
       
  9337 	/**
       
  9338 	 * Prepares view for display.
       
  9339 	 *
       
  9340 	 * Creates views for every attachment in collection if the collection is not
       
  9341 	 * empty, otherwise clears all views and loads more attachments.
       
  9342 	 *
       
  9343 	 * @since 3.5.0
       
  9344 	 *
       
  9345 	 * @return {void}
       
  9346 	 */
       
  9347 	prepare: function() {
       
  9348 		if ( this.collection.length ) {
       
  9349 			this.views.set( this.collection.map( this.createAttachmentView, this ) );
       
  9350 		} else {
       
  9351 			this.views.unset();
       
  9352 			if ( this.options.infiniteScrolling ) {
       
  9353 				this.collection.more().done( this.scroll );
       
  9354 			}
       
  9355 		}
       
  9356 	},
       
  9357 
       
  9358 	/**
       
  9359 	 * Triggers the scroll function to check if we should query for additional
       
  9360 	 * attachments right away.
       
  9361 	 *
       
  9362 	 * @since 3.5.0
       
  9363 	 *
       
  9364 	 * @return {void}
       
  9365 	 */
       
  9366 	ready: function() {
       
  9367 		if ( this.options.infiniteScrolling ) {
       
  9368 			this.scroll();
       
  9369 		}
       
  9370 	},
       
  9371 
       
  9372 	/**
       
  9373 	 * Handles scroll events.
       
  9374 	 *
       
  9375 	 * Shows the spinner if we're close to the bottom. Loads more attachments from
       
  9376 	 * server if we're {refreshThreshold} times away from the bottom.
       
  9377 	 *
       
  9378 	 * @since 3.5.0
       
  9379 	 *
       
  9380 	 * @return {void}
       
  9381 	 */
       
  9382 	scroll: function() {
       
  9383 		var view = this,
       
  9384 			el = this.options.scrollElement,
       
  9385 			scrollTop = el.scrollTop,
       
  9386 			toolbar;
       
  9387 
       
  9388 		/*
       
  9389 		 * The scroll event occurs on the document, but the element that should be
       
  9390 		 * checked is the document body.
       
  9391 		 */
       
  9392 		if ( el === document ) {
       
  9393 			el = document.body;
       
  9394 			scrollTop = $(document).scrollTop();
       
  9395 		}
       
  9396 
       
  9397 		if ( ! $(el).is(':visible') || ! this.collection.hasMore() ) {
       
  9398 			return;
       
  9399 		}
       
  9400 
       
  9401 		toolbar = this.views.parent.toolbar;
       
  9402 
       
  9403 		// Show the spinner only if we are close to the bottom.
       
  9404 		if ( el.scrollHeight - ( scrollTop + el.clientHeight ) < el.clientHeight / 3 ) {
       
  9405 			toolbar.get('spinner').show();
       
  9406 		}
       
  9407 
       
  9408 		if ( el.scrollHeight < scrollTop + ( el.clientHeight * this.options.refreshThreshold ) ) {
       
  9409 			this.collection.more().done(function() {
       
  9410 				view.scroll();
       
  9411 				toolbar.get('spinner').hide();
       
  9412 			});
       
  9413 		}
       
  9414 	}
       
  9415 });
       
  9416 
       
  9417 module.exports = Attachments;
       
  9418 
       
  9419 
       
  9420 /***/ }),
       
  9421 
       
  9422 /***/ "qe5n":
  2229 /***/ (function(module, exports) {
  9423 /***/ (function(module, exports) {
  2230 
  9424 
  2231 var l10n = wp.media.view.l10n,
  9425 var l10n = wp.media.view.l10n,
  2232 	$ = Backbone.$,
  9426 	$ = Backbone.$,
  2233 	Embed;
  9427 	Embed;
  2367 
  9561 
  2368 module.exports = Embed;
  9562 module.exports = Embed;
  2369 
  9563 
  2370 
  9564 
  2371 /***/ }),
  9565 /***/ }),
  2372 /* 46 */
  9566 
  2373 /***/ (function(module, exports) {
  9567 /***/ "sULL":
  2374 
       
  2375 var l10n = wp.media.view.l10n,
       
  2376 	Cropper;
       
  2377 
       
  2378 /**
       
  2379  * wp.media.controller.Cropper
       
  2380  *
       
  2381  * A class for cropping an image when called from the header media customization panel.
       
  2382  *
       
  2383  * @memberOf wp.media.controller
       
  2384  *
       
  2385  * @class
       
  2386  * @augments wp.media.controller.State
       
  2387  * @augments Backbone.Model
       
  2388  */
       
  2389 Cropper = wp.media.controller.State.extend(/** @lends wp.media.controller.Cropper.prototype */{
       
  2390 	defaults: {
       
  2391 		id:          'cropper',
       
  2392 		title:       l10n.cropImage,
       
  2393 		// Region mode defaults.
       
  2394 		toolbar:     'crop',
       
  2395 		content:     'crop',
       
  2396 		router:      false,
       
  2397 		canSkipCrop: false,
       
  2398 
       
  2399 		// Default doCrop Ajax arguments to allow the Customizer (for example) to inject state.
       
  2400 		doCropArgs: {}
       
  2401 	},
       
  2402 
       
  2403 	/**
       
  2404 	 * Shows the crop image window when called from the Add new image button.
       
  2405 	 *
       
  2406 	 * @since 4.2.0
       
  2407 	 *
       
  2408 	 * @return {void}
       
  2409 	 */
       
  2410 	activate: function() {
       
  2411 		this.frame.on( 'content:create:crop', this.createCropContent, this );
       
  2412 		this.frame.on( 'close', this.removeCropper, this );
       
  2413 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
       
  2414 	},
       
  2415 
       
  2416 	/**
       
  2417 	 * Changes the state of the toolbar window to browse mode.
       
  2418 	 *
       
  2419 	 * @since 4.2.0
       
  2420 	 *
       
  2421 	 * @return {void}
       
  2422 	 */
       
  2423 	deactivate: function() {
       
  2424 		this.frame.toolbar.mode('browse');
       
  2425 	},
       
  2426 
       
  2427 	/**
       
  2428 	 * Creates the crop image window.
       
  2429 	 *
       
  2430 	 * Initialized when clicking on the Select and Crop button.
       
  2431 	 *
       
  2432 	 * @since 4.2.0
       
  2433 	 *
       
  2434 	 * @fires crop window
       
  2435 	 *
       
  2436 	 * @return {void}
       
  2437 	 */
       
  2438 	createCropContent: function() {
       
  2439 		this.cropperView = new wp.media.view.Cropper({
       
  2440 			controller: this,
       
  2441 			attachment: this.get('selection').first()
       
  2442 		});
       
  2443 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
       
  2444 		this.frame.content.set(this.cropperView);
       
  2445 
       
  2446 	},
       
  2447 
       
  2448 	/**
       
  2449 	 * Removes the image selection and closes the cropping window.
       
  2450 	 *
       
  2451 	 * @since 4.2.0
       
  2452 	 *
       
  2453 	 * @return {void}
       
  2454 	 */
       
  2455 	removeCropper: function() {
       
  2456 		this.imgSelect.cancelSelection();
       
  2457 		this.imgSelect.setOptions({remove: true});
       
  2458 		this.imgSelect.update();
       
  2459 		this.cropperView.remove();
       
  2460 	},
       
  2461 
       
  2462 	/**
       
  2463 	 * Checks if cropping can be skipped and creates crop toolbar accordingly.
       
  2464 	 *
       
  2465 	 * @since 4.2.0
       
  2466 	 *
       
  2467 	 * @return {void}
       
  2468 	 */
       
  2469 	createCropToolbar: function() {
       
  2470 		var canSkipCrop, toolbarOptions;
       
  2471 
       
  2472 		canSkipCrop = this.get('canSkipCrop') || false;
       
  2473 
       
  2474 		toolbarOptions = {
       
  2475 			controller: this.frame,
       
  2476 			items: {
       
  2477 				insert: {
       
  2478 					style:    'primary',
       
  2479 					text:     l10n.cropImage,
       
  2480 					priority: 80,
       
  2481 					requires: { library: false, selection: false },
       
  2482 
       
  2483 					click: function() {
       
  2484 						var controller = this.controller,
       
  2485 							selection;
       
  2486 
       
  2487 						selection = controller.state().get('selection').first();
       
  2488 						selection.set({cropDetails: controller.state().imgSelect.getSelection()});
       
  2489 
       
  2490 						this.$el.text(l10n.cropping);
       
  2491 						this.$el.attr('disabled', true);
       
  2492 
       
  2493 						controller.state().doCrop( selection ).done( function( croppedImage ) {
       
  2494 							controller.trigger('cropped', croppedImage );
       
  2495 							controller.close();
       
  2496 						}).fail( function() {
       
  2497 							controller.trigger('content:error:crop');
       
  2498 						});
       
  2499 					}
       
  2500 				}
       
  2501 			}
       
  2502 		};
       
  2503 
       
  2504 		if ( canSkipCrop ) {
       
  2505 			_.extend( toolbarOptions.items, {
       
  2506 				skip: {
       
  2507 					style:      'secondary',
       
  2508 					text:       l10n.skipCropping,
       
  2509 					priority:   70,
       
  2510 					requires:   { library: false, selection: false },
       
  2511 					click:      function() {
       
  2512 						var selection = this.controller.state().get('selection').first();
       
  2513 						this.controller.state().cropperView.remove();
       
  2514 						this.controller.trigger('skippedcrop', selection);
       
  2515 						this.controller.close();
       
  2516 					}
       
  2517 				}
       
  2518 			});
       
  2519 		}
       
  2520 
       
  2521 		this.frame.toolbar.set( new wp.media.view.Toolbar(toolbarOptions) );
       
  2522 	},
       
  2523 
       
  2524 	/**
       
  2525 	 * Creates an object with the image attachment and crop properties.
       
  2526 	 *
       
  2527 	 * @since 4.2.0
       
  2528 	 *
       
  2529 	 * @return {$.promise} A jQuery promise with the custom header crop details.
       
  2530 	 */
       
  2531 	doCrop: function( attachment ) {
       
  2532 		return wp.ajax.post( 'custom-header-crop', _.extend(
       
  2533 			{},
       
  2534 			this.defaults.doCropArgs,
       
  2535 			{
       
  2536 				nonce: attachment.get( 'nonces' ).edit,
       
  2537 				id: attachment.get( 'id' ),
       
  2538 				cropDetails: attachment.get( 'cropDetails' )
       
  2539 			}
       
  2540 		) );
       
  2541 	}
       
  2542 });
       
  2543 
       
  2544 module.exports = Cropper;
       
  2545 
       
  2546 
       
  2547 /***/ }),
       
  2548 /* 47 */
       
  2549 /***/ (function(module, exports) {
       
  2550 
       
  2551 var Controller = wp.media.controller,
       
  2552 	CustomizeImageCropper;
       
  2553 
       
  2554 /**
       
  2555  * A state for cropping an image in the customizer.
       
  2556  *
       
  2557  * @since 4.3.0
       
  2558  *
       
  2559  * @constructs wp.media.controller.CustomizeImageCropper
       
  2560  * @memberOf wp.media.controller
       
  2561  * @augments wp.media.controller.CustomizeImageCropper.Cropper
       
  2562  * @inheritDoc
       
  2563  */
       
  2564 CustomizeImageCropper = Controller.Cropper.extend(/** @lends wp.media.controller.CustomizeImageCropper.prototype */{
       
  2565 	/**
       
  2566 	 * Posts the crop details to the admin.
       
  2567 	 *
       
  2568 	 * Uses crop measurements when flexible in both directions.
       
  2569 	 * Constrains flexible side based on image ratio and size of the fixed side.
       
  2570 	 *
       
  2571 	 * @since 4.3.0
       
  2572 	 *
       
  2573 	 * @param {Object} attachment The attachment to crop.
       
  2574 	 *
       
  2575 	 * @return {$.promise} A jQuery promise that represents the crop image request.
       
  2576 	 */
       
  2577 	doCrop: function( attachment ) {
       
  2578 		var cropDetails = attachment.get( 'cropDetails' ),
       
  2579 			control = this.get( 'control' ),
       
  2580 			ratio = cropDetails.width / cropDetails.height;
       
  2581 
       
  2582 		// Use crop measurements when flexible in both directions.
       
  2583 		if ( control.params.flex_width && control.params.flex_height ) {
       
  2584 			cropDetails.dst_width  = cropDetails.width;
       
  2585 			cropDetails.dst_height = cropDetails.height;
       
  2586 
       
  2587 		// Constrain flexible side based on image ratio and size of the fixed side.
       
  2588 		} else {
       
  2589 			cropDetails.dst_width  = control.params.flex_width  ? control.params.height * ratio : control.params.width;
       
  2590 			cropDetails.dst_height = control.params.flex_height ? control.params.width  / ratio : control.params.height;
       
  2591 		}
       
  2592 
       
  2593 		return wp.ajax.post( 'crop-image', {
       
  2594 			wp_customize: 'on',
       
  2595 			nonce: attachment.get( 'nonces' ).edit,
       
  2596 			id: attachment.get( 'id' ),
       
  2597 			context: control.id,
       
  2598 			cropDetails: cropDetails
       
  2599 		} );
       
  2600 	}
       
  2601 });
       
  2602 
       
  2603 module.exports = CustomizeImageCropper;
       
  2604 
       
  2605 
       
  2606 /***/ }),
       
  2607 /* 48 */
       
  2608 /***/ (function(module, exports) {
       
  2609 
       
  2610 var Controller = wp.media.controller,
       
  2611 	SiteIconCropper;
       
  2612 
       
  2613 /**
       
  2614  * wp.media.controller.SiteIconCropper
       
  2615  *
       
  2616  * A state for cropping a Site Icon.
       
  2617  *
       
  2618  * @memberOf wp.media.controller
       
  2619  *
       
  2620  * @class
       
  2621  * @augments wp.media.controller.Cropper
       
  2622  * @augments wp.media.controller.State
       
  2623  * @augments Backbone.Model
       
  2624  */
       
  2625 SiteIconCropper = Controller.Cropper.extend(/** @lends wp.media.controller.SiteIconCropper.prototype */{
       
  2626 	activate: function() {
       
  2627 		this.frame.on( 'content:create:crop', this.createCropContent, this );
       
  2628 		this.frame.on( 'close', this.removeCropper, this );
       
  2629 		this.set('selection', new Backbone.Collection(this.frame._selection.single));
       
  2630 	},
       
  2631 
       
  2632 	createCropContent: function() {
       
  2633 		this.cropperView = new wp.media.view.SiteIconCropper({
       
  2634 			controller: this,
       
  2635 			attachment: this.get('selection').first()
       
  2636 		});
       
  2637 		this.cropperView.on('image-loaded', this.createCropToolbar, this);
       
  2638 		this.frame.content.set(this.cropperView);
       
  2639 
       
  2640 	},
       
  2641 
       
  2642 	doCrop: function( attachment ) {
       
  2643 		var cropDetails = attachment.get( 'cropDetails' ),
       
  2644 			control = this.get( 'control' );
       
  2645 
       
  2646 		cropDetails.dst_width  = control.params.width;
       
  2647 		cropDetails.dst_height = control.params.height;
       
  2648 
       
  2649 		return wp.ajax.post( 'crop-image', {
       
  2650 			nonce: attachment.get( 'nonces' ).edit,
       
  2651 			id: attachment.get( 'id' ),
       
  2652 			context: 'site-icon',
       
  2653 			cropDetails: cropDetails
       
  2654 		} );
       
  2655 	}
       
  2656 });
       
  2657 
       
  2658 module.exports = SiteIconCropper;
       
  2659 
       
  2660 
       
  2661 /***/ }),
       
  2662 /* 49 */
       
  2663 /***/ (function(module, exports) {
       
  2664 
       
  2665 /**
       
  2666  * wp.media.View
       
  2667  *
       
  2668  * The base view class for media.
       
  2669  *
       
  2670  * Undelegating events, removing events from the model, and
       
  2671  * removing events from the controller mirror the code for
       
  2672  * `Backbone.View.dispose` in Backbone 0.9.8 development.
       
  2673  *
       
  2674  * This behavior has since been removed, and should not be used
       
  2675  * outside of the media manager.
       
  2676  *
       
  2677  * @memberOf wp.media
       
  2678  *
       
  2679  * @class
       
  2680  * @augments wp.Backbone.View
       
  2681  * @augments Backbone.View
       
  2682  */
       
  2683 var View = wp.Backbone.View.extend(/** @lends wp.media.View.prototype */{
       
  2684 	constructor: function( options ) {
       
  2685 		if ( options && options.controller ) {
       
  2686 			this.controller = options.controller;
       
  2687 		}
       
  2688 		wp.Backbone.View.apply( this, arguments );
       
  2689 	},
       
  2690 	/**
       
  2691 	 * @todo The internal comment mentions this might have been a stop-gap
       
  2692 	 *       before Backbone 0.9.8 came out. Figure out if Backbone core takes
       
  2693 	 *       care of this in Backbone.View now.
       
  2694 	 *
       
  2695 	 * @return {wp.media.View} Returns itself to allow chaining.
       
  2696 	 */
       
  2697 	dispose: function() {
       
  2698 		/*
       
  2699 		 * Undelegating events, removing events from the model, and
       
  2700 		 * removing events from the controller mirror the code for
       
  2701 		 * `Backbone.View.dispose` in Backbone 0.9.8 development.
       
  2702 		 */
       
  2703 		this.undelegateEvents();
       
  2704 
       
  2705 		if ( this.model && this.model.off ) {
       
  2706 			this.model.off( null, null, this );
       
  2707 		}
       
  2708 
       
  2709 		if ( this.collection && this.collection.off ) {
       
  2710 			this.collection.off( null, null, this );
       
  2711 		}
       
  2712 
       
  2713 		// Unbind controller events.
       
  2714 		if ( this.controller && this.controller.off ) {
       
  2715 			this.controller.off( null, null, this );
       
  2716 		}
       
  2717 
       
  2718 		return this;
       
  2719 	},
       
  2720 	/**
       
  2721 	 * @return {wp.media.View} Returns itself to allow chaining.
       
  2722 	 */
       
  2723 	remove: function() {
       
  2724 		this.dispose();
       
  2725 		/**
       
  2726 		 * call 'remove' directly on the parent class
       
  2727 		 */
       
  2728 		return wp.Backbone.View.prototype.remove.apply( this, arguments );
       
  2729 	}
       
  2730 });
       
  2731 
       
  2732 module.exports = View;
       
  2733 
       
  2734 
       
  2735 /***/ }),
       
  2736 /* 50 */
       
  2737 /***/ (function(module, exports) {
       
  2738 
       
  2739 /**
       
  2740  * wp.media.view.Frame
       
  2741  *
       
  2742  * A frame is a composite view consisting of one or more regions and one or more
       
  2743  * states.
       
  2744  *
       
  2745  * @memberOf wp.media.view
       
  2746  *
       
  2747  * @see wp.media.controller.State
       
  2748  * @see wp.media.controller.Region
       
  2749  *
       
  2750  * @class
       
  2751  * @augments wp.media.View
       
  2752  * @augments wp.Backbone.View
       
  2753  * @augments Backbone.View
       
  2754  * @mixes wp.media.controller.StateMachine
       
  2755  */
       
  2756 var Frame = wp.media.View.extend(/** @lends wp.media.view.Frame.prototype */{
       
  2757 	initialize: function() {
       
  2758 		_.defaults( this.options, {
       
  2759 			mode: [ 'select' ]
       
  2760 		});
       
  2761 		this._createRegions();
       
  2762 		this._createStates();
       
  2763 		this._createModes();
       
  2764 	},
       
  2765 
       
  2766 	_createRegions: function() {
       
  2767 		// Clone the regions array.
       
  2768 		this.regions = this.regions ? this.regions.slice() : [];
       
  2769 
       
  2770 		// Initialize regions.
       
  2771 		_.each( this.regions, function( region ) {
       
  2772 			this[ region ] = new wp.media.controller.Region({
       
  2773 				view:     this,
       
  2774 				id:       region,
       
  2775 				selector: '.media-frame-' + region
       
  2776 			});
       
  2777 		}, this );
       
  2778 	},
       
  2779 	/**
       
  2780 	 * Create the frame's states.
       
  2781 	 *
       
  2782 	 * @see wp.media.controller.State
       
  2783 	 * @see wp.media.controller.StateMachine
       
  2784 	 *
       
  2785 	 * @fires wp.media.controller.State#ready
       
  2786 	 */
       
  2787 	_createStates: function() {
       
  2788 		// Create the default `states` collection.
       
  2789 		this.states = new Backbone.Collection( null, {
       
  2790 			model: wp.media.controller.State
       
  2791 		});
       
  2792 
       
  2793 		// Ensure states have a reference to the frame.
       
  2794 		this.states.on( 'add', function( model ) {
       
  2795 			model.frame = this;
       
  2796 			model.trigger('ready');
       
  2797 		}, this );
       
  2798 
       
  2799 		if ( this.options.states ) {
       
  2800 			this.states.add( this.options.states );
       
  2801 		}
       
  2802 	},
       
  2803 
       
  2804 	/**
       
  2805 	 * A frame can be in a mode or multiple modes at one time.
       
  2806 	 *
       
  2807 	 * For example, the manage media frame can be in the `Bulk Select` or `Edit` mode.
       
  2808 	 */
       
  2809 	_createModes: function() {
       
  2810 		// Store active "modes" that the frame is in. Unrelated to region modes.
       
  2811 		this.activeModes = new Backbone.Collection();
       
  2812 		this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );
       
  2813 
       
  2814 		_.each( this.options.mode, function( mode ) {
       
  2815 			this.activateMode( mode );
       
  2816 		}, this );
       
  2817 	},
       
  2818 	/**
       
  2819 	 * Reset all states on the frame to their defaults.
       
  2820 	 *
       
  2821 	 * @return {wp.media.view.Frame} Returns itself to allow chaining.
       
  2822 	 */
       
  2823 	reset: function() {
       
  2824 		this.states.invoke( 'trigger', 'reset' );
       
  2825 		return this;
       
  2826 	},
       
  2827 	/**
       
  2828 	 * Map activeMode collection events to the frame.
       
  2829 	 */
       
  2830 	triggerModeEvents: function( model, collection, options ) {
       
  2831 		var collectionEvent,
       
  2832 			modeEventMap = {
       
  2833 				add: 'activate',
       
  2834 				remove: 'deactivate'
       
  2835 			},
       
  2836 			eventToTrigger;
       
  2837 		// Probably a better way to do this.
       
  2838 		_.each( options, function( value, key ) {
       
  2839 			if ( value ) {
       
  2840 				collectionEvent = key;
       
  2841 			}
       
  2842 		} );
       
  2843 
       
  2844 		if ( ! _.has( modeEventMap, collectionEvent ) ) {
       
  2845 			return;
       
  2846 		}
       
  2847 
       
  2848 		eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];
       
  2849 		this.trigger( eventToTrigger );
       
  2850 	},
       
  2851 	/**
       
  2852 	 * Activate a mode on the frame.
       
  2853 	 *
       
  2854 	 * @param string mode Mode ID.
       
  2855 	 * @return {this} Returns itself to allow chaining.
       
  2856 	 */
       
  2857 	activateMode: function( mode ) {
       
  2858 		// Bail if the mode is already active.
       
  2859 		if ( this.isModeActive( mode ) ) {
       
  2860 			return;
       
  2861 		}
       
  2862 		this.activeModes.add( [ { id: mode } ] );
       
  2863 		// Add a CSS class to the frame so elements can be styled for the mode.
       
  2864 		this.$el.addClass( 'mode-' + mode );
       
  2865 
       
  2866 		return this;
       
  2867 	},
       
  2868 	/**
       
  2869 	 * Deactivate a mode on the frame.
       
  2870 	 *
       
  2871 	 * @param string mode Mode ID.
       
  2872 	 * @return {this} Returns itself to allow chaining.
       
  2873 	 */
       
  2874 	deactivateMode: function( mode ) {
       
  2875 		// Bail if the mode isn't active.
       
  2876 		if ( ! this.isModeActive( mode ) ) {
       
  2877 			return this;
       
  2878 		}
       
  2879 		this.activeModes.remove( this.activeModes.where( { id: mode } ) );
       
  2880 		this.$el.removeClass( 'mode-' + mode );
       
  2881 		/**
       
  2882 		 * Frame mode deactivation event.
       
  2883 		 *
       
  2884 		 * @event wp.media.view.Frame#{mode}:deactivate
       
  2885 		 */
       
  2886 		this.trigger( mode + ':deactivate' );
       
  2887 
       
  2888 		return this;
       
  2889 	},
       
  2890 	/**
       
  2891 	 * Check if a mode is enabled on the frame.
       
  2892 	 *
       
  2893 	 * @param string mode Mode ID.
       
  2894 	 * @return bool
       
  2895 	 */
       
  2896 	isModeActive: function( mode ) {
       
  2897 		return Boolean( this.activeModes.where( { id: mode } ).length );
       
  2898 	}
       
  2899 });
       
  2900 
       
  2901 // Make the `Frame` a `StateMachine`.
       
  2902 _.extend( Frame.prototype, wp.media.controller.StateMachine.prototype );
       
  2903 
       
  2904 module.exports = Frame;
       
  2905 
       
  2906 
       
  2907 /***/ }),
       
  2908 /* 51 */
       
  2909 /***/ (function(module, exports) {
       
  2910 
       
  2911 var Frame = wp.media.view.Frame,
       
  2912 	l10n = wp.media.view.l10n,
       
  2913 	$ = jQuery,
       
  2914 	MediaFrame;
       
  2915 
       
  2916 /**
       
  2917  * wp.media.view.MediaFrame
       
  2918  *
       
  2919  * The frame used to create the media modal.
       
  2920  *
       
  2921  * @memberOf wp.media.view
       
  2922  *
       
  2923  * @class
       
  2924  * @augments wp.media.view.Frame
       
  2925  * @augments wp.media.View
       
  2926  * @augments wp.Backbone.View
       
  2927  * @augments Backbone.View
       
  2928  * @mixes wp.media.controller.StateMachine
       
  2929  */
       
  2930 MediaFrame = Frame.extend(/** @lends wp.media.view.MediaFrame.prototype */{
       
  2931 	className: 'media-frame',
       
  2932 	template:  wp.template('media-frame'),
       
  2933 	regions:   ['menu','title','content','toolbar','router'],
       
  2934 
       
  2935 	events: {
       
  2936 		'click .media-frame-menu-toggle': 'toggleMenu'
       
  2937 	},
       
  2938 
       
  2939 	/**
       
  2940 	 * @constructs
       
  2941 	 */
       
  2942 	initialize: function() {
       
  2943 		Frame.prototype.initialize.apply( this, arguments );
       
  2944 
       
  2945 		_.defaults( this.options, {
       
  2946 			title:    l10n.mediaFrameDefaultTitle,
       
  2947 			modal:    true,
       
  2948 			uploader: true
       
  2949 		});
       
  2950 
       
  2951 		// Ensure core UI is enabled.
       
  2952 		this.$el.addClass('wp-core-ui');
       
  2953 
       
  2954 		// Initialize modal container view.
       
  2955 		if ( this.options.modal ) {
       
  2956 			this.modal = new wp.media.view.Modal({
       
  2957 				controller: this,
       
  2958 				title:      this.options.title
       
  2959 			});
       
  2960 
       
  2961 			this.modal.content( this );
       
  2962 		}
       
  2963 
       
  2964 		// Force the uploader off if the upload limit has been exceeded or
       
  2965 		// if the browser isn't supported.
       
  2966 		if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
       
  2967 			this.options.uploader = false;
       
  2968 		}
       
  2969 
       
  2970 		// Initialize window-wide uploader.
       
  2971 		if ( this.options.uploader ) {
       
  2972 			this.uploader = new wp.media.view.UploaderWindow({
       
  2973 				controller: this,
       
  2974 				uploader: {
       
  2975 					dropzone:  this.modal ? this.modal.$el : this.$el,
       
  2976 					container: this.$el
       
  2977 				}
       
  2978 			});
       
  2979 			this.views.set( '.media-frame-uploader', this.uploader );
       
  2980 		}
       
  2981 
       
  2982 		this.on( 'attach', _.bind( this.views.ready, this.views ), this );
       
  2983 
       
  2984 		// Bind default title creation.
       
  2985 		this.on( 'title:create:default', this.createTitle, this );
       
  2986 		this.title.mode('default');
       
  2987 
       
  2988 		// Bind default menu.
       
  2989 		this.on( 'menu:create:default', this.createMenu, this );
       
  2990 
       
  2991 		// Set the menu ARIA tab panel attributes when the modal opens.
       
  2992 		this.on( 'open', this.setMenuTabPanelAriaAttributes, this );
       
  2993 		// Set the router ARIA tab panel attributes when the modal opens.
       
  2994 		this.on( 'open', this.setRouterTabPanelAriaAttributes, this );
       
  2995 
       
  2996 		// Update the menu ARIA tab panel attributes when the content updates.
       
  2997 		this.on( 'content:render', this.setMenuTabPanelAriaAttributes, this );
       
  2998 		// Update the router ARIA tab panel attributes when the content updates.
       
  2999 		this.on( 'content:render', this.setRouterTabPanelAriaAttributes, this );
       
  3000 	},
       
  3001 
       
  3002 	/**
       
  3003 	 * Sets the attributes to be used on the menu ARIA tab panel.
       
  3004 	 *
       
  3005 	 * @since 5.3.0
       
  3006 	 *
       
  3007 	 * @return {void}
       
  3008 	 */
       
  3009 	setMenuTabPanelAriaAttributes: function() {
       
  3010 		var stateId = this.state().get( 'id' ),
       
  3011 			tabPanelEl = this.$el.find( '.media-frame-tab-panel' ),
       
  3012 			ariaLabelledby;
       
  3013 
       
  3014 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
       
  3015 
       
  3016 		if ( this.state().get( 'menu' ) && this.menuView && this.menuView.isVisible ) {
       
  3017 			ariaLabelledby = 'menu-item-' + stateId;
       
  3018 
       
  3019 			// Set the tab panel attributes only if the tabs are visible.
       
  3020 			tabPanelEl
       
  3021 				.attr( {
       
  3022 					role: 'tabpanel',
       
  3023 					'aria-labelledby': ariaLabelledby,
       
  3024 					tabIndex: '0'
       
  3025 				} );
       
  3026 		}
       
  3027 	},
       
  3028 
       
  3029 	/**
       
  3030 	 * Sets the attributes to be used on the router ARIA tab panel.
       
  3031 	 *
       
  3032 	 * @since 5.3.0
       
  3033 	 *
       
  3034 	 * @return {void}
       
  3035 	 */
       
  3036 	setRouterTabPanelAriaAttributes: function() {
       
  3037 		var tabPanelEl = this.$el.find( '.media-frame-content' ),
       
  3038 			ariaLabelledby;
       
  3039 
       
  3040 		tabPanelEl.removeAttr( 'role aria-labelledby tabindex' );
       
  3041 
       
  3042 		// Set the tab panel attributes only if the tabs are visible.
       
  3043 		if ( this.state().get( 'router' ) && this.routerView && this.routerView.isVisible && this.content._mode ) {
       
  3044 			ariaLabelledby = 'menu-item-' + this.content._mode;
       
  3045 
       
  3046 			tabPanelEl
       
  3047 				.attr( {
       
  3048 					role: 'tabpanel',
       
  3049 					'aria-labelledby': ariaLabelledby,
       
  3050 					tabIndex: '0'
       
  3051 				} );
       
  3052 		}
       
  3053 	},
       
  3054 
       
  3055 	/**
       
  3056 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3057 	 */
       
  3058 	render: function() {
       
  3059 		// Activate the default state if no active state exists.
       
  3060 		if ( ! this.state() && this.options.state ) {
       
  3061 			this.setState( this.options.state );
       
  3062 		}
       
  3063 		/**
       
  3064 		 * call 'render' directly on the parent class
       
  3065 		 */
       
  3066 		return Frame.prototype.render.apply( this, arguments );
       
  3067 	},
       
  3068 	/**
       
  3069 	 * @param {Object} title
       
  3070 	 * @this wp.media.controller.Region
       
  3071 	 */
       
  3072 	createTitle: function( title ) {
       
  3073 		title.view = new wp.media.View({
       
  3074 			controller: this,
       
  3075 			tagName: 'h1'
       
  3076 		});
       
  3077 	},
       
  3078 	/**
       
  3079 	 * @param {Object} menu
       
  3080 	 * @this wp.media.controller.Region
       
  3081 	 */
       
  3082 	createMenu: function( menu ) {
       
  3083 		menu.view = new wp.media.view.Menu({
       
  3084 			controller: this,
       
  3085 
       
  3086 			attributes: {
       
  3087 				role:               'tablist',
       
  3088 				'aria-orientation': 'vertical'
       
  3089 			}
       
  3090 		});
       
  3091 
       
  3092 		this.menuView = menu.view;
       
  3093 	},
       
  3094 
       
  3095 	toggleMenu: function( event ) {
       
  3096 		var menu = this.$el.find( '.media-menu' );
       
  3097 
       
  3098 		menu.toggleClass( 'visible' );
       
  3099 		$( event.target ).attr( 'aria-expanded', menu.hasClass( 'visible' ) );
       
  3100 	},
       
  3101 
       
  3102 	/**
       
  3103 	 * @param {Object} toolbar
       
  3104 	 * @this wp.media.controller.Region
       
  3105 	 */
       
  3106 	createToolbar: function( toolbar ) {
       
  3107 		toolbar.view = new wp.media.view.Toolbar({
       
  3108 			controller: this
       
  3109 		});
       
  3110 	},
       
  3111 	/**
       
  3112 	 * @param {Object} router
       
  3113 	 * @this wp.media.controller.Region
       
  3114 	 */
       
  3115 	createRouter: function( router ) {
       
  3116 		router.view = new wp.media.view.Router({
       
  3117 			controller: this,
       
  3118 
       
  3119 			attributes: {
       
  3120 				role:               'tablist',
       
  3121 				'aria-orientation': 'horizontal'
       
  3122 			}
       
  3123 		});
       
  3124 
       
  3125 		this.routerView = router.view;
       
  3126 	},
       
  3127 	/**
       
  3128 	 * @param {Object} options
       
  3129 	 */
       
  3130 	createIframeStates: function( options ) {
       
  3131 		var settings = wp.media.view.settings,
       
  3132 			tabs = settings.tabs,
       
  3133 			tabUrl = settings.tabUrl,
       
  3134 			$postId;
       
  3135 
       
  3136 		if ( ! tabs || ! tabUrl ) {
       
  3137 			return;
       
  3138 		}
       
  3139 
       
  3140 		// Add the post ID to the tab URL if it exists.
       
  3141 		$postId = $('#post_ID');
       
  3142 		if ( $postId.length ) {
       
  3143 			tabUrl += '&post_id=' + $postId.val();
       
  3144 		}
       
  3145 
       
  3146 		// Generate the tab states.
       
  3147 		_.each( tabs, function( title, id ) {
       
  3148 			this.state( 'iframe:' + id ).set( _.defaults({
       
  3149 				tab:     id,
       
  3150 				src:     tabUrl + '&tab=' + id,
       
  3151 				title:   title,
       
  3152 				content: 'iframe',
       
  3153 				menu:    'default'
       
  3154 			}, options ) );
       
  3155 		}, this );
       
  3156 
       
  3157 		this.on( 'content:create:iframe', this.iframeContent, this );
       
  3158 		this.on( 'content:deactivate:iframe', this.iframeContentCleanup, this );
       
  3159 		this.on( 'menu:render:default', this.iframeMenu, this );
       
  3160 		this.on( 'open', this.hijackThickbox, this );
       
  3161 		this.on( 'close', this.restoreThickbox, this );
       
  3162 	},
       
  3163 
       
  3164 	/**
       
  3165 	 * @param {Object} content
       
  3166 	 * @this wp.media.controller.Region
       
  3167 	 */
       
  3168 	iframeContent: function( content ) {
       
  3169 		this.$el.addClass('hide-toolbar');
       
  3170 		content.view = new wp.media.view.Iframe({
       
  3171 			controller: this
       
  3172 		});
       
  3173 	},
       
  3174 
       
  3175 	iframeContentCleanup: function() {
       
  3176 		this.$el.removeClass('hide-toolbar');
       
  3177 	},
       
  3178 
       
  3179 	iframeMenu: function( view ) {
       
  3180 		var views = {};
       
  3181 
       
  3182 		if ( ! view ) {
       
  3183 			return;
       
  3184 		}
       
  3185 
       
  3186 		_.each( wp.media.view.settings.tabs, function( title, id ) {
       
  3187 			views[ 'iframe:' + id ] = {
       
  3188 				text: this.state( 'iframe:' + id ).get('title'),
       
  3189 				priority: 200
       
  3190 			};
       
  3191 		}, this );
       
  3192 
       
  3193 		view.set( views );
       
  3194 	},
       
  3195 
       
  3196 	hijackThickbox: function() {
       
  3197 		var frame = this;
       
  3198 
       
  3199 		if ( ! window.tb_remove || this._tb_remove ) {
       
  3200 			return;
       
  3201 		}
       
  3202 
       
  3203 		this._tb_remove = window.tb_remove;
       
  3204 		window.tb_remove = function() {
       
  3205 			frame.close();
       
  3206 			frame.reset();
       
  3207 			frame.setState( frame.options.state );
       
  3208 			frame._tb_remove.call( window );
       
  3209 		};
       
  3210 	},
       
  3211 
       
  3212 	restoreThickbox: function() {
       
  3213 		if ( ! this._tb_remove ) {
       
  3214 			return;
       
  3215 		}
       
  3216 
       
  3217 		window.tb_remove = this._tb_remove;
       
  3218 		delete this._tb_remove;
       
  3219 	}
       
  3220 });
       
  3221 
       
  3222 // Map some of the modal's methods to the frame.
       
  3223 _.each(['open','close','attach','detach','escape'], function( method ) {
       
  3224 	/**
       
  3225 	 * @function open
       
  3226 	 * @memberOf wp.media.view.MediaFrame
       
  3227 	 * @instance
       
  3228 	 *
       
  3229 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3230 	 */
       
  3231 	/**
       
  3232 	 * @function close
       
  3233 	 * @memberOf wp.media.view.MediaFrame
       
  3234 	 * @instance
       
  3235 	 *
       
  3236 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3237 	 */
       
  3238 	/**
       
  3239 	 * @function attach
       
  3240 	 * @memberOf wp.media.view.MediaFrame
       
  3241 	 * @instance
       
  3242 	 *
       
  3243 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3244 	 */
       
  3245 	/**
       
  3246 	 * @function detach
       
  3247 	 * @memberOf wp.media.view.MediaFrame
       
  3248 	 * @instance
       
  3249 	 *
       
  3250 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3251 	 */
       
  3252 	/**
       
  3253 	 * @function escape
       
  3254 	 * @memberOf wp.media.view.MediaFrame
       
  3255 	 * @instance
       
  3256 	 *
       
  3257 	 * @return {wp.media.view.MediaFrame} Returns itself to allow chaining.
       
  3258 	 */
       
  3259 	MediaFrame.prototype[ method ] = function() {
       
  3260 		if ( this.modal ) {
       
  3261 			this.modal[ method ].apply( this.modal, arguments );
       
  3262 		}
       
  3263 		return this;
       
  3264 	};
       
  3265 });
       
  3266 
       
  3267 module.exports = MediaFrame;
       
  3268 
       
  3269 
       
  3270 /***/ }),
       
  3271 /* 52 */
       
  3272 /***/ (function(module, exports) {
       
  3273 
       
  3274 var MediaFrame = wp.media.view.MediaFrame,
       
  3275 	l10n = wp.media.view.l10n,
       
  3276 	Select;
       
  3277 
       
  3278 /**
       
  3279  * wp.media.view.MediaFrame.Select
       
  3280  *
       
  3281  * A frame for selecting an item or items from the media library.
       
  3282  *
       
  3283  * @memberOf wp.media.view.MediaFrame
       
  3284  *
       
  3285  * @class
       
  3286  * @augments wp.media.view.MediaFrame
       
  3287  * @augments wp.media.view.Frame
       
  3288  * @augments wp.media.View
       
  3289  * @augments wp.Backbone.View
       
  3290  * @augments Backbone.View
       
  3291  * @mixes wp.media.controller.StateMachine
       
  3292  */
       
  3293 Select = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Select.prototype */{
       
  3294 	initialize: function() {
       
  3295 		// Call 'initialize' directly on the parent class.
       
  3296 		MediaFrame.prototype.initialize.apply( this, arguments );
       
  3297 
       
  3298 		_.defaults( this.options, {
       
  3299 			selection: [],
       
  3300 			library:   {},
       
  3301 			multiple:  false,
       
  3302 			state:    'library'
       
  3303 		});
       
  3304 
       
  3305 		this.createSelection();
       
  3306 		this.createStates();
       
  3307 		this.bindHandlers();
       
  3308 	},
       
  3309 
       
  3310 	/**
       
  3311 	 * Attach a selection collection to the frame.
       
  3312 	 *
       
  3313 	 * A selection is a collection of attachments used for a specific purpose
       
  3314 	 * by a media frame. e.g. Selecting an attachment (or many) to insert into
       
  3315 	 * post content.
       
  3316 	 *
       
  3317 	 * @see media.model.Selection
       
  3318 	 */
       
  3319 	createSelection: function() {
       
  3320 		var selection = this.options.selection;
       
  3321 
       
  3322 		if ( ! (selection instanceof wp.media.model.Selection) ) {
       
  3323 			this.options.selection = new wp.media.model.Selection( selection, {
       
  3324 				multiple: this.options.multiple
       
  3325 			});
       
  3326 		}
       
  3327 
       
  3328 		this._selection = {
       
  3329 			attachments: new wp.media.model.Attachments(),
       
  3330 			difference: []
       
  3331 		};
       
  3332 	},
       
  3333 
       
  3334 	editImageContent: function() {
       
  3335 		var image = this.state().get('image'),
       
  3336 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
       
  3337 
       
  3338 		this.content.set( view );
       
  3339 
       
  3340 		// After creating the wrapper view, load the actual editor via an Ajax call.
       
  3341 		view.loadEditor();
       
  3342 	},
       
  3343 
       
  3344 	/**
       
  3345 	 * Create the default states on the frame.
       
  3346 	 */
       
  3347 	createStates: function() {
       
  3348 		var options = this.options;
       
  3349 
       
  3350 		if ( this.options.states ) {
       
  3351 			return;
       
  3352 		}
       
  3353 
       
  3354 		// Add the default states.
       
  3355 		this.states.add([
       
  3356 			// Main states.
       
  3357 			new wp.media.controller.Library({
       
  3358 				library:   wp.media.query( options.library ),
       
  3359 				multiple:  options.multiple,
       
  3360 				title:     options.title,
       
  3361 				priority:  20
       
  3362 			}),
       
  3363 			new wp.media.controller.EditImage( { model: options.editImage } )
       
  3364 		]);
       
  3365 	},
       
  3366 
       
  3367 	/**
       
  3368 	 * Bind region mode event callbacks.
       
  3369 	 *
       
  3370 	 * @see media.controller.Region.render
       
  3371 	 */
       
  3372 	bindHandlers: function() {
       
  3373 		this.on( 'router:create:browse', this.createRouter, this );
       
  3374 		this.on( 'router:render:browse', this.browseRouter, this );
       
  3375 		this.on( 'content:create:browse', this.browseContent, this );
       
  3376 		this.on( 'content:render:upload', this.uploadContent, this );
       
  3377 		this.on( 'toolbar:create:select', this.createSelectToolbar, this );
       
  3378 		this.on( 'content:render:edit-image', this.editImageContent, this );
       
  3379 	},
       
  3380 
       
  3381 	/**
       
  3382 	 * Render callback for the router region in the `browse` mode.
       
  3383 	 *
       
  3384 	 * @param {wp.media.view.Router} routerView
       
  3385 	 */
       
  3386 	browseRouter: function( routerView ) {
       
  3387 		routerView.set({
       
  3388 			upload: {
       
  3389 				text:     l10n.uploadFilesTitle,
       
  3390 				priority: 20
       
  3391 			},
       
  3392 			browse: {
       
  3393 				text:     l10n.mediaLibraryTitle,
       
  3394 				priority: 40
       
  3395 			}
       
  3396 		});
       
  3397 	},
       
  3398 
       
  3399 	/**
       
  3400 	 * Render callback for the content region in the `browse` mode.
       
  3401 	 *
       
  3402 	 * @param {wp.media.controller.Region} contentRegion
       
  3403 	 */
       
  3404 	browseContent: function( contentRegion ) {
       
  3405 		var state = this.state();
       
  3406 
       
  3407 		this.$el.removeClass('hide-toolbar');
       
  3408 
       
  3409 		// Browse our library of attachments.
       
  3410 		contentRegion.view = new wp.media.view.AttachmentsBrowser({
       
  3411 			controller: this,
       
  3412 			collection: state.get('library'),
       
  3413 			selection:  state.get('selection'),
       
  3414 			model:      state,
       
  3415 			sortable:   state.get('sortable'),
       
  3416 			search:     state.get('searchable'),
       
  3417 			filters:    state.get('filterable'),
       
  3418 			date:       state.get('date'),
       
  3419 			display:    state.has('display') ? state.get('display') : state.get('displaySettings'),
       
  3420 			dragInfo:   state.get('dragInfo'),
       
  3421 
       
  3422 			idealColumnWidth: state.get('idealColumnWidth'),
       
  3423 			suggestedWidth:   state.get('suggestedWidth'),
       
  3424 			suggestedHeight:  state.get('suggestedHeight'),
       
  3425 
       
  3426 			AttachmentView: state.get('AttachmentView')
       
  3427 		});
       
  3428 	},
       
  3429 
       
  3430 	/**
       
  3431 	 * Render callback for the content region in the `upload` mode.
       
  3432 	 */
       
  3433 	uploadContent: function() {
       
  3434 		this.$el.removeClass( 'hide-toolbar' );
       
  3435 		this.content.set( new wp.media.view.UploaderInline({
       
  3436 			controller: this
       
  3437 		}) );
       
  3438 	},
       
  3439 
       
  3440 	/**
       
  3441 	 * Toolbars
       
  3442 	 *
       
  3443 	 * @param {Object} toolbar
       
  3444 	 * @param {Object} [options={}]
       
  3445 	 * @this wp.media.controller.Region
       
  3446 	 */
       
  3447 	createSelectToolbar: function( toolbar, options ) {
       
  3448 		options = options || this.options.button || {};
       
  3449 		options.controller = this;
       
  3450 
       
  3451 		toolbar.view = new wp.media.view.Toolbar.Select( options );
       
  3452 	}
       
  3453 });
       
  3454 
       
  3455 module.exports = Select;
       
  3456 
       
  3457 
       
  3458 /***/ }),
       
  3459 /* 53 */
       
  3460 /***/ (function(module, exports) {
       
  3461 
       
  3462 var Select = wp.media.view.MediaFrame.Select,
       
  3463 	Library = wp.media.controller.Library,
       
  3464 	l10n = wp.media.view.l10n,
       
  3465 	Post;
       
  3466 
       
  3467 /**
       
  3468  * wp.media.view.MediaFrame.Post
       
  3469  *
       
  3470  * The frame for manipulating media on the Edit Post page.
       
  3471  *
       
  3472  * @memberOf wp.media.view.MediaFrame
       
  3473  *
       
  3474  * @class
       
  3475  * @augments wp.media.view.MediaFrame.Select
       
  3476  * @augments wp.media.view.MediaFrame
       
  3477  * @augments wp.media.view.Frame
       
  3478  * @augments wp.media.View
       
  3479  * @augments wp.Backbone.View
       
  3480  * @augments Backbone.View
       
  3481  * @mixes wp.media.controller.StateMachine
       
  3482  */
       
  3483 Post = Select.extend(/** @lends wp.media.view.MediaFrame.Post.prototype */{
       
  3484 	initialize: function() {
       
  3485 		this.counts = {
       
  3486 			audio: {
       
  3487 				count: wp.media.view.settings.attachmentCounts.audio,
       
  3488 				state: 'playlist'
       
  3489 			},
       
  3490 			video: {
       
  3491 				count: wp.media.view.settings.attachmentCounts.video,
       
  3492 				state: 'video-playlist'
       
  3493 			}
       
  3494 		};
       
  3495 
       
  3496 		_.defaults( this.options, {
       
  3497 			multiple:  true,
       
  3498 			editing:   false,
       
  3499 			state:    'insert',
       
  3500 			metadata:  {}
       
  3501 		});
       
  3502 
       
  3503 		// Call 'initialize' directly on the parent class.
       
  3504 		Select.prototype.initialize.apply( this, arguments );
       
  3505 		this.createIframeStates();
       
  3506 
       
  3507 	},
       
  3508 
       
  3509 	/**
       
  3510 	 * Create the default states.
       
  3511 	 */
       
  3512 	createStates: function() {
       
  3513 		var options = this.options;
       
  3514 
       
  3515 		this.states.add([
       
  3516 			// Main states.
       
  3517 			new Library({
       
  3518 				id:         'insert',
       
  3519 				title:      l10n.insertMediaTitle,
       
  3520 				priority:   20,
       
  3521 				toolbar:    'main-insert',
       
  3522 				filterable: 'all',
       
  3523 				library:    wp.media.query( options.library ),
       
  3524 				multiple:   options.multiple ? 'reset' : false,
       
  3525 				editable:   true,
       
  3526 
       
  3527 				// If the user isn't allowed to edit fields,
       
  3528 				// can they still edit it locally?
       
  3529 				allowLocalEdits: true,
       
  3530 
       
  3531 				// Show the attachment display settings.
       
  3532 				displaySettings: true,
       
  3533 				// Update user settings when users adjust the
       
  3534 				// attachment display settings.
       
  3535 				displayUserSettings: true
       
  3536 			}),
       
  3537 
       
  3538 			new Library({
       
  3539 				id:         'gallery',
       
  3540 				title:      l10n.createGalleryTitle,
       
  3541 				priority:   40,
       
  3542 				toolbar:    'main-gallery',
       
  3543 				filterable: 'uploaded',
       
  3544 				multiple:   'add',
       
  3545 				editable:   false,
       
  3546 
       
  3547 				library:  wp.media.query( _.defaults({
       
  3548 					type: 'image'
       
  3549 				}, options.library ) )
       
  3550 			}),
       
  3551 
       
  3552 			// Embed states.
       
  3553 			new wp.media.controller.Embed( { metadata: options.metadata } ),
       
  3554 
       
  3555 			new wp.media.controller.EditImage( { model: options.editImage } ),
       
  3556 
       
  3557 			// Gallery states.
       
  3558 			new wp.media.controller.GalleryEdit({
       
  3559 				library: options.selection,
       
  3560 				editing: options.editing,
       
  3561 				menu:    'gallery'
       
  3562 			}),
       
  3563 
       
  3564 			new wp.media.controller.GalleryAdd(),
       
  3565 
       
  3566 			new Library({
       
  3567 				id:         'playlist',
       
  3568 				title:      l10n.createPlaylistTitle,
       
  3569 				priority:   60,
       
  3570 				toolbar:    'main-playlist',
       
  3571 				filterable: 'uploaded',
       
  3572 				multiple:   'add',
       
  3573 				editable:   false,
       
  3574 
       
  3575 				library:  wp.media.query( _.defaults({
       
  3576 					type: 'audio'
       
  3577 				}, options.library ) )
       
  3578 			}),
       
  3579 
       
  3580 			// Playlist states.
       
  3581 			new wp.media.controller.CollectionEdit({
       
  3582 				type: 'audio',
       
  3583 				collectionType: 'playlist',
       
  3584 				title:          l10n.editPlaylistTitle,
       
  3585 				SettingsView:   wp.media.view.Settings.Playlist,
       
  3586 				library:        options.selection,
       
  3587 				editing:        options.editing,
       
  3588 				menu:           'playlist',
       
  3589 				dragInfoText:   l10n.playlistDragInfo,
       
  3590 				dragInfo:       false
       
  3591 			}),
       
  3592 
       
  3593 			new wp.media.controller.CollectionAdd({
       
  3594 				type: 'audio',
       
  3595 				collectionType: 'playlist',
       
  3596 				title: l10n.addToPlaylistTitle
       
  3597 			}),
       
  3598 
       
  3599 			new Library({
       
  3600 				id:         'video-playlist',
       
  3601 				title:      l10n.createVideoPlaylistTitle,
       
  3602 				priority:   60,
       
  3603 				toolbar:    'main-video-playlist',
       
  3604 				filterable: 'uploaded',
       
  3605 				multiple:   'add',
       
  3606 				editable:   false,
       
  3607 
       
  3608 				library:  wp.media.query( _.defaults({
       
  3609 					type: 'video'
       
  3610 				}, options.library ) )
       
  3611 			}),
       
  3612 
       
  3613 			new wp.media.controller.CollectionEdit({
       
  3614 				type: 'video',
       
  3615 				collectionType: 'playlist',
       
  3616 				title:          l10n.editVideoPlaylistTitle,
       
  3617 				SettingsView:   wp.media.view.Settings.Playlist,
       
  3618 				library:        options.selection,
       
  3619 				editing:        options.editing,
       
  3620 				menu:           'video-playlist',
       
  3621 				dragInfoText:   l10n.videoPlaylistDragInfo,
       
  3622 				dragInfo:       false
       
  3623 			}),
       
  3624 
       
  3625 			new wp.media.controller.CollectionAdd({
       
  3626 				type: 'video',
       
  3627 				collectionType: 'playlist',
       
  3628 				title: l10n.addToVideoPlaylistTitle
       
  3629 			})
       
  3630 		]);
       
  3631 
       
  3632 		if ( wp.media.view.settings.post.featuredImageId ) {
       
  3633 			this.states.add( new wp.media.controller.FeaturedImage() );
       
  3634 		}
       
  3635 	},
       
  3636 
       
  3637 	bindHandlers: function() {
       
  3638 		var handlers, checkCounts;
       
  3639 
       
  3640 		Select.prototype.bindHandlers.apply( this, arguments );
       
  3641 
       
  3642 		this.on( 'activate', this.activate, this );
       
  3643 
       
  3644 		// Only bother checking media type counts if one of the counts is zero.
       
  3645 		checkCounts = _.find( this.counts, function( type ) {
       
  3646 			return type.count === 0;
       
  3647 		} );
       
  3648 
       
  3649 		if ( typeof checkCounts !== 'undefined' ) {
       
  3650 			this.listenTo( wp.media.model.Attachments.all, 'change:type', this.mediaTypeCounts );
       
  3651 		}
       
  3652 
       
  3653 		this.on( 'menu:create:gallery', this.createMenu, this );
       
  3654 		this.on( 'menu:create:playlist', this.createMenu, this );
       
  3655 		this.on( 'menu:create:video-playlist', this.createMenu, this );
       
  3656 		this.on( 'toolbar:create:main-insert', this.createToolbar, this );
       
  3657 		this.on( 'toolbar:create:main-gallery', this.createToolbar, this );
       
  3658 		this.on( 'toolbar:create:main-playlist', this.createToolbar, this );
       
  3659 		this.on( 'toolbar:create:main-video-playlist', this.createToolbar, this );
       
  3660 		this.on( 'toolbar:create:featured-image', this.featuredImageToolbar, this );
       
  3661 		this.on( 'toolbar:create:main-embed', this.mainEmbedToolbar, this );
       
  3662 
       
  3663 		handlers = {
       
  3664 			menu: {
       
  3665 				'default': 'mainMenu',
       
  3666 				'gallery': 'galleryMenu',
       
  3667 				'playlist': 'playlistMenu',
       
  3668 				'video-playlist': 'videoPlaylistMenu'
       
  3669 			},
       
  3670 
       
  3671 			content: {
       
  3672 				'embed':          'embedContent',
       
  3673 				'edit-image':     'editImageContent',
       
  3674 				'edit-selection': 'editSelectionContent'
       
  3675 			},
       
  3676 
       
  3677 			toolbar: {
       
  3678 				'main-insert':      'mainInsertToolbar',
       
  3679 				'main-gallery':     'mainGalleryToolbar',
       
  3680 				'gallery-edit':     'galleryEditToolbar',
       
  3681 				'gallery-add':      'galleryAddToolbar',
       
  3682 				'main-playlist':	'mainPlaylistToolbar',
       
  3683 				'playlist-edit':	'playlistEditToolbar',
       
  3684 				'playlist-add':		'playlistAddToolbar',
       
  3685 				'main-video-playlist': 'mainVideoPlaylistToolbar',
       
  3686 				'video-playlist-edit': 'videoPlaylistEditToolbar',
       
  3687 				'video-playlist-add': 'videoPlaylistAddToolbar'
       
  3688 			}
       
  3689 		};
       
  3690 
       
  3691 		_.each( handlers, function( regionHandlers, region ) {
       
  3692 			_.each( regionHandlers, function( callback, handler ) {
       
  3693 				this.on( region + ':render:' + handler, this[ callback ], this );
       
  3694 			}, this );
       
  3695 		}, this );
       
  3696 	},
       
  3697 
       
  3698 	activate: function() {
       
  3699 		// Hide menu items for states tied to particular media types if there are no items.
       
  3700 		_.each( this.counts, function( type ) {
       
  3701 			if ( type.count < 1 ) {
       
  3702 				this.menuItemVisibility( type.state, 'hide' );
       
  3703 			}
       
  3704 		}, this );
       
  3705 	},
       
  3706 
       
  3707 	mediaTypeCounts: function( model, attr ) {
       
  3708 		if ( typeof this.counts[ attr ] !== 'undefined' && this.counts[ attr ].count < 1 ) {
       
  3709 			this.counts[ attr ].count++;
       
  3710 			this.menuItemVisibility( this.counts[ attr ].state, 'show' );
       
  3711 		}
       
  3712 	},
       
  3713 
       
  3714 	// Menus.
       
  3715 	/**
       
  3716 	 * @param {wp.Backbone.View} view
       
  3717 	 */
       
  3718 	mainMenu: function( view ) {
       
  3719 		view.set({
       
  3720 			'library-separator': new wp.media.View({
       
  3721 				className:  'separator',
       
  3722 				priority:   100,
       
  3723 				attributes: {
       
  3724 					role: 'presentation'
       
  3725 				}
       
  3726 			})
       
  3727 		});
       
  3728 	},
       
  3729 
       
  3730 	menuItemVisibility: function( state, visibility ) {
       
  3731 		var menu = this.menu.get();
       
  3732 		if ( visibility === 'hide' ) {
       
  3733 			menu.hide( state );
       
  3734 		} else if ( visibility === 'show' ) {
       
  3735 			menu.show( state );
       
  3736 		}
       
  3737 	},
       
  3738 	/**
       
  3739 	 * @param {wp.Backbone.View} view
       
  3740 	 */
       
  3741 	galleryMenu: function( view ) {
       
  3742 		var lastState = this.lastState(),
       
  3743 			previous = lastState && lastState.id,
       
  3744 			frame = this;
       
  3745 
       
  3746 		view.set({
       
  3747 			cancel: {
       
  3748 				text:     l10n.cancelGalleryTitle,
       
  3749 				priority: 20,
       
  3750 				click:    function() {
       
  3751 					if ( previous ) {
       
  3752 						frame.setState( previous );
       
  3753 					} else {
       
  3754 						frame.close();
       
  3755 					}
       
  3756 
       
  3757 					// Move focus to the modal after canceling a Gallery.
       
  3758 					this.controller.modal.focusManager.focus();
       
  3759 				}
       
  3760 			},
       
  3761 			separateCancel: new wp.media.View({
       
  3762 				className: 'separator',
       
  3763 				priority: 40
       
  3764 			})
       
  3765 		});
       
  3766 	},
       
  3767 
       
  3768 	playlistMenu: function( view ) {
       
  3769 		var lastState = this.lastState(),
       
  3770 			previous = lastState && lastState.id,
       
  3771 			frame = this;
       
  3772 
       
  3773 		view.set({
       
  3774 			cancel: {
       
  3775 				text:     l10n.cancelPlaylistTitle,
       
  3776 				priority: 20,
       
  3777 				click:    function() {
       
  3778 					if ( previous ) {
       
  3779 						frame.setState( previous );
       
  3780 					} else {
       
  3781 						frame.close();
       
  3782 					}
       
  3783 
       
  3784 					// Move focus to the modal after canceling an Audio Playlist.
       
  3785 					this.controller.modal.focusManager.focus();
       
  3786 				}
       
  3787 			},
       
  3788 			separateCancel: new wp.media.View({
       
  3789 				className: 'separator',
       
  3790 				priority: 40
       
  3791 			})
       
  3792 		});
       
  3793 	},
       
  3794 
       
  3795 	videoPlaylistMenu: function( view ) {
       
  3796 		var lastState = this.lastState(),
       
  3797 			previous = lastState && lastState.id,
       
  3798 			frame = this;
       
  3799 
       
  3800 		view.set({
       
  3801 			cancel: {
       
  3802 				text:     l10n.cancelVideoPlaylistTitle,
       
  3803 				priority: 20,
       
  3804 				click:    function() {
       
  3805 					if ( previous ) {
       
  3806 						frame.setState( previous );
       
  3807 					} else {
       
  3808 						frame.close();
       
  3809 					}
       
  3810 
       
  3811 					// Move focus to the modal after canceling a Video Playlist.
       
  3812 					this.controller.modal.focusManager.focus();
       
  3813 				}
       
  3814 			},
       
  3815 			separateCancel: new wp.media.View({
       
  3816 				className: 'separator',
       
  3817 				priority: 40
       
  3818 			})
       
  3819 		});
       
  3820 	},
       
  3821 
       
  3822 	// Content.
       
  3823 	embedContent: function() {
       
  3824 		var view = new wp.media.view.Embed({
       
  3825 			controller: this,
       
  3826 			model:      this.state()
       
  3827 		}).render();
       
  3828 
       
  3829 		this.content.set( view );
       
  3830 	},
       
  3831 
       
  3832 	editSelectionContent: function() {
       
  3833 		var state = this.state(),
       
  3834 			selection = state.get('selection'),
       
  3835 			view;
       
  3836 
       
  3837 		view = new wp.media.view.AttachmentsBrowser({
       
  3838 			controller: this,
       
  3839 			collection: selection,
       
  3840 			selection:  selection,
       
  3841 			model:      state,
       
  3842 			sortable:   true,
       
  3843 			search:     false,
       
  3844 			date:       false,
       
  3845 			dragInfo:   true,
       
  3846 
       
  3847 			AttachmentView: wp.media.view.Attachments.EditSelection
       
  3848 		}).render();
       
  3849 
       
  3850 		view.toolbar.set( 'backToLibrary', {
       
  3851 			text:     l10n.returnToLibrary,
       
  3852 			priority: -100,
       
  3853 
       
  3854 			click: function() {
       
  3855 				this.controller.content.mode('browse');
       
  3856 				// Move focus to the modal when jumping back from Edit Selection to Add Media view.
       
  3857 				this.controller.modal.focusManager.focus();
       
  3858 			}
       
  3859 		});
       
  3860 
       
  3861 		// Browse our library of attachments.
       
  3862 		this.content.set( view );
       
  3863 
       
  3864 		// Trigger the controller to set focus.
       
  3865 		this.trigger( 'edit:selection', this );
       
  3866 	},
       
  3867 
       
  3868 	editImageContent: function() {
       
  3869 		var image = this.state().get('image'),
       
  3870 			view = new wp.media.view.EditImage( { model: image, controller: this } ).render();
       
  3871 
       
  3872 		this.content.set( view );
       
  3873 
       
  3874 		// After creating the wrapper view, load the actual editor via an Ajax call.
       
  3875 		view.loadEditor();
       
  3876 
       
  3877 	},
       
  3878 
       
  3879 	// Toolbars.
       
  3880 
       
  3881 	/**
       
  3882 	 * @param {wp.Backbone.View} view
       
  3883 	 */
       
  3884 	selectionStatusToolbar: function( view ) {
       
  3885 		var editable = this.state().get('editable');
       
  3886 
       
  3887 		view.set( 'selection', new wp.media.view.Selection({
       
  3888 			controller: this,
       
  3889 			collection: this.state().get('selection'),
       
  3890 			priority:   -40,
       
  3891 
       
  3892 			// If the selection is editable, pass the callback to
       
  3893 			// switch the content mode.
       
  3894 			editable: editable && function() {
       
  3895 				this.controller.content.mode('edit-selection');
       
  3896 			}
       
  3897 		}).render() );
       
  3898 	},
       
  3899 
       
  3900 	/**
       
  3901 	 * @param {wp.Backbone.View} view
       
  3902 	 */
       
  3903 	mainInsertToolbar: function( view ) {
       
  3904 		var controller = this;
       
  3905 
       
  3906 		this.selectionStatusToolbar( view );
       
  3907 
       
  3908 		view.set( 'insert', {
       
  3909 			style:    'primary',
       
  3910 			priority: 80,
       
  3911 			text:     l10n.insertIntoPost,
       
  3912 			requires: { selection: true },
       
  3913 
       
  3914 			/**
       
  3915 			 * @ignore
       
  3916 			 *
       
  3917 			 * @fires wp.media.controller.State#insert
       
  3918 			 */
       
  3919 			click: function() {
       
  3920 				var state = controller.state(),
       
  3921 					selection = state.get('selection');
       
  3922 
       
  3923 				controller.close();
       
  3924 				state.trigger( 'insert', selection ).reset();
       
  3925 			}
       
  3926 		});
       
  3927 	},
       
  3928 
       
  3929 	/**
       
  3930 	 * @param {wp.Backbone.View} view
       
  3931 	 */
       
  3932 	mainGalleryToolbar: function( view ) {
       
  3933 		var controller = this;
       
  3934 
       
  3935 		this.selectionStatusToolbar( view );
       
  3936 
       
  3937 		view.set( 'gallery', {
       
  3938 			style:    'primary',
       
  3939 			text:     l10n.createNewGallery,
       
  3940 			priority: 60,
       
  3941 			requires: { selection: true },
       
  3942 
       
  3943 			click: function() {
       
  3944 				var selection = controller.state().get('selection'),
       
  3945 					edit = controller.state('gallery-edit'),
       
  3946 					models = selection.where({ type: 'image' });
       
  3947 
       
  3948 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  3949 					props:    selection.props.toJSON(),
       
  3950 					multiple: true
       
  3951 				}) );
       
  3952 
       
  3953 				// Jump to Edit Gallery view.
       
  3954 				this.controller.setState( 'gallery-edit' );
       
  3955 
       
  3956 				// Move focus to the modal after jumping to Edit Gallery view.
       
  3957 				this.controller.modal.focusManager.focus();
       
  3958 			}
       
  3959 		});
       
  3960 	},
       
  3961 
       
  3962 	mainPlaylistToolbar: function( view ) {
       
  3963 		var controller = this;
       
  3964 
       
  3965 		this.selectionStatusToolbar( view );
       
  3966 
       
  3967 		view.set( 'playlist', {
       
  3968 			style:    'primary',
       
  3969 			text:     l10n.createNewPlaylist,
       
  3970 			priority: 100,
       
  3971 			requires: { selection: true },
       
  3972 
       
  3973 			click: function() {
       
  3974 				var selection = controller.state().get('selection'),
       
  3975 					edit = controller.state('playlist-edit'),
       
  3976 					models = selection.where({ type: 'audio' });
       
  3977 
       
  3978 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  3979 					props:    selection.props.toJSON(),
       
  3980 					multiple: true
       
  3981 				}) );
       
  3982 
       
  3983 				// Jump to Edit Audio Playlist view.
       
  3984 				this.controller.setState( 'playlist-edit' );
       
  3985 
       
  3986 				// Move focus to the modal after jumping to Edit Audio Playlist view.
       
  3987 				this.controller.modal.focusManager.focus();
       
  3988 			}
       
  3989 		});
       
  3990 	},
       
  3991 
       
  3992 	mainVideoPlaylistToolbar: function( view ) {
       
  3993 		var controller = this;
       
  3994 
       
  3995 		this.selectionStatusToolbar( view );
       
  3996 
       
  3997 		view.set( 'video-playlist', {
       
  3998 			style:    'primary',
       
  3999 			text:     l10n.createNewVideoPlaylist,
       
  4000 			priority: 100,
       
  4001 			requires: { selection: true },
       
  4002 
       
  4003 			click: function() {
       
  4004 				var selection = controller.state().get('selection'),
       
  4005 					edit = controller.state('video-playlist-edit'),
       
  4006 					models = selection.where({ type: 'video' });
       
  4007 
       
  4008 				edit.set( 'library', new wp.media.model.Selection( models, {
       
  4009 					props:    selection.props.toJSON(),
       
  4010 					multiple: true
       
  4011 				}) );
       
  4012 
       
  4013 				// Jump to Edit Video Playlist view.
       
  4014 				this.controller.setState( 'video-playlist-edit' );
       
  4015 
       
  4016 				// Move focus to the modal after jumping to Edit Video Playlist view.
       
  4017 				this.controller.modal.focusManager.focus();
       
  4018 			}
       
  4019 		});
       
  4020 	},
       
  4021 
       
  4022 	featuredImageToolbar: function( toolbar ) {
       
  4023 		this.createSelectToolbar( toolbar, {
       
  4024 			text:  l10n.setFeaturedImage,
       
  4025 			state: this.options.state
       
  4026 		});
       
  4027 	},
       
  4028 
       
  4029 	mainEmbedToolbar: function( toolbar ) {
       
  4030 		toolbar.view = new wp.media.view.Toolbar.Embed({
       
  4031 			controller: this
       
  4032 		});
       
  4033 	},
       
  4034 
       
  4035 	galleryEditToolbar: function() {
       
  4036 		var editing = this.state().get('editing');
       
  4037 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4038 			controller: this,
       
  4039 			items: {
       
  4040 				insert: {
       
  4041 					style:    'primary',
       
  4042 					text:     editing ? l10n.updateGallery : l10n.insertGallery,
       
  4043 					priority: 80,
       
  4044 					requires: { library: true },
       
  4045 
       
  4046 					/**
       
  4047 					 * @fires wp.media.controller.State#update
       
  4048 					 */
       
  4049 					click: function() {
       
  4050 						var controller = this.controller,
       
  4051 							state = controller.state();
       
  4052 
       
  4053 						controller.close();
       
  4054 						state.trigger( 'update', state.get('library') );
       
  4055 
       
  4056 						// Restore and reset the default state.
       
  4057 						controller.setState( controller.options.state );
       
  4058 						controller.reset();
       
  4059 					}
       
  4060 				}
       
  4061 			}
       
  4062 		}) );
       
  4063 	},
       
  4064 
       
  4065 	galleryAddToolbar: function() {
       
  4066 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4067 			controller: this,
       
  4068 			items: {
       
  4069 				insert: {
       
  4070 					style:    'primary',
       
  4071 					text:     l10n.addToGallery,
       
  4072 					priority: 80,
       
  4073 					requires: { selection: true },
       
  4074 
       
  4075 					/**
       
  4076 					 * @fires wp.media.controller.State#reset
       
  4077 					 */
       
  4078 					click: function() {
       
  4079 						var controller = this.controller,
       
  4080 							state = controller.state(),
       
  4081 							edit = controller.state('gallery-edit');
       
  4082 
       
  4083 						edit.get('library').add( state.get('selection').models );
       
  4084 						state.trigger('reset');
       
  4085 						controller.setState('gallery-edit');
       
  4086 						// Move focus to the modal when jumping back from Add to Gallery to Edit Gallery view.
       
  4087 						this.controller.modal.focusManager.focus();
       
  4088 					}
       
  4089 				}
       
  4090 			}
       
  4091 		}) );
       
  4092 	},
       
  4093 
       
  4094 	playlistEditToolbar: function() {
       
  4095 		var editing = this.state().get('editing');
       
  4096 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4097 			controller: this,
       
  4098 			items: {
       
  4099 				insert: {
       
  4100 					style:    'primary',
       
  4101 					text:     editing ? l10n.updatePlaylist : l10n.insertPlaylist,
       
  4102 					priority: 80,
       
  4103 					requires: { library: true },
       
  4104 
       
  4105 					/**
       
  4106 					 * @fires wp.media.controller.State#update
       
  4107 					 */
       
  4108 					click: function() {
       
  4109 						var controller = this.controller,
       
  4110 							state = controller.state();
       
  4111 
       
  4112 						controller.close();
       
  4113 						state.trigger( 'update', state.get('library') );
       
  4114 
       
  4115 						// Restore and reset the default state.
       
  4116 						controller.setState( controller.options.state );
       
  4117 						controller.reset();
       
  4118 					}
       
  4119 				}
       
  4120 			}
       
  4121 		}) );
       
  4122 	},
       
  4123 
       
  4124 	playlistAddToolbar: function() {
       
  4125 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4126 			controller: this,
       
  4127 			items: {
       
  4128 				insert: {
       
  4129 					style:    'primary',
       
  4130 					text:     l10n.addToPlaylist,
       
  4131 					priority: 80,
       
  4132 					requires: { selection: true },
       
  4133 
       
  4134 					/**
       
  4135 					 * @fires wp.media.controller.State#reset
       
  4136 					 */
       
  4137 					click: function() {
       
  4138 						var controller = this.controller,
       
  4139 							state = controller.state(),
       
  4140 							edit = controller.state('playlist-edit');
       
  4141 
       
  4142 						edit.get('library').add( state.get('selection').models );
       
  4143 						state.trigger('reset');
       
  4144 						controller.setState('playlist-edit');
       
  4145 						// Move focus to the modal when jumping back from Add to Audio Playlist to Edit Audio Playlist view.
       
  4146 						this.controller.modal.focusManager.focus();
       
  4147 					}
       
  4148 				}
       
  4149 			}
       
  4150 		}) );
       
  4151 	},
       
  4152 
       
  4153 	videoPlaylistEditToolbar: function() {
       
  4154 		var editing = this.state().get('editing');
       
  4155 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4156 			controller: this,
       
  4157 			items: {
       
  4158 				insert: {
       
  4159 					style:    'primary',
       
  4160 					text:     editing ? l10n.updateVideoPlaylist : l10n.insertVideoPlaylist,
       
  4161 					priority: 140,
       
  4162 					requires: { library: true },
       
  4163 
       
  4164 					click: function() {
       
  4165 						var controller = this.controller,
       
  4166 							state = controller.state(),
       
  4167 							library = state.get('library');
       
  4168 
       
  4169 						library.type = 'video';
       
  4170 
       
  4171 						controller.close();
       
  4172 						state.trigger( 'update', library );
       
  4173 
       
  4174 						// Restore and reset the default state.
       
  4175 						controller.setState( controller.options.state );
       
  4176 						controller.reset();
       
  4177 					}
       
  4178 				}
       
  4179 			}
       
  4180 		}) );
       
  4181 	},
       
  4182 
       
  4183 	videoPlaylistAddToolbar: function() {
       
  4184 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4185 			controller: this,
       
  4186 			items: {
       
  4187 				insert: {
       
  4188 					style:    'primary',
       
  4189 					text:     l10n.addToVideoPlaylist,
       
  4190 					priority: 140,
       
  4191 					requires: { selection: true },
       
  4192 
       
  4193 					click: function() {
       
  4194 						var controller = this.controller,
       
  4195 							state = controller.state(),
       
  4196 							edit = controller.state('video-playlist-edit');
       
  4197 
       
  4198 						edit.get('library').add( state.get('selection').models );
       
  4199 						state.trigger('reset');
       
  4200 						controller.setState('video-playlist-edit');
       
  4201 						// Move focus to the modal when jumping back from Add to Video Playlist to Edit Video Playlist view.
       
  4202 						this.controller.modal.focusManager.focus();
       
  4203 					}
       
  4204 				}
       
  4205 			}
       
  4206 		}) );
       
  4207 	}
       
  4208 });
       
  4209 
       
  4210 module.exports = Post;
       
  4211 
       
  4212 
       
  4213 /***/ }),
       
  4214 /* 54 */
       
  4215 /***/ (function(module, exports) {
       
  4216 
       
  4217 var Select = wp.media.view.MediaFrame.Select,
       
  4218 	l10n = wp.media.view.l10n,
       
  4219 	ImageDetails;
       
  4220 
       
  4221 /**
       
  4222  * wp.media.view.MediaFrame.ImageDetails
       
  4223  *
       
  4224  * A media frame for manipulating an image that's already been inserted
       
  4225  * into a post.
       
  4226  *
       
  4227  * @memberOf wp.media.view.MediaFrame
       
  4228  *
       
  4229  * @class
       
  4230  * @augments wp.media.view.MediaFrame.Select
       
  4231  * @augments wp.media.view.MediaFrame
       
  4232  * @augments wp.media.view.Frame
       
  4233  * @augments wp.media.View
       
  4234  * @augments wp.Backbone.View
       
  4235  * @augments Backbone.View
       
  4236  * @mixes wp.media.controller.StateMachine
       
  4237  */
       
  4238 ImageDetails = Select.extend(/** @lends wp.media.view.MediaFrame.ImageDetails.prototype */{
       
  4239 	defaults: {
       
  4240 		id:      'image',
       
  4241 		url:     '',
       
  4242 		menu:    'image-details',
       
  4243 		content: 'image-details',
       
  4244 		toolbar: 'image-details',
       
  4245 		type:    'link',
       
  4246 		title:    l10n.imageDetailsTitle,
       
  4247 		priority: 120
       
  4248 	},
       
  4249 
       
  4250 	initialize: function( options ) {
       
  4251 		this.image = new wp.media.model.PostImage( options.metadata );
       
  4252 		this.options.selection = new wp.media.model.Selection( this.image.attachment, { multiple: false } );
       
  4253 		Select.prototype.initialize.apply( this, arguments );
       
  4254 	},
       
  4255 
       
  4256 	bindHandlers: function() {
       
  4257 		Select.prototype.bindHandlers.apply( this, arguments );
       
  4258 		this.on( 'menu:create:image-details', this.createMenu, this );
       
  4259 		this.on( 'content:create:image-details', this.imageDetailsContent, this );
       
  4260 		this.on( 'content:render:edit-image', this.editImageContent, this );
       
  4261 		this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
       
  4262 		// Override the select toolbar.
       
  4263 		this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
       
  4264 	},
       
  4265 
       
  4266 	createStates: function() {
       
  4267 		this.states.add([
       
  4268 			new wp.media.controller.ImageDetails({
       
  4269 				image: this.image,
       
  4270 				editable: false
       
  4271 			}),
       
  4272 			new wp.media.controller.ReplaceImage({
       
  4273 				id: 'replace-image',
       
  4274 				library: wp.media.query( { type: 'image' } ),
       
  4275 				image: this.image,
       
  4276 				multiple:  false,
       
  4277 				title:     l10n.imageReplaceTitle,
       
  4278 				toolbar: 'replace',
       
  4279 				priority:  80,
       
  4280 				displaySettings: true
       
  4281 			}),
       
  4282 			new wp.media.controller.EditImage( {
       
  4283 				image: this.image,
       
  4284 				selection: this.options.selection
       
  4285 			} )
       
  4286 		]);
       
  4287 	},
       
  4288 
       
  4289 	imageDetailsContent: function( options ) {
       
  4290 		options.view = new wp.media.view.ImageDetails({
       
  4291 			controller: this,
       
  4292 			model: this.state().image,
       
  4293 			attachment: this.state().image.attachment
       
  4294 		});
       
  4295 	},
       
  4296 
       
  4297 	editImageContent: function() {
       
  4298 		var state = this.state(),
       
  4299 			model = state.get('image'),
       
  4300 			view;
       
  4301 
       
  4302 		if ( ! model ) {
       
  4303 			return;
       
  4304 		}
       
  4305 
       
  4306 		view = new wp.media.view.EditImage( { model: model, controller: this } ).render();
       
  4307 
       
  4308 		this.content.set( view );
       
  4309 
       
  4310 		// After bringing in the frame, load the actual editor via an Ajax call.
       
  4311 		view.loadEditor();
       
  4312 
       
  4313 	},
       
  4314 
       
  4315 	renderImageDetailsToolbar: function() {
       
  4316 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4317 			controller: this,
       
  4318 			items: {
       
  4319 				select: {
       
  4320 					style:    'primary',
       
  4321 					text:     l10n.update,
       
  4322 					priority: 80,
       
  4323 
       
  4324 					click: function() {
       
  4325 						var controller = this.controller,
       
  4326 							state = controller.state();
       
  4327 
       
  4328 						controller.close();
       
  4329 
       
  4330 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
       
  4331 						// perhaps wp.html.string to at least to build the <img />.
       
  4332 						state.trigger( 'update', controller.image.toJSON() );
       
  4333 
       
  4334 						// Restore and reset the default state.
       
  4335 						controller.setState( controller.options.state );
       
  4336 						controller.reset();
       
  4337 					}
       
  4338 				}
       
  4339 			}
       
  4340 		}) );
       
  4341 	},
       
  4342 
       
  4343 	renderReplaceImageToolbar: function() {
       
  4344 		var frame = this,
       
  4345 			lastState = frame.lastState(),
       
  4346 			previous = lastState && lastState.id;
       
  4347 
       
  4348 		this.toolbar.set( new wp.media.view.Toolbar({
       
  4349 			controller: this,
       
  4350 			items: {
       
  4351 				back: {
       
  4352 					text:     l10n.back,
       
  4353 					priority: 80,
       
  4354 					click:    function() {
       
  4355 						if ( previous ) {
       
  4356 							frame.setState( previous );
       
  4357 						} else {
       
  4358 							frame.close();
       
  4359 						}
       
  4360 					}
       
  4361 				},
       
  4362 
       
  4363 				replace: {
       
  4364 					style:    'primary',
       
  4365 					text:     l10n.replace,
       
  4366 					priority: 20,
       
  4367 					requires: { selection: true },
       
  4368 
       
  4369 					click: function() {
       
  4370 						var controller = this.controller,
       
  4371 							state = controller.state(),
       
  4372 							selection = state.get( 'selection' ),
       
  4373 							attachment = selection.single();
       
  4374 
       
  4375 						controller.close();
       
  4376 
       
  4377 						controller.image.changeAttachment( attachment, state.display( attachment ) );
       
  4378 
       
  4379 						// Not sure if we want to use wp.media.string.image which will create a shortcode or
       
  4380 						// perhaps wp.html.string to at least to build the <img />.
       
  4381 						state.trigger( 'replace', controller.image.toJSON() );
       
  4382 
       
  4383 						// Restore and reset the default state.
       
  4384 						controller.setState( controller.options.state );
       
  4385 						controller.reset();
       
  4386 					}
       
  4387 				}
       
  4388 			}
       
  4389 		}) );
       
  4390 	}
       
  4391 
       
  4392 });
       
  4393 
       
  4394 module.exports = ImageDetails;
       
  4395 
       
  4396 
       
  4397 /***/ }),
       
  4398 /* 55 */
       
  4399 /***/ (function(module, exports) {
       
  4400 
       
  4401 var $ = jQuery,
       
  4402 	Modal;
       
  4403 
       
  4404 /**
       
  4405  * wp.media.view.Modal
       
  4406  *
       
  4407  * A modal view, which the media modal uses as its default container.
       
  4408  *
       
  4409  * @memberOf wp.media.view
       
  4410  *
       
  4411  * @class
       
  4412  * @augments wp.media.View
       
  4413  * @augments wp.Backbone.View
       
  4414  * @augments Backbone.View
       
  4415  */
       
  4416 Modal = wp.media.View.extend(/** @lends wp.media.view.Modal.prototype */{
       
  4417 	tagName:  'div',
       
  4418 	template: wp.template('media-modal'),
       
  4419 
       
  4420 	events: {
       
  4421 		'click .media-modal-backdrop, .media-modal-close': 'escapeHandler',
       
  4422 		'keydown': 'keydown'
       
  4423 	},
       
  4424 
       
  4425 	clickedOpenerEl: null,
       
  4426 
       
  4427 	initialize: function() {
       
  4428 		_.defaults( this.options, {
       
  4429 			container:      document.body,
       
  4430 			title:          '',
       
  4431 			propagate:      true,
       
  4432 			hasCloseButton: true
       
  4433 		});
       
  4434 
       
  4435 		this.focusManager = new wp.media.view.FocusManager({
       
  4436 			el: this.el
       
  4437 		});
       
  4438 	},
       
  4439 	/**
       
  4440 	 * @return {Object}
       
  4441 	 */
       
  4442 	prepare: function() {
       
  4443 		return {
       
  4444 			title:          this.options.title,
       
  4445 			hasCloseButton: this.options.hasCloseButton
       
  4446 		};
       
  4447 	},
       
  4448 
       
  4449 	/**
       
  4450 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  4451 	 */
       
  4452 	attach: function() {
       
  4453 		if ( this.views.attached ) {
       
  4454 			return this;
       
  4455 		}
       
  4456 
       
  4457 		if ( ! this.views.rendered ) {
       
  4458 			this.render();
       
  4459 		}
       
  4460 
       
  4461 		this.$el.appendTo( this.options.container );
       
  4462 
       
  4463 		// Manually mark the view as attached and trigger ready.
       
  4464 		this.views.attached = true;
       
  4465 		this.views.ready();
       
  4466 
       
  4467 		return this.propagate('attach');
       
  4468 	},
       
  4469 
       
  4470 	/**
       
  4471 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  4472 	 */
       
  4473 	detach: function() {
       
  4474 		if ( this.$el.is(':visible') ) {
       
  4475 			this.close();
       
  4476 		}
       
  4477 
       
  4478 		this.$el.detach();
       
  4479 		this.views.attached = false;
       
  4480 		return this.propagate('detach');
       
  4481 	},
       
  4482 
       
  4483 	/**
       
  4484 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  4485 	 */
       
  4486 	open: function() {
       
  4487 		var $el = this.$el,
       
  4488 			mceEditor;
       
  4489 
       
  4490 		if ( $el.is(':visible') ) {
       
  4491 			return this;
       
  4492 		}
       
  4493 
       
  4494 		this.clickedOpenerEl = document.activeElement;
       
  4495 
       
  4496 		if ( ! this.views.attached ) {
       
  4497 			this.attach();
       
  4498 		}
       
  4499 
       
  4500 		// Disable page scrolling.
       
  4501 		$( 'body' ).addClass( 'modal-open' );
       
  4502 
       
  4503 		$el.show();
       
  4504 
       
  4505 		// Try to close the onscreen keyboard.
       
  4506 		if ( 'ontouchend' in document ) {
       
  4507 			if ( ( mceEditor = window.tinymce && window.tinymce.activeEditor ) && ! mceEditor.isHidden() && mceEditor.iframeElement ) {
       
  4508 				mceEditor.iframeElement.focus();
       
  4509 				mceEditor.iframeElement.blur();
       
  4510 
       
  4511 				setTimeout( function() {
       
  4512 					mceEditor.iframeElement.blur();
       
  4513 				}, 100 );
       
  4514 			}
       
  4515 		}
       
  4516 
       
  4517 		// Set initial focus on the content instead of this view element, to avoid page scrolling.
       
  4518 		this.$( '.media-modal' ).focus();
       
  4519 
       
  4520 		// Hide the page content from assistive technologies.
       
  4521 		this.focusManager.setAriaHiddenOnBodyChildren( $el );
       
  4522 
       
  4523 		return this.propagate('open');
       
  4524 	},
       
  4525 
       
  4526 	/**
       
  4527 	 * @param {Object} options
       
  4528 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  4529 	 */
       
  4530 	close: function( options ) {
       
  4531 		if ( ! this.views.attached || ! this.$el.is(':visible') ) {
       
  4532 			return this;
       
  4533 		}
       
  4534 
       
  4535 		// Enable page scrolling.
       
  4536 		$( 'body' ).removeClass( 'modal-open' );
       
  4537 
       
  4538 		// Hide modal and remove restricted media modal tab focus once it's closed.
       
  4539 		this.$el.hide().undelegate( 'keydown' );
       
  4540 
       
  4541 		/*
       
  4542 		 * Make visible again to assistive technologies all body children that
       
  4543 		 * have been made hidden when the modal opened.
       
  4544 		 */
       
  4545 		this.focusManager.removeAriaHiddenFromBodyChildren();
       
  4546 
       
  4547 		// Move focus back in useful location once modal is closed.
       
  4548 		if ( null !== this.clickedOpenerEl ) {
       
  4549 			// Move focus back to the element that opened the modal.
       
  4550 			this.clickedOpenerEl.focus();
       
  4551 		} else {
       
  4552 			// Fallback to the admin page main element.
       
  4553 			$( '#wpbody-content' )
       
  4554 				.attr( 'tabindex', '-1' )
       
  4555 				.focus();
       
  4556 		}
       
  4557 
       
  4558 		this.propagate('close');
       
  4559 
       
  4560 		if ( options && options.escape ) {
       
  4561 			this.propagate('escape');
       
  4562 		}
       
  4563 
       
  4564 		return this;
       
  4565 	},
       
  4566 	/**
       
  4567 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  4568 	 */
       
  4569 	escape: function() {
       
  4570 		return this.close({ escape: true });
       
  4571 	},
       
  4572 	/**
       
  4573 	 * @param {Object} event
       
  4574 	 */
       
  4575 	escapeHandler: function( event ) {
       
  4576 		event.preventDefault();
       
  4577 		this.escape();
       
  4578 	},
       
  4579 
       
  4580 	/**
       
  4581 	 * @param {Array|Object} content Views to register to '.media-modal-content'
       
  4582 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  4583 	 */
       
  4584 	content: function( content ) {
       
  4585 		this.views.set( '.media-modal-content', content );
       
  4586 		return this;
       
  4587 	},
       
  4588 
       
  4589 	/**
       
  4590 	 * Triggers a modal event and if the `propagate` option is set,
       
  4591 	 * forwards events to the modal's controller.
       
  4592 	 *
       
  4593 	 * @param {string} id
       
  4594 	 * @return {wp.media.view.Modal} Returns itself to allow chaining.
       
  4595 	 */
       
  4596 	propagate: function( id ) {
       
  4597 		this.trigger( id );
       
  4598 
       
  4599 		if ( this.options.propagate ) {
       
  4600 			this.controller.trigger( id );
       
  4601 		}
       
  4602 
       
  4603 		return this;
       
  4604 	},
       
  4605 	/**
       
  4606 	 * @param {Object} event
       
  4607 	 */
       
  4608 	keydown: function( event ) {
       
  4609 		// Close the modal when escape is pressed.
       
  4610 		if ( 27 === event.which && this.$el.is(':visible') ) {
       
  4611 			this.escape();
       
  4612 			event.stopImmediatePropagation();
       
  4613 		}
       
  4614 	}
       
  4615 });
       
  4616 
       
  4617 module.exports = Modal;
       
  4618 
       
  4619 
       
  4620 /***/ }),
       
  4621 /* 56 */
       
  4622 /***/ (function(module, exports) {
       
  4623 
       
  4624 var $ = jQuery;
       
  4625 
       
  4626 /**
       
  4627  * wp.media.view.FocusManager
       
  4628  *
       
  4629  * @memberOf wp.media.view
       
  4630  *
       
  4631  * @class
       
  4632  * @augments wp.media.View
       
  4633  * @augments wp.Backbone.View
       
  4634  * @augments Backbone.View
       
  4635  */
       
  4636 var FocusManager = wp.media.View.extend(/** @lends wp.media.view.FocusManager.prototype */{
       
  4637 
       
  4638 	events: {
       
  4639 		'keydown': 'focusManagementMode'
       
  4640 	},
       
  4641 
       
  4642 	/**
       
  4643 	 * Initializes the Focus Manager.
       
  4644 	 *
       
  4645 	 * @param {Object} options The Focus Manager options.
       
  4646 	 *
       
  4647 	 * @since 5.3.0
       
  4648 	 *
       
  4649 	 * @return {void}
       
  4650 	 */
       
  4651 	initialize: function( options ) {
       
  4652 		this.mode                    = options.mode || 'constrainTabbing';
       
  4653 		this.tabsAutomaticActivation = options.tabsAutomaticActivation || false;
       
  4654 	},
       
  4655 
       
  4656  	/**
       
  4657 	 * Determines which focus management mode to use.
       
  4658 	 *
       
  4659 	 * @since 5.3.0
       
  4660 	 *
       
  4661 	 * @param {Object} event jQuery event object.
       
  4662 	 *
       
  4663 	 * @return {void}
       
  4664 	 */
       
  4665 	focusManagementMode: function( event ) {
       
  4666 		if ( this.mode === 'constrainTabbing' ) {
       
  4667 			this.constrainTabbing( event );
       
  4668 		}
       
  4669 
       
  4670 		if ( this.mode === 'tabsNavigation' ) {
       
  4671 			this.tabsNavigation( event );
       
  4672 		}
       
  4673 	},
       
  4674 
       
  4675 	/**
       
  4676 	 * Gets all the tabbable elements.
       
  4677 	 *
       
  4678 	 * @since 5.3.0
       
  4679 	 *
       
  4680 	 * @return {Object} A jQuery collection of tabbable elements.
       
  4681 	 */
       
  4682 	getTabbables: function() {
       
  4683 		// Skip the file input added by Plupload.
       
  4684 		return this.$( ':tabbable' ).not( '.moxie-shim input[type="file"]' );
       
  4685 	},
       
  4686 
       
  4687 	/**
       
  4688 	 * Moves focus to the modal dialog.
       
  4689 	 *
       
  4690 	 * @since 3.5.0
       
  4691 	 *
       
  4692 	 * @return {void}
       
  4693 	 */
       
  4694 	focus: function() {
       
  4695 		this.$( '.media-modal' ).focus();
       
  4696 	},
       
  4697 
       
  4698 	/**
       
  4699 	 * Constrains navigation with the Tab key within the media view element.
       
  4700 	 *
       
  4701 	 * @since 4.0.0
       
  4702 	 *
       
  4703 	 * @param {Object} event A keydown jQuery event.
       
  4704 	 *
       
  4705 	 * @return {void}
       
  4706 	 */
       
  4707 	constrainTabbing: function( event ) {
       
  4708 		var tabbables;
       
  4709 
       
  4710 		// Look for the tab key.
       
  4711 		if ( 9 !== event.keyCode ) {
       
  4712 			return;
       
  4713 		}
       
  4714 
       
  4715 		tabbables = this.getTabbables();
       
  4716 
       
  4717 		// Keep tab focus within media modal while it's open.
       
  4718 		if ( tabbables.last()[0] === event.target && ! event.shiftKey ) {
       
  4719 			tabbables.first().focus();
       
  4720 			return false;
       
  4721 		} else if ( tabbables.first()[0] === event.target && event.shiftKey ) {
       
  4722 			tabbables.last().focus();
       
  4723 			return false;
       
  4724 		}
       
  4725 	},
       
  4726 
       
  4727 	/**
       
  4728 	 * Hides from assistive technologies all the body children.
       
  4729 	 *
       
  4730 	 * Sets an `aria-hidden="true"` attribute on all the body children except
       
  4731 	 * the provided element and other elements that should not be hidden.
       
  4732 	 *
       
  4733 	 * The reason why we use `aria-hidden` is that `aria-modal="true"` is buggy
       
  4734 	 * in Safari 11.1 and support is spotty in other browsers. Also, `aria-modal="true"`
       
  4735 	 * prevents the `wp.a11y.speak()` ARIA live regions to work as they're outside
       
  4736 	 * of the modal dialog and get hidden from assistive technologies.
       
  4737 	 *
       
  4738 	 * @since 5.2.3
       
  4739 	 *
       
  4740 	 * @param {Object} visibleElement The jQuery object representing the element that should not be hidden.
       
  4741 	 *
       
  4742 	 * @return {void}
       
  4743 	 */
       
  4744 	setAriaHiddenOnBodyChildren: function( visibleElement ) {
       
  4745 		var bodyChildren,
       
  4746 			self = this;
       
  4747 
       
  4748 		if ( this.isBodyAriaHidden ) {
       
  4749 			return;
       
  4750 		}
       
  4751 
       
  4752 		// Get all the body children.
       
  4753 		bodyChildren = document.body.children;
       
  4754 
       
  4755 		// Loop through the body children and hide the ones that should be hidden.
       
  4756 		_.each( bodyChildren, function( element ) {
       
  4757 			// Don't hide the modal element.
       
  4758 			if ( element === visibleElement[0] ) {
       
  4759 				return;
       
  4760 			}
       
  4761 
       
  4762 			// Determine the body children to hide.
       
  4763 			if ( self.elementShouldBeHidden( element ) ) {
       
  4764 				element.setAttribute( 'aria-hidden', 'true' );
       
  4765 				// Store the hidden elements.
       
  4766 				self.ariaHiddenElements.push( element );
       
  4767 			}
       
  4768 		} );
       
  4769 
       
  4770 		this.isBodyAriaHidden = true;
       
  4771 	},
       
  4772 
       
  4773 	/**
       
  4774 	 * Unhides from assistive technologies all the body children.
       
  4775 	 *
       
  4776 	 * Makes visible again to assistive technologies all the body children
       
  4777 	 * previously hidden and stored in this.ariaHiddenElements.
       
  4778 	 *
       
  4779 	 * @since 5.2.3
       
  4780 	 *
       
  4781 	 * @return {void}
       
  4782 	 */
       
  4783 	removeAriaHiddenFromBodyChildren: function() {
       
  4784 		_.each( this.ariaHiddenElements, function( element ) {
       
  4785 			element.removeAttribute( 'aria-hidden' );
       
  4786 		} );
       
  4787 
       
  4788 		this.ariaHiddenElements = [];
       
  4789 		this.isBodyAriaHidden   = false;
       
  4790 	},
       
  4791 
       
  4792 	/**
       
  4793 	 * Determines if the passed element should not be hidden from assistive technologies.
       
  4794 	 *
       
  4795 	 * @since 5.2.3
       
  4796 	 *
       
  4797 	 * @param {Object} element The DOM element that should be checked.
       
  4798 	 *
       
  4799 	 * @return {boolean} Whether the element should not be hidden from assistive technologies.
       
  4800 	 */
       
  4801 	elementShouldBeHidden: function( element ) {
       
  4802 		var role = element.getAttribute( 'role' ),
       
  4803 			liveRegionsRoles = [ 'alert', 'status', 'log', 'marquee', 'timer' ];
       
  4804 
       
  4805 		/*
       
  4806 		 * Don't hide scripts, elements that already have `aria-hidden`, and
       
  4807 		 * ARIA live regions.
       
  4808 		 */
       
  4809 		return ! (
       
  4810 			element.tagName === 'SCRIPT' ||
       
  4811 			element.hasAttribute( 'aria-hidden' ) ||
       
  4812 			element.hasAttribute( 'aria-live' ) ||
       
  4813 			liveRegionsRoles.indexOf( role ) !== -1
       
  4814 		);
       
  4815 	},
       
  4816 
       
  4817 	/**
       
  4818 	 * Whether the body children are hidden from assistive technologies.
       
  4819 	 *
       
  4820 	 * @since 5.2.3
       
  4821 	 */
       
  4822 	isBodyAriaHidden: false,
       
  4823 
       
  4824 	/**
       
  4825 	 * Stores an array of DOM elements that should be hidden from assistive
       
  4826 	 * technologies, for example when the media modal dialog opens.
       
  4827 	 *
       
  4828 	 * @since 5.2.3
       
  4829 	 */
       
  4830 	ariaHiddenElements: [],
       
  4831 
       
  4832 	/**
       
  4833 	 * Holds the jQuery collection of ARIA tabs.
       
  4834 	 *
       
  4835 	 * @since 5.3.0
       
  4836 	 */
       
  4837 	tabs: $(),
       
  4838 
       
  4839 	/**
       
  4840 	 * Sets up tabs in an ARIA tabbed interface.
       
  4841 	 *
       
  4842 	 * @since 5.3.0
       
  4843 	 *
       
  4844 	 * @param {Object} event jQuery event object.
       
  4845 	 *
       
  4846 	 * @return {void}
       
  4847 	 */
       
  4848 	setupAriaTabs: function() {
       
  4849 		this.tabs = this.$( '[role="tab"]' );
       
  4850 
       
  4851 		// Set up initial attributes.
       
  4852 		this.tabs.attr( {
       
  4853 			'aria-selected': 'false',
       
  4854 			tabIndex: '-1'
       
  4855 		} );
       
  4856 
       
  4857 		// Set up attributes on the initially active tab.
       
  4858 		this.tabs.filter( '.active' )
       
  4859 			.removeAttr( 'tabindex' )
       
  4860 			.attr( 'aria-selected', 'true' );
       
  4861 	},
       
  4862 
       
  4863 	/**
       
  4864 	 * Enables arrows navigation within the ARIA tabbed interface.
       
  4865 	 *
       
  4866 	 * @since 5.3.0
       
  4867 	 *
       
  4868 	 * @param {Object} event jQuery event object.
       
  4869 	 *
       
  4870 	 * @return {void}
       
  4871 	 */
       
  4872 	tabsNavigation: function( event ) {
       
  4873 		var orientation = 'horizontal',
       
  4874 			keys = [ 32, 35, 36, 37, 38, 39, 40 ];
       
  4875 
       
  4876 		// Return if not Spacebar, End, Home, or Arrow keys.
       
  4877 		if ( keys.indexOf( event.which ) === -1 ) {
       
  4878 			return;
       
  4879 		}
       
  4880 
       
  4881 		// Determine navigation direction.
       
  4882 		if ( this.$el.attr( 'aria-orientation' ) === 'vertical' ) {
       
  4883 			orientation = 'vertical';
       
  4884 		}
       
  4885 
       
  4886 		// Make Up and Down arrow keys do nothing with horizontal tabs.
       
  4887 		if ( orientation === 'horizontal' && [ 38, 40 ].indexOf( event.which ) !== -1 ) {
       
  4888 			return;
       
  4889 		}
       
  4890 
       
  4891 		// Make Left and Right arrow keys do nothing with vertical tabs.
       
  4892 		if ( orientation === 'vertical' && [ 37, 39 ].indexOf( event.which ) !== -1 ) {
       
  4893 			return;
       
  4894 		}
       
  4895 
       
  4896 		this.switchTabs( event, this.tabs );
       
  4897 	},
       
  4898 
       
  4899 	/**
       
  4900 	 * Switches tabs in the ARIA tabbed interface.
       
  4901 	 *
       
  4902 	 * @since 5.3.0
       
  4903 	 *
       
  4904 	 * @param {Object} event jQuery event object.
       
  4905 	 *
       
  4906 	 * @return {void}
       
  4907 	 */
       
  4908 	switchTabs: function( event ) {
       
  4909 		var key   = event.which,
       
  4910 			index = this.tabs.index( $( event.target ) ),
       
  4911 			newIndex;
       
  4912 
       
  4913 		switch ( key ) {
       
  4914 			// Space bar: Activate current targeted tab.
       
  4915 			case 32: {
       
  4916 				this.activateTab( this.tabs[ index ] );
       
  4917 				break;
       
  4918 			}
       
  4919 			// End key: Activate last tab.
       
  4920 			case 35: {
       
  4921 				event.preventDefault();
       
  4922 				this.activateTab( this.tabs[ this.tabs.length - 1 ] );
       
  4923 				break;
       
  4924 			}
       
  4925 			// Home key: Activate first tab.
       
  4926 			case 36: {
       
  4927 				event.preventDefault();
       
  4928 				this.activateTab( this.tabs[ 0 ] );
       
  4929 				break;
       
  4930 			}
       
  4931 			// Left and up keys: Activate previous tab.
       
  4932 			case 37:
       
  4933 			case 38: {
       
  4934 				event.preventDefault();
       
  4935 				newIndex = ( index - 1 ) < 0 ? this.tabs.length - 1 : index - 1;
       
  4936 				this.activateTab( this.tabs[ newIndex ] );
       
  4937 				break;
       
  4938 			}
       
  4939 			// Right and down keys: Activate next tab.
       
  4940 			case 39:
       
  4941 			case 40: {
       
  4942 				event.preventDefault();
       
  4943 				newIndex = ( index + 1 ) === this.tabs.length ? 0 : index + 1;
       
  4944 				this.activateTab( this.tabs[ newIndex ] );
       
  4945 				break;
       
  4946 			}
       
  4947 		}
       
  4948 	},
       
  4949 
       
  4950 	/**
       
  4951 	 * Sets a single tab to be focusable and semantically selected.
       
  4952 	 *
       
  4953 	 * @since 5.3.0
       
  4954 	 *
       
  4955 	 * @param {Object} tab The tab DOM element.
       
  4956 	 *
       
  4957 	 * @return {void}
       
  4958 	 */
       
  4959 	activateTab: function( tab ) {
       
  4960 		if ( ! tab ) {
       
  4961 			return;
       
  4962 		}
       
  4963 
       
  4964 		// The tab is a DOM element: no need for jQuery methods.
       
  4965 		tab.focus();
       
  4966 
       
  4967 		// Handle automatic activation.
       
  4968 		if ( this.tabsAutomaticActivation ) {
       
  4969 			tab.removeAttribute( 'tabindex' );
       
  4970 			tab.setAttribute( 'aria-selected', 'true' );
       
  4971 			tab.click();
       
  4972 
       
  4973 			return;
       
  4974 		}
       
  4975 
       
  4976 		// Handle manual activation.
       
  4977 		$( tab ).on( 'click', function() {
       
  4978 			tab.removeAttribute( 'tabindex' );
       
  4979 			tab.setAttribute( 'aria-selected', 'true' );
       
  4980 		} );
       
  4981  	}
       
  4982 });
       
  4983 
       
  4984 module.exports = FocusManager;
       
  4985 
       
  4986 
       
  4987 /***/ }),
       
  4988 /* 57 */
       
  4989 /***/ (function(module, exports) {
       
  4990 
       
  4991 var $ = jQuery,
       
  4992 	UploaderWindow;
       
  4993 
       
  4994 /**
       
  4995  * wp.media.view.UploaderWindow
       
  4996  *
       
  4997  * An uploader window that allows for dragging and dropping media.
       
  4998  *
       
  4999  * @memberOf wp.media.view
       
  5000  *
       
  5001  * @class
       
  5002  * @augments wp.media.View
       
  5003  * @augments wp.Backbone.View
       
  5004  * @augments Backbone.View
       
  5005  *
       
  5006  * @param {object} [options]                   Options hash passed to the view.
       
  5007  * @param {object} [options.uploader]          Uploader properties.
       
  5008  * @param {jQuery} [options.uploader.browser]
       
  5009  * @param {jQuery} [options.uploader.dropzone] jQuery collection of the dropzone.
       
  5010  * @param {object} [options.uploader.params]
       
  5011  */
       
  5012 UploaderWindow = wp.media.View.extend(/** @lends wp.media.view.UploaderWindow.prototype */{
       
  5013 	tagName:   'div',
       
  5014 	className: 'uploader-window',
       
  5015 	template:  wp.template('uploader-window'),
       
  5016 
       
  5017 	initialize: function() {
       
  5018 		var uploader;
       
  5019 
       
  5020 		this.$browser = $( '<button type="button" class="browser" />' ).hide().appendTo( 'body' );
       
  5021 
       
  5022 		uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
       
  5023 			dropzone:  this.$el,
       
  5024 			browser:   this.$browser,
       
  5025 			params:    {}
       
  5026 		});
       
  5027 
       
  5028 		// Ensure the dropzone is a jQuery collection.
       
  5029 		if ( uploader.dropzone && ! (uploader.dropzone instanceof $) ) {
       
  5030 			uploader.dropzone = $( uploader.dropzone );
       
  5031 		}
       
  5032 
       
  5033 		this.controller.on( 'activate', this.refresh, this );
       
  5034 
       
  5035 		this.controller.on( 'detach', function() {
       
  5036 			this.$browser.remove();
       
  5037 		}, this );
       
  5038 	},
       
  5039 
       
  5040 	refresh: function() {
       
  5041 		if ( this.uploader ) {
       
  5042 			this.uploader.refresh();
       
  5043 		}
       
  5044 	},
       
  5045 
       
  5046 	ready: function() {
       
  5047 		var postId = wp.media.view.settings.post.id,
       
  5048 			dropzone;
       
  5049 
       
  5050 		// If the uploader already exists, bail.
       
  5051 		if ( this.uploader ) {
       
  5052 			return;
       
  5053 		}
       
  5054 
       
  5055 		if ( postId ) {
       
  5056 			this.options.uploader.params.post_id = postId;
       
  5057 		}
       
  5058 		this.uploader = new wp.Uploader( this.options.uploader );
       
  5059 
       
  5060 		dropzone = this.uploader.dropzone;
       
  5061 		dropzone.on( 'dropzone:enter', _.bind( this.show, this ) );
       
  5062 		dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) );
       
  5063 
       
  5064 		$( this.uploader ).on( 'uploader:ready', _.bind( this._ready, this ) );
       
  5065 	},
       
  5066 
       
  5067 	_ready: function() {
       
  5068 		this.controller.trigger( 'uploader:ready' );
       
  5069 	},
       
  5070 
       
  5071 	show: function() {
       
  5072 		var $el = this.$el.show();
       
  5073 
       
  5074 		// Ensure that the animation is triggered by waiting until
       
  5075 		// the transparent element is painted into the DOM.
       
  5076 		_.defer( function() {
       
  5077 			$el.css({ opacity: 1 });
       
  5078 		});
       
  5079 	},
       
  5080 
       
  5081 	hide: function() {
       
  5082 		var $el = this.$el.css({ opacity: 0 });
       
  5083 
       
  5084 		wp.media.transition( $el ).done( function() {
       
  5085 			// Transition end events are subject to race conditions.
       
  5086 			// Make sure that the value is set as intended.
       
  5087 			if ( '0' === $el.css('opacity') ) {
       
  5088 				$el.hide();
       
  5089 			}
       
  5090 		});
       
  5091 
       
  5092 		// https://core.trac.wordpress.org/ticket/27341
       
  5093 		_.delay( function() {
       
  5094 			if ( '0' === $el.css('opacity') && $el.is(':visible') ) {
       
  5095 				$el.hide();
       
  5096 			}
       
  5097 		}, 500 );
       
  5098 	}
       
  5099 });
       
  5100 
       
  5101 module.exports = UploaderWindow;
       
  5102 
       
  5103 
       
  5104 /***/ }),
       
  5105 /* 58 */
       
  5106 /***/ (function(module, exports) {
       
  5107 
       
  5108 var View = wp.media.View,
       
  5109 	l10n = wp.media.view.l10n,
       
  5110 	$ = jQuery,
       
  5111 	EditorUploader;
       
  5112 
       
  5113 /**
       
  5114  * Creates a dropzone on WP editor instances (elements with .wp-editor-wrap)
       
  5115  * and relays drag'n'dropped files to a media workflow.
       
  5116  *
       
  5117  * wp.media.view.EditorUploader
       
  5118  *
       
  5119  * @memberOf wp.media.view
       
  5120  *
       
  5121  * @class
       
  5122  * @augments wp.media.View
       
  5123  * @augments wp.Backbone.View
       
  5124  * @augments Backbone.View
       
  5125  */
       
  5126 EditorUploader = View.extend(/** @lends wp.media.view.EditorUploader.prototype */{
       
  5127 	tagName:   'div',
       
  5128 	className: 'uploader-editor',
       
  5129 	template:  wp.template( 'uploader-editor' ),
       
  5130 
       
  5131 	localDrag: false,
       
  5132 	overContainer: false,
       
  5133 	overDropzone: false,
       
  5134 	draggingFile: null,
       
  5135 
       
  5136 	/**
       
  5137 	 * Bind drag'n'drop events to callbacks.
       
  5138 	 */
       
  5139 	initialize: function() {
       
  5140 		this.initialized = false;
       
  5141 
       
  5142 		// Bail if not enabled or UA does not support drag'n'drop or File API.
       
  5143 		if ( ! window.tinyMCEPreInit || ! window.tinyMCEPreInit.dragDropUpload || ! this.browserSupport() ) {
       
  5144 			return this;
       
  5145 		}
       
  5146 
       
  5147 		this.$document = $(document);
       
  5148 		this.dropzones = [];
       
  5149 		this.files = [];
       
  5150 
       
  5151 		this.$document.on( 'drop', '.uploader-editor', _.bind( this.drop, this ) );
       
  5152 		this.$document.on( 'dragover', '.uploader-editor', _.bind( this.dropzoneDragover, this ) );
       
  5153 		this.$document.on( 'dragleave', '.uploader-editor', _.bind( this.dropzoneDragleave, this ) );
       
  5154 		this.$document.on( 'click', '.uploader-editor', _.bind( this.click, this ) );
       
  5155 
       
  5156 		this.$document.on( 'dragover', _.bind( this.containerDragover, this ) );
       
  5157 		this.$document.on( 'dragleave', _.bind( this.containerDragleave, this ) );
       
  5158 
       
  5159 		this.$document.on( 'dragstart dragend drop', _.bind( function( event ) {
       
  5160 			this.localDrag = event.type === 'dragstart';
       
  5161 
       
  5162 			if ( event.type === 'drop' ) {
       
  5163 				this.containerDragleave();
       
  5164 			}
       
  5165 		}, this ) );
       
  5166 
       
  5167 		this.initialized = true;
       
  5168 		return this;
       
  5169 	},
       
  5170 
       
  5171 	/**
       
  5172 	 * Check browser support for drag'n'drop.
       
  5173 	 *
       
  5174 	 * @return {boolean}
       
  5175 	 */
       
  5176 	browserSupport: function() {
       
  5177 		var supports = false, div = document.createElement('div');
       
  5178 
       
  5179 		supports = ( 'draggable' in div ) || ( 'ondragstart' in div && 'ondrop' in div );
       
  5180 		supports = supports && !! ( window.File && window.FileList && window.FileReader );
       
  5181 		return supports;
       
  5182 	},
       
  5183 
       
  5184 	isDraggingFile: function( event ) {
       
  5185 		if ( this.draggingFile !== null ) {
       
  5186 			return this.draggingFile;
       
  5187 		}
       
  5188 
       
  5189 		if ( _.isUndefined( event.originalEvent ) || _.isUndefined( event.originalEvent.dataTransfer ) ) {
       
  5190 			return false;
       
  5191 		}
       
  5192 
       
  5193 		this.draggingFile = _.indexOf( event.originalEvent.dataTransfer.types, 'Files' ) > -1 &&
       
  5194 			_.indexOf( event.originalEvent.dataTransfer.types, 'text/plain' ) === -1;
       
  5195 
       
  5196 		return this.draggingFile;
       
  5197 	},
       
  5198 
       
  5199 	refresh: function( e ) {
       
  5200 		var dropzone_id;
       
  5201 		for ( dropzone_id in this.dropzones ) {
       
  5202 			// Hide the dropzones only if dragging has left the screen.
       
  5203 			this.dropzones[ dropzone_id ].toggle( this.overContainer || this.overDropzone );
       
  5204 		}
       
  5205 
       
  5206 		if ( ! _.isUndefined( e ) ) {
       
  5207 			$( e.target ).closest( '.uploader-editor' ).toggleClass( 'droppable', this.overDropzone );
       
  5208 		}
       
  5209 
       
  5210 		if ( ! this.overContainer && ! this.overDropzone ) {
       
  5211 			this.draggingFile = null;
       
  5212 		}
       
  5213 
       
  5214 		return this;
       
  5215 	},
       
  5216 
       
  5217 	render: function() {
       
  5218 		if ( ! this.initialized ) {
       
  5219 			return this;
       
  5220 		}
       
  5221 
       
  5222 		View.prototype.render.apply( this, arguments );
       
  5223 		$( '.wp-editor-wrap' ).each( _.bind( this.attach, this ) );
       
  5224 		return this;
       
  5225 	},
       
  5226 
       
  5227 	attach: function( index, editor ) {
       
  5228 		// Attach a dropzone to an editor.
       
  5229 		var dropzone = this.$el.clone();
       
  5230 		this.dropzones.push( dropzone );
       
  5231 		$( editor ).append( dropzone );
       
  5232 		return this;
       
  5233 	},
       
  5234 
       
  5235 	/**
       
  5236 	 * When a file is dropped on the editor uploader, open up an editor media workflow
       
  5237 	 * and upload the file immediately.
       
  5238 	 *
       
  5239 	 * @param {jQuery.Event} event The 'drop' event.
       
  5240 	 */
       
  5241 	drop: function( event ) {
       
  5242 		var $wrap, uploadView;
       
  5243 
       
  5244 		this.containerDragleave( event );
       
  5245 		this.dropzoneDragleave( event );
       
  5246 
       
  5247 		this.files = event.originalEvent.dataTransfer.files;
       
  5248 		if ( this.files.length < 1 ) {
       
  5249 			return;
       
  5250 		}
       
  5251 
       
  5252 		// Set the active editor to the drop target.
       
  5253 		$wrap = $( event.target ).parents( '.wp-editor-wrap' );
       
  5254 		if ( $wrap.length > 0 && $wrap[0].id ) {
       
  5255 			window.wpActiveEditor = $wrap[0].id.slice( 3, -5 );
       
  5256 		}
       
  5257 
       
  5258 		if ( ! this.workflow ) {
       
  5259 			this.workflow = wp.media.editor.open( window.wpActiveEditor, {
       
  5260 				frame:    'post',
       
  5261 				state:    'insert',
       
  5262 				title:    l10n.addMedia,
       
  5263 				multiple: true
       
  5264 			});
       
  5265 
       
  5266 			uploadView = this.workflow.uploader;
       
  5267 
       
  5268 			if ( uploadView.uploader && uploadView.uploader.ready ) {
       
  5269 				this.addFiles.apply( this );
       
  5270 			} else {
       
  5271 				this.workflow.on( 'uploader:ready', this.addFiles, this );
       
  5272 			}
       
  5273 		} else {
       
  5274 			this.workflow.state().reset();
       
  5275 			this.addFiles.apply( this );
       
  5276 			this.workflow.open();
       
  5277 		}
       
  5278 
       
  5279 		return false;
       
  5280 	},
       
  5281 
       
  5282 	/**
       
  5283 	 * Add the files to the uploader.
       
  5284 	 */
       
  5285 	addFiles: function() {
       
  5286 		if ( this.files.length ) {
       
  5287 			this.workflow.uploader.uploader.uploader.addFile( _.toArray( this.files ) );
       
  5288 			this.files = [];
       
  5289 		}
       
  5290 		return this;
       
  5291 	},
       
  5292 
       
  5293 	containerDragover: function( event ) {
       
  5294 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
       
  5295 			return;
       
  5296 		}
       
  5297 
       
  5298 		this.overContainer = true;
       
  5299 		this.refresh();
       
  5300 	},
       
  5301 
       
  5302 	containerDragleave: function() {
       
  5303 		this.overContainer = false;
       
  5304 
       
  5305 		// Throttle dragleave because it's called when bouncing from some elements to others.
       
  5306 		_.delay( _.bind( this.refresh, this ), 50 );
       
  5307 	},
       
  5308 
       
  5309 	dropzoneDragover: function( event ) {
       
  5310 		if ( this.localDrag || ! this.isDraggingFile( event ) ) {
       
  5311 			return;
       
  5312 		}
       
  5313 
       
  5314 		this.overDropzone = true;
       
  5315 		this.refresh( event );
       
  5316 		return false;
       
  5317 	},
       
  5318 
       
  5319 	dropzoneDragleave: function( e ) {
       
  5320 		this.overDropzone = false;
       
  5321 		_.delay( _.bind( this.refresh, this, e ), 50 );
       
  5322 	},
       
  5323 
       
  5324 	click: function( e ) {
       
  5325 		// In the rare case where the dropzone gets stuck, hide it on click.
       
  5326 		this.containerDragleave( e );
       
  5327 		this.dropzoneDragleave( e );
       
  5328 		this.localDrag = false;
       
  5329 	}
       
  5330 });
       
  5331 
       
  5332 module.exports = EditorUploader;
       
  5333 
       
  5334 
       
  5335 /***/ }),
       
  5336 /* 59 */
       
  5337 /***/ (function(module, exports) {
       
  5338 
       
  5339 var View = wp.media.View,
       
  5340 	UploaderInline;
       
  5341 
       
  5342 /**
       
  5343  * wp.media.view.UploaderInline
       
  5344  *
       
  5345  * The inline uploader that shows up in the 'Upload Files' tab.
       
  5346  *
       
  5347  * @memberOf wp.media.view
       
  5348  *
       
  5349  * @class
       
  5350  * @augments wp.media.View
       
  5351  * @augments wp.Backbone.View
       
  5352  * @augments Backbone.View
       
  5353  */
       
  5354 UploaderInline = View.extend(/** @lends wp.media.view.UploaderInline.prototype */{
       
  5355 	tagName:   'div',
       
  5356 	className: 'uploader-inline',
       
  5357 	template:  wp.template('uploader-inline'),
       
  5358 
       
  5359 	events: {
       
  5360 		'click .close': 'hide'
       
  5361 	},
       
  5362 
       
  5363 	initialize: function() {
       
  5364 		_.defaults( this.options, {
       
  5365 			message: '',
       
  5366 			status:  true,
       
  5367 			canClose: false
       
  5368 		});
       
  5369 
       
  5370 		if ( ! this.options.$browser && this.controller.uploader ) {
       
  5371 			this.options.$browser = this.controller.uploader.$browser;
       
  5372 		}
       
  5373 
       
  5374 		if ( _.isUndefined( this.options.postId ) ) {
       
  5375 			this.options.postId = wp.media.view.settings.post.id;
       
  5376 		}
       
  5377 
       
  5378 		if ( this.options.status ) {
       
  5379 			this.views.set( '.upload-inline-status', new wp.media.view.UploaderStatus({
       
  5380 				controller: this.controller
       
  5381 			}) );
       
  5382 		}
       
  5383 	},
       
  5384 
       
  5385 	prepare: function() {
       
  5386 		var suggestedWidth = this.controller.state().get('suggestedWidth'),
       
  5387 			suggestedHeight = this.controller.state().get('suggestedHeight'),
       
  5388 			data = {};
       
  5389 
       
  5390 		data.message = this.options.message;
       
  5391 		data.canClose = this.options.canClose;
       
  5392 
       
  5393 		if ( suggestedWidth && suggestedHeight ) {
       
  5394 			data.suggestedWidth = suggestedWidth;
       
  5395 			data.suggestedHeight = suggestedHeight;
       
  5396 		}
       
  5397 
       
  5398 		return data;
       
  5399 	},
       
  5400 	/**
       
  5401 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
       
  5402 	 */
       
  5403 	dispose: function() {
       
  5404 		if ( this.disposing ) {
       
  5405 			/**
       
  5406 			 * call 'dispose' directly on the parent class
       
  5407 			 */
       
  5408 			return View.prototype.dispose.apply( this, arguments );
       
  5409 		}
       
  5410 
       
  5411 		/*
       
  5412 		 * Run remove on `dispose`, so we can be sure to refresh the
       
  5413 		 * uploader with a view-less DOM. Track whether we're disposing
       
  5414 		 * so we don't trigger an infinite loop.
       
  5415 		 */
       
  5416 		this.disposing = true;
       
  5417 		return this.remove();
       
  5418 	},
       
  5419 	/**
       
  5420 	 * @return {wp.media.view.UploaderInline} Returns itself to allow chaining.
       
  5421 	 */
       
  5422 	remove: function() {
       
  5423 		/**
       
  5424 		 * call 'remove' directly on the parent class
       
  5425 		 */
       
  5426 		var result = View.prototype.remove.apply( this, arguments );
       
  5427 
       
  5428 		_.defer( _.bind( this.refresh, this ) );
       
  5429 		return result;
       
  5430 	},
       
  5431 
       
  5432 	refresh: function() {
       
  5433 		var uploader = this.controller.uploader;
       
  5434 
       
  5435 		if ( uploader ) {
       
  5436 			uploader.refresh();
       
  5437 		}
       
  5438 	},
       
  5439 	/**
       
  5440 	 * @return {wp.media.view.UploaderInline}
       
  5441 	 */
       
  5442 	ready: function() {
       
  5443 		var $browser = this.options.$browser,
       
  5444 			$placeholder;
       
  5445 
       
  5446 		if ( this.controller.uploader ) {
       
  5447 			$placeholder = this.$('.browser');
       
  5448 
       
  5449 			// Check if we've already replaced the placeholder.
       
  5450 			if ( $placeholder[0] === $browser[0] ) {
       
  5451 				return;
       
  5452 			}
       
  5453 
       
  5454 			$browser.detach().text( $placeholder.text() );
       
  5455 			$browser[0].className = $placeholder[0].className;
       
  5456 			$placeholder.replaceWith( $browser.show() );
       
  5457 		}
       
  5458 
       
  5459 		this.refresh();
       
  5460 		return this;
       
  5461 	},
       
  5462 	show: function() {
       
  5463 		this.$el.removeClass( 'hidden' );
       
  5464 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
       
  5465 			this.controller.$uploaderToggler.attr( 'aria-expanded', 'true' );
       
  5466 		}
       
  5467 	},
       
  5468 	hide: function() {
       
  5469 		this.$el.addClass( 'hidden' );
       
  5470 		if ( this.controller.$uploaderToggler && this.controller.$uploaderToggler.length ) {
       
  5471 			this.controller.$uploaderToggler
       
  5472 				.attr( 'aria-expanded', 'false' )
       
  5473 				// Move focus back to the toggle button when closing the uploader.
       
  5474 				.focus();
       
  5475 		}
       
  5476 	}
       
  5477 
       
  5478 });
       
  5479 
       
  5480 module.exports = UploaderInline;
       
  5481 
       
  5482 
       
  5483 /***/ }),
       
  5484 /* 60 */
       
  5485 /***/ (function(module, exports) {
       
  5486 
       
  5487 var View = wp.media.View,
       
  5488 	UploaderStatus;
       
  5489 
       
  5490 /**
       
  5491  * wp.media.view.UploaderStatus
       
  5492  *
       
  5493  * An uploader status for on-going uploads.
       
  5494  *
       
  5495  * @memberOf wp.media.view
       
  5496  *
       
  5497  * @class
       
  5498  * @augments wp.media.View
       
  5499  * @augments wp.Backbone.View
       
  5500  * @augments Backbone.View
       
  5501  */
       
  5502 UploaderStatus = View.extend(/** @lends wp.media.view.UploaderStatus.prototype */{
       
  5503 	className: 'media-uploader-status',
       
  5504 	template:  wp.template('uploader-status'),
       
  5505 
       
  5506 	events: {
       
  5507 		'click .upload-dismiss-errors': 'dismiss'
       
  5508 	},
       
  5509 
       
  5510 	initialize: function() {
       
  5511 		this.queue = wp.Uploader.queue;
       
  5512 		this.queue.on( 'add remove reset', this.visibility, this );
       
  5513 		this.queue.on( 'add remove reset change:percent', this.progress, this );
       
  5514 		this.queue.on( 'add remove reset change:uploading', this.info, this );
       
  5515 
       
  5516 		this.errors = wp.Uploader.errors;
       
  5517 		this.errors.reset();
       
  5518 		this.errors.on( 'add remove reset', this.visibility, this );
       
  5519 		this.errors.on( 'add', this.error, this );
       
  5520 	},
       
  5521 	/**
       
  5522 	 * @return {wp.media.view.UploaderStatus}
       
  5523 	 */
       
  5524 	dispose: function() {
       
  5525 		wp.Uploader.queue.off( null, null, this );
       
  5526 		/**
       
  5527 		 * call 'dispose' directly on the parent class
       
  5528 		 */
       
  5529 		View.prototype.dispose.apply( this, arguments );
       
  5530 		return this;
       
  5531 	},
       
  5532 
       
  5533 	visibility: function() {
       
  5534 		this.$el.toggleClass( 'uploading', !! this.queue.length );
       
  5535 		this.$el.toggleClass( 'errors', !! this.errors.length );
       
  5536 		this.$el.toggle( !! this.queue.length || !! this.errors.length );
       
  5537 	},
       
  5538 
       
  5539 	ready: function() {
       
  5540 		_.each({
       
  5541 			'$bar':      '.media-progress-bar div',
       
  5542 			'$index':    '.upload-index',
       
  5543 			'$total':    '.upload-total',
       
  5544 			'$filename': '.upload-filename'
       
  5545 		}, function( selector, key ) {
       
  5546 			this[ key ] = this.$( selector );
       
  5547 		}, this );
       
  5548 
       
  5549 		this.visibility();
       
  5550 		this.progress();
       
  5551 		this.info();
       
  5552 	},
       
  5553 
       
  5554 	progress: function() {
       
  5555 		var queue = this.queue,
       
  5556 			$bar = this.$bar;
       
  5557 
       
  5558 		if ( ! $bar || ! queue.length ) {
       
  5559 			return;
       
  5560 		}
       
  5561 
       
  5562 		$bar.width( ( queue.reduce( function( memo, attachment ) {
       
  5563 			if ( ! attachment.get('uploading') ) {
       
  5564 				return memo + 100;
       
  5565 			}
       
  5566 
       
  5567 			var percent = attachment.get('percent');
       
  5568 			return memo + ( _.isNumber( percent ) ? percent : 100 );
       
  5569 		}, 0 ) / queue.length ) + '%' );
       
  5570 	},
       
  5571 
       
  5572 	info: function() {
       
  5573 		var queue = this.queue,
       
  5574 			index = 0, active;
       
  5575 
       
  5576 		if ( ! queue.length ) {
       
  5577 			return;
       
  5578 		}
       
  5579 
       
  5580 		active = this.queue.find( function( attachment, i ) {
       
  5581 			index = i;
       
  5582 			return attachment.get('uploading');
       
  5583 		});
       
  5584 
       
  5585 		this.$index.text( index + 1 );
       
  5586 		this.$total.text( queue.length );
       
  5587 		this.$filename.html( active ? this.filename( active.get('filename') ) : '' );
       
  5588 	},
       
  5589 	/**
       
  5590 	 * @param {string} filename
       
  5591 	 * @return {string}
       
  5592 	 */
       
  5593 	filename: function( filename ) {
       
  5594 		return _.escape( filename );
       
  5595 	},
       
  5596 	/**
       
  5597 	 * @param {Backbone.Model} error
       
  5598 	 */
       
  5599 	error: function( error ) {
       
  5600 		var statusError = new wp.media.view.UploaderStatusError( {
       
  5601 			filename: this.filename( error.get( 'file' ).name ),
       
  5602 			message:  error.get( 'message' )
       
  5603 		} );
       
  5604 
       
  5605 		// Can show additional info here while retrying to create image sub-sizes.
       
  5606 		this.views.add( '.upload-errors', statusError, { at: 0 } );
       
  5607 	},
       
  5608 
       
  5609 	dismiss: function() {
       
  5610 		var errors = this.views.get('.upload-errors');
       
  5611 
       
  5612 		if ( errors ) {
       
  5613 			_.invoke( errors, 'remove' );
       
  5614 		}
       
  5615 		wp.Uploader.errors.reset();
       
  5616 		// Move focus to the modal after the dismiss button gets removed from the DOM.
       
  5617 		if ( this.controller.modal ) {
       
  5618 			this.controller.modal.focusManager.focus();
       
  5619 		}
       
  5620 	}
       
  5621 });
       
  5622 
       
  5623 module.exports = UploaderStatus;
       
  5624 
       
  5625 
       
  5626 /***/ }),
       
  5627 /* 61 */
       
  5628 /***/ (function(module, exports) {
       
  5629 
       
  5630 /**
       
  5631  * wp.media.view.UploaderStatusError
       
  5632  *
       
  5633  * @memberOf wp.media.view
       
  5634  *
       
  5635  * @class
       
  5636  * @augments wp.media.View
       
  5637  * @augments wp.Backbone.View
       
  5638  * @augments Backbone.View
       
  5639  */
       
  5640 var UploaderStatusError = wp.media.View.extend(/** @lends wp.media.view.UploaderStatusError.prototype */{
       
  5641 	className: 'upload-error',
       
  5642 	template:  wp.template('uploader-status-error')
       
  5643 });
       
  5644 
       
  5645 module.exports = UploaderStatusError;
       
  5646 
       
  5647 
       
  5648 /***/ }),
       
  5649 /* 62 */
       
  5650 /***/ (function(module, exports) {
       
  5651 
       
  5652 var View = wp.media.View,
       
  5653 	Toolbar;
       
  5654 
       
  5655 /**
       
  5656  * wp.media.view.Toolbar
       
  5657  *
       
  5658  * A toolbar which consists of a primary and a secondary section. Each sections
       
  5659  * can be filled with views.
       
  5660  *
       
  5661  * @memberOf wp.media.view
       
  5662  *
       
  5663  * @class
       
  5664  * @augments wp.media.View
       
  5665  * @augments wp.Backbone.View
       
  5666  * @augments Backbone.View
       
  5667  */
       
  5668 Toolbar = View.extend(/** @lends wp.media.view.Toolbar.prototype */{
       
  5669 	tagName:   'div',
       
  5670 	className: 'media-toolbar',
       
  5671 
       
  5672 	initialize: function() {
       
  5673 		var state = this.controller.state(),
       
  5674 			selection = this.selection = state.get('selection'),
       
  5675 			library = this.library = state.get('library');
       
  5676 
       
  5677 		this._views = {};
       
  5678 
       
  5679 		// The toolbar is composed of two `PriorityList` views.
       
  5680 		this.primary   = new wp.media.view.PriorityList();
       
  5681 		this.secondary = new wp.media.view.PriorityList();
       
  5682 		this.primary.$el.addClass('media-toolbar-primary search-form');
       
  5683 		this.secondary.$el.addClass('media-toolbar-secondary');
       
  5684 
       
  5685 		this.views.set([ this.secondary, this.primary ]);
       
  5686 
       
  5687 		if ( this.options.items ) {
       
  5688 			this.set( this.options.items, { silent: true });
       
  5689 		}
       
  5690 
       
  5691 		if ( ! this.options.silent ) {
       
  5692 			this.render();
       
  5693 		}
       
  5694 
       
  5695 		if ( selection ) {
       
  5696 			selection.on( 'add remove reset', this.refresh, this );
       
  5697 		}
       
  5698 
       
  5699 		if ( library ) {
       
  5700 			library.on( 'add remove reset', this.refresh, this );
       
  5701 		}
       
  5702 	},
       
  5703 	/**
       
  5704 	 * @return {wp.media.view.Toolbar} Returns itsef to allow chaining
       
  5705 	 */
       
  5706 	dispose: function() {
       
  5707 		if ( this.selection ) {
       
  5708 			this.selection.off( null, null, this );
       
  5709 		}
       
  5710 
       
  5711 		if ( this.library ) {
       
  5712 			this.library.off( null, null, this );
       
  5713 		}
       
  5714 		/**
       
  5715 		 * call 'dispose' directly on the parent class
       
  5716 		 */
       
  5717 		return View.prototype.dispose.apply( this, arguments );
       
  5718 	},
       
  5719 
       
  5720 	ready: function() {
       
  5721 		this.refresh();
       
  5722 	},
       
  5723 
       
  5724 	/**
       
  5725 	 * @param {string} id
       
  5726 	 * @param {Backbone.View|Object} view
       
  5727 	 * @param {Object} [options={}]
       
  5728 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
       
  5729 	 */
       
  5730 	set: function( id, view, options ) {
       
  5731 		var list;
       
  5732 		options = options || {};
       
  5733 
       
  5734 		// Accept an object with an `id` : `view` mapping.
       
  5735 		if ( _.isObject( id ) ) {
       
  5736 			_.each( id, function( view, id ) {
       
  5737 				this.set( id, view, { silent: true });
       
  5738 			}, this );
       
  5739 
       
  5740 		} else {
       
  5741 			if ( ! ( view instanceof Backbone.View ) ) {
       
  5742 				view.classes = [ 'media-button-' + id ].concat( view.classes || [] );
       
  5743 				view = new wp.media.view.Button( view ).render();
       
  5744 			}
       
  5745 
       
  5746 			view.controller = view.controller || this.controller;
       
  5747 
       
  5748 			this._views[ id ] = view;
       
  5749 
       
  5750 			list = view.options.priority < 0 ? 'secondary' : 'primary';
       
  5751 			this[ list ].set( id, view, options );
       
  5752 		}
       
  5753 
       
  5754 		if ( ! options.silent ) {
       
  5755 			this.refresh();
       
  5756 		}
       
  5757 
       
  5758 		return this;
       
  5759 	},
       
  5760 	/**
       
  5761 	 * @param {string} id
       
  5762 	 * @return {wp.media.view.Button}
       
  5763 	 */
       
  5764 	get: function( id ) {
       
  5765 		return this._views[ id ];
       
  5766 	},
       
  5767 	/**
       
  5768 	 * @param {string} id
       
  5769 	 * @param {Object} options
       
  5770 	 * @return {wp.media.view.Toolbar} Returns itself to allow chaining.
       
  5771 	 */
       
  5772 	unset: function( id, options ) {
       
  5773 		delete this._views[ id ];
       
  5774 		this.primary.unset( id, options );
       
  5775 		this.secondary.unset( id, options );
       
  5776 
       
  5777 		if ( ! options || ! options.silent ) {
       
  5778 			this.refresh();
       
  5779 		}
       
  5780 		return this;
       
  5781 	},
       
  5782 
       
  5783 	refresh: function() {
       
  5784 		var state = this.controller.state(),
       
  5785 			library = state.get('library'),
       
  5786 			selection = state.get('selection');
       
  5787 
       
  5788 		_.each( this._views, function( button ) {
       
  5789 			if ( ! button.model || ! button.options || ! button.options.requires ) {
       
  5790 				return;
       
  5791 			}
       
  5792 
       
  5793 			var requires = button.options.requires,
       
  5794 				disabled = false;
       
  5795 
       
  5796 			// Prevent insertion of attachments if any of them are still uploading.
       
  5797 			if ( selection && selection.models ) {
       
  5798 				disabled = _.some( selection.models, function( attachment ) {
       
  5799 					return attachment.get('uploading') === true;
       
  5800 				});
       
  5801 			}
       
  5802 
       
  5803 			if ( requires.selection && selection && ! selection.length ) {
       
  5804 				disabled = true;
       
  5805 			} else if ( requires.library && library && ! library.length ) {
       
  5806 				disabled = true;
       
  5807 			}
       
  5808 			button.model.set( 'disabled', disabled );
       
  5809 		});
       
  5810 	}
       
  5811 });
       
  5812 
       
  5813 module.exports = Toolbar;
       
  5814 
       
  5815 
       
  5816 /***/ }),
       
  5817 /* 63 */
       
  5818 /***/ (function(module, exports) {
       
  5819 
       
  5820 var Toolbar = wp.media.view.Toolbar,
       
  5821 	l10n = wp.media.view.l10n,
       
  5822 	Select;
       
  5823 
       
  5824 /**
       
  5825  * wp.media.view.Toolbar.Select
       
  5826  *
       
  5827  * @memberOf wp.media.view.Toolbar
       
  5828  *
       
  5829  * @class
       
  5830  * @augments wp.media.view.Toolbar
       
  5831  * @augments wp.media.View
       
  5832  * @augments wp.Backbone.View
       
  5833  * @augments Backbone.View
       
  5834  */
       
  5835 Select = Toolbar.extend(/** @lends wp.media.view.Toolbar.Select.prototype */{
       
  5836 	initialize: function() {
       
  5837 		var options = this.options;
       
  5838 
       
  5839 		_.bindAll( this, 'clickSelect' );
       
  5840 
       
  5841 		_.defaults( options, {
       
  5842 			event: 'select',
       
  5843 			state: false,
       
  5844 			reset: true,
       
  5845 			close: true,
       
  5846 			text:  l10n.select,
       
  5847 
       
  5848 			// Does the button rely on the selection?
       
  5849 			requires: {
       
  5850 				selection: true
       
  5851 			}
       
  5852 		});
       
  5853 
       
  5854 		options.items = _.defaults( options.items || {}, {
       
  5855 			select: {
       
  5856 				style:    'primary',
       
  5857 				text:     options.text,
       
  5858 				priority: 80,
       
  5859 				click:    this.clickSelect,
       
  5860 				requires: options.requires
       
  5861 			}
       
  5862 		});
       
  5863 		// Call 'initialize' directly on the parent class.
       
  5864 		Toolbar.prototype.initialize.apply( this, arguments );
       
  5865 	},
       
  5866 
       
  5867 	clickSelect: function() {
       
  5868 		var options = this.options,
       
  5869 			controller = this.controller;
       
  5870 
       
  5871 		if ( options.close ) {
       
  5872 			controller.close();
       
  5873 		}
       
  5874 
       
  5875 		if ( options.event ) {
       
  5876 			controller.state().trigger( options.event );
       
  5877 		}
       
  5878 
       
  5879 		if ( options.state ) {
       
  5880 			controller.setState( options.state );
       
  5881 		}
       
  5882 
       
  5883 		if ( options.reset ) {
       
  5884 			controller.reset();
       
  5885 		}
       
  5886 	}
       
  5887 });
       
  5888 
       
  5889 module.exports = Select;
       
  5890 
       
  5891 
       
  5892 /***/ }),
       
  5893 /* 64 */
       
  5894 /***/ (function(module, exports) {
       
  5895 
       
  5896 var Select = wp.media.view.Toolbar.Select,
       
  5897 	l10n = wp.media.view.l10n,
       
  5898 	Embed;
       
  5899 
       
  5900 /**
       
  5901  * wp.media.view.Toolbar.Embed
       
  5902  *
       
  5903  * @memberOf wp.media.view.Toolbar
       
  5904  *
       
  5905  * @class
       
  5906  * @augments wp.media.view.Toolbar.Select
       
  5907  * @augments wp.media.view.Toolbar
       
  5908  * @augments wp.media.View
       
  5909  * @augments wp.Backbone.View
       
  5910  * @augments Backbone.View
       
  5911  */
       
  5912 Embed = Select.extend(/** @lends wp.media.view.Toolbar.Embed.prototype */{
       
  5913 	initialize: function() {
       
  5914 		_.defaults( this.options, {
       
  5915 			text: l10n.insertIntoPost,
       
  5916 			requires: false
       
  5917 		});
       
  5918 		// Call 'initialize' directly on the parent class.
       
  5919 		Select.prototype.initialize.apply( this, arguments );
       
  5920 	},
       
  5921 
       
  5922 	refresh: function() {
       
  5923 		var url = this.controller.state().props.get('url');
       
  5924 		this.get('select').model.set( 'disabled', ! url || url === 'http://' );
       
  5925 		/**
       
  5926 		 * call 'refresh' directly on the parent class
       
  5927 		 */
       
  5928 		Select.prototype.refresh.apply( this, arguments );
       
  5929 	}
       
  5930 });
       
  5931 
       
  5932 module.exports = Embed;
       
  5933 
       
  5934 
       
  5935 /***/ }),
       
  5936 /* 65 */
       
  5937 /***/ (function(module, exports) {
       
  5938 
       
  5939 /**
       
  5940  * wp.media.view.Button
       
  5941  *
       
  5942  * @memberOf wp.media.view
       
  5943  *
       
  5944  * @class
       
  5945  * @augments wp.media.View
       
  5946  * @augments wp.Backbone.View
       
  5947  * @augments Backbone.View
       
  5948  */
       
  5949 var Button = wp.media.View.extend(/** @lends wp.media.view.Button.prototype */{
       
  5950 	tagName:    'button',
       
  5951 	className:  'media-button',
       
  5952 	attributes: { type: 'button' },
       
  5953 
       
  5954 	events: {
       
  5955 		'click': 'click'
       
  5956 	},
       
  5957 
       
  5958 	defaults: {
       
  5959 		text:     '',
       
  5960 		style:    '',
       
  5961 		size:     'large',
       
  5962 		disabled: false
       
  5963 	},
       
  5964 
       
  5965 	initialize: function() {
       
  5966 		/**
       
  5967 		 * Create a model with the provided `defaults`.
       
  5968 		 *
       
  5969 		 * @member {Backbone.Model}
       
  5970 		 */
       
  5971 		this.model = new Backbone.Model( this.defaults );
       
  5972 
       
  5973 		// If any of the `options` have a key from `defaults`, apply its
       
  5974 		// value to the `model` and remove it from the `options object.
       
  5975 		_.each( this.defaults, function( def, key ) {
       
  5976 			var value = this.options[ key ];
       
  5977 			if ( _.isUndefined( value ) ) {
       
  5978 				return;
       
  5979 			}
       
  5980 
       
  5981 			this.model.set( key, value );
       
  5982 			delete this.options[ key ];
       
  5983 		}, this );
       
  5984 
       
  5985 		this.listenTo( this.model, 'change', this.render );
       
  5986 	},
       
  5987 	/**
       
  5988 	 * @return {wp.media.view.Button} Returns itself to allow chaining.
       
  5989 	 */
       
  5990 	render: function() {
       
  5991 		var classes = [ 'button', this.className ],
       
  5992 			model = this.model.toJSON();
       
  5993 
       
  5994 		if ( model.style ) {
       
  5995 			classes.push( 'button-' + model.style );
       
  5996 		}
       
  5997 
       
  5998 		if ( model.size ) {
       
  5999 			classes.push( 'button-' + model.size );
       
  6000 		}
       
  6001 
       
  6002 		classes = _.uniq( classes.concat( this.options.classes ) );
       
  6003 		this.el.className = classes.join(' ');
       
  6004 
       
  6005 		this.$el.attr( 'disabled', model.disabled );
       
  6006 		this.$el.text( this.model.get('text') );
       
  6007 
       
  6008 		return this;
       
  6009 	},
       
  6010 	/**
       
  6011 	 * @param {Object} event
       
  6012 	 */
       
  6013 	click: function( event ) {
       
  6014 		if ( '#' === this.attributes.href ) {
       
  6015 			event.preventDefault();
       
  6016 		}
       
  6017 
       
  6018 		if ( this.options.click && ! this.model.get('disabled') ) {
       
  6019 			this.options.click.apply( this, arguments );
       
  6020 		}
       
  6021 	}
       
  6022 });
       
  6023 
       
  6024 module.exports = Button;
       
  6025 
       
  6026 
       
  6027 /***/ }),
       
  6028 /* 66 */
       
  6029 /***/ (function(module, exports) {
       
  6030 
       
  6031 var $ = Backbone.$,
       
  6032 	ButtonGroup;
       
  6033 
       
  6034 /**
       
  6035  * wp.media.view.ButtonGroup
       
  6036  *
       
  6037  * @memberOf wp.media.view
       
  6038  *
       
  6039  * @class
       
  6040  * @augments wp.media.View
       
  6041  * @augments wp.Backbone.View
       
  6042  * @augments Backbone.View
       
  6043  */
       
  6044 ButtonGroup = wp.media.View.extend(/** @lends wp.media.view.ButtonGroup.prototype */{
       
  6045 	tagName:   'div',
       
  6046 	className: 'button-group button-large media-button-group',
       
  6047 
       
  6048 	initialize: function() {
       
  6049 		/**
       
  6050 		 * @member {wp.media.view.Button[]}
       
  6051 		 */
       
  6052 		this.buttons = _.map( this.options.buttons || [], function( button ) {
       
  6053 			if ( button instanceof Backbone.View ) {
       
  6054 				return button;
       
  6055 			} else {
       
  6056 				return new wp.media.view.Button( button ).render();
       
  6057 			}
       
  6058 		});
       
  6059 
       
  6060 		delete this.options.buttons;
       
  6061 
       
  6062 		if ( this.options.classes ) {
       
  6063 			this.$el.addClass( this.options.classes );
       
  6064 		}
       
  6065 	},
       
  6066 
       
  6067 	/**
       
  6068 	 * @return {wp.media.view.ButtonGroup}
       
  6069 	 */
       
  6070 	render: function() {
       
  6071 		this.$el.html( $( _.pluck( this.buttons, 'el' ) ).detach() );
       
  6072 		return this;
       
  6073 	}
       
  6074 });
       
  6075 
       
  6076 module.exports = ButtonGroup;
       
  6077 
       
  6078 
       
  6079 /***/ }),
       
  6080 /* 67 */
       
  6081 /***/ (function(module, exports) {
       
  6082 
       
  6083 /**
       
  6084  * wp.media.view.PriorityList
       
  6085  *
       
  6086  * @memberOf wp.media.view
       
  6087  *
       
  6088  * @class
       
  6089  * @augments wp.media.View
       
  6090  * @augments wp.Backbone.View
       
  6091  * @augments Backbone.View
       
  6092  */
       
  6093 var PriorityList = wp.media.View.extend(/** @lends wp.media.view.PriorityList.prototype */{
       
  6094 	tagName:   'div',
       
  6095 
       
  6096 	initialize: function() {
       
  6097 		this._views = {};
       
  6098 
       
  6099 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
       
  6100 		delete this.options.views;
       
  6101 
       
  6102 		if ( ! this.options.silent ) {
       
  6103 			this.render();
       
  6104 		}
       
  6105 	},
       
  6106 	/**
       
  6107 	 * @param {string} id
       
  6108 	 * @param {wp.media.View|Object} view
       
  6109 	 * @param {Object} options
       
  6110 	 * @return {wp.media.view.PriorityList} Returns itself to allow chaining.
       
  6111 	 */
       
  6112 	set: function( id, view, options ) {
       
  6113 		var priority, views, index;
       
  6114 
       
  6115 		options = options || {};
       
  6116 
       
  6117 		// Accept an object with an `id` : `view` mapping.
       
  6118 		if ( _.isObject( id ) ) {
       
  6119 			_.each( id, function( view, id ) {
       
  6120 				this.set( id, view );
       
  6121 			}, this );
       
  6122 			return this;
       
  6123 		}
       
  6124 
       
  6125 		if ( ! (view instanceof Backbone.View) ) {
       
  6126 			view = this.toView( view, id, options );
       
  6127 		}
       
  6128 		view.controller = view.controller || this.controller;
       
  6129 
       
  6130 		this.unset( id );
       
  6131 
       
  6132 		priority = view.options.priority || 10;
       
  6133 		views = this.views.get() || [];
       
  6134 
       
  6135 		_.find( views, function( existing, i ) {
       
  6136 			if ( existing.options.priority > priority ) {
       
  6137 				index = i;
       
  6138 				return true;
       
  6139 			}
       
  6140 		});
       
  6141 
       
  6142 		this._views[ id ] = view;
       
  6143 		this.views.add( view, {
       
  6144 			at: _.isNumber( index ) ? index : views.length || 0
       
  6145 		});
       
  6146 
       
  6147 		return this;
       
  6148 	},
       
  6149 	/**
       
  6150 	 * @param {string} id
       
  6151 	 * @return {wp.media.View}
       
  6152 	 */
       
  6153 	get: function( id ) {
       
  6154 		return this._views[ id ];
       
  6155 	},
       
  6156 	/**
       
  6157 	 * @param {string} id
       
  6158 	 * @return {wp.media.view.PriorityList}
       
  6159 	 */
       
  6160 	unset: function( id ) {
       
  6161 		var view = this.get( id );
       
  6162 
       
  6163 		if ( view ) {
       
  6164 			view.remove();
       
  6165 		}
       
  6166 
       
  6167 		delete this._views[ id ];
       
  6168 		return this;
       
  6169 	},
       
  6170 	/**
       
  6171 	 * @param {Object} options
       
  6172 	 * @return {wp.media.View}
       
  6173 	 */
       
  6174 	toView: function( options ) {
       
  6175 		return new wp.media.View( options );
       
  6176 	}
       
  6177 });
       
  6178 
       
  6179 module.exports = PriorityList;
       
  6180 
       
  6181 
       
  6182 /***/ }),
       
  6183 /* 68 */
       
  6184 /***/ (function(module, exports) {
       
  6185 
       
  6186 var MenuItem;
       
  6187 
       
  6188 /**
       
  6189  * wp.media.view.MenuItem
       
  6190  *
       
  6191  * @memberOf wp.media.view
       
  6192  *
       
  6193  * @class
       
  6194  * @augments wp.media.View
       
  6195  * @augments wp.Backbone.View
       
  6196  * @augments Backbone.View
       
  6197  */
       
  6198 MenuItem = wp.media.View.extend(/** @lends wp.media.view.MenuItem.prototype */{
       
  6199 	tagName:   'button',
       
  6200 	className: 'media-menu-item',
       
  6201 
       
  6202 	attributes: {
       
  6203 		type: 'button',
       
  6204 		role: 'tab'
       
  6205 	},
       
  6206 
       
  6207 	events: {
       
  6208 		'click': '_click'
       
  6209 	},
       
  6210 
       
  6211 	/**
       
  6212 	 * Allows to override the click event.
       
  6213 	 */
       
  6214 	_click: function() {
       
  6215 		var clickOverride = this.options.click;
       
  6216 
       
  6217 		if ( clickOverride ) {
       
  6218 			clickOverride.call( this );
       
  6219 		} else {
       
  6220 			this.click();
       
  6221 		}
       
  6222 	},
       
  6223 
       
  6224 	click: function() {
       
  6225 		var state = this.options.state;
       
  6226 
       
  6227 		if ( state ) {
       
  6228 			this.controller.setState( state );
       
  6229 			// Toggle the menu visibility in the responsive view.
       
  6230 			this.views.parent.$el.removeClass( 'visible' ); // @todo Or hide on any click, see below.
       
  6231 		}
       
  6232 	},
       
  6233 
       
  6234 	/**
       
  6235 	 * @return {wp.media.view.MenuItem} returns itself to allow chaining.
       
  6236 	 */
       
  6237 	render: function() {
       
  6238 		var options = this.options,
       
  6239 			menuProperty = options.state || options.contentMode;
       
  6240 
       
  6241 		if ( options.text ) {
       
  6242 			this.$el.text( options.text );
       
  6243 		} else if ( options.html ) {
       
  6244 			this.$el.html( options.html );
       
  6245 		}
       
  6246 
       
  6247 		// Set the menu item ID based on the frame state associated to the menu item.
       
  6248 		this.$el.attr( 'id', 'menu-item-' + menuProperty );
       
  6249 
       
  6250 		return this;
       
  6251 	}
       
  6252 });
       
  6253 
       
  6254 module.exports = MenuItem;
       
  6255 
       
  6256 
       
  6257 /***/ }),
       
  6258 /* 69 */
       
  6259 /***/ (function(module, exports) {
       
  6260 
       
  6261 var MenuItem = wp.media.view.MenuItem,
       
  6262 	PriorityList = wp.media.view.PriorityList,
       
  6263 	Menu;
       
  6264 
       
  6265 /**
       
  6266  * wp.media.view.Menu
       
  6267  *
       
  6268  * @memberOf wp.media.view
       
  6269  *
       
  6270  * @class
       
  6271  * @augments wp.media.view.PriorityList
       
  6272  * @augments wp.media.View
       
  6273  * @augments wp.Backbone.View
       
  6274  * @augments Backbone.View
       
  6275  */
       
  6276 Menu = PriorityList.extend(/** @lends wp.media.view.Menu.prototype */{
       
  6277 	tagName:   'div',
       
  6278 	className: 'media-menu',
       
  6279 	property:  'state',
       
  6280 	ItemView:  MenuItem,
       
  6281 	region:    'menu',
       
  6282 
       
  6283 	attributes: {
       
  6284 		role:               'tablist',
       
  6285 		'aria-orientation': 'horizontal'
       
  6286 	},
       
  6287 
       
  6288 	initialize: function() {
       
  6289 		this._views = {};
       
  6290 
       
  6291 		this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
       
  6292 		delete this.options.views;
       
  6293 
       
  6294 		if ( ! this.options.silent ) {
       
  6295 			this.render();
       
  6296 		}
       
  6297 
       
  6298 		// Initialize the Focus Manager.
       
  6299 		this.focusManager = new wp.media.view.FocusManager( {
       
  6300 			el:   this.el,
       
  6301 			mode: 'tabsNavigation'
       
  6302 		} );
       
  6303 
       
  6304 		// The menu is always rendered and can be visible or hidden on some frames.
       
  6305 		this.isVisible = true;
       
  6306 	},
       
  6307 
       
  6308 	/**
       
  6309 	 * @param {Object} options
       
  6310 	 * @param {string} id
       
  6311 	 * @return {wp.media.View}
       
  6312 	 */
       
  6313 	toView: function( options, id ) {
       
  6314 		options = options || {};
       
  6315 		options[ this.property ] = options[ this.property ] || id;
       
  6316 		return new this.ItemView( options ).render();
       
  6317 	},
       
  6318 
       
  6319 	ready: function() {
       
  6320 		/**
       
  6321 		 * call 'ready' directly on the parent class
       
  6322 		 */
       
  6323 		PriorityList.prototype.ready.apply( this, arguments );
       
  6324 		this.visibility();
       
  6325 
       
  6326 		// Set up aria tabs initial attributes.
       
  6327 		this.focusManager.setupAriaTabs();
       
  6328 	},
       
  6329 
       
  6330 	set: function() {
       
  6331 		/**
       
  6332 		 * call 'set' directly on the parent class
       
  6333 		 */
       
  6334 		PriorityList.prototype.set.apply( this, arguments );
       
  6335 		this.visibility();
       
  6336 	},
       
  6337 
       
  6338 	unset: function() {
       
  6339 		/**
       
  6340 		 * call 'unset' directly on the parent class
       
  6341 		 */
       
  6342 		PriorityList.prototype.unset.apply( this, arguments );
       
  6343 		this.visibility();
       
  6344 	},
       
  6345 
       
  6346 	visibility: function() {
       
  6347 		var region = this.region,
       
  6348 			view = this.controller[ region ].get(),
       
  6349 			views = this.views.get(),
       
  6350 			hide = ! views || views.length < 2;
       
  6351 
       
  6352 		if ( this === view ) {
       
  6353 			// Flag this menu as hidden or visible.
       
  6354 			this.isVisible = ! hide;
       
  6355 			// Set or remove a CSS class to hide the menu.
       
  6356 			this.controller.$el.toggleClass( 'hide-' + region, hide );
       
  6357 		}
       
  6358 	},
       
  6359 	/**
       
  6360 	 * @param {string} id
       
  6361 	 */
       
  6362 	select: function( id ) {
       
  6363 		var view = this.get( id );
       
  6364 
       
  6365 		if ( ! view ) {
       
  6366 			return;
       
  6367 		}
       
  6368 
       
  6369 		this.deselect();
       
  6370 		view.$el.addClass('active');
       
  6371 
       
  6372 		// Set up again the aria tabs initial attributes after the menu updates.
       
  6373 		this.focusManager.setupAriaTabs();
       
  6374 	},
       
  6375 
       
  6376 	deselect: function() {
       
  6377 		this.$el.children().removeClass('active');
       
  6378 	},
       
  6379 
       
  6380 	hide: function( id ) {
       
  6381 		var view = this.get( id );
       
  6382 
       
  6383 		if ( ! view ) {
       
  6384 			return;
       
  6385 		}
       
  6386 
       
  6387 		view.$el.addClass('hidden');
       
  6388 	},
       
  6389 
       
  6390 	show: function( id ) {
       
  6391 		var view = this.get( id );
       
  6392 
       
  6393 		if ( ! view ) {
       
  6394 			return;
       
  6395 		}
       
  6396 
       
  6397 		view.$el.removeClass('hidden');
       
  6398 	}
       
  6399 });
       
  6400 
       
  6401 module.exports = Menu;
       
  6402 
       
  6403 
       
  6404 /***/ }),
       
  6405 /* 70 */
       
  6406 /***/ (function(module, exports) {
       
  6407 
       
  6408 /**
       
  6409  * wp.media.view.RouterItem
       
  6410  *
       
  6411  * @memberOf wp.media.view
       
  6412  *
       
  6413  * @class
       
  6414  * @augments wp.media.view.MenuItem
       
  6415  * @augments wp.media.View
       
  6416  * @augments wp.Backbone.View
       
  6417  * @augments Backbone.View
       
  6418  */
       
  6419 var RouterItem = wp.media.view.MenuItem.extend(/** @lends wp.media.view.RouterItem.prototype */{
       
  6420 	/**
       
  6421 	 * On click handler to activate the content region's corresponding mode.
       
  6422 	 */
       
  6423 	click: function() {
       
  6424 		var contentMode = this.options.contentMode;
       
  6425 		if ( contentMode ) {
       
  6426 			this.controller.content.mode( contentMode );
       
  6427 		}
       
  6428 	}
       
  6429 });
       
  6430 
       
  6431 module.exports = RouterItem;
       
  6432 
       
  6433 
       
  6434 /***/ }),
       
  6435 /* 71 */
       
  6436 /***/ (function(module, exports) {
       
  6437 
       
  6438 var Menu = wp.media.view.Menu,
       
  6439 	Router;
       
  6440 
       
  6441 /**
       
  6442  * wp.media.view.Router
       
  6443  *
       
  6444  * @memberOf wp.media.view
       
  6445  *
       
  6446  * @class
       
  6447  * @augments wp.media.view.Menu
       
  6448  * @augments wp.media.view.PriorityList
       
  6449  * @augments wp.media.View
       
  6450  * @augments wp.Backbone.View
       
  6451  * @augments Backbone.View
       
  6452  */
       
  6453 Router = Menu.extend(/** @lends wp.media.view.Router.prototype */{
       
  6454 	tagName:   'div',
       
  6455 	className: 'media-router',
       
  6456 	property:  'contentMode',
       
  6457 	ItemView:  wp.media.view.RouterItem,
       
  6458 	region:    'router',
       
  6459 
       
  6460 	attributes: {
       
  6461 		role:               'tablist',
       
  6462 		'aria-orientation': 'horizontal'
       
  6463 	},
       
  6464 
       
  6465 	initialize: function() {
       
  6466 		this.controller.on( 'content:render', this.update, this );
       
  6467 		// Call 'initialize' directly on the parent class.
       
  6468 		Menu.prototype.initialize.apply( this, arguments );
       
  6469 	},
       
  6470 
       
  6471 	update: function() {
       
  6472 		var mode = this.controller.content.mode();
       
  6473 		if ( mode ) {
       
  6474 			this.select( mode );
       
  6475 		}
       
  6476 	}
       
  6477 });
       
  6478 
       
  6479 module.exports = Router;
       
  6480 
       
  6481 
       
  6482 /***/ }),
       
  6483 /* 72 */
       
  6484 /***/ (function(module, exports) {
       
  6485 
       
  6486 /**
       
  6487  * wp.media.view.Sidebar
       
  6488  *
       
  6489  * @memberOf wp.media.view
       
  6490  *
       
  6491  * @class
       
  6492  * @augments wp.media.view.PriorityList
       
  6493  * @augments wp.media.View
       
  6494  * @augments wp.Backbone.View
       
  6495  * @augments Backbone.View
       
  6496  */
       
  6497 var Sidebar = wp.media.view.PriorityList.extend(/** @lends wp.media.view.Sidebar.prototype */{
       
  6498 	className: 'media-sidebar'
       
  6499 });
       
  6500 
       
  6501 module.exports = Sidebar;
       
  6502 
       
  6503 
       
  6504 /***/ }),
       
  6505 /* 73 */
       
  6506 /***/ (function(module, exports) {
  9568 /***/ (function(module, exports) {
  6507 
  9569 
  6508 var View = wp.media.View,
  9570 var View = wp.media.View,
  6509 	$ = jQuery,
  9571 	$ = jQuery,
  6510 	Attachment;
  9572 	Attachment;
  7096 
 10158 
  7097 module.exports = Attachment;
 10159 module.exports = Attachment;
  7098 
 10160 
  7099 
 10161 
  7100 /***/ }),
 10162 /***/ }),
  7101 /* 74 */
 10163 
       
 10164 /***/ "t3nl":
  7102 /***/ (function(module, exports) {
 10165 /***/ (function(module, exports) {
  7103 
 10166 
  7104 /**
 10167 /**
  7105  * wp.media.view.Attachment.Library
 10168  * wp.media.view.Iframe
  7106  *
       
  7107  * @memberOf wp.media.view.Attachment
       
  7108  *
       
  7109  * @class
       
  7110  * @augments wp.media.view.Attachment
       
  7111  * @augments wp.media.View
       
  7112  * @augments wp.Backbone.View
       
  7113  * @augments Backbone.View
       
  7114  */
       
  7115 var Library = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Library.prototype */{
       
  7116 	buttons: {
       
  7117 		check: true
       
  7118 	}
       
  7119 });
       
  7120 
       
  7121 module.exports = Library;
       
  7122 
       
  7123 
       
  7124 /***/ }),
       
  7125 /* 75 */
       
  7126 /***/ (function(module, exports) {
       
  7127 
       
  7128 /**
       
  7129  * wp.media.view.Attachment.EditLibrary
       
  7130  *
       
  7131  * @memberOf wp.media.view.Attachment
       
  7132  *
       
  7133  * @class
       
  7134  * @augments wp.media.view.Attachment
       
  7135  * @augments wp.media.View
       
  7136  * @augments wp.Backbone.View
       
  7137  * @augments Backbone.View
       
  7138  */
       
  7139 var EditLibrary = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.EditLibrary.prototype */{
       
  7140 	buttons: {
       
  7141 		close: true
       
  7142 	}
       
  7143 });
       
  7144 
       
  7145 module.exports = EditLibrary;
       
  7146 
       
  7147 
       
  7148 /***/ }),
       
  7149 /* 76 */
       
  7150 /***/ (function(module, exports) {
       
  7151 
       
  7152 var View = wp.media.View,
       
  7153 	$ = jQuery,
       
  7154 	Attachments;
       
  7155 
       
  7156 Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{
       
  7157 	tagName:   'ul',
       
  7158 	className: 'attachments',
       
  7159 
       
  7160 	attributes: {
       
  7161 		tabIndex: -1
       
  7162 	},
       
  7163 
       
  7164 	/**
       
  7165 	 * Represents the overview of attachments in the Media Library.
       
  7166 	 *
       
  7167 	 * The constructor binds events to the collection this view represents when
       
  7168 	 * adding or removing attachments or resetting the entire collection.
       
  7169 	 *
       
  7170 	 * @since 3.5.0
       
  7171 	 *
       
  7172 	 * @constructs
       
  7173 	 * @memberof wp.media.view
       
  7174 	 *
       
  7175 	 * @augments wp.media.View
       
  7176 	 *
       
  7177 	 * @listens collection:add
       
  7178 	 * @listens collection:remove
       
  7179 	 * @listens collection:reset
       
  7180 	 * @listens controller:library:selection:add
       
  7181 	 * @listens scrollElement:scroll
       
  7182 	 * @listens this:ready
       
  7183 	 * @listens controller:open
       
  7184 	 */
       
  7185 	initialize: function() {
       
  7186 		this.el.id = _.uniqueId('__attachments-view-');
       
  7187 
       
  7188 		/**
       
  7189 		 * @param refreshSensitivity The time in milliseconds to throttle the scroll
       
  7190 		 *                           handler.
       
  7191 		 * @param refreshThreshold   The amount of pixels that should be scrolled before
       
  7192 		 *                           loading more attachments from the server.
       
  7193 		 * @param AttachmentView     The view class to be used for models in the
       
  7194 		 *                           collection.
       
  7195 		 * @param sortable           A jQuery sortable options object
       
  7196 		 *                           ( http://api.jqueryui.com/sortable/ ).
       
  7197 		 * @param resize             A boolean indicating whether or not to listen to
       
  7198 		 *                           resize events.
       
  7199 		 * @param idealColumnWidth   The width in pixels which a column should have when
       
  7200 		 *                           calculating the total number of columns.
       
  7201 		 */
       
  7202 		_.defaults( this.options, {
       
  7203 			refreshSensitivity: wp.media.isTouchDevice ? 300 : 200,
       
  7204 			refreshThreshold:   3,
       
  7205 			AttachmentView:     wp.media.view.Attachment,
       
  7206 			sortable:           false,
       
  7207 			resize:             true,
       
  7208 			idealColumnWidth:   $( window ).width() < 640 ? 135 : 150
       
  7209 		});
       
  7210 
       
  7211 		this._viewsByCid = {};
       
  7212 		this.$window = $( window );
       
  7213 		this.resizeEvent = 'resize.media-modal-columns';
       
  7214 
       
  7215 		this.collection.on( 'add', function( attachment ) {
       
  7216 			this.views.add( this.createAttachmentView( attachment ), {
       
  7217 				at: this.collection.indexOf( attachment )
       
  7218 			});
       
  7219 		}, this );
       
  7220 
       
  7221 		/*
       
  7222 		 * Find the view to be removed, delete it and call the remove function to clear
       
  7223 		 * any set event handlers.
       
  7224 		 */
       
  7225 		this.collection.on( 'remove', function( attachment ) {
       
  7226 			var view = this._viewsByCid[ attachment.cid ];
       
  7227 			delete this._viewsByCid[ attachment.cid ];
       
  7228 
       
  7229 			if ( view ) {
       
  7230 				view.remove();
       
  7231 			}
       
  7232 		}, this );
       
  7233 
       
  7234 		this.collection.on( 'reset', this.render, this );
       
  7235 
       
  7236 		this.controller.on( 'library:selection:add', this.attachmentFocus, this );
       
  7237 
       
  7238 		// Throttle the scroll handler and bind this.
       
  7239 		this.scroll = _.chain( this.scroll ).bind( this ).throttle( this.options.refreshSensitivity ).value();
       
  7240 
       
  7241 		this.options.scrollElement = this.options.scrollElement || this.el;
       
  7242 		$( this.options.scrollElement ).on( 'scroll', this.scroll );
       
  7243 
       
  7244 		this.initSortable();
       
  7245 
       
  7246 		_.bindAll( this, 'setColumns' );
       
  7247 
       
  7248 		if ( this.options.resize ) {
       
  7249 			this.on( 'ready', this.bindEvents );
       
  7250 			this.controller.on( 'open', this.setColumns );
       
  7251 
       
  7252 			/*
       
  7253 			 * Call this.setColumns() after this view has been rendered in the
       
  7254 			 * DOM so attachments get proper width applied.
       
  7255 			 */
       
  7256 			_.defer( this.setColumns, this );
       
  7257 		}
       
  7258 	},
       
  7259 
       
  7260 	/**
       
  7261 	 * Listens to the resizeEvent on the window.
       
  7262 	 *
       
  7263 	 * Adjusts the amount of columns accordingly. First removes any existing event
       
  7264 	 * handlers to prevent duplicate listeners.
       
  7265 	 *
       
  7266 	 * @since 4.0.0
       
  7267 	 *
       
  7268 	 * @listens window:resize
       
  7269 	 *
       
  7270 	 * @return {void}
       
  7271 	 */
       
  7272 	bindEvents: function() {
       
  7273 		this.$window.off( this.resizeEvent ).on( this.resizeEvent, _.debounce( this.setColumns, 50 ) );
       
  7274 	},
       
  7275 
       
  7276 	/**
       
  7277 	 * Focuses the first item in the collection.
       
  7278 	 *
       
  7279 	 * @since 4.0.0
       
  7280 	 *
       
  7281 	 * @return {void}
       
  7282 	 */
       
  7283 	attachmentFocus: function() {
       
  7284 		/*
       
  7285 		 * @todo When uploading new attachments, this tries to move focus to
       
  7286 		 * the attachments grid. Actually, a progress bar gets initially displayed
       
  7287 		 * and then updated when uploading completes, so focus is lost.
       
  7288 		 * Additionally: this view is used for both the attachments list and
       
  7289 		 * the list of selected attachments in the bottom media toolbar. Thus, when
       
  7290 		 * uploading attachments, it is called twice and returns two different `this`.
       
  7291 		 * `this.columns` is truthy within the modal.
       
  7292 		 */
       
  7293 		if ( this.columns ) {
       
  7294 			// Move focus to the grid list within the modal.
       
  7295 			this.$el.focus();
       
  7296 		}
       
  7297 	},
       
  7298 
       
  7299 	/**
       
  7300 	 * Restores focus to the selected item in the collection.
       
  7301 	 *
       
  7302 	 * Moves focus back to the first selected attachment in the grid. Used when
       
  7303 	 * tabbing backwards from the attachment details sidebar.
       
  7304 	 * See media.view.AttachmentsBrowser.
       
  7305 	 *
       
  7306 	 * @since 4.0.0
       
  7307 	 *
       
  7308 	 * @return {void}
       
  7309 	 */
       
  7310 	restoreFocus: function() {
       
  7311 		this.$( 'li.selected:first' ).focus();
       
  7312 	},
       
  7313 
       
  7314 	/**
       
  7315 	 * Handles events for arrow key presses.
       
  7316 	 *
       
  7317 	 * Focuses the attachment in the direction of the used arrow key if it exists.
       
  7318 	 *
       
  7319 	 * @since 4.0.0
       
  7320 	 *
       
  7321 	 * @param {KeyboardEvent} event The keyboard event that triggered this function.
       
  7322 	 *
       
  7323 	 * @return {void}
       
  7324 	 */
       
  7325 	arrowEvent: function( event ) {
       
  7326 		var attachments = this.$el.children( 'li' ),
       
  7327 			perRow = this.columns,
       
  7328 			index = attachments.filter( ':focus' ).index(),
       
  7329 			row = ( index + 1 ) <= perRow ? 1 : Math.ceil( ( index + 1 ) / perRow );
       
  7330 
       
  7331 		if ( index === -1 ) {
       
  7332 			return;
       
  7333 		}
       
  7334 
       
  7335 		// Left arrow = 37.
       
  7336 		if ( 37 === event.keyCode ) {
       
  7337 			if ( 0 === index ) {
       
  7338 				return;
       
  7339 			}
       
  7340 			attachments.eq( index - 1 ).focus();
       
  7341 		}
       
  7342 
       
  7343 		// Up arrow = 38.
       
  7344 		if ( 38 === event.keyCode ) {
       
  7345 			if ( 1 === row ) {
       
  7346 				return;
       
  7347 			}
       
  7348 			attachments.eq( index - perRow ).focus();
       
  7349 		}
       
  7350 
       
  7351 		// Right arrow = 39.
       
  7352 		if ( 39 === event.keyCode ) {
       
  7353 			if ( attachments.length === index ) {
       
  7354 				return;
       
  7355 			}
       
  7356 			attachments.eq( index + 1 ).focus();
       
  7357 		}
       
  7358 
       
  7359 		// Down arrow = 40.
       
  7360 		if ( 40 === event.keyCode ) {
       
  7361 			if ( Math.ceil( attachments.length / perRow ) === row ) {
       
  7362 				return;
       
  7363 			}
       
  7364 			attachments.eq( index + perRow ).focus();
       
  7365 		}
       
  7366 	},
       
  7367 
       
  7368 	/**
       
  7369 	 * Clears any set event handlers.
       
  7370 	 *
       
  7371 	 * @since 3.5.0
       
  7372 	 *
       
  7373 	 * @return {void}
       
  7374 	 */
       
  7375 	dispose: function() {
       
  7376 		this.collection.props.off( null, null, this );
       
  7377 		if ( this.options.resize ) {
       
  7378 			this.$window.off( this.resizeEvent );
       
  7379 		}
       
  7380 
       
  7381 		// Call 'dispose' directly on the parent class.
       
  7382 		View.prototype.dispose.apply( this, arguments );
       
  7383 	},
       
  7384 
       
  7385 	/**
       
  7386 	 * Calculates the amount of columns.
       
  7387 	 *
       
  7388 	 * Calculates the amount of columns and sets it on the data-columns attribute
       
  7389 	 * of .media-frame-content.
       
  7390 	 *
       
  7391 	 * @since 4.0.0
       
  7392 	 *
       
  7393 	 * @return {void}
       
  7394 	 */
       
  7395 	setColumns: function() {
       
  7396 		var prev = this.columns,
       
  7397 			width = this.$el.width();
       
  7398 
       
  7399 		if ( width ) {
       
  7400 			this.columns = Math.min( Math.round( width / this.options.idealColumnWidth ), 12 ) || 1;
       
  7401 
       
  7402 			if ( ! prev || prev !== this.columns ) {
       
  7403 				this.$el.closest( '.media-frame-content' ).attr( 'data-columns', this.columns );
       
  7404 			}
       
  7405 		}
       
  7406 	},
       
  7407 
       
  7408 	/**
       
  7409 	 * Initializes jQuery sortable on the attachment list.
       
  7410 	 *
       
  7411 	 * Fails gracefully if jQuery sortable doesn't exist or isn't passed
       
  7412 	 * in the options.
       
  7413 	 *
       
  7414 	 * @since 3.5.0
       
  7415 	 *
       
  7416 	 * @fires collection:reset
       
  7417 	 *
       
  7418 	 * @return {void}
       
  7419 	 */
       
  7420 	initSortable: function() {
       
  7421 		var collection = this.collection;
       
  7422 
       
  7423 		if ( ! this.options.sortable || ! $.fn.sortable ) {
       
  7424 			return;
       
  7425 		}
       
  7426 
       
  7427 		this.$el.sortable( _.extend({
       
  7428 			// If the `collection` has a `comparator`, disable sorting.
       
  7429 			disabled: !! collection.comparator,
       
  7430 
       
  7431 			/*
       
  7432 			 * Change the position of the attachment as soon as the mouse pointer
       
  7433 			 * overlaps a thumbnail.
       
  7434 			 */
       
  7435 			tolerance: 'pointer',
       
  7436 
       
  7437 			// Record the initial `index` of the dragged model.
       
  7438 			start: function( event, ui ) {
       
  7439 				ui.item.data('sortableIndexStart', ui.item.index());
       
  7440 			},
       
  7441 
       
  7442 			/*
       
  7443 			 * Update the model's index in the collection. Do so silently, as the view
       
  7444 			 * is already accurate.
       
  7445 			 */
       
  7446 			update: function( event, ui ) {
       
  7447 				var model = collection.at( ui.item.data('sortableIndexStart') ),
       
  7448 					comparator = collection.comparator;
       
  7449 
       
  7450 				// Temporarily disable the comparator to prevent `add`
       
  7451 				// from re-sorting.
       
  7452 				delete collection.comparator;
       
  7453 
       
  7454 				// Silently shift the model to its new index.
       
  7455 				collection.remove( model, {
       
  7456 					silent: true
       
  7457 				});
       
  7458 				collection.add( model, {
       
  7459 					silent: true,
       
  7460 					at:     ui.item.index()
       
  7461 				});
       
  7462 
       
  7463 				// Restore the comparator.
       
  7464 				collection.comparator = comparator;
       
  7465 
       
  7466 				// Fire the `reset` event to ensure other collections sync.
       
  7467 				collection.trigger( 'reset', collection );
       
  7468 
       
  7469 				// If the collection is sorted by menu order, update the menu order.
       
  7470 				collection.saveMenuOrder();
       
  7471 			}
       
  7472 		}, this.options.sortable ) );
       
  7473 
       
  7474 		/*
       
  7475 		 * If the `orderby` property is changed on the `collection`,
       
  7476 		 * check to see if we have a `comparator`. If so, disable sorting.
       
  7477 		 */
       
  7478 		collection.props.on( 'change:orderby', function() {
       
  7479 			this.$el.sortable( 'option', 'disabled', !! collection.comparator );
       
  7480 		}, this );
       
  7481 
       
  7482 		this.collection.props.on( 'change:orderby', this.refreshSortable, this );
       
  7483 		this.refreshSortable();
       
  7484 	},
       
  7485 
       
  7486 	/**
       
  7487 	 * Disables jQuery sortable if collection has a comparator or collection.orderby
       
  7488 	 * equals menuOrder.
       
  7489 	 *
       
  7490 	 * @since 3.5.0
       
  7491 	 *
       
  7492 	 * @return {void}
       
  7493 	 */
       
  7494 	refreshSortable: function() {
       
  7495 		if ( ! this.options.sortable || ! $.fn.sortable ) {
       
  7496 			return;
       
  7497 		}
       
  7498 
       
  7499 		var collection = this.collection,
       
  7500 			orderby = collection.props.get('orderby'),
       
  7501 			enabled = 'menuOrder' === orderby || ! collection.comparator;
       
  7502 
       
  7503 		this.$el.sortable( 'option', 'disabled', ! enabled );
       
  7504 	},
       
  7505 
       
  7506 	/**
       
  7507 	 * Creates a new view for an attachment and adds it to _viewsByCid.
       
  7508 	 *
       
  7509 	 * @since 3.5.0
       
  7510 	 *
       
  7511 	 * @param {wp.media.model.Attachment} attachment
       
  7512 	 *
       
  7513 	 * @return {wp.media.View} The created view.
       
  7514 	 */
       
  7515 	createAttachmentView: function( attachment ) {
       
  7516 		var view = new this.options.AttachmentView({
       
  7517 			controller:           this.controller,
       
  7518 			model:                attachment,
       
  7519 			collection:           this.collection,
       
  7520 			selection:            this.options.selection
       
  7521 		});
       
  7522 
       
  7523 		return this._viewsByCid[ attachment.cid ] = view;
       
  7524 	},
       
  7525 
       
  7526 	/**
       
  7527 	 * Prepares view for display.
       
  7528 	 *
       
  7529 	 * Creates views for every attachment in collection if the collection is not
       
  7530 	 * empty, otherwise clears all views and loads more attachments.
       
  7531 	 *
       
  7532 	 * @since 3.5.0
       
  7533 	 *
       
  7534 	 * @return {void}
       
  7535 	 */
       
  7536 	prepare: function() {
       
  7537 		if ( this.collection.length ) {
       
  7538 			this.views.set( this.collection.map( this.createAttachmentView, this ) );
       
  7539 		} else {
       
  7540 			this.views.unset();
       
  7541 			this.collection.more().done( this.scroll );
       
  7542 		}
       
  7543 	},
       
  7544 
       
  7545 	/**
       
  7546 	 * Triggers the scroll function to check if we should query for additional
       
  7547 	 * attachments right away.
       
  7548 	 *
       
  7549 	 * @since 3.5.0
       
  7550 	 *
       
  7551 	 * @return {void}
       
  7552 	 */
       
  7553 	ready: function() {
       
  7554 		this.scroll();
       
  7555 	},
       
  7556 
       
  7557 	/**
       
  7558 	 * Handles scroll events.
       
  7559 	 *
       
  7560 	 * Shows the spinner if we're close to the bottom. Loads more attachments from
       
  7561 	 * server if we're {refreshThreshold} times away from the bottom.
       
  7562 	 *
       
  7563 	 * @since 3.5.0
       
  7564 	 *
       
  7565 	 * @return {void}
       
  7566 	 */
       
  7567 	scroll: function() {
       
  7568 		var view = this,
       
  7569 			el = this.options.scrollElement,
       
  7570 			scrollTop = el.scrollTop,
       
  7571 			toolbar;
       
  7572 
       
  7573 		/*
       
  7574 		 * The scroll event occurs on the document, but the element that should be
       
  7575 		 * checked is the document body.
       
  7576 		 */
       
  7577 		if ( el === document ) {
       
  7578 			el = document.body;
       
  7579 			scrollTop = $(document).scrollTop();
       
  7580 		}
       
  7581 
       
  7582 		if ( ! $(el).is(':visible') || ! this.collection.hasMore() ) {
       
  7583 			return;
       
  7584 		}
       
  7585 
       
  7586 		toolbar = this.views.parent.toolbar;
       
  7587 
       
  7588 		// Show the spinner only if we are close to the bottom.
       
  7589 		if ( el.scrollHeight - ( scrollTop + el.clientHeight ) < el.clientHeight / 3 ) {
       
  7590 			toolbar.get('spinner').show();
       
  7591 		}
       
  7592 
       
  7593 		if ( el.scrollHeight < scrollTop + ( el.clientHeight * this.options.refreshThreshold ) ) {
       
  7594 			this.collection.more().done(function() {
       
  7595 				view.scroll();
       
  7596 				toolbar.get('spinner').hide();
       
  7597 			});
       
  7598 		}
       
  7599 	}
       
  7600 });
       
  7601 
       
  7602 module.exports = Attachments;
       
  7603 
       
  7604 
       
  7605 /***/ }),
       
  7606 /* 77 */
       
  7607 /***/ (function(module, exports) {
       
  7608 
       
  7609 var Search;
       
  7610 
       
  7611 /**
       
  7612  * wp.media.view.Search
       
  7613  *
 10169  *
  7614  * @memberOf wp.media.view
 10170  * @memberOf wp.media.view
  7615  *
 10171  *
  7616  * @class
 10172  * @class
  7617  * @augments wp.media.View
 10173  * @augments wp.media.View
  7618  * @augments wp.Backbone.View
 10174  * @augments wp.Backbone.View
  7619  * @augments Backbone.View
 10175  * @augments Backbone.View
  7620  */
 10176  */
  7621 Search = wp.media.View.extend(/** @lends wp.media.view.Search.prototype */{
 10177 var Iframe = wp.media.View.extend(/** @lends wp.media.view.Iframe.prototype */{
  7622 	tagName:   'input',
 10178 	className: 'media-iframe',
  7623 	className: 'search',
 10179 	/**
  7624 	id:        'media-search-input',
 10180 	 * @return {wp.media.view.Iframe} Returns itself to allow chaining.
  7625 
       
  7626 	attributes: {
       
  7627 		type: 'search'
       
  7628 	},
       
  7629 
       
  7630 	events: {
       
  7631 		'input': 'search'
       
  7632 	},
       
  7633 
       
  7634 	/**
       
  7635 	 * @return {wp.media.view.Search} Returns itself to allow chaining.
       
  7636 	 */
 10181 	 */
  7637 	render: function() {
 10182 	render: function() {
  7638 		this.el.value = this.model.escape('search');
 10183 		this.views.detach();
       
 10184 		this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
       
 10185 		this.views.render();
  7639 		return this;
 10186 		return this;
  7640 	},
 10187 	}
  7641 
       
  7642 	search: _.debounce( function( event ) {
       
  7643 		var searchTerm = event.target.value.trim();
       
  7644 
       
  7645 		// Trigger the search only after 2 ASCII characters.
       
  7646 		if ( searchTerm && searchTerm.length > 1 ) {
       
  7647 			this.model.set( 'search', searchTerm );
       
  7648 		} else {
       
  7649 			this.model.unset( 'search' );
       
  7650 		}
       
  7651 	}, 500 )
       
  7652 });
 10188 });
  7653 
 10189 
  7654 module.exports = Search;
 10190 module.exports = Iframe;
  7655 
 10191 
  7656 
 10192 
  7657 /***/ }),
 10193 /***/ }),
  7658 /* 78 */
 10194 
       
 10195 /***/ "tg/Y":
       
 10196 /***/ (function(module, exports, __webpack_require__) {
       
 10197 
       
 10198 /**
       
 10199  * @output wp-includes/js/media-views.js
       
 10200  */
       
 10201 
       
 10202 var media = wp.media,
       
 10203 	$ = jQuery,
       
 10204 	l10n;
       
 10205 
       
 10206 media.isTouchDevice = ( 'ontouchend' in document );
       
 10207 
       
 10208 // Link any localized strings.
       
 10209 l10n = media.view.l10n = window._wpMediaViewsL10n || {};
       
 10210 
       
 10211 // Link any settings.
       
 10212 media.view.settings = l10n.settings || {};
       
 10213 delete l10n.settings;
       
 10214 
       
 10215 // Copy the `post` setting over to the model settings.
       
 10216 media.model.settings.post = media.view.settings.post;
       
 10217 
       
 10218 // Check if the browser supports CSS 3.0 transitions.
       
 10219 $.support.transition = (function(){
       
 10220 	var style = document.documentElement.style,
       
 10221 		transitions = {
       
 10222 			WebkitTransition: 'webkitTransitionEnd',
       
 10223 			MozTransition:    'transitionend',
       
 10224 			OTransition:      'oTransitionEnd otransitionend',
       
 10225 			transition:       'transitionend'
       
 10226 		}, transition;
       
 10227 
       
 10228 	transition = _.find( _.keys( transitions ), function( transition ) {
       
 10229 		return ! _.isUndefined( style[ transition ] );
       
 10230 	});
       
 10231 
       
 10232 	return transition && {
       
 10233 		end: transitions[ transition ]
       
 10234 	};
       
 10235 }());
       
 10236 
       
 10237 /**
       
 10238  * A shared event bus used to provide events into
       
 10239  * the media workflows that 3rd-party devs can use to hook
       
 10240  * in.
       
 10241  */
       
 10242 media.events = _.extend( {}, Backbone.Events );
       
 10243 
       
 10244 /**
       
 10245  * Makes it easier to bind events using transitions.
       
 10246  *
       
 10247  * @param {string} selector
       
 10248  * @param {number} sensitivity
       
 10249  * @return {Promise}
       
 10250  */
       
 10251 media.transition = function( selector, sensitivity ) {
       
 10252 	var deferred = $.Deferred();
       
 10253 
       
 10254 	sensitivity = sensitivity || 2000;
       
 10255 
       
 10256 	if ( $.support.transition ) {
       
 10257 		if ( ! (selector instanceof $) ) {
       
 10258 			selector = $( selector );
       
 10259 		}
       
 10260 
       
 10261 		// Resolve the deferred when the first element finishes animating.
       
 10262 		selector.first().one( $.support.transition.end, deferred.resolve );
       
 10263 
       
 10264 		// Just in case the event doesn't trigger, fire a callback.
       
 10265 		_.delay( deferred.resolve, sensitivity );
       
 10266 
       
 10267 	// Otherwise, execute on the spot.
       
 10268 	} else {
       
 10269 		deferred.resolve();
       
 10270 	}
       
 10271 
       
 10272 	return deferred.promise();
       
 10273 };
       
 10274 
       
 10275 media.controller.Region = __webpack_require__( "WiNq" );
       
 10276 media.controller.StateMachine = __webpack_require__( "U3Se" );
       
 10277 media.controller.State = __webpack_require__( "M5ZC" );
       
 10278 
       
 10279 media.selectionSync = __webpack_require__( "PgTd" );
       
 10280 media.controller.Library = __webpack_require__( "F/kE" );
       
 10281 media.controller.ImageDetails = __webpack_require__( "IkWq" );
       
 10282 media.controller.GalleryEdit = __webpack_require__( "99yY" );
       
 10283 media.controller.GalleryAdd = __webpack_require__( "ng6N" );
       
 10284 media.controller.CollectionEdit = __webpack_require__( "Mt+m" );
       
 10285 media.controller.CollectionAdd = __webpack_require__( "iipZ" );
       
 10286 media.controller.FeaturedImage = __webpack_require__( "I7TD" );
       
 10287 media.controller.ReplaceImage = __webpack_require__( "aBqq" );
       
 10288 media.controller.EditImage = __webpack_require__( "4tHu" );
       
 10289 media.controller.MediaLibrary = __webpack_require__( "mVaH" );
       
 10290 media.controller.Embed = __webpack_require__( "qe5n" );
       
 10291 media.controller.Cropper = __webpack_require__( "M+xU" );
       
 10292 media.controller.CustomizeImageCropper = __webpack_require__( "eqTc" );
       
 10293 media.controller.SiteIconCropper = __webpack_require__( "W+32" );
       
 10294 
       
 10295 media.View = __webpack_require__( "Bbnu" );
       
 10296 media.view.Frame = __webpack_require__( "LGdN" );
       
 10297 media.view.MediaFrame = __webpack_require__( "Pt9x" );
       
 10298 media.view.MediaFrame.Select = __webpack_require__( "fYN4" );
       
 10299 media.view.MediaFrame.Post = __webpack_require__( "6B7g" );
       
 10300 media.view.MediaFrame.ImageDetails = __webpack_require__( "VIJ9" );
       
 10301 media.view.Modal = __webpack_require__( "gOpb" );
       
 10302 media.view.FocusManager = __webpack_require__( "3nJM" );
       
 10303 media.view.UploaderWindow = __webpack_require__( "S4jH" );
       
 10304 media.view.EditorUploader = __webpack_require__( "GXkx" );
       
 10305 media.view.UploaderInline = __webpack_require__( "7Bpz" );
       
 10306 media.view.UploaderStatus = __webpack_require__( "NguE" );
       
 10307 media.view.UploaderStatusError = __webpack_require__( "ZeG4" );
       
 10308 media.view.Toolbar = __webpack_require__( "2NU8" );
       
 10309 media.view.Toolbar.Select = __webpack_require__( "IgEq" );
       
 10310 media.view.Toolbar.Embed = __webpack_require__( "xQvM" );
       
 10311 media.view.Button = __webpack_require__( "LZpE" );
       
 10312 media.view.ButtonGroup = __webpack_require__( "z/+l" );
       
 10313 media.view.PriorityList = __webpack_require__( "NjyZ" );
       
 10314 media.view.MenuItem = __webpack_require__( "dpRc" );
       
 10315 media.view.Menu = __webpack_require__( "Ju2C" );
       
 10316 media.view.RouterItem = __webpack_require__( "Q9T/" );
       
 10317 media.view.Router = __webpack_require__( "EVvK" );
       
 10318 media.view.Sidebar = __webpack_require__( "9ARG" );
       
 10319 media.view.Attachment = __webpack_require__( "sULL" );
       
 10320 media.view.Attachment.Library = __webpack_require__( "2jku" );
       
 10321 media.view.Attachment.EditLibrary = __webpack_require__( "EvXF" );
       
 10322 media.view.Attachments = __webpack_require__( "ojD6" );
       
 10323 media.view.Search = __webpack_require__( "ZgZ7" );
       
 10324 media.view.AttachmentFilters = __webpack_require__( "1S4+" );
       
 10325 media.view.DateFilter = __webpack_require__( "VkcK" );
       
 10326 media.view.AttachmentFilters.Uploaded = __webpack_require__( "4jjk" );
       
 10327 media.view.AttachmentFilters.All = __webpack_require__( "KerO" );
       
 10328 media.view.AttachmentsBrowser = __webpack_require__( "72mI" );
       
 10329 media.view.Selection = __webpack_require__( "04Ix" );
       
 10330 media.view.Attachment.Selection = __webpack_require__( "yGM1" );
       
 10331 media.view.Attachments.Selection = __webpack_require__( "wfCN" );
       
 10332 media.view.Attachment.EditSelection = __webpack_require__( "P6DV" );
       
 10333 media.view.Settings = __webpack_require__( "nwwF" );
       
 10334 media.view.Settings.AttachmentDisplay = __webpack_require__( "2AvB" );
       
 10335 media.view.Settings.Gallery = __webpack_require__( "umxe" );
       
 10336 media.view.Settings.Playlist = __webpack_require__( "76BF" );
       
 10337 media.view.Attachment.Details = __webpack_require__( "iupV" );
       
 10338 media.view.AttachmentCompat = __webpack_require__( "LND6" );
       
 10339 media.view.Iframe = __webpack_require__( "t3nl" );
       
 10340 media.view.Embed = __webpack_require__( "VMHs" );
       
 10341 media.view.Label = __webpack_require__( "V6sy" );
       
 10342 media.view.EmbedUrl = __webpack_require__( "+mQJ" );
       
 10343 media.view.EmbedLink = __webpack_require__( "JecU" );
       
 10344 media.view.EmbedImage = __webpack_require__( "+B8m" );
       
 10345 media.view.ImageDetails = __webpack_require__( "GXJ6" );
       
 10346 media.view.Cropper = __webpack_require__( "Vh02" );
       
 10347 media.view.SiteIconCropper = __webpack_require__( "UmHM" );
       
 10348 media.view.SiteIconPreview = __webpack_require__( "d3xu" );
       
 10349 media.view.EditImage = __webpack_require__( "ibOK" );
       
 10350 media.view.Spinner = __webpack_require__( "cH3P" );
       
 10351 media.view.Heading = __webpack_require__( "l2j4" );
       
 10352 
       
 10353 
       
 10354 /***/ }),
       
 10355 
       
 10356 /***/ "umxe":
  7659 /***/ (function(module, exports) {
 10357 /***/ (function(module, exports) {
  7660 
 10358 
  7661 var $ = jQuery,
       
  7662 	AttachmentFilters;
       
  7663 
       
  7664 /**
 10359 /**
  7665  * wp.media.view.AttachmentFilters
 10360  * wp.media.view.Settings.Gallery
  7666  *
 10361  *
  7667  * @memberOf wp.media.view
 10362  * @memberOf wp.media.view.Settings
  7668  *
 10363  *
  7669  * @class
 10364  * @class
       
 10365  * @augments wp.media.view.Settings
  7670  * @augments wp.media.View
 10366  * @augments wp.media.View
  7671  * @augments wp.Backbone.View
 10367  * @augments wp.Backbone.View
  7672  * @augments Backbone.View
 10368  * @augments Backbone.View
  7673  */
 10369  */
  7674 AttachmentFilters = wp.media.View.extend(/** @lends wp.media.view.AttachmentFilters.prototype */{
 10370 var Gallery = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Gallery.prototype */{
  7675 	tagName:   'select',
 10371 	className: 'collection-settings gallery-settings',
  7676 	className: 'attachment-filters',
 10372 	template:  wp.template('gallery-settings')
  7677 	id:        'media-attachment-filters',
       
  7678 
       
  7679 	events: {
       
  7680 		change: 'change'
       
  7681 	},
       
  7682 
       
  7683 	keys: [],
       
  7684 
       
  7685 	initialize: function() {
       
  7686 		this.createFilters();
       
  7687 		_.extend( this.filters, this.options.filters );
       
  7688 
       
  7689 		// Build `<option>` elements.
       
  7690 		this.$el.html( _.chain( this.filters ).map( function( filter, value ) {
       
  7691 			return {
       
  7692 				el: $( '<option></option>' ).val( value ).html( filter.text )[0],
       
  7693 				priority: filter.priority || 50
       
  7694 			};
       
  7695 		}, this ).sortBy('priority').pluck('el').value() );
       
  7696 
       
  7697 		this.listenTo( this.model, 'change', this.select );
       
  7698 		this.select();
       
  7699 	},
       
  7700 
       
  7701 	/**
       
  7702 	 * @abstract
       
  7703 	 */
       
  7704 	createFilters: function() {
       
  7705 		this.filters = {};
       
  7706 	},
       
  7707 
       
  7708 	/**
       
  7709 	 * When the selected filter changes, update the Attachment Query properties to match.
       
  7710 	 */
       
  7711 	change: function() {
       
  7712 		var filter = this.filters[ this.el.value ];
       
  7713 		if ( filter ) {
       
  7714 			this.model.set( filter.props );
       
  7715 		}
       
  7716 	},
       
  7717 
       
  7718 	select: function() {
       
  7719 		var model = this.model,
       
  7720 			value = 'all',
       
  7721 			props = model.toJSON();
       
  7722 
       
  7723 		_.find( this.filters, function( filter, id ) {
       
  7724 			var equal = _.all( filter.props, function( prop, key ) {
       
  7725 				return prop === ( _.isUndefined( props[ key ] ) ? null : props[ key ] );
       
  7726 			});
       
  7727 
       
  7728 			if ( equal ) {
       
  7729 				return value = id;
       
  7730 			}
       
  7731 		});
       
  7732 
       
  7733 		this.$el.val( value );
       
  7734 	}
       
  7735 });
 10373 });
  7736 
 10374 
  7737 module.exports = AttachmentFilters;
 10375 module.exports = Gallery;
  7738 
 10376 
  7739 
 10377 
  7740 /***/ }),
 10378 /***/ }),
  7741 /* 79 */
 10379 
  7742 /***/ (function(module, exports) {
 10380 /***/ "wfCN":
  7743 
       
  7744 var l10n = wp.media.view.l10n,
       
  7745 	DateFilter;
       
  7746 
       
  7747 /**
       
  7748  * A filter dropdown for month/dates.
       
  7749  *
       
  7750  * @memberOf wp.media.view.AttachmentFilters
       
  7751  *
       
  7752  * @class
       
  7753  * @augments wp.media.view.AttachmentFilters
       
  7754  * @augments wp.media.View
       
  7755  * @augments wp.Backbone.View
       
  7756  * @augments Backbone.View
       
  7757  */
       
  7758 DateFilter = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Date.prototype */{
       
  7759 	id: 'media-attachment-date-filters',
       
  7760 
       
  7761 	createFilters: function() {
       
  7762 		var filters = {};
       
  7763 		_.each( wp.media.view.settings.months || {}, function( value, index ) {
       
  7764 			filters[ index ] = {
       
  7765 				text: value.text,
       
  7766 				props: {
       
  7767 					year: value.year,
       
  7768 					monthnum: value.month
       
  7769 				}
       
  7770 			};
       
  7771 		});
       
  7772 		filters.all = {
       
  7773 			text:  l10n.allDates,
       
  7774 			props: {
       
  7775 				monthnum: false,
       
  7776 				year:  false
       
  7777 			},
       
  7778 			priority: 10
       
  7779 		};
       
  7780 		this.filters = filters;
       
  7781 	}
       
  7782 });
       
  7783 
       
  7784 module.exports = DateFilter;
       
  7785 
       
  7786 
       
  7787 /***/ }),
       
  7788 /* 80 */
       
  7789 /***/ (function(module, exports) {
       
  7790 
       
  7791 var l10n = wp.media.view.l10n,
       
  7792 	Uploaded;
       
  7793 
       
  7794 /**
       
  7795  * wp.media.view.AttachmentFilters.Uploaded
       
  7796  *
       
  7797  * @memberOf wp.media.view.AttachmentFilters
       
  7798  *
       
  7799  * @class
       
  7800  * @augments wp.media.view.AttachmentFilters
       
  7801  * @augments wp.media.View
       
  7802  * @augments wp.Backbone.View
       
  7803  * @augments Backbone.View
       
  7804  */
       
  7805 Uploaded = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.Uploaded.prototype */{
       
  7806 	createFilters: function() {
       
  7807 		var type = this.model.get('type'),
       
  7808 			types = wp.media.view.settings.mimeTypes,
       
  7809 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0,
       
  7810 			text;
       
  7811 
       
  7812 		if ( types && type ) {
       
  7813 			text = types[ type ];
       
  7814 		}
       
  7815 
       
  7816 		this.filters = {
       
  7817 			all: {
       
  7818 				text:  text || l10n.allMediaItems,
       
  7819 				props: {
       
  7820 					uploadedTo: null,
       
  7821 					orderby: 'date',
       
  7822 					order:   'DESC',
       
  7823 					author:	 null
       
  7824 				},
       
  7825 				priority: 10
       
  7826 			},
       
  7827 
       
  7828 			uploaded: {
       
  7829 				text:  l10n.uploadedToThisPost,
       
  7830 				props: {
       
  7831 					uploadedTo: wp.media.view.settings.post.id,
       
  7832 					orderby: 'menuOrder',
       
  7833 					order:   'ASC',
       
  7834 					author:	 null
       
  7835 				},
       
  7836 				priority: 20
       
  7837 			},
       
  7838 
       
  7839 			unattached: {
       
  7840 				text:  l10n.unattached,
       
  7841 				props: {
       
  7842 					uploadedTo: 0,
       
  7843 					orderby: 'menuOrder',
       
  7844 					order:   'ASC',
       
  7845 					author:	 null
       
  7846 				},
       
  7847 				priority: 50
       
  7848 			}
       
  7849 		};
       
  7850 
       
  7851 		if ( uid ) {
       
  7852 			this.filters.mine = {
       
  7853 				text:  l10n.mine,
       
  7854 				props: {
       
  7855 					orderby: 'date',
       
  7856 					order:   'DESC',
       
  7857 					author:  uid
       
  7858 				},
       
  7859 				priority: 50
       
  7860 			};
       
  7861 		}
       
  7862 	}
       
  7863 });
       
  7864 
       
  7865 module.exports = Uploaded;
       
  7866 
       
  7867 
       
  7868 /***/ }),
       
  7869 /* 81 */
       
  7870 /***/ (function(module, exports) {
       
  7871 
       
  7872 var l10n = wp.media.view.l10n,
       
  7873 	All;
       
  7874 
       
  7875 /**
       
  7876  * wp.media.view.AttachmentFilters.All
       
  7877  *
       
  7878  * @memberOf wp.media.view.AttachmentFilters
       
  7879  *
       
  7880  * @class
       
  7881  * @augments wp.media.view.AttachmentFilters
       
  7882  * @augments wp.media.View
       
  7883  * @augments wp.Backbone.View
       
  7884  * @augments Backbone.View
       
  7885  */
       
  7886 All = wp.media.view.AttachmentFilters.extend(/** @lends wp.media.view.AttachmentFilters.All.prototype */{
       
  7887 	createFilters: function() {
       
  7888 		var filters = {},
       
  7889 			uid = window.userSettings ? parseInt( window.userSettings.uid, 10 ) : 0;
       
  7890 
       
  7891 		_.each( wp.media.view.settings.mimeTypes || {}, function( text, key ) {
       
  7892 			filters[ key ] = {
       
  7893 				text: text,
       
  7894 				props: {
       
  7895 					status:  null,
       
  7896 					type:    key,
       
  7897 					uploadedTo: null,
       
  7898 					orderby: 'date',
       
  7899 					order:   'DESC',
       
  7900 					author:  null
       
  7901 				}
       
  7902 			};
       
  7903 		});
       
  7904 
       
  7905 		filters.all = {
       
  7906 			text:  l10n.allMediaItems,
       
  7907 			props: {
       
  7908 				status:  null,
       
  7909 				type:    null,
       
  7910 				uploadedTo: null,
       
  7911 				orderby: 'date',
       
  7912 				order:   'DESC',
       
  7913 				author:  null
       
  7914 			},
       
  7915 			priority: 10
       
  7916 		};
       
  7917 
       
  7918 		if ( wp.media.view.settings.post.id ) {
       
  7919 			filters.uploaded = {
       
  7920 				text:  l10n.uploadedToThisPost,
       
  7921 				props: {
       
  7922 					status:  null,
       
  7923 					type:    null,
       
  7924 					uploadedTo: wp.media.view.settings.post.id,
       
  7925 					orderby: 'menuOrder',
       
  7926 					order:   'ASC',
       
  7927 					author:  null
       
  7928 				},
       
  7929 				priority: 20
       
  7930 			};
       
  7931 		}
       
  7932 
       
  7933 		filters.unattached = {
       
  7934 			text:  l10n.unattached,
       
  7935 			props: {
       
  7936 				status:     null,
       
  7937 				uploadedTo: 0,
       
  7938 				type:       null,
       
  7939 				orderby:    'menuOrder',
       
  7940 				order:      'ASC',
       
  7941 				author:     null
       
  7942 			},
       
  7943 			priority: 50
       
  7944 		};
       
  7945 
       
  7946 		if ( uid ) {
       
  7947 			filters.mine = {
       
  7948 				text:  l10n.mine,
       
  7949 				props: {
       
  7950 					status:		null,
       
  7951 					type:		null,
       
  7952 					uploadedTo:	null,
       
  7953 					orderby:	'date',
       
  7954 					order:		'DESC',
       
  7955 					author:		uid
       
  7956 				},
       
  7957 				priority: 50
       
  7958 			};
       
  7959 		}
       
  7960 
       
  7961 		if ( wp.media.view.settings.mediaTrash &&
       
  7962 			this.controller.isModeActive( 'grid' ) ) {
       
  7963 
       
  7964 			filters.trash = {
       
  7965 				text:  l10n.trash,
       
  7966 				props: {
       
  7967 					uploadedTo: null,
       
  7968 					status:     'trash',
       
  7969 					type:       null,
       
  7970 					orderby:    'date',
       
  7971 					order:      'DESC',
       
  7972 					author:     null
       
  7973 				},
       
  7974 				priority: 50
       
  7975 			};
       
  7976 		}
       
  7977 
       
  7978 		this.filters = filters;
       
  7979 	}
       
  7980 });
       
  7981 
       
  7982 module.exports = All;
       
  7983 
       
  7984 
       
  7985 /***/ }),
       
  7986 /* 82 */
       
  7987 /***/ (function(module, exports) {
       
  7988 
       
  7989 var View = wp.media.View,
       
  7990 	mediaTrash = wp.media.view.settings.mediaTrash,
       
  7991 	l10n = wp.media.view.l10n,
       
  7992 	$ = jQuery,
       
  7993 	AttachmentsBrowser;
       
  7994 
       
  7995 /**
       
  7996  * wp.media.view.AttachmentsBrowser
       
  7997  *
       
  7998  * @memberOf wp.media.view
       
  7999  *
       
  8000  * @class
       
  8001  * @augments wp.media.View
       
  8002  * @augments wp.Backbone.View
       
  8003  * @augments Backbone.View
       
  8004  *
       
  8005  * @param {object}         [options]               The options hash passed to the view.
       
  8006  * @param {boolean|string} [options.filters=false] Which filters to show in the browser's toolbar.
       
  8007  *                                                 Accepts 'uploaded' and 'all'.
       
  8008  * @param {boolean}        [options.search=true]   Whether to show the search interface in the
       
  8009  *                                                 browser's toolbar.
       
  8010  * @param {boolean}        [options.date=true]     Whether to show the date filter in the
       
  8011  *                                                 browser's toolbar.
       
  8012  * @param {boolean}        [options.display=false] Whether to show the attachments display settings
       
  8013  *                                                 view in the sidebar.
       
  8014  * @param {boolean|string} [options.sidebar=true]  Whether to create a sidebar for the browser.
       
  8015  *                                                 Accepts true, false, and 'errors'.
       
  8016  */
       
  8017 AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.prototype */{
       
  8018 	tagName:   'div',
       
  8019 	className: 'attachments-browser',
       
  8020 
       
  8021 	initialize: function() {
       
  8022 		_.defaults( this.options, {
       
  8023 			filters: false,
       
  8024 			search:  true,
       
  8025 			date:    true,
       
  8026 			display: false,
       
  8027 			sidebar: true,
       
  8028 			AttachmentView: wp.media.view.Attachment.Library
       
  8029 		});
       
  8030 
       
  8031 		this.controller.on( 'toggle:upload:attachment', this.toggleUploader, this );
       
  8032 		this.controller.on( 'edit:selection', this.editSelection );
       
  8033 
       
  8034 		// In the Media Library, the sidebar is used to display errors before the attachments grid.
       
  8035 		if ( this.options.sidebar && 'errors' === this.options.sidebar ) {
       
  8036 			this.createSidebar();
       
  8037 		}
       
  8038 
       
  8039 		/*
       
  8040 		 * In the grid mode (the Media Library), place the Inline Uploader before
       
  8041 		 * other sections so that the visual order and the DOM order match. This way,
       
  8042 		 * the Inline Uploader in the Media Library is right after the "Add New"
       
  8043 		 * button, see ticket #37188.
       
  8044 		 */
       
  8045 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  8046 			this.createUploader();
       
  8047 
       
  8048 			/*
       
  8049 			 * Create a multi-purpose toolbar. Used as main toolbar in the Media Library
       
  8050 			 * and also for other things, for example the "Drag and drop to reorder" and
       
  8051 			 * "Suggested dimensions" info in the media modal.
       
  8052 			 */
       
  8053 			this.createToolbar();
       
  8054 		} else {
       
  8055 			this.createToolbar();
       
  8056 			this.createUploader();
       
  8057 		}
       
  8058 
       
  8059 
       
  8060 		// Add a heading before the attachments list.
       
  8061 		this.createAttachmentsHeading();
       
  8062 
       
  8063 		// Create the list of attachments.
       
  8064 		this.createAttachments();
       
  8065 
       
  8066 		// For accessibility reasons, place the normal sidebar after the attachments, see ticket #36909.
       
  8067 		if ( this.options.sidebar && 'errors' !== this.options.sidebar ) {
       
  8068 			this.createSidebar();
       
  8069 		}
       
  8070 
       
  8071 		this.updateContent();
       
  8072 
       
  8073 		if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
       
  8074 			this.$el.addClass( 'hide-sidebar' );
       
  8075 
       
  8076 			if ( 'errors' === this.options.sidebar ) {
       
  8077 				this.$el.addClass( 'sidebar-for-errors' );
       
  8078 			}
       
  8079 		}
       
  8080 
       
  8081 		this.collection.on( 'add remove reset', this.updateContent, this );
       
  8082 
       
  8083 		// The non-cached or cached attachments query has completed.
       
  8084 		this.collection.on( 'attachments:received', this.announceSearchResults, this );
       
  8085 	},
       
  8086 
       
  8087 	/**
       
  8088 	 * Updates the `wp.a11y.speak()` ARIA live region with a message to communicate
       
  8089 	 * the number of search results to screen reader users. This function is
       
  8090 	 * debounced because the collection updates multiple times.
       
  8091 	 *
       
  8092 	 * @since 5.3.0
       
  8093 	 *
       
  8094 	 * @return {void}
       
  8095 	 */
       
  8096 	announceSearchResults: _.debounce( function() {
       
  8097 		var count;
       
  8098 
       
  8099 		if ( this.collection.mirroring.args.s ) {
       
  8100 			count = this.collection.length;
       
  8101 
       
  8102 			if ( 0 === count ) {
       
  8103 				wp.a11y.speak( l10n.noMediaTryNewSearch );
       
  8104 				return;
       
  8105 			}
       
  8106 
       
  8107 			if ( this.collection.hasMore() ) {
       
  8108 				wp.a11y.speak( l10n.mediaFoundHasMoreResults.replace( '%d', count ) );
       
  8109 				return;
       
  8110 			}
       
  8111 
       
  8112 			wp.a11y.speak( l10n.mediaFound.replace( '%d', count ) );
       
  8113 		}
       
  8114 	}, 200 ),
       
  8115 
       
  8116 	editSelection: function( modal ) {
       
  8117 		// When editing a selection, move focus to the "Return to library" button.
       
  8118 		modal.$( '.media-button-backToLibrary' ).focus();
       
  8119 	},
       
  8120 
       
  8121 	/**
       
  8122 	 * @return {wp.media.view.AttachmentsBrowser} Returns itself to allow chaining.
       
  8123 	 */
       
  8124 	dispose: function() {
       
  8125 		this.options.selection.off( null, null, this );
       
  8126 		View.prototype.dispose.apply( this, arguments );
       
  8127 		return this;
       
  8128 	},
       
  8129 
       
  8130 	createToolbar: function() {
       
  8131 		var LibraryViewSwitcher, Filters, toolbarOptions,
       
  8132 			showFilterByType = -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] );
       
  8133 
       
  8134 		toolbarOptions = {
       
  8135 			controller: this.controller
       
  8136 		};
       
  8137 
       
  8138 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  8139 			toolbarOptions.className = 'media-toolbar wp-filter';
       
  8140 		}
       
  8141 
       
  8142 		/**
       
  8143 		* @member {wp.media.view.Toolbar}
       
  8144 		*/
       
  8145 		this.toolbar = new wp.media.view.Toolbar( toolbarOptions );
       
  8146 
       
  8147 		this.views.add( this.toolbar );
       
  8148 
       
  8149 		this.toolbar.set( 'spinner', new wp.media.view.Spinner({
       
  8150 			priority: -20
       
  8151 		}) );
       
  8152 
       
  8153 		if ( showFilterByType || this.options.date ) {
       
  8154 			/*
       
  8155 			 * Create a h2 heading before the select elements that filter attachments.
       
  8156 			 * This heading is visible in the modal and visually hidden in the grid.
       
  8157 			 */
       
  8158 			this.toolbar.set( 'filters-heading', new wp.media.view.Heading( {
       
  8159 				priority:   -100,
       
  8160 				text:       l10n.filterAttachments,
       
  8161 				level:      'h2',
       
  8162 				className:  'media-attachments-filter-heading'
       
  8163 			}).render() );
       
  8164 		}
       
  8165 
       
  8166 		if ( showFilterByType ) {
       
  8167 			// "Filters" is a <select>, a visually hidden label element needs to be rendered before.
       
  8168 			this.toolbar.set( 'filtersLabel', new wp.media.view.Label({
       
  8169 				value: l10n.filterByType,
       
  8170 				attributes: {
       
  8171 					'for':  'media-attachment-filters'
       
  8172 				},
       
  8173 				priority:   -80
       
  8174 			}).render() );
       
  8175 
       
  8176 			if ( 'uploaded' === this.options.filters ) {
       
  8177 				this.toolbar.set( 'filters', new wp.media.view.AttachmentFilters.Uploaded({
       
  8178 					controller: this.controller,
       
  8179 					model:      this.collection.props,
       
  8180 					priority:   -80
       
  8181 				}).render() );
       
  8182 			} else {
       
  8183 				Filters = new wp.media.view.AttachmentFilters.All({
       
  8184 					controller: this.controller,
       
  8185 					model:      this.collection.props,
       
  8186 					priority:   -80
       
  8187 				});
       
  8188 
       
  8189 				this.toolbar.set( 'filters', Filters.render() );
       
  8190 			}
       
  8191 		}
       
  8192 
       
  8193 		/*
       
  8194 		 * Feels odd to bring the global media library switcher into the Attachment browser view.
       
  8195 		 * Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
       
  8196 		 * which the controller can tap into and add this view?
       
  8197 		 */
       
  8198 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  8199 			LibraryViewSwitcher = View.extend({
       
  8200 				className: 'view-switch media-grid-view-switch',
       
  8201 				template: wp.template( 'media-library-view-switcher')
       
  8202 			});
       
  8203 
       
  8204 			this.toolbar.set( 'libraryViewSwitcher', new LibraryViewSwitcher({
       
  8205 				controller: this.controller,
       
  8206 				priority: -90
       
  8207 			}).render() );
       
  8208 
       
  8209 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
       
  8210 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
       
  8211 				value: l10n.filterByDate,
       
  8212 				attributes: {
       
  8213 					'for': 'media-attachment-date-filters'
       
  8214 				},
       
  8215 				priority: -75
       
  8216 			}).render() );
       
  8217 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
       
  8218 				controller: this.controller,
       
  8219 				model:      this.collection.props,
       
  8220 				priority: -75
       
  8221 			}).render() );
       
  8222 
       
  8223 			// BulkSelection is a <div> with subviews, including screen reader text.
       
  8224 			this.toolbar.set( 'selectModeToggleButton', new wp.media.view.SelectModeToggleButton({
       
  8225 				text: l10n.bulkSelect,
       
  8226 				controller: this.controller,
       
  8227 				priority: -70
       
  8228 			}).render() );
       
  8229 
       
  8230 			this.toolbar.set( 'deleteSelectedButton', new wp.media.view.DeleteSelectedButton({
       
  8231 				filters: Filters,
       
  8232 				style: 'primary',
       
  8233 				disabled: true,
       
  8234 				text: mediaTrash ? l10n.trashSelected : l10n.deletePermanently,
       
  8235 				controller: this.controller,
       
  8236 				priority: -80,
       
  8237 				click: function() {
       
  8238 					var changed = [], removed = [],
       
  8239 						selection = this.controller.state().get( 'selection' ),
       
  8240 						library = this.controller.state().get( 'library' );
       
  8241 
       
  8242 					if ( ! selection.length ) {
       
  8243 						return;
       
  8244 					}
       
  8245 
       
  8246 					if ( ! mediaTrash && ! window.confirm( l10n.warnBulkDelete ) ) {
       
  8247 						return;
       
  8248 					}
       
  8249 
       
  8250 					if ( mediaTrash &&
       
  8251 						'trash' !== selection.at( 0 ).get( 'status' ) &&
       
  8252 						! window.confirm( l10n.warnBulkTrash ) ) {
       
  8253 
       
  8254 						return;
       
  8255 					}
       
  8256 
       
  8257 					selection.each( function( model ) {
       
  8258 						if ( ! model.get( 'nonces' )['delete'] ) {
       
  8259 							removed.push( model );
       
  8260 							return;
       
  8261 						}
       
  8262 
       
  8263 						if ( mediaTrash && 'trash' === model.get( 'status' ) ) {
       
  8264 							model.set( 'status', 'inherit' );
       
  8265 							changed.push( model.save() );
       
  8266 							removed.push( model );
       
  8267 						} else if ( mediaTrash ) {
       
  8268 							model.set( 'status', 'trash' );
       
  8269 							changed.push( model.save() );
       
  8270 							removed.push( model );
       
  8271 						} else {
       
  8272 							model.destroy({wait: true});
       
  8273 						}
       
  8274 					} );
       
  8275 
       
  8276 					if ( changed.length ) {
       
  8277 						selection.remove( removed );
       
  8278 
       
  8279 						$.when.apply( null, changed ).then( _.bind( function() {
       
  8280 							library._requery( true );
       
  8281 							this.controller.trigger( 'selection:action:done' );
       
  8282 						}, this ) );
       
  8283 					} else {
       
  8284 						this.controller.trigger( 'selection:action:done' );
       
  8285 					}
       
  8286 				}
       
  8287 			}).render() );
       
  8288 
       
  8289 			if ( mediaTrash ) {
       
  8290 				this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
       
  8291 					filters: Filters,
       
  8292 					style: 'link button-link-delete',
       
  8293 					disabled: true,
       
  8294 					text: l10n.deletePermanently,
       
  8295 					controller: this.controller,
       
  8296 					priority: -55,
       
  8297 					click: function() {
       
  8298 						var removed = [],
       
  8299 							destroy = [],
       
  8300 							selection = this.controller.state().get( 'selection' );
       
  8301 
       
  8302 						if ( ! selection.length || ! window.confirm( l10n.warnBulkDelete ) ) {
       
  8303 							return;
       
  8304 						}
       
  8305 
       
  8306 						selection.each( function( model ) {
       
  8307 							if ( ! model.get( 'nonces' )['delete'] ) {
       
  8308 								removed.push( model );
       
  8309 								return;
       
  8310 							}
       
  8311 
       
  8312 							destroy.push( model );
       
  8313 						} );
       
  8314 
       
  8315 						if ( removed.length ) {
       
  8316 							selection.remove( removed );
       
  8317 						}
       
  8318 
       
  8319 						if ( destroy.length ) {
       
  8320 							$.when.apply( null, destroy.map( function (item) {
       
  8321 								return item.destroy();
       
  8322 							} ) ).then( _.bind( function() {
       
  8323 								this.controller.trigger( 'selection:action:done' );
       
  8324 							}, this ) );
       
  8325 						}
       
  8326 					}
       
  8327 				}).render() );
       
  8328 			}
       
  8329 
       
  8330 		} else if ( this.options.date ) {
       
  8331 			// DateFilter is a <select>, a visually hidden label element needs to be rendered before.
       
  8332 			this.toolbar.set( 'dateFilterLabel', new wp.media.view.Label({
       
  8333 				value: l10n.filterByDate,
       
  8334 				attributes: {
       
  8335 					'for': 'media-attachment-date-filters'
       
  8336 				},
       
  8337 				priority: -75
       
  8338 			}).render() );
       
  8339 			this.toolbar.set( 'dateFilter', new wp.media.view.DateFilter({
       
  8340 				controller: this.controller,
       
  8341 				model:      this.collection.props,
       
  8342 				priority: -75
       
  8343 			}).render() );
       
  8344 		}
       
  8345 
       
  8346 		if ( this.options.search ) {
       
  8347 			// Search is an input, a visually hidden label element needs to be rendered before.
       
  8348 			this.toolbar.set( 'searchLabel', new wp.media.view.Label({
       
  8349 				value: l10n.searchLabel,
       
  8350 				className: 'media-search-input-label',
       
  8351 				attributes: {
       
  8352 					'for': 'media-search-input'
       
  8353 				},
       
  8354 				priority:   60
       
  8355 			}).render() );
       
  8356 			this.toolbar.set( 'search', new wp.media.view.Search({
       
  8357 				controller: this.controller,
       
  8358 				model:      this.collection.props,
       
  8359 				priority:   60
       
  8360 			}).render() );
       
  8361 		}
       
  8362 
       
  8363 		if ( this.options.dragInfo ) {
       
  8364 			this.toolbar.set( 'dragInfo', new View({
       
  8365 				el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
       
  8366 				priority: -40
       
  8367 			}) );
       
  8368 		}
       
  8369 
       
  8370 		if ( this.options.suggestedWidth && this.options.suggestedHeight ) {
       
  8371 			this.toolbar.set( 'suggestedDimensions', new View({
       
  8372 				el: $( '<div class="instructions">' + l10n.suggestedDimensions.replace( '%1$s', this.options.suggestedWidth ).replace( '%2$s', this.options.suggestedHeight ) + '</div>' )[0],
       
  8373 				priority: -40
       
  8374 			}) );
       
  8375 		}
       
  8376 	},
       
  8377 
       
  8378 	updateContent: function() {
       
  8379 		var view = this,
       
  8380 			noItemsView;
       
  8381 
       
  8382 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  8383 			noItemsView = view.attachmentsNoResults;
       
  8384 		} else {
       
  8385 			noItemsView = view.uploader;
       
  8386 		}
       
  8387 
       
  8388 		if ( ! this.collection.length ) {
       
  8389 			this.toolbar.get( 'spinner' ).show();
       
  8390 			this.dfd = this.collection.more().done( function() {
       
  8391 				if ( ! view.collection.length ) {
       
  8392 					noItemsView.$el.removeClass( 'hidden' );
       
  8393 				} else {
       
  8394 					noItemsView.$el.addClass( 'hidden' );
       
  8395 				}
       
  8396 				view.toolbar.get( 'spinner' ).hide();
       
  8397 			} );
       
  8398 		} else {
       
  8399 			noItemsView.$el.addClass( 'hidden' );
       
  8400 			view.toolbar.get( 'spinner' ).hide();
       
  8401 		}
       
  8402 	},
       
  8403 
       
  8404 	createUploader: function() {
       
  8405 		this.uploader = new wp.media.view.UploaderInline({
       
  8406 			controller: this.controller,
       
  8407 			status:     false,
       
  8408 			message:    this.controller.isModeActive( 'grid' ) ? '' : l10n.noItemsFound,
       
  8409 			canClose:   this.controller.isModeActive( 'grid' )
       
  8410 		});
       
  8411 
       
  8412 		this.uploader.$el.addClass( 'hidden' );
       
  8413 		this.views.add( this.uploader );
       
  8414 	},
       
  8415 
       
  8416 	toggleUploader: function() {
       
  8417 		if ( this.uploader.$el.hasClass( 'hidden' ) ) {
       
  8418 			this.uploader.show();
       
  8419 		} else {
       
  8420 			this.uploader.hide();
       
  8421 		}
       
  8422 	},
       
  8423 
       
  8424 	createAttachments: function() {
       
  8425 		this.attachments = new wp.media.view.Attachments({
       
  8426 			controller:           this.controller,
       
  8427 			collection:           this.collection,
       
  8428 			selection:            this.options.selection,
       
  8429 			model:                this.model,
       
  8430 			sortable:             this.options.sortable,
       
  8431 			scrollElement:        this.options.scrollElement,
       
  8432 			idealColumnWidth:     this.options.idealColumnWidth,
       
  8433 
       
  8434 			// The single `Attachment` view to be used in the `Attachments` view.
       
  8435 			AttachmentView: this.options.AttachmentView
       
  8436 		});
       
  8437 
       
  8438 		// Add keydown listener to the instance of the Attachments view.
       
  8439 		this.controller.on( 'attachment:keydown:arrow',     _.bind( this.attachments.arrowEvent, this.attachments ) );
       
  8440 		this.controller.on( 'attachment:details:shift-tab', _.bind( this.attachments.restoreFocus, this.attachments ) );
       
  8441 
       
  8442 		this.views.add( this.attachments );
       
  8443 
       
  8444 
       
  8445 		if ( this.controller.isModeActive( 'grid' ) ) {
       
  8446 			this.attachmentsNoResults = new View({
       
  8447 				controller: this.controller,
       
  8448 				tagName: 'p'
       
  8449 			});
       
  8450 
       
  8451 			this.attachmentsNoResults.$el.addClass( 'hidden no-media' );
       
  8452 			this.attachmentsNoResults.$el.html( l10n.noMedia );
       
  8453 
       
  8454 			this.views.add( this.attachmentsNoResults );
       
  8455 		}
       
  8456 	},
       
  8457 
       
  8458 	createAttachmentsHeading: function() {
       
  8459 		this.attachmentsHeading = new wp.media.view.Heading( {
       
  8460 			text: l10n.attachmentsList,
       
  8461 			level: 'h2',
       
  8462 			className: 'media-views-heading screen-reader-text'
       
  8463 		} );
       
  8464 		this.views.add( this.attachmentsHeading );
       
  8465 	},
       
  8466 
       
  8467 	createSidebar: function() {
       
  8468 		var options = this.options,
       
  8469 			selection = options.selection,
       
  8470 			sidebar = this.sidebar = new wp.media.view.Sidebar({
       
  8471 				controller: this.controller
       
  8472 			});
       
  8473 
       
  8474 		this.views.add( sidebar );
       
  8475 
       
  8476 		if ( this.controller.uploader ) {
       
  8477 			sidebar.set( 'uploads', new wp.media.view.UploaderStatus({
       
  8478 				controller: this.controller,
       
  8479 				priority:   40
       
  8480 			}) );
       
  8481 		}
       
  8482 
       
  8483 		selection.on( 'selection:single', this.createSingle, this );
       
  8484 		selection.on( 'selection:unsingle', this.disposeSingle, this );
       
  8485 
       
  8486 		if ( selection.single() ) {
       
  8487 			this.createSingle();
       
  8488 		}
       
  8489 	},
       
  8490 
       
  8491 	createSingle: function() {
       
  8492 		var sidebar = this.sidebar,
       
  8493 			single = this.options.selection.single();
       
  8494 
       
  8495 		sidebar.set( 'details', new wp.media.view.Attachment.Details({
       
  8496 			controller: this.controller,
       
  8497 			model:      single,
       
  8498 			priority:   80
       
  8499 		}) );
       
  8500 
       
  8501 		sidebar.set( 'compat', new wp.media.view.AttachmentCompat({
       
  8502 			controller: this.controller,
       
  8503 			model:      single,
       
  8504 			priority:   120
       
  8505 		}) );
       
  8506 
       
  8507 		if ( this.options.display ) {
       
  8508 			sidebar.set( 'display', new wp.media.view.Settings.AttachmentDisplay({
       
  8509 				controller:   this.controller,
       
  8510 				model:        this.model.display( single ),
       
  8511 				attachment:   single,
       
  8512 				priority:     160,
       
  8513 				userSettings: this.model.get('displayUserSettings')
       
  8514 			}) );
       
  8515 		}
       
  8516 
       
  8517 		// Show the sidebar on mobile.
       
  8518 		if ( this.model.id === 'insert' ) {
       
  8519 			sidebar.$el.addClass( 'visible' );
       
  8520 		}
       
  8521 	},
       
  8522 
       
  8523 	disposeSingle: function() {
       
  8524 		var sidebar = this.sidebar;
       
  8525 		sidebar.unset('details');
       
  8526 		sidebar.unset('compat');
       
  8527 		sidebar.unset('display');
       
  8528 		// Hide the sidebar on mobile.
       
  8529 		sidebar.$el.removeClass( 'visible' );
       
  8530 	}
       
  8531 });
       
  8532 
       
  8533 module.exports = AttachmentsBrowser;
       
  8534 
       
  8535 
       
  8536 /***/ }),
       
  8537 /* 83 */
       
  8538 /***/ (function(module, exports) {
       
  8539 
       
  8540 var _n = wp.i18n._n,
       
  8541 	sprintf = wp.i18n.sprintf,
       
  8542 	Selection;
       
  8543 
       
  8544 /**
       
  8545  * wp.media.view.Selection
       
  8546  *
       
  8547  * @memberOf wp.media.view
       
  8548  *
       
  8549  * @class
       
  8550  * @augments wp.media.View
       
  8551  * @augments wp.Backbone.View
       
  8552  * @augments Backbone.View
       
  8553  */
       
  8554 Selection = wp.media.View.extend(/** @lends wp.media.view.Selection.prototype */{
       
  8555 	tagName:   'div',
       
  8556 	className: 'media-selection',
       
  8557 	template:  wp.template('media-selection'),
       
  8558 
       
  8559 	events: {
       
  8560 		'click .edit-selection':  'edit',
       
  8561 		'click .clear-selection': 'clear'
       
  8562 	},
       
  8563 
       
  8564 	initialize: function() {
       
  8565 		_.defaults( this.options, {
       
  8566 			editable:  false,
       
  8567 			clearable: true
       
  8568 		});
       
  8569 
       
  8570 		/**
       
  8571 		 * @member {wp.media.view.Attachments.Selection}
       
  8572 		 */
       
  8573 		this.attachments = new wp.media.view.Attachments.Selection({
       
  8574 			controller: this.controller,
       
  8575 			collection: this.collection,
       
  8576 			selection:  this.collection,
       
  8577 			model:      new Backbone.Model()
       
  8578 		});
       
  8579 
       
  8580 		this.views.set( '.selection-view', this.attachments );
       
  8581 		this.collection.on( 'add remove reset', this.refresh, this );
       
  8582 		this.controller.on( 'content:activate', this.refresh, this );
       
  8583 	},
       
  8584 
       
  8585 	ready: function() {
       
  8586 		this.refresh();
       
  8587 	},
       
  8588 
       
  8589 	refresh: function() {
       
  8590 		// If the selection hasn't been rendered, bail.
       
  8591 		if ( ! this.$el.children().length ) {
       
  8592 			return;
       
  8593 		}
       
  8594 
       
  8595 		var collection = this.collection,
       
  8596 			editing = 'edit-selection' === this.controller.content.mode();
       
  8597 
       
  8598 		// If nothing is selected, display nothing.
       
  8599 		this.$el.toggleClass( 'empty', ! collection.length );
       
  8600 		this.$el.toggleClass( 'one', 1 === collection.length );
       
  8601 		this.$el.toggleClass( 'editing', editing );
       
  8602 
       
  8603 		this.$( '.count' ).text(
       
  8604 			/* translators: %s: Number of selected media attachments. */
       
  8605 			sprintf( _n( '%s item selected', '%s items selected', collection.length ), collection.length )
       
  8606 		);
       
  8607 	},
       
  8608 
       
  8609 	edit: function( event ) {
       
  8610 		event.preventDefault();
       
  8611 		if ( this.options.editable ) {
       
  8612 			this.options.editable.call( this, this.collection );
       
  8613 		}
       
  8614 	},
       
  8615 
       
  8616 	clear: function( event ) {
       
  8617 		event.preventDefault();
       
  8618 		this.collection.reset();
       
  8619 
       
  8620 		// Move focus to the modal.
       
  8621 		this.controller.modal.focusManager.focus();
       
  8622 	}
       
  8623 });
       
  8624 
       
  8625 module.exports = Selection;
       
  8626 
       
  8627 
       
  8628 /***/ }),
       
  8629 /* 84 */
       
  8630 /***/ (function(module, exports) {
       
  8631 
       
  8632 /**
       
  8633  * wp.media.view.Attachment.Selection
       
  8634  *
       
  8635  * @memberOf wp.media.view.Attachment
       
  8636  *
       
  8637  * @class
       
  8638  * @augments wp.media.view.Attachment
       
  8639  * @augments wp.media.View
       
  8640  * @augments wp.Backbone.View
       
  8641  * @augments Backbone.View
       
  8642  */
       
  8643 var Selection = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Selection.prototype */{
       
  8644 	className: 'attachment selection',
       
  8645 
       
  8646 	// On click, just select the model, instead of removing the model from
       
  8647 	// the selection.
       
  8648 	toggleSelection: function() {
       
  8649 		this.options.selection.single( this.model );
       
  8650 	}
       
  8651 });
       
  8652 
       
  8653 module.exports = Selection;
       
  8654 
       
  8655 
       
  8656 /***/ }),
       
  8657 /* 85 */
       
  8658 /***/ (function(module, exports) {
 10381 /***/ (function(module, exports) {
  8659 
 10382 
  8660 var Attachments = wp.media.view.Attachments,
 10383 var Attachments = wp.media.view.Attachments,
  8661 	Selection;
 10384 	Selection;
  8662 
 10385 
  8688 
 10411 
  8689 module.exports = Selection;
 10412 module.exports = Selection;
  8690 
 10413 
  8691 
 10414 
  8692 /***/ }),
 10415 /***/ }),
  8693 /* 86 */
 10416 
       
 10417 /***/ "xQvM":
  8694 /***/ (function(module, exports) {
 10418 /***/ (function(module, exports) {
  8695 
 10419 
       
 10420 var Select = wp.media.view.Toolbar.Select,
       
 10421 	l10n = wp.media.view.l10n,
       
 10422 	Embed;
       
 10423 
  8696 /**
 10424 /**
  8697  * wp.media.view.Attachment.EditSelection
 10425  * wp.media.view.Toolbar.Embed
       
 10426  *
       
 10427  * @memberOf wp.media.view.Toolbar
       
 10428  *
       
 10429  * @class
       
 10430  * @augments wp.media.view.Toolbar.Select
       
 10431  * @augments wp.media.view.Toolbar
       
 10432  * @augments wp.media.View
       
 10433  * @augments wp.Backbone.View
       
 10434  * @augments Backbone.View
       
 10435  */
       
 10436 Embed = Select.extend(/** @lends wp.media.view.Toolbar.Embed.prototype */{
       
 10437 	initialize: function() {
       
 10438 		_.defaults( this.options, {
       
 10439 			text: l10n.insertIntoPost,
       
 10440 			requires: false
       
 10441 		});
       
 10442 		// Call 'initialize' directly on the parent class.
       
 10443 		Select.prototype.initialize.apply( this, arguments );
       
 10444 	},
       
 10445 
       
 10446 	refresh: function() {
       
 10447 		var url = this.controller.state().props.get('url');
       
 10448 		this.get('select').model.set( 'disabled', ! url || url === 'http://' );
       
 10449 		/**
       
 10450 		 * call 'refresh' directly on the parent class
       
 10451 		 */
       
 10452 		Select.prototype.refresh.apply( this, arguments );
       
 10453 	}
       
 10454 });
       
 10455 
       
 10456 module.exports = Embed;
       
 10457 
       
 10458 
       
 10459 /***/ }),
       
 10460 
       
 10461 /***/ "yGM1":
       
 10462 /***/ (function(module, exports) {
       
 10463 
       
 10464 /**
       
 10465  * wp.media.view.Attachment.Selection
  8698  *
 10466  *
  8699  * @memberOf wp.media.view.Attachment
 10467  * @memberOf wp.media.view.Attachment
  8700  *
 10468  *
  8701  * @class
 10469  * @class
  8702  * @augments wp.media.view.Attachment.Selection
       
  8703  * @augments wp.media.view.Attachment
 10470  * @augments wp.media.view.Attachment
  8704  * @augments wp.media.View
 10471  * @augments wp.media.View
  8705  * @augments wp.Backbone.View
 10472  * @augments wp.Backbone.View
  8706  * @augments Backbone.View
 10473  * @augments Backbone.View
  8707  */
 10474  */
  8708 var EditSelection = wp.media.view.Attachment.Selection.extend(/** @lends wp.media.view.Attachment.EditSelection.prototype */{
 10475 var Selection = wp.media.view.Attachment.extend(/** @lends wp.media.view.Attachment.Selection.prototype */{
  8709 	buttons: {
 10476 	className: 'attachment selection',
  8710 		close: true
 10477 
       
 10478 	// On click, just select the model, instead of removing the model from
       
 10479 	// the selection.
       
 10480 	toggleSelection: function() {
       
 10481 		this.options.selection.single( this.model );
  8711 	}
 10482 	}
  8712 });
 10483 });
  8713 
 10484 
  8714 module.exports = EditSelection;
 10485 module.exports = Selection;
  8715 
 10486 
  8716 
 10487 
  8717 /***/ }),
 10488 /***/ }),
  8718 /* 87 */
 10489 
       
 10490 /***/ "z/+l":
  8719 /***/ (function(module, exports) {
 10491 /***/ (function(module, exports) {
  8720 
 10492 
  8721 var View = wp.media.View,
 10493 var $ = Backbone.$,
  8722 	$ = Backbone.$,
 10494 	ButtonGroup;
  8723 	Settings;
       
  8724 
 10495 
  8725 /**
 10496 /**
  8726  * wp.media.view.Settings
 10497  * wp.media.view.ButtonGroup
  8727  *
 10498  *
  8728  * @memberOf wp.media.view
 10499  * @memberOf wp.media.view
  8729  *
 10500  *
  8730  * @class
 10501  * @class
  8731  * @augments wp.media.View
 10502  * @augments wp.media.View
  8732  * @augments wp.Backbone.View
 10503  * @augments wp.Backbone.View
  8733  * @augments Backbone.View
 10504  * @augments Backbone.View
  8734  */
 10505  */
  8735 Settings = View.extend(/** @lends wp.media.view.Settings.prototype */{
 10506 ButtonGroup = wp.media.View.extend(/** @lends wp.media.view.ButtonGroup.prototype */{
  8736 	events: {
 10507 	tagName:   'div',
  8737 		'click button':    'updateHandler',
 10508 	className: 'button-group button-large media-button-group',
  8738 		'change input':    'updateHandler',
       
  8739 		'change select':   'updateHandler',
       
  8740 		'change textarea': 'updateHandler'
       
  8741 	},
       
  8742 
 10509 
  8743 	initialize: function() {
 10510 	initialize: function() {
  8744 		this.model = this.model || new Backbone.Model();
 10511 		/**
  8745 		this.listenTo( this.model, 'change', this.updateChanges );
 10512 		 * @member {wp.media.view.Button[]}
  8746 	},
 10513 		 */
  8747 
 10514 		this.buttons = _.map( this.options.buttons || [], function( button ) {
  8748 	prepare: function() {
 10515 			if ( button instanceof Backbone.View ) {
  8749 		return _.defaults({
 10516 				return button;
  8750 			model: this.model.toJSON()
 10517 			} else {
  8751 		}, this.options );
 10518 				return new wp.media.view.Button( button ).render();
  8752 	},
 10519 			}
  8753 	/**
 10520 		});
  8754 	 * @return {wp.media.view.Settings} Returns itself to allow chaining.
 10521 
       
 10522 		delete this.options.buttons;
       
 10523 
       
 10524 		if ( this.options.classes ) {
       
 10525 			this.$el.addClass( this.options.classes );
       
 10526 		}
       
 10527 	},
       
 10528 
       
 10529 	/**
       
 10530 	 * @return {wp.media.view.ButtonGroup}
  8755 	 */
 10531 	 */
  8756 	render: function() {
 10532 	render: function() {
  8757 		View.prototype.render.apply( this, arguments );
 10533 		this.$el.html( $( _.pluck( this.buttons, 'el' ) ).detach() );
  8758 		// Select the correct values.
       
  8759 		_( this.model.attributes ).chain().keys().each( this.update, this );
       
  8760 		return this;
       
  8761 	},
       
  8762 	/**
       
  8763 	 * @param {string} key
       
  8764 	 */
       
  8765 	update: function( key ) {
       
  8766 		var value = this.model.get( key ),
       
  8767 			$setting = this.$('[data-setting="' + key + '"]'),
       
  8768 			$buttons, $value;
       
  8769 
       
  8770 		// Bail if we didn't find a matching setting.
       
  8771 		if ( ! $setting.length ) {
       
  8772 			return;
       
  8773 		}
       
  8774 
       
  8775 		// Attempt to determine how the setting is rendered and update
       
  8776 		// the selected value.
       
  8777 
       
  8778 		// Handle dropdowns.
       
  8779 		if ( $setting.is('select') ) {
       
  8780 			$value = $setting.find('[value="' + value + '"]');
       
  8781 
       
  8782 			if ( $value.length ) {
       
  8783 				$setting.find('option').prop( 'selected', false );
       
  8784 				$value.prop( 'selected', true );
       
  8785 			} else {
       
  8786 				// If we can't find the desired value, record what *is* selected.
       
  8787 				this.model.set( key, $setting.find(':selected').val() );
       
  8788 			}
       
  8789 
       
  8790 		// Handle button groups.
       
  8791 		} else if ( $setting.hasClass('button-group') ) {
       
  8792 			$buttons = $setting.find( 'button' )
       
  8793 				.removeClass( 'active' )
       
  8794 				.attr( 'aria-pressed', 'false' );
       
  8795 			$buttons.filter( '[value="' + value + '"]' )
       
  8796 				.addClass( 'active' )
       
  8797 				.attr( 'aria-pressed', 'true' );
       
  8798 
       
  8799 		// Handle text inputs and textareas.
       
  8800 		} else if ( $setting.is('input[type="text"], textarea') ) {
       
  8801 			if ( ! $setting.is(':focus') ) {
       
  8802 				$setting.val( value );
       
  8803 			}
       
  8804 		// Handle checkboxes.
       
  8805 		} else if ( $setting.is('input[type="checkbox"]') ) {
       
  8806 			$setting.prop( 'checked', !! value && 'false' !== value );
       
  8807 		}
       
  8808 	},
       
  8809 	/**
       
  8810 	 * @param {Object} event
       
  8811 	 */
       
  8812 	updateHandler: function( event ) {
       
  8813 		var $setting = $( event.target ).closest('[data-setting]'),
       
  8814 			value = event.target.value,
       
  8815 			userSetting;
       
  8816 
       
  8817 		event.preventDefault();
       
  8818 
       
  8819 		if ( ! $setting.length ) {
       
  8820 			return;
       
  8821 		}
       
  8822 
       
  8823 		// Use the correct value for checkboxes.
       
  8824 		if ( $setting.is('input[type="checkbox"]') ) {
       
  8825 			value = $setting[0].checked;
       
  8826 		}
       
  8827 
       
  8828 		// Update the corresponding setting.
       
  8829 		this.model.set( $setting.data('setting'), value );
       
  8830 
       
  8831 		// If the setting has a corresponding user setting,
       
  8832 		// update that as well.
       
  8833 		userSetting = $setting.data('userSetting');
       
  8834 		if ( userSetting ) {
       
  8835 			window.setUserSetting( userSetting, value );
       
  8836 		}
       
  8837 	},
       
  8838 
       
  8839 	updateChanges: function( model ) {
       
  8840 		if ( model.hasChanged() ) {
       
  8841 			_( model.changed ).chain().keys().each( this.update, this );
       
  8842 		}
       
  8843 	}
       
  8844 });
       
  8845 
       
  8846 module.exports = Settings;
       
  8847 
       
  8848 
       
  8849 /***/ }),
       
  8850 /* 88 */
       
  8851 /***/ (function(module, exports) {
       
  8852 
       
  8853 var Settings = wp.media.view.Settings,
       
  8854 	AttachmentDisplay;
       
  8855 
       
  8856 /**
       
  8857  * wp.media.view.Settings.AttachmentDisplay
       
  8858  *
       
  8859  * @memberOf wp.media.view.Settings
       
  8860  *
       
  8861  * @class
       
  8862  * @augments wp.media.view.Settings
       
  8863  * @augments wp.media.View
       
  8864  * @augments wp.Backbone.View
       
  8865  * @augments Backbone.View
       
  8866  */
       
  8867 AttachmentDisplay = Settings.extend(/** @lends wp.media.view.Settings.AttachmentDisplay.prototype */{
       
  8868 	className: 'attachment-display-settings',
       
  8869 	template:  wp.template('attachment-display-settings'),
       
  8870 
       
  8871 	initialize: function() {
       
  8872 		var attachment = this.options.attachment;
       
  8873 
       
  8874 		_.defaults( this.options, {
       
  8875 			userSettings: false
       
  8876 		});
       
  8877 		// Call 'initialize' directly on the parent class.
       
  8878 		Settings.prototype.initialize.apply( this, arguments );
       
  8879 		this.listenTo( this.model, 'change:link', this.updateLinkTo );
       
  8880 
       
  8881 		if ( attachment ) {
       
  8882 			attachment.on( 'change:uploading', this.render, this );
       
  8883 		}
       
  8884 	},
       
  8885 
       
  8886 	dispose: function() {
       
  8887 		var attachment = this.options.attachment;
       
  8888 		if ( attachment ) {
       
  8889 			attachment.off( null, null, this );
       
  8890 		}
       
  8891 		/**
       
  8892 		 * call 'dispose' directly on the parent class
       
  8893 		 */
       
  8894 		Settings.prototype.dispose.apply( this, arguments );
       
  8895 	},
       
  8896 	/**
       
  8897 	 * @return {wp.media.view.AttachmentDisplay} Returns itself to allow chaining.
       
  8898 	 */
       
  8899 	render: function() {
       
  8900 		var attachment = this.options.attachment;
       
  8901 		if ( attachment ) {
       
  8902 			_.extend( this.options, {
       
  8903 				sizes: attachment.get('sizes'),
       
  8904 				type:  attachment.get('type')
       
  8905 			});
       
  8906 		}
       
  8907 		/**
       
  8908 		 * call 'render' directly on the parent class
       
  8909 		 */
       
  8910 		Settings.prototype.render.call( this );
       
  8911 		this.updateLinkTo();
       
  8912 		return this;
       
  8913 	},
       
  8914 
       
  8915 	updateLinkTo: function() {
       
  8916 		var linkTo = this.model.get('link'),
       
  8917 			$input = this.$('.link-to-custom'),
       
  8918 			attachment = this.options.attachment;
       
  8919 
       
  8920 		if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
       
  8921 			$input.closest( '.setting' ).addClass( 'hidden' );
       
  8922 			return;
       
  8923 		}
       
  8924 
       
  8925 		if ( attachment ) {
       
  8926 			if ( 'post' === linkTo ) {
       
  8927 				$input.val( attachment.get('link') );
       
  8928 			} else if ( 'file' === linkTo ) {
       
  8929 				$input.val( attachment.get('url') );
       
  8930 			} else if ( ! this.model.get('linkUrl') ) {
       
  8931 				$input.val('http://');
       
  8932 			}
       
  8933 
       
  8934 			$input.prop( 'readonly', 'custom' !== linkTo );
       
  8935 		}
       
  8936 
       
  8937 		$input.closest( '.setting' ).removeClass( 'hidden' );
       
  8938 		if ( $input.length ) {
       
  8939 			$input[0].scrollIntoView();
       
  8940 		}
       
  8941 	}
       
  8942 });
       
  8943 
       
  8944 module.exports = AttachmentDisplay;
       
  8945 
       
  8946 
       
  8947 /***/ }),
       
  8948 /* 89 */
       
  8949 /***/ (function(module, exports) {
       
  8950 
       
  8951 /**
       
  8952  * wp.media.view.Settings.Gallery
       
  8953  *
       
  8954  * @memberOf wp.media.view.Settings
       
  8955  *
       
  8956  * @class
       
  8957  * @augments wp.media.view.Settings
       
  8958  * @augments wp.media.View
       
  8959  * @augments wp.Backbone.View
       
  8960  * @augments Backbone.View
       
  8961  */
       
  8962 var Gallery = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Gallery.prototype */{
       
  8963 	className: 'collection-settings gallery-settings',
       
  8964 	template:  wp.template('gallery-settings')
       
  8965 });
       
  8966 
       
  8967 module.exports = Gallery;
       
  8968 
       
  8969 
       
  8970 /***/ }),
       
  8971 /* 90 */
       
  8972 /***/ (function(module, exports) {
       
  8973 
       
  8974 /**
       
  8975  * wp.media.view.Settings.Playlist
       
  8976  *
       
  8977  * @memberOf wp.media.view.Settings
       
  8978  *
       
  8979  * @class
       
  8980  * @augments wp.media.view.Settings
       
  8981  * @augments wp.media.View
       
  8982  * @augments wp.Backbone.View
       
  8983  * @augments Backbone.View
       
  8984  */
       
  8985 var Playlist = wp.media.view.Settings.extend(/** @lends wp.media.view.Settings.Playlist.prototype */{
       
  8986 	className: 'collection-settings playlist-settings',
       
  8987 	template:  wp.template('playlist-settings')
       
  8988 });
       
  8989 
       
  8990 module.exports = Playlist;
       
  8991 
       
  8992 
       
  8993 /***/ }),
       
  8994 /* 91 */
       
  8995 /***/ (function(module, exports) {
       
  8996 
       
  8997 /* global ClipboardJS */
       
  8998 var Attachment = wp.media.view.Attachment,
       
  8999 	l10n = wp.media.view.l10n,
       
  9000 	$ = jQuery,
       
  9001 	Details,
       
  9002 	__ = wp.i18n.__;
       
  9003 
       
  9004 Details = Attachment.extend(/** @lends wp.media.view.Attachment.Details.prototype */{
       
  9005 	tagName:   'div',
       
  9006 	className: 'attachment-details',
       
  9007 	template:  wp.template('attachment-details'),
       
  9008 
       
  9009 	/*
       
  9010 	 * Reset all the attributes inherited from Attachment including role=checkbox,
       
  9011 	 * tabindex, etc., as they are inappropriate for this view. See #47458 and [30483] / #30390.
       
  9012 	 */
       
  9013 	attributes: {},
       
  9014 
       
  9015 	events: {
       
  9016 		'change [data-setting]':          'updateSetting',
       
  9017 		'change [data-setting] input':    'updateSetting',
       
  9018 		'change [data-setting] select':   'updateSetting',
       
  9019 		'change [data-setting] textarea': 'updateSetting',
       
  9020 		'click .delete-attachment':       'deleteAttachment',
       
  9021 		'click .trash-attachment':        'trashAttachment',
       
  9022 		'click .untrash-attachment':      'untrashAttachment',
       
  9023 		'click .edit-attachment':         'editAttachment',
       
  9024 		'keydown':                        'toggleSelectionHandler'
       
  9025 	},
       
  9026 
       
  9027 	/**
       
  9028 	 * Copies the attachment URL to the clipboard.
       
  9029 	 *
       
  9030 	 * @since 5.5.0
       
  9031 	 *
       
  9032 	 * @param {MouseEvent} event A click event.
       
  9033 	 *
       
  9034 	 * @return {void}
       
  9035 	 */
       
  9036 	 copyAttachmentDetailsURLClipboard: function() {
       
  9037 		var clipboard = new ClipboardJS( '.copy-attachment-url' ),
       
  9038 			successTimeout;
       
  9039 
       
  9040 		clipboard.on( 'success', function( event ) {
       
  9041 			var triggerElement = $( event.trigger ),
       
  9042 				successElement = $( '.success', triggerElement.closest( '.copy-to-clipboard-container' ) );
       
  9043 
       
  9044 			// Clear the selection and move focus back to the trigger.
       
  9045 			event.clearSelection();
       
  9046 			// Handle ClipboardJS focus bug, see https://github.com/zenorocha/clipboard.js/issues/680
       
  9047 			triggerElement.focus();
       
  9048 
       
  9049 			// Show success visual feedback.
       
  9050 			clearTimeout( successTimeout );
       
  9051 			successElement.removeClass( 'hidden' );
       
  9052 
       
  9053 			// Hide success visual feedback after 3 seconds since last success.
       
  9054 			successTimeout = setTimeout( function() {
       
  9055 				successElement.addClass( 'hidden' );
       
  9056 			}, 3000 );
       
  9057 
       
  9058 			// Handle success audible feedback.
       
  9059 			wp.a11y.speak( __( 'The file URL has been copied to your clipboard' ) );
       
  9060 		} );
       
  9061 	 },
       
  9062 
       
  9063 	/**
       
  9064 	 * Shows the details of an attachment.
       
  9065 	 *
       
  9066 	 * @since 3.5.0
       
  9067 	 *
       
  9068 	 * @constructs wp.media.view.Attachment.Details
       
  9069 	 * @augments wp.media.view.Attachment
       
  9070 	 *
       
  9071 	 * @return {void}
       
  9072 	 */
       
  9073 	initialize: function() {
       
  9074 		this.options = _.defaults( this.options, {
       
  9075 			rerenderOnModelChange: false
       
  9076 		});
       
  9077 
       
  9078 		// Call 'initialize' directly on the parent class.
       
  9079 		Attachment.prototype.initialize.apply( this, arguments );
       
  9080 
       
  9081 		this.copyAttachmentDetailsURLClipboard();
       
  9082 	},
       
  9083 
       
  9084 	/**
       
  9085 	 * Gets the focusable elements to move focus to.
       
  9086 	 *
       
  9087 	 * @since 5.3.0
       
  9088 	 */
       
  9089 	getFocusableElements: function() {
       
  9090 		var editedAttachment = $( 'li[data-id="' + this.model.id + '"]' );
       
  9091 
       
  9092 		this.previousAttachment = editedAttachment.prev();
       
  9093 		this.nextAttachment = editedAttachment.next();
       
  9094 	},
       
  9095 
       
  9096 	/**
       
  9097 	 * Moves focus to the previous or next attachment in the grid.
       
  9098 	 * Fallbacks to the upload button or media frame when there are no attachments.
       
  9099 	 *
       
  9100 	 * @since 5.3.0
       
  9101 	 */
       
  9102 	moveFocus: function() {
       
  9103 		if ( this.previousAttachment.length ) {
       
  9104 			this.previousAttachment.focus();
       
  9105 			return;
       
  9106 		}
       
  9107 
       
  9108 		if ( this.nextAttachment.length ) {
       
  9109 			this.nextAttachment.focus();
       
  9110 			return;
       
  9111 		}
       
  9112 
       
  9113 		// Fallback: move focus to the "Select Files" button in the media modal.
       
  9114 		if ( this.controller.uploader && this.controller.uploader.$browser ) {
       
  9115 			this.controller.uploader.$browser.focus();
       
  9116 			return;
       
  9117 		}
       
  9118 
       
  9119 		// Last fallback.
       
  9120 		this.moveFocusToLastFallback();
       
  9121 	},
       
  9122 
       
  9123 	/**
       
  9124 	 * Moves focus to the media frame as last fallback.
       
  9125 	 *
       
  9126 	 * @since 5.3.0
       
  9127 	 */
       
  9128 	moveFocusToLastFallback: function() {
       
  9129 		// Last fallback: make the frame focusable and move focus to it.
       
  9130 		$( '.media-frame' )
       
  9131 			.attr( 'tabindex', '-1' )
       
  9132 			.focus();
       
  9133 	},
       
  9134 
       
  9135 	/**
       
  9136 	 * Deletes an attachment.
       
  9137 	 *
       
  9138 	 * Deletes an attachment after asking for confirmation. After deletion,
       
  9139 	 * keeps focus in the modal.
       
  9140 	 *
       
  9141 	 * @since 3.5.0
       
  9142 	 *
       
  9143 	 * @param {MouseEvent} event A click event.
       
  9144 	 *
       
  9145 	 * @return {void}
       
  9146 	 */
       
  9147 	deleteAttachment: function( event ) {
       
  9148 		event.preventDefault();
       
  9149 
       
  9150 		this.getFocusableElements();
       
  9151 
       
  9152 		if ( window.confirm( l10n.warnDelete ) ) {
       
  9153 			this.model.destroy();
       
  9154 			this.moveFocus();
       
  9155 		}
       
  9156 	},
       
  9157 
       
  9158 	/**
       
  9159 	 * Sets the Trash state on an attachment, or destroys the model itself.
       
  9160 	 *
       
  9161 	 * If the mediaTrash setting is set to true, trashes the attachment.
       
  9162 	 * Otherwise, the model itself is destroyed.
       
  9163 	 *
       
  9164 	 * @since 3.9.0
       
  9165 	 *
       
  9166 	 * @param {MouseEvent} event A click event.
       
  9167 	 *
       
  9168 	 * @return {void}
       
  9169 	 */
       
  9170 	trashAttachment: function( event ) {
       
  9171 		var library = this.controller.library,
       
  9172 			self = this;
       
  9173 		event.preventDefault();
       
  9174 
       
  9175 		this.getFocusableElements();
       
  9176 
       
  9177 		// When in the Media Library and the Media Trash is enabled.
       
  9178 		if ( wp.media.view.settings.mediaTrash &&
       
  9179 			'edit-metadata' === this.controller.content.mode() ) {
       
  9180 
       
  9181 			this.model.set( 'status', 'trash' );
       
  9182 			this.model.save().done( function() {
       
  9183 				library._requery( true );
       
  9184 				/*
       
  9185 				 * @todo We need to move focus back to the previous, next, or first
       
  9186 				 * attachment but the library gets re-queried and refreshed.
       
  9187 				 * Thus, the references to the previous attachments are lost.
       
  9188 				 * We need an alternate method.
       
  9189 				 */
       
  9190 				self.moveFocusToLastFallback();
       
  9191 			} );
       
  9192 		} else {
       
  9193 			this.model.destroy();
       
  9194 			this.moveFocus();
       
  9195 		}
       
  9196 	},
       
  9197 	/**
       
  9198 	 * Untrashes an attachment.
       
  9199 	 *
       
  9200 	 * @since 4.0.0
       
  9201 	 *
       
  9202 	 * @param {MouseEvent} event A click event.
       
  9203 	 *
       
  9204 	 * @return {void}
       
  9205 	 */
       
  9206 	untrashAttachment: function( event ) {
       
  9207 		var library = this.controller.library;
       
  9208 		event.preventDefault();
       
  9209 
       
  9210 		this.model.set( 'status', 'inherit' );
       
  9211 		this.model.save().done( function() {
       
  9212 			library._requery( true );
       
  9213 		} );
       
  9214 	},
       
  9215 
       
  9216 	/**
       
  9217 	 * Opens the edit page for a specific attachment.
       
  9218 	 *
       
  9219 	 * @since 3.5.0
       
  9220 	 *
       
  9221 	 * @param {MouseEvent} event A click event.
       
  9222 	 *
       
  9223 	 * @return {void}
       
  9224 	 */
       
  9225 	editAttachment: function( event ) {
       
  9226 		var editState = this.controller.states.get( 'edit-image' );
       
  9227 		if ( window.imageEdit && editState ) {
       
  9228 			event.preventDefault();
       
  9229 
       
  9230 			editState.set( 'image', this.model );
       
  9231 			this.controller.setState( 'edit-image' );
       
  9232 		} else {
       
  9233 			this.$el.addClass('needs-refresh');
       
  9234 		}
       
  9235 	},
       
  9236 
       
  9237 	/**
       
  9238 	 * Triggers an event on the controller when reverse tabbing (shift+tab).
       
  9239 	 *
       
  9240 	 * This event can be used to make sure to move the focus correctly.
       
  9241 	 *
       
  9242 	 * @since 4.0.0
       
  9243 	 *
       
  9244 	 * @fires wp.media.controller.MediaLibrary#attachment:details:shift-tab
       
  9245 	 * @fires wp.media.controller.MediaLibrary#attachment:keydown:arrow
       
  9246 	 *
       
  9247 	 * @param {KeyboardEvent} event A keyboard event.
       
  9248 	 *
       
  9249 	 * @return {boolean|void} Returns false or undefined.
       
  9250 	 */
       
  9251 	toggleSelectionHandler: function( event ) {
       
  9252 		if ( 'keydown' === event.type && 9 === event.keyCode && event.shiftKey && event.target === this.$( ':tabbable' ).get( 0 ) ) {
       
  9253 			this.controller.trigger( 'attachment:details:shift-tab', event );
       
  9254 			return false;
       
  9255 		}
       
  9256 	}
       
  9257 });
       
  9258 
       
  9259 module.exports = Details;
       
  9260 
       
  9261 
       
  9262 /***/ }),
       
  9263 /* 92 */
       
  9264 /***/ (function(module, exports) {
       
  9265 
       
  9266 var View = wp.media.View,
       
  9267 	AttachmentCompat;
       
  9268 
       
  9269 /**
       
  9270  * wp.media.view.AttachmentCompat
       
  9271  *
       
  9272  * A view to display fields added via the `attachment_fields_to_edit` filter.
       
  9273  *
       
  9274  * @memberOf wp.media.view
       
  9275  *
       
  9276  * @class
       
  9277  * @augments wp.media.View
       
  9278  * @augments wp.Backbone.View
       
  9279  * @augments Backbone.View
       
  9280  */
       
  9281 AttachmentCompat = View.extend(/** @lends wp.media.view.AttachmentCompat.prototype */{
       
  9282 	tagName:   'form',
       
  9283 	className: 'compat-item',
       
  9284 
       
  9285 	events: {
       
  9286 		'submit':          'preventDefault',
       
  9287 		'change input':    'save',
       
  9288 		'change select':   'save',
       
  9289 		'change textarea': 'save'
       
  9290 	},
       
  9291 
       
  9292 	initialize: function() {
       
  9293 		this.listenTo( this.model, 'change:compat', this.render );
       
  9294 	},
       
  9295 	/**
       
  9296 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
       
  9297 	 */
       
  9298 	dispose: function() {
       
  9299 		if ( this.$(':focus').length ) {
       
  9300 			this.save();
       
  9301 		}
       
  9302 		/**
       
  9303 		 * call 'dispose' directly on the parent class
       
  9304 		 */
       
  9305 		return View.prototype.dispose.apply( this, arguments );
       
  9306 	},
       
  9307 	/**
       
  9308 	 * @return {wp.media.view.AttachmentCompat} Returns itself to allow chaining.
       
  9309 	 */
       
  9310 	render: function() {
       
  9311 		var compat = this.model.get('compat');
       
  9312 		if ( ! compat || ! compat.item ) {
       
  9313 			return;
       
  9314 		}
       
  9315 
       
  9316 		this.views.detach();
       
  9317 		this.$el.html( compat.item );
       
  9318 		this.views.render();
       
  9319 		return this;
       
  9320 	},
       
  9321 	/**
       
  9322 	 * @param {Object} event
       
  9323 	 */
       
  9324 	preventDefault: function( event ) {
       
  9325 		event.preventDefault();
       
  9326 	},
       
  9327 	/**
       
  9328 	 * @param {Object} event
       
  9329 	 */
       
  9330 	save: function( event ) {
       
  9331 		var data = {};
       
  9332 
       
  9333 		if ( event ) {
       
  9334 			event.preventDefault();
       
  9335 		}
       
  9336 
       
  9337 		_.each( this.$el.serializeArray(), function( pair ) {
       
  9338 			data[ pair.name ] = pair.value;
       
  9339 		});
       
  9340 
       
  9341 		this.controller.trigger( 'attachment:compat:waiting', ['waiting'] );
       
  9342 		this.model.saveCompat( data ).always( _.bind( this.postSave, this ) );
       
  9343 	},
       
  9344 
       
  9345 	postSave: function() {
       
  9346 		this.controller.trigger( 'attachment:compat:ready', ['ready'] );
       
  9347 	}
       
  9348 });
       
  9349 
       
  9350 module.exports = AttachmentCompat;
       
  9351 
       
  9352 
       
  9353 /***/ }),
       
  9354 /* 93 */
       
  9355 /***/ (function(module, exports) {
       
  9356 
       
  9357 /**
       
  9358  * wp.media.view.Iframe
       
  9359  *
       
  9360  * @memberOf wp.media.view
       
  9361  *
       
  9362  * @class
       
  9363  * @augments wp.media.View
       
  9364  * @augments wp.Backbone.View
       
  9365  * @augments Backbone.View
       
  9366  */
       
  9367 var Iframe = wp.media.View.extend(/** @lends wp.media.view.Iframe.prototype */{
       
  9368 	className: 'media-iframe',
       
  9369 	/**
       
  9370 	 * @return {wp.media.view.Iframe} Returns itself to allow chaining.
       
  9371 	 */
       
  9372 	render: function() {
       
  9373 		this.views.detach();
       
  9374 		this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
       
  9375 		this.views.render();
       
  9376 		return this;
 10534 		return this;
  9377 	}
 10535 	}
  9378 });
 10536 });
  9379 
 10537 
  9380 module.exports = Iframe;
 10538 module.exports = ButtonGroup;
  9381 
       
  9382 
       
  9383 /***/ }),
       
  9384 /* 94 */
       
  9385 /***/ (function(module, exports) {
       
  9386 
       
  9387 /**
       
  9388  * wp.media.view.Embed
       
  9389  *
       
  9390  * @memberOf wp.media.view
       
  9391  *
       
  9392  * @class
       
  9393  * @augments wp.media.View
       
  9394  * @augments wp.Backbone.View
       
  9395  * @augments Backbone.View
       
  9396  */
       
  9397 var Embed = wp.media.View.extend(/** @lends wp.media.view.Ember.prototype */{
       
  9398 	className: 'media-embed',
       
  9399 
       
  9400 	initialize: function() {
       
  9401 		/**
       
  9402 		 * @member {wp.media.view.EmbedUrl}
       
  9403 		 */
       
  9404 		this.url = new wp.media.view.EmbedUrl({
       
  9405 			controller: this.controller,
       
  9406 			model:      this.model.props
       
  9407 		}).render();
       
  9408 
       
  9409 		this.views.set([ this.url ]);
       
  9410 		this.refresh();
       
  9411 		this.listenTo( this.model, 'change:type', this.refresh );
       
  9412 		this.listenTo( this.model, 'change:loading', this.loading );
       
  9413 	},
       
  9414 
       
  9415 	/**
       
  9416 	 * @param {Object} view
       
  9417 	 */
       
  9418 	settings: function( view ) {
       
  9419 		if ( this._settings ) {
       
  9420 			this._settings.remove();
       
  9421 		}
       
  9422 		this._settings = view;
       
  9423 		this.views.add( view );
       
  9424 	},
       
  9425 
       
  9426 	refresh: function() {
       
  9427 		var type = this.model.get('type'),
       
  9428 			constructor;
       
  9429 
       
  9430 		if ( 'image' === type ) {
       
  9431 			constructor = wp.media.view.EmbedImage;
       
  9432 		} else if ( 'link' === type ) {
       
  9433 			constructor = wp.media.view.EmbedLink;
       
  9434 		} else {
       
  9435 			return;
       
  9436 		}
       
  9437 
       
  9438 		this.settings( new constructor({
       
  9439 			controller: this.controller,
       
  9440 			model:      this.model.props,
       
  9441 			priority:   40
       
  9442 		}) );
       
  9443 	},
       
  9444 
       
  9445 	loading: function() {
       
  9446 		this.$el.toggleClass( 'embed-loading', this.model.get('loading') );
       
  9447 	}
       
  9448 });
       
  9449 
       
  9450 module.exports = Embed;
       
  9451 
       
  9452 
       
  9453 /***/ }),
       
  9454 /* 95 */
       
  9455 /***/ (function(module, exports) {
       
  9456 
       
  9457 /**
       
  9458  * wp.media.view.Label
       
  9459  *
       
  9460  * @memberOf wp.media.view
       
  9461  *
       
  9462  * @class
       
  9463  * @augments wp.media.View
       
  9464  * @augments wp.Backbone.View
       
  9465  * @augments Backbone.View
       
  9466  */
       
  9467 var Label = wp.media.View.extend(/** @lends wp.media.view.Label.prototype */{
       
  9468 	tagName: 'label',
       
  9469 	className: 'screen-reader-text',
       
  9470 
       
  9471 	initialize: function() {
       
  9472 		this.value = this.options.value;
       
  9473 	},
       
  9474 
       
  9475 	render: function() {
       
  9476 		this.$el.html( this.value );
       
  9477 
       
  9478 		return this;
       
  9479 	}
       
  9480 });
       
  9481 
       
  9482 module.exports = Label;
       
  9483 
       
  9484 
       
  9485 /***/ }),
       
  9486 /* 96 */
       
  9487 /***/ (function(module, exports) {
       
  9488 
       
  9489 var View = wp.media.View,
       
  9490 	$ = jQuery,
       
  9491 	l10n = wp.media.view.l10n,
       
  9492 	EmbedUrl;
       
  9493 
       
  9494 /**
       
  9495  * wp.media.view.EmbedUrl
       
  9496  *
       
  9497  * @memberOf wp.media.view
       
  9498  *
       
  9499  * @class
       
  9500  * @augments wp.media.View
       
  9501  * @augments wp.Backbone.View
       
  9502  * @augments Backbone.View
       
  9503  */
       
  9504 EmbedUrl = View.extend(/** @lends wp.media.view.EmbedUrl.prototype */{
       
  9505 	tagName:   'span',
       
  9506 	className: 'embed-url',
       
  9507 
       
  9508 	events: {
       
  9509 		'input': 'url'
       
  9510 	},
       
  9511 
       
  9512 	initialize: function() {
       
  9513 		this.$input = $( '<input id="embed-url-field" type="url" />' )
       
  9514 			.attr( 'aria-label', l10n.insertFromUrlTitle )
       
  9515 			.val( this.model.get('url') );
       
  9516 		this.input = this.$input[0];
       
  9517 
       
  9518 		this.spinner = $('<span class="spinner" />')[0];
       
  9519 		this.$el.append([ this.input, this.spinner ]);
       
  9520 
       
  9521 		this.listenTo( this.model, 'change:url', this.render );
       
  9522 
       
  9523 		if ( this.model.get( 'url' ) ) {
       
  9524 			_.delay( _.bind( function () {
       
  9525 				this.model.trigger( 'change:url' );
       
  9526 			}, this ), 500 );
       
  9527 		}
       
  9528 	},
       
  9529 	/**
       
  9530 	 * @return {wp.media.view.EmbedUrl} Returns itself to allow chaining.
       
  9531 	 */
       
  9532 	render: function() {
       
  9533 		var $input = this.$input;
       
  9534 
       
  9535 		if ( $input.is(':focus') ) {
       
  9536 			return;
       
  9537 		}
       
  9538 
       
  9539 		this.input.value = this.model.get('url') || 'http://';
       
  9540 		/**
       
  9541 		 * Call `render` directly on parent class with passed arguments
       
  9542 		 */
       
  9543 		View.prototype.render.apply( this, arguments );
       
  9544 		return this;
       
  9545 	},
       
  9546 
       
  9547 	url: function( event ) {
       
  9548 		this.model.set( 'url', $.trim( event.target.value ) );
       
  9549 	}
       
  9550 });
       
  9551 
       
  9552 module.exports = EmbedUrl;
       
  9553 
       
  9554 
       
  9555 /***/ }),
       
  9556 /* 97 */
       
  9557 /***/ (function(module, exports) {
       
  9558 
       
  9559 var $ = jQuery,
       
  9560 	EmbedLink;
       
  9561 
       
  9562 /**
       
  9563  * wp.media.view.EmbedLink
       
  9564  *
       
  9565  * @memberOf wp.media.view
       
  9566  *
       
  9567  * @class
       
  9568  * @augments wp.media.view.Settings
       
  9569  * @augments wp.media.View
       
  9570  * @augments wp.Backbone.View
       
  9571  * @augments Backbone.View
       
  9572  */
       
  9573 EmbedLink = wp.media.view.Settings.extend(/** @lends wp.media.view.EmbedLink.prototype */{
       
  9574 	className: 'embed-link-settings',
       
  9575 	template:  wp.template('embed-link-settings'),
       
  9576 
       
  9577 	initialize: function() {
       
  9578 		this.listenTo( this.model, 'change:url', this.updateoEmbed );
       
  9579 	},
       
  9580 
       
  9581 	updateoEmbed: _.debounce( function() {
       
  9582 		var url = this.model.get( 'url' );
       
  9583 
       
  9584 		// Clear out previous results.
       
  9585 		this.$('.embed-container').hide().find('.embed-preview').empty();
       
  9586 		this.$( '.setting' ).hide();
       
  9587 
       
  9588 		// Only proceed with embed if the field contains more than 11 characters.
       
  9589 		// Example: http://a.io is 11 chars
       
  9590 		if ( url && ( url.length < 11 || ! url.match(/^http(s)?:\/\//) ) ) {
       
  9591 			return;
       
  9592 		}
       
  9593 
       
  9594 		this.fetch();
       
  9595 	}, wp.media.controller.Embed.sensitivity ),
       
  9596 
       
  9597 	fetch: function() {
       
  9598 		var url = this.model.get( 'url' ), re, youTubeEmbedMatch;
       
  9599 
       
  9600 		// Check if they haven't typed in 500 ms.
       
  9601 		if ( $('#embed-url-field').val() !== url ) {
       
  9602 			return;
       
  9603 		}
       
  9604 
       
  9605 		if ( this.dfd && 'pending' === this.dfd.state() ) {
       
  9606 			this.dfd.abort();
       
  9607 		}
       
  9608 
       
  9609 		// Support YouTube embed urls, since they work once in the editor.
       
  9610 		re = /https?:\/\/www\.youtube\.com\/embed\/([^/]+)/;
       
  9611 		youTubeEmbedMatch = re.exec( url );
       
  9612 		if ( youTubeEmbedMatch ) {
       
  9613 			url = 'https://www.youtube.com/watch?v=' + youTubeEmbedMatch[ 1 ];
       
  9614 		}
       
  9615 
       
  9616 		this.dfd = wp.apiRequest({
       
  9617 			url: wp.media.view.settings.oEmbedProxyUrl,
       
  9618 			data: {
       
  9619 				url: url,
       
  9620 				maxwidth: this.model.get( 'width' ),
       
  9621 				maxheight: this.model.get( 'height' )
       
  9622 			},
       
  9623 			type: 'GET',
       
  9624 			dataType: 'json',
       
  9625 			context: this
       
  9626 		})
       
  9627 			.done( function( response ) {
       
  9628 				this.renderoEmbed( {
       
  9629 					data: {
       
  9630 						body: response.html || ''
       
  9631 					}
       
  9632 				} );
       
  9633 			} )
       
  9634 			.fail( this.renderFail );
       
  9635 	},
       
  9636 
       
  9637 	renderFail: function ( response, status ) {
       
  9638 		if ( 'abort' === status ) {
       
  9639 			return;
       
  9640 		}
       
  9641 		this.$( '.link-text' ).show();
       
  9642 	},
       
  9643 
       
  9644 	renderoEmbed: function( response ) {
       
  9645 		var html = ( response && response.data && response.data.body ) || '';
       
  9646 
       
  9647 		if ( html ) {
       
  9648 			this.$('.embed-container').show().find('.embed-preview').html( html );
       
  9649 		} else {
       
  9650 			this.renderFail();
       
  9651 		}
       
  9652 	}
       
  9653 });
       
  9654 
       
  9655 module.exports = EmbedLink;
       
  9656 
       
  9657 
       
  9658 /***/ }),
       
  9659 /* 98 */
       
  9660 /***/ (function(module, exports) {
       
  9661 
       
  9662 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
       
  9663 	EmbedImage;
       
  9664 
       
  9665 /**
       
  9666  * wp.media.view.EmbedImage
       
  9667  *
       
  9668  * @memberOf wp.media.view
       
  9669  *
       
  9670  * @class
       
  9671  * @augments wp.media.view.Settings.AttachmentDisplay
       
  9672  * @augments wp.media.view.Settings
       
  9673  * @augments wp.media.View
       
  9674  * @augments wp.Backbone.View
       
  9675  * @augments Backbone.View
       
  9676  */
       
  9677 EmbedImage = AttachmentDisplay.extend(/** @lends wp.media.view.EmbedImage.prototype */{
       
  9678 	className: 'embed-media-settings',
       
  9679 	template:  wp.template('embed-image-settings'),
       
  9680 
       
  9681 	initialize: function() {
       
  9682 		/**
       
  9683 		 * Call `initialize` directly on parent class with passed arguments
       
  9684 		 */
       
  9685 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
       
  9686 		this.listenTo( this.model, 'change:url', this.updateImage );
       
  9687 	},
       
  9688 
       
  9689 	updateImage: function() {
       
  9690 		this.$('img').attr( 'src', this.model.get('url') );
       
  9691 	}
       
  9692 });
       
  9693 
       
  9694 module.exports = EmbedImage;
       
  9695 
       
  9696 
       
  9697 /***/ }),
       
  9698 /* 99 */
       
  9699 /***/ (function(module, exports) {
       
  9700 
       
  9701 var AttachmentDisplay = wp.media.view.Settings.AttachmentDisplay,
       
  9702 	$ = jQuery,
       
  9703 	ImageDetails;
       
  9704 
       
  9705 /**
       
  9706  * wp.media.view.ImageDetails
       
  9707  *
       
  9708  * @memberOf wp.media.view
       
  9709  *
       
  9710  * @class
       
  9711  * @augments wp.media.view.Settings.AttachmentDisplay
       
  9712  * @augments wp.media.view.Settings
       
  9713  * @augments wp.media.View
       
  9714  * @augments wp.Backbone.View
       
  9715  * @augments Backbone.View
       
  9716  */
       
  9717 ImageDetails = AttachmentDisplay.extend(/** @lends wp.media.view.ImageDetails.prototype */{
       
  9718 	className: 'image-details',
       
  9719 	template:  wp.template('image-details'),
       
  9720 	events: _.defaults( AttachmentDisplay.prototype.events, {
       
  9721 		'click .edit-attachment': 'editAttachment',
       
  9722 		'click .replace-attachment': 'replaceAttachment',
       
  9723 		'click .advanced-toggle': 'onToggleAdvanced',
       
  9724 		'change [data-setting="customWidth"]': 'onCustomSize',
       
  9725 		'change [data-setting="customHeight"]': 'onCustomSize',
       
  9726 		'keyup [data-setting="customWidth"]': 'onCustomSize',
       
  9727 		'keyup [data-setting="customHeight"]': 'onCustomSize'
       
  9728 	} ),
       
  9729 	initialize: function() {
       
  9730 		// Used in AttachmentDisplay.prototype.updateLinkTo.
       
  9731 		this.options.attachment = this.model.attachment;
       
  9732 		this.listenTo( this.model, 'change:url', this.updateUrl );
       
  9733 		this.listenTo( this.model, 'change:link', this.toggleLinkSettings );
       
  9734 		this.listenTo( this.model, 'change:size', this.toggleCustomSize );
       
  9735 
       
  9736 		AttachmentDisplay.prototype.initialize.apply( this, arguments );
       
  9737 	},
       
  9738 
       
  9739 	prepare: function() {
       
  9740 		var attachment = false;
       
  9741 
       
  9742 		if ( this.model.attachment ) {
       
  9743 			attachment = this.model.attachment.toJSON();
       
  9744 		}
       
  9745 		return _.defaults({
       
  9746 			model: this.model.toJSON(),
       
  9747 			attachment: attachment
       
  9748 		}, this.options );
       
  9749 	},
       
  9750 
       
  9751 	render: function() {
       
  9752 		var args = arguments;
       
  9753 
       
  9754 		if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
       
  9755 			this.model.dfd
       
  9756 				.done( _.bind( function() {
       
  9757 					AttachmentDisplay.prototype.render.apply( this, args );
       
  9758 					this.postRender();
       
  9759 				}, this ) )
       
  9760 				.fail( _.bind( function() {
       
  9761 					this.model.attachment = false;
       
  9762 					AttachmentDisplay.prototype.render.apply( this, args );
       
  9763 					this.postRender();
       
  9764 				}, this ) );
       
  9765 		} else {
       
  9766 			AttachmentDisplay.prototype.render.apply( this, arguments );
       
  9767 			this.postRender();
       
  9768 		}
       
  9769 
       
  9770 		return this;
       
  9771 	},
       
  9772 
       
  9773 	postRender: function() {
       
  9774 		setTimeout( _.bind( this.scrollToTop, this ), 10 );
       
  9775 		this.toggleLinkSettings();
       
  9776 		if ( window.getUserSetting( 'advImgDetails' ) === 'show' ) {
       
  9777 			this.toggleAdvanced( true );
       
  9778 		}
       
  9779 		this.trigger( 'post-render' );
       
  9780 	},
       
  9781 
       
  9782 	scrollToTop: function() {
       
  9783 		this.$( '.embed-media-settings' ).scrollTop( 0 );
       
  9784 	},
       
  9785 
       
  9786 	updateUrl: function() {
       
  9787 		this.$( '.image img' ).attr( 'src', this.model.get( 'url' ) );
       
  9788 		this.$( '.url' ).val( this.model.get( 'url' ) );
       
  9789 	},
       
  9790 
       
  9791 	toggleLinkSettings: function() {
       
  9792 		if ( this.model.get( 'link' ) === 'none' ) {
       
  9793 			this.$( '.link-settings' ).addClass('hidden');
       
  9794 		} else {
       
  9795 			this.$( '.link-settings' ).removeClass('hidden');
       
  9796 		}
       
  9797 	},
       
  9798 
       
  9799 	toggleCustomSize: function() {
       
  9800 		if ( this.model.get( 'size' ) !== 'custom' ) {
       
  9801 			this.$( '.custom-size' ).addClass('hidden');
       
  9802 		} else {
       
  9803 			this.$( '.custom-size' ).removeClass('hidden');
       
  9804 		}
       
  9805 	},
       
  9806 
       
  9807 	onCustomSize: function( event ) {
       
  9808 		var dimension = $( event.target ).data('setting'),
       
  9809 			num = $( event.target ).val(),
       
  9810 			value;
       
  9811 
       
  9812 		// Ignore bogus input.
       
  9813 		if ( ! /^\d+/.test( num ) || parseInt( num, 10 ) < 1 ) {
       
  9814 			event.preventDefault();
       
  9815 			return;
       
  9816 		}
       
  9817 
       
  9818 		if ( dimension === 'customWidth' ) {
       
  9819 			value = Math.round( 1 / this.model.get( 'aspectRatio' ) * num );
       
  9820 			this.model.set( 'customHeight', value, { silent: true } );
       
  9821 			this.$( '[data-setting="customHeight"]' ).val( value );
       
  9822 		} else {
       
  9823 			value = Math.round( this.model.get( 'aspectRatio' ) * num );
       
  9824 			this.model.set( 'customWidth', value, { silent: true  } );
       
  9825 			this.$( '[data-setting="customWidth"]' ).val( value );
       
  9826 		}
       
  9827 	},
       
  9828 
       
  9829 	onToggleAdvanced: function( event ) {
       
  9830 		event.preventDefault();
       
  9831 		this.toggleAdvanced();
       
  9832 	},
       
  9833 
       
  9834 	toggleAdvanced: function( show ) {
       
  9835 		var $advanced = this.$el.find( '.advanced-section' ),
       
  9836 			mode;
       
  9837 
       
  9838 		if ( $advanced.hasClass('advanced-visible') || show === false ) {
       
  9839 			$advanced.removeClass('advanced-visible');
       
  9840 			$advanced.find('.advanced-settings').addClass('hidden');
       
  9841 			mode = 'hide';
       
  9842 		} else {
       
  9843 			$advanced.addClass('advanced-visible');
       
  9844 			$advanced.find('.advanced-settings').removeClass('hidden');
       
  9845 			mode = 'show';
       
  9846 		}
       
  9847 
       
  9848 		window.setUserSetting( 'advImgDetails', mode );
       
  9849 	},
       
  9850 
       
  9851 	editAttachment: function( event ) {
       
  9852 		var editState = this.controller.states.get( 'edit-image' );
       
  9853 
       
  9854 		if ( window.imageEdit && editState ) {
       
  9855 			event.preventDefault();
       
  9856 			editState.set( 'image', this.model.attachment );
       
  9857 			this.controller.setState( 'edit-image' );
       
  9858 		}
       
  9859 	},
       
  9860 
       
  9861 	replaceAttachment: function( event ) {
       
  9862 		event.preventDefault();
       
  9863 		this.controller.setState( 'replace-image' );
       
  9864 	}
       
  9865 });
       
  9866 
       
  9867 module.exports = ImageDetails;
       
  9868 
       
  9869 
       
  9870 /***/ }),
       
  9871 /* 100 */
       
  9872 /***/ (function(module, exports) {
       
  9873 
       
  9874 var View = wp.media.View,
       
  9875 	UploaderStatus = wp.media.view.UploaderStatus,
       
  9876 	l10n = wp.media.view.l10n,
       
  9877 	$ = jQuery,
       
  9878 	Cropper;
       
  9879 
       
  9880 /**
       
  9881  * wp.media.view.Cropper
       
  9882  *
       
  9883  * Uses the imgAreaSelect plugin to allow a user to crop an image.
       
  9884  *
       
  9885  * Takes imgAreaSelect options from
       
  9886  * wp.customize.HeaderControl.calculateImageSelectOptions via
       
  9887  * wp.customize.HeaderControl.openMM.
       
  9888  *
       
  9889  * @memberOf wp.media.view
       
  9890  *
       
  9891  * @class
       
  9892  * @augments wp.media.View
       
  9893  * @augments wp.Backbone.View
       
  9894  * @augments Backbone.View
       
  9895  */
       
  9896 Cropper = View.extend(/** @lends wp.media.view.Cropper.prototype */{
       
  9897 	className: 'crop-content',
       
  9898 	template: wp.template('crop-content'),
       
  9899 	initialize: function() {
       
  9900 		_.bindAll(this, 'onImageLoad');
       
  9901 	},
       
  9902 	ready: function() {
       
  9903 		this.controller.frame.on('content:error:crop', this.onError, this);
       
  9904 		this.$image = this.$el.find('.crop-image');
       
  9905 		this.$image.on('load', this.onImageLoad);
       
  9906 		$(window).on('resize.cropper', _.debounce(this.onImageLoad, 250));
       
  9907 	},
       
  9908 	remove: function() {
       
  9909 		$(window).off('resize.cropper');
       
  9910 		this.$el.remove();
       
  9911 		this.$el.off();
       
  9912 		View.prototype.remove.apply(this, arguments);
       
  9913 	},
       
  9914 	prepare: function() {
       
  9915 		return {
       
  9916 			title: l10n.cropYourImage,
       
  9917 			url: this.options.attachment.get('url')
       
  9918 		};
       
  9919 	},
       
  9920 	onImageLoad: function() {
       
  9921 		var imgOptions = this.controller.get('imgSelectOptions'),
       
  9922 			imgSelect;
       
  9923 
       
  9924 		if (typeof imgOptions === 'function') {
       
  9925 			imgOptions = imgOptions(this.options.attachment, this.controller);
       
  9926 		}
       
  9927 
       
  9928 		imgOptions = _.extend(imgOptions, {
       
  9929 			parent: this.$el,
       
  9930 			onInit: function() {
       
  9931 
       
  9932 				// Store the set ratio.
       
  9933 				var setRatio = imgSelect.getOptions().aspectRatio;
       
  9934 
       
  9935 				// On mousedown, if no ratio is set and the Shift key is down, use a 1:1 ratio.
       
  9936 				this.parent.children().on( 'mousedown touchstart', function( e ) {
       
  9937 
       
  9938 					// If no ratio is set and the shift key is down, use a 1:1 ratio.
       
  9939 					if ( ! setRatio && e.shiftKey ) {
       
  9940 						imgSelect.setOptions( {
       
  9941 							aspectRatio: '1:1'
       
  9942 						} );
       
  9943 					}
       
  9944 				} );
       
  9945 
       
  9946 				this.parent.children().on( 'mouseup touchend', function() {
       
  9947 
       
  9948 					// Restore the set ratio.
       
  9949 					imgSelect.setOptions( {
       
  9950 						aspectRatio: setRatio ? setRatio : false
       
  9951 					} );
       
  9952 				} );
       
  9953 			}
       
  9954 		} );
       
  9955 		this.trigger('image-loaded');
       
  9956 		imgSelect = this.controller.imgSelect = this.$image.imgAreaSelect(imgOptions);
       
  9957 	},
       
  9958 	onError: function() {
       
  9959 		var filename = this.options.attachment.get('filename');
       
  9960 
       
  9961 		this.views.add( '.upload-errors', new wp.media.view.UploaderStatusError({
       
  9962 			filename: UploaderStatus.prototype.filename(filename),
       
  9963 			message: window._wpMediaViewsL10n.cropError
       
  9964 		}), { at: 0 });
       
  9965 	}
       
  9966 });
       
  9967 
       
  9968 module.exports = Cropper;
       
  9969 
       
  9970 
       
  9971 /***/ }),
       
  9972 /* 101 */
       
  9973 /***/ (function(module, exports) {
       
  9974 
       
  9975 var View = wp.media.view,
       
  9976 	SiteIconCropper;
       
  9977 
       
  9978 /**
       
  9979  * wp.media.view.SiteIconCropper
       
  9980  *
       
  9981  * Uses the imgAreaSelect plugin to allow a user to crop a Site Icon.
       
  9982  *
       
  9983  * Takes imgAreaSelect options from
       
  9984  * wp.customize.SiteIconControl.calculateImageSelectOptions.
       
  9985  *
       
  9986  * @memberOf wp.media.view
       
  9987  *
       
  9988  * @class
       
  9989  * @augments wp.media.view.Cropper
       
  9990  * @augments wp.media.View
       
  9991  * @augments wp.Backbone.View
       
  9992  * @augments Backbone.View
       
  9993  */
       
  9994 SiteIconCropper = View.Cropper.extend(/** @lends wp.media.view.SiteIconCropper.prototype */{
       
  9995 	className: 'crop-content site-icon',
       
  9996 
       
  9997 	ready: function () {
       
  9998 		View.Cropper.prototype.ready.apply( this, arguments );
       
  9999 
       
 10000 		this.$( '.crop-image' ).on( 'load', _.bind( this.addSidebar, this ) );
       
 10001 	},
       
 10002 
       
 10003 	addSidebar: function() {
       
 10004 		this.sidebar = new wp.media.view.Sidebar({
       
 10005 			controller: this.controller
       
 10006 		});
       
 10007 
       
 10008 		this.sidebar.set( 'preview', new wp.media.view.SiteIconPreview({
       
 10009 			controller: this.controller,
       
 10010 			attachment: this.options.attachment
       
 10011 		}) );
       
 10012 
       
 10013 		this.controller.cropperView.views.add( this.sidebar );
       
 10014 	}
       
 10015 });
       
 10016 
       
 10017 module.exports = SiteIconCropper;
       
 10018 
       
 10019 
       
 10020 /***/ }),
       
 10021 /* 102 */
       
 10022 /***/ (function(module, exports) {
       
 10023 
       
 10024 var View = wp.media.View,
       
 10025 	$ = jQuery,
       
 10026 	SiteIconPreview;
       
 10027 
       
 10028 /**
       
 10029  * wp.media.view.SiteIconPreview
       
 10030  *
       
 10031  * Shows a preview of the Site Icon as a favicon and app icon while cropping.
       
 10032  *
       
 10033  * @memberOf wp.media.view
       
 10034  *
       
 10035  * @class
       
 10036  * @augments wp.media.View
       
 10037  * @augments wp.Backbone.View
       
 10038  * @augments Backbone.View
       
 10039  */
       
 10040 SiteIconPreview = View.extend(/** @lends wp.media.view.SiteIconPreview.prototype */{
       
 10041 	className: 'site-icon-preview',
       
 10042 	template: wp.template( 'site-icon-preview' ),
       
 10043 
       
 10044 	ready: function() {
       
 10045 		this.controller.imgSelect.setOptions({
       
 10046 			onInit: this.updatePreview,
       
 10047 			onSelectChange: this.updatePreview
       
 10048 		});
       
 10049 	},
       
 10050 
       
 10051 	prepare: function() {
       
 10052 		return {
       
 10053 			url: this.options.attachment.get( 'url' )
       
 10054 		};
       
 10055 	},
       
 10056 
       
 10057 	updatePreview: function( img, coords ) {
       
 10058 		var rx = 64 / coords.width,
       
 10059 			ry = 64 / coords.height,
       
 10060 			preview_rx = 16 / coords.width,
       
 10061 			preview_ry = 16 / coords.height;
       
 10062 
       
 10063 		$( '#preview-app-icon' ).css({
       
 10064 			width: Math.round(rx * this.imageWidth ) + 'px',
       
 10065 			height: Math.round(ry * this.imageHeight ) + 'px',
       
 10066 			marginLeft: '-' + Math.round(rx * coords.x1) + 'px',
       
 10067 			marginTop: '-' + Math.round(ry * coords.y1) + 'px'
       
 10068 		});
       
 10069 
       
 10070 		$( '#preview-favicon' ).css({
       
 10071 			width: Math.round( preview_rx * this.imageWidth ) + 'px',
       
 10072 			height: Math.round( preview_ry * this.imageHeight ) + 'px',
       
 10073 			marginLeft: '-' + Math.round( preview_rx * coords.x1 ) + 'px',
       
 10074 			marginTop: '-' + Math.floor( preview_ry* coords.y1 ) + 'px'
       
 10075 		});
       
 10076 	}
       
 10077 });
       
 10078 
       
 10079 module.exports = SiteIconPreview;
       
 10080 
       
 10081 
       
 10082 /***/ }),
       
 10083 /* 103 */
       
 10084 /***/ (function(module, exports) {
       
 10085 
       
 10086 var View = wp.media.View,
       
 10087 	EditImage;
       
 10088 
       
 10089 /**
       
 10090  * wp.media.view.EditImage
       
 10091  *
       
 10092  * @memberOf wp.media.view
       
 10093  *
       
 10094  * @class
       
 10095  * @augments wp.media.View
       
 10096  * @augments wp.Backbone.View
       
 10097  * @augments Backbone.View
       
 10098  */
       
 10099 EditImage = View.extend(/** @lends wp.media.view.EditImage.prototype */{
       
 10100 	className: 'image-editor',
       
 10101 	template: wp.template('image-editor'),
       
 10102 
       
 10103 	initialize: function( options ) {
       
 10104 		this.editor = window.imageEdit;
       
 10105 		this.controller = options.controller;
       
 10106 		View.prototype.initialize.apply( this, arguments );
       
 10107 	},
       
 10108 
       
 10109 	prepare: function() {
       
 10110 		return this.model.toJSON();
       
 10111 	},
       
 10112 
       
 10113 	loadEditor: function() {
       
 10114 		this.editor.open( this.model.get( 'id' ), this.model.get( 'nonces' ).edit, this );
       
 10115 	},
       
 10116 
       
 10117 	back: function() {
       
 10118 		var lastState = this.controller.lastState();
       
 10119 		this.controller.setState( lastState );
       
 10120 	},
       
 10121 
       
 10122 	refresh: function() {
       
 10123 		this.model.fetch();
       
 10124 	},
       
 10125 
       
 10126 	save: function() {
       
 10127 		var lastState = this.controller.lastState();
       
 10128 
       
 10129 		this.model.fetch().done( _.bind( function() {
       
 10130 			this.controller.setState( lastState );
       
 10131 		}, this ) );
       
 10132 	}
       
 10133 
       
 10134 });
       
 10135 
       
 10136 module.exports = EditImage;
       
 10137 
       
 10138 
       
 10139 /***/ }),
       
 10140 /* 104 */
       
 10141 /***/ (function(module, exports) {
       
 10142 
       
 10143 /**
       
 10144  * wp.media.view.Spinner
       
 10145  *
       
 10146  * Represents a spinner in the Media Library.
       
 10147  *
       
 10148  * @since 3.9.0
       
 10149  *
       
 10150  * @memberOf wp.media.view
       
 10151  *
       
 10152  * @class
       
 10153  * @augments wp.media.View
       
 10154  * @augments wp.Backbone.View
       
 10155  * @augments Backbone.View
       
 10156  */
       
 10157 var Spinner = wp.media.View.extend(/** @lends wp.media.view.Spinner.prototype */{
       
 10158 	tagName:   'span',
       
 10159 	className: 'spinner',
       
 10160 	spinnerTimeout: false,
       
 10161 	delay: 400,
       
 10162 
       
 10163 	/**
       
 10164 	 * Shows the spinner. Delays the visibility by the configured amount.
       
 10165 	 *
       
 10166 	 * @since 3.9.0
       
 10167 	 *
       
 10168 	 * @return {wp.media.view.Spinner} The spinner.
       
 10169 	 */
       
 10170 	show: function() {
       
 10171 		if ( ! this.spinnerTimeout ) {
       
 10172 			this.spinnerTimeout = _.delay(function( $el ) {
       
 10173 				$el.addClass( 'is-active' );
       
 10174 			}, this.delay, this.$el );
       
 10175 		}
       
 10176 
       
 10177 		return this;
       
 10178 	},
       
 10179 
       
 10180 	/**
       
 10181 	 * Hides the spinner.
       
 10182 	 *
       
 10183 	 * @since 3.9.0
       
 10184 	 *
       
 10185 	 * @return {wp.media.view.Spinner} The spinner.
       
 10186 	 */
       
 10187 	hide: function() {
       
 10188 		this.$el.removeClass( 'is-active' );
       
 10189 		this.spinnerTimeout = clearTimeout( this.spinnerTimeout );
       
 10190 
       
 10191 		return this;
       
 10192 	}
       
 10193 });
       
 10194 
       
 10195 module.exports = Spinner;
       
 10196 
       
 10197 
       
 10198 /***/ }),
       
 10199 /* 105 */
       
 10200 /***/ (function(module, exports) {
       
 10201 
       
 10202 /**
       
 10203  * wp.media.view.Heading
       
 10204  *
       
 10205  * A reusable heading component for the media library
       
 10206  *
       
 10207  * Used to add accessibility friendly headers in the media library/modal.
       
 10208  *
       
 10209  * @class
       
 10210  * @augments wp.media.View
       
 10211  * @augments wp.Backbone.View
       
 10212  * @augments Backbone.View
       
 10213  */
       
 10214 var Heading = wp.media.View.extend( {
       
 10215 	tagName: function() {
       
 10216 		return this.options.level || 'h1';
       
 10217 	},
       
 10218 	className: 'media-views-heading',
       
 10219 
       
 10220 	initialize: function() {
       
 10221 
       
 10222 		if ( this.options.className ) {
       
 10223 			this.$el.addClass( this.options.className );
       
 10224 		}
       
 10225 
       
 10226 		this.text = this.options.text;
       
 10227 	},
       
 10228 
       
 10229 	render: function() {
       
 10230 		this.$el.html( this.text );
       
 10231 		return this;
       
 10232 	}
       
 10233 } );
       
 10234 
       
 10235 module.exports = Heading;
       
 10236 
 10539 
 10237 
 10540 
 10238 /***/ })
 10541 /***/ })
 10239 /******/ ]));
 10542 
       
 10543 /******/ });