wp/wp-includes/js/media-grid.js
changeset 7 cf61fcea0001
parent 5 5e2f62d02dcd
child 9 177826044cd9
equal deleted inserted replaced
6:490d5cc509ed 7:cf61fcea0001
     1 (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
     1 /******/ (function(modules) { // webpackBootstrap
     2 /*globals wp */
     2 /******/ 	// The module cache
       
     3 /******/ 	var installedModules = {};
       
     4 /******/
       
     5 /******/ 	// The require function
       
     6 /******/ 	function __webpack_require__(moduleId) {
       
     7 /******/
       
     8 /******/ 		// Check if module is in cache
       
     9 /******/ 		if(installedModules[moduleId]) {
       
    10 /******/ 			return installedModules[moduleId].exports;
       
    11 /******/ 		}
       
    12 /******/ 		// Create a new module (and put it into the cache)
       
    13 /******/ 		var module = installedModules[moduleId] = {
       
    14 /******/ 			i: moduleId,
       
    15 /******/ 			l: false,
       
    16 /******/ 			exports: {}
       
    17 /******/ 		};
       
    18 /******/
       
    19 /******/ 		// Execute the module function
       
    20 /******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
       
    21 /******/
       
    22 /******/ 		// Flag the module as loaded
       
    23 /******/ 		module.l = true;
       
    24 /******/
       
    25 /******/ 		// Return the exports of the module
       
    26 /******/ 		return module.exports;
       
    27 /******/ 	}
       
    28 /******/
       
    29 /******/
       
    30 /******/ 	// expose the modules object (__webpack_modules__)
       
    31 /******/ 	__webpack_require__.m = modules;
       
    32 /******/
       
    33 /******/ 	// expose the module cache
       
    34 /******/ 	__webpack_require__.c = installedModules;
       
    35 /******/
       
    36 /******/ 	// define getter function for harmony exports
       
    37 /******/ 	__webpack_require__.d = function(exports, name, getter) {
       
    38 /******/ 		if(!__webpack_require__.o(exports, name)) {
       
    39 /******/ 			Object.defineProperty(exports, name, {
       
    40 /******/ 				configurable: false,
       
    41 /******/ 				enumerable: true,
       
    42 /******/ 				get: getter
       
    43 /******/ 			});
       
    44 /******/ 		}
       
    45 /******/ 	};
       
    46 /******/
       
    47 /******/ 	// getDefaultExport function for compatibility with non-harmony modules
       
    48 /******/ 	__webpack_require__.n = function(module) {
       
    49 /******/ 		var getter = module && module.__esModule ?
       
    50 /******/ 			function getDefault() { return module['default']; } :
       
    51 /******/ 			function getModuleExports() { return module; };
       
    52 /******/ 		__webpack_require__.d(getter, 'a', getter);
       
    53 /******/ 		return getter;
       
    54 /******/ 	};
       
    55 /******/
       
    56 /******/ 	// Object.prototype.hasOwnProperty.call
       
    57 /******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
       
    58 /******/
       
    59 /******/ 	// __webpack_public_path__
       
    60 /******/ 	__webpack_require__.p = "";
       
    61 /******/
       
    62 /******/ 	// Load entry module and return exports
       
    63 /******/ 	return __webpack_require__(__webpack_require__.s = 10);
       
    64 /******/ })
       
    65 /************************************************************************/
       
    66 /******/ ([
       
    67 /* 0 */,
       
    68 /* 1 */,
       
    69 /* 2 */,
       
    70 /* 3 */,
       
    71 /* 4 */,
       
    72 /* 5 */,
       
    73 /* 6 */,
       
    74 /* 7 */,
       
    75 /* 8 */,
       
    76 /* 9 */,
       
    77 /* 10 */
       
    78 /***/ (function(module, exports, __webpack_require__) {
       
    79 
       
    80 var media = wp.media;
       
    81 
       
    82 media.controller.EditAttachmentMetadata = __webpack_require__( 11 );
       
    83 media.view.MediaFrame.Manage = __webpack_require__( 12 );
       
    84 media.view.Attachment.Details.TwoColumn = __webpack_require__( 13 );
       
    85 media.view.MediaFrame.Manage.Router = __webpack_require__( 14 );
       
    86 media.view.EditImage.Details = __webpack_require__( 15 );
       
    87 media.view.MediaFrame.EditAttachments = __webpack_require__( 16 );
       
    88 media.view.SelectModeToggleButton = __webpack_require__( 17 );
       
    89 media.view.DeleteSelectedButton = __webpack_require__( 18 );
       
    90 media.view.DeleteSelectedPermanentlyButton = __webpack_require__( 19 );
       
    91 
       
    92 
       
    93 /***/ }),
       
    94 /* 11 */
       
    95 /***/ (function(module, exports) {
       
    96 
       
    97 var l10n = wp.media.view.l10n,
       
    98 	EditAttachmentMetadata;
     3 
    99 
     4 /**
   100 /**
     5  * wp.media.controller.EditAttachmentMetadata
   101  * wp.media.controller.EditAttachmentMetadata
     6  *
   102  *
     7  * A state for editing an attachment's metadata.
   103  * A state for editing an attachment's metadata.
       
   104  *
       
   105  * @memberOf wp.media.controller
     8  *
   106  *
     9  * @class
   107  * @class
    10  * @augments wp.media.controller.State
   108  * @augments wp.media.controller.State
    11  * @augments Backbone.Model
   109  * @augments Backbone.Model
    12  */
   110  */
    13 var l10n = wp.media.view.l10n,
   111 EditAttachmentMetadata = wp.media.controller.State.extend(/** @lends wp.media.controller.EditAttachmentMetadata.prototype */{
    14 	EditAttachmentMetadata;
       
    15 
       
    16 EditAttachmentMetadata = wp.media.controller.State.extend({
       
    17 	defaults: {
   112 	defaults: {
    18 		id:      'edit-attachment',
   113 		id:      'edit-attachment',
    19 		// Title string passed to the frame's title region view.
   114 		// Title string passed to the frame's title region view.
    20 		title:   l10n.attachmentDetails,
   115 		title:   l10n.attachmentDetails,
    21 		// Region mode defaults.
   116 		// Region mode defaults.
    26 	}
   121 	}
    27 });
   122 });
    28 
   123 
    29 module.exports = EditAttachmentMetadata;
   124 module.exports = EditAttachmentMetadata;
    30 
   125 
    31 },{}],2:[function(require,module,exports){
   126 
    32 /*globals wp */
   127 /***/ }),
    33 
   128 /* 12 */
    34 var media = wp.media;
   129 /***/ (function(module, exports) {
    35 
   130 
    36 media.controller.EditAttachmentMetadata = require( './controllers/edit-attachment-metadata.js' );
   131 var MediaFrame = wp.media.view.MediaFrame,
    37 media.view.MediaFrame.Manage = require( './views/frame/manage.js' );
   132 	Library = wp.media.controller.Library,
    38 media.view.Attachment.Details.TwoColumn = require( './views/attachment/details-two-column.js' );
   133 
    39 media.view.MediaFrame.Manage.Router = require( './routers/manage.js' );
   134 	$ = Backbone.$,
    40 media.view.EditImage.Details = require( './views/edit-image-details.js' );
   135 	Manage;
    41 media.view.MediaFrame.EditAttachments = require( './views/frame/edit-attachments.js' );
       
    42 media.view.SelectModeToggleButton = require( './views/button/select-mode-toggle.js' );
       
    43 media.view.DeleteSelectedButton = require( './views/button/delete-selected.js' );
       
    44 media.view.DeleteSelectedPermanentlyButton = require( './views/button/delete-selected-permanently.js' );
       
    45 
       
    46 },{"./controllers/edit-attachment-metadata.js":1,"./routers/manage.js":3,"./views/attachment/details-two-column.js":4,"./views/button/delete-selected-permanently.js":5,"./views/button/delete-selected.js":6,"./views/button/select-mode-toggle.js":7,"./views/edit-image-details.js":8,"./views/frame/edit-attachments.js":9,"./views/frame/manage.js":10}],3:[function(require,module,exports){
       
    47 /*globals wp, Backbone */
       
    48 
       
    49 /**
       
    50  * wp.media.view.MediaFrame.Manage.Router
       
    51  *
       
    52  * A router for handling the browser history and application state.
       
    53  *
       
    54  * @class
       
    55  * @augments Backbone.Router
       
    56  */
       
    57 var Router = Backbone.Router.extend({
       
    58 	routes: {
       
    59 		'upload.php?item=:slug':    'showItem',
       
    60 		'upload.php?search=:query': 'search'
       
    61 	},
       
    62 
       
    63 	// Map routes against the page URL
       
    64 	baseUrl: function( url ) {
       
    65 		return 'upload.php' + url;
       
    66 	},
       
    67 
       
    68 	// Respond to the search route by filling the search field and trigggering the input event
       
    69 	search: function( query ) {
       
    70 		jQuery( '#media-search-input' ).val( query ).trigger( 'input' );
       
    71 	},
       
    72 
       
    73 	// Show the modal with a specific item
       
    74 	showItem: function( query ) {
       
    75 		var media = wp.media,
       
    76 			library = media.frame.state().get('library'),
       
    77 			item;
       
    78 
       
    79 		// Trigger the media frame to open the correct item
       
    80 		item = library.findWhere( { id: parseInt( query, 10 ) } );
       
    81 		if ( item ) {
       
    82 			media.frame.trigger( 'edit:attachment', item );
       
    83 		} else {
       
    84 			item = media.attachment( query );
       
    85 			media.frame.listenTo( item, 'change', function( model ) {
       
    86 				media.frame.stopListening( item );
       
    87 				media.frame.trigger( 'edit:attachment', model );
       
    88 			} );
       
    89 			item.fetch();
       
    90 		}
       
    91 	}
       
    92 });
       
    93 
       
    94 module.exports = Router;
       
    95 
       
    96 },{}],4:[function(require,module,exports){
       
    97 /*globals wp */
       
    98 
       
    99 /**
       
   100  * wp.media.view.Attachment.Details.TwoColumn
       
   101  *
       
   102  * A similar view to media.view.Attachment.Details
       
   103  * for use in the Edit Attachment modal.
       
   104  *
       
   105  * @class
       
   106  * @augments wp.media.view.Attachment.Details
       
   107  * @augments wp.media.view.Attachment
       
   108  * @augments wp.media.View
       
   109  * @augments wp.Backbone.View
       
   110  * @augments Backbone.View
       
   111  */
       
   112 var Details = wp.media.view.Attachment.Details,
       
   113 	TwoColumn;
       
   114 
       
   115 TwoColumn = Details.extend({
       
   116 	template: wp.template( 'attachment-details-two-column' ),
       
   117 
       
   118 	editAttachment: function( event ) {
       
   119 		event.preventDefault();
       
   120 		this.controller.content.mode( 'edit-image' );
       
   121 	},
       
   122 
       
   123 	/**
       
   124 	 * Noop this from parent class, doesn't apply here.
       
   125 	 */
       
   126 	toggleSelectionHandler: function() {},
       
   127 
       
   128 	render: function() {
       
   129 		Details.prototype.render.apply( this, arguments );
       
   130 
       
   131 		wp.media.mixin.removeAllPlayers();
       
   132 		this.$( 'audio, video' ).each( function (i, elem) {
       
   133 			var el = wp.media.view.MediaDetails.prepareSrc( elem );
       
   134 			new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings );
       
   135 		} );
       
   136 	}
       
   137 });
       
   138 
       
   139 module.exports = TwoColumn;
       
   140 
       
   141 },{}],5:[function(require,module,exports){
       
   142 /*globals wp */
       
   143 
       
   144 /**
       
   145  * wp.media.view.DeleteSelectedPermanentlyButton
       
   146  *
       
   147  * When MEDIA_TRASH is true, a button that handles bulk Delete Permanently logic
       
   148  *
       
   149  * @class
       
   150  * @augments wp.media.view.DeleteSelectedButton
       
   151  * @augments wp.media.view.Button
       
   152  * @augments wp.media.View
       
   153  * @augments wp.Backbone.View
       
   154  * @augments Backbone.View
       
   155  */
       
   156 var Button = wp.media.view.Button,
       
   157 	DeleteSelected = wp.media.view.DeleteSelectedButton,
       
   158 	DeleteSelectedPermanently;
       
   159 
       
   160 DeleteSelectedPermanently = DeleteSelected.extend({
       
   161 	initialize: function() {
       
   162 		DeleteSelected.prototype.initialize.apply( this, arguments );
       
   163 		this.listenTo( this.controller, 'select:activate', this.selectActivate );
       
   164 		this.listenTo( this.controller, 'select:deactivate', this.selectDeactivate );
       
   165 	},
       
   166 
       
   167 	filterChange: function( model ) {
       
   168 		this.canShow = ( 'trash' === model.get( 'status' ) );
       
   169 	},
       
   170 
       
   171 	selectActivate: function() {
       
   172 		this.toggleDisabled();
       
   173 		this.$el.toggleClass( 'hidden', ! this.canShow );
       
   174 	},
       
   175 
       
   176 	selectDeactivate: function() {
       
   177 		this.toggleDisabled();
       
   178 		this.$el.addClass( 'hidden' );
       
   179 	},
       
   180 
       
   181 	render: function() {
       
   182 		Button.prototype.render.apply( this, arguments );
       
   183 		this.selectActivate();
       
   184 		return this;
       
   185 	}
       
   186 });
       
   187 
       
   188 module.exports = DeleteSelectedPermanently;
       
   189 
       
   190 },{}],6:[function(require,module,exports){
       
   191 /*globals wp */
       
   192 
       
   193 /**
       
   194  * wp.media.view.DeleteSelectedButton
       
   195  *
       
   196  * A button that handles bulk Delete/Trash logic
       
   197  *
       
   198  * @class
       
   199  * @augments wp.media.view.Button
       
   200  * @augments wp.media.View
       
   201  * @augments wp.Backbone.View
       
   202  * @augments Backbone.View
       
   203  */
       
   204 var Button = wp.media.view.Button,
       
   205 	l10n = wp.media.view.l10n,
       
   206 	DeleteSelected;
       
   207 
       
   208 DeleteSelected = Button.extend({
       
   209 	initialize: function() {
       
   210 		Button.prototype.initialize.apply( this, arguments );
       
   211 		if ( this.options.filters ) {
       
   212 			this.listenTo( this.options.filters.model, 'change', this.filterChange );
       
   213 		}
       
   214 		this.listenTo( this.controller, 'selection:toggle', this.toggleDisabled );
       
   215 	},
       
   216 
       
   217 	filterChange: function( model ) {
       
   218 		if ( 'trash' === model.get( 'status' ) ) {
       
   219 			this.model.set( 'text', l10n.untrashSelected );
       
   220 		} else if ( wp.media.view.settings.mediaTrash ) {
       
   221 			this.model.set( 'text', l10n.trashSelected );
       
   222 		} else {
       
   223 			this.model.set( 'text', l10n.deleteSelected );
       
   224 		}
       
   225 	},
       
   226 
       
   227 	toggleDisabled: function() {
       
   228 		this.model.set( 'disabled', ! this.controller.state().get( 'selection' ).length );
       
   229 	},
       
   230 
       
   231 	render: function() {
       
   232 		Button.prototype.render.apply( this, arguments );
       
   233 		if ( this.controller.isModeActive( 'select' ) ) {
       
   234 			this.$el.addClass( 'delete-selected-button' );
       
   235 		} else {
       
   236 			this.$el.addClass( 'delete-selected-button hidden' );
       
   237 		}
       
   238 		this.toggleDisabled();
       
   239 		return this;
       
   240 	}
       
   241 });
       
   242 
       
   243 module.exports = DeleteSelected;
       
   244 
       
   245 },{}],7:[function(require,module,exports){
       
   246 /*globals wp */
       
   247 
       
   248 /**
       
   249  * wp.media.view.SelectModeToggleButton
       
   250  *
       
   251  * @class
       
   252  * @augments wp.media.view.Button
       
   253  * @augments wp.media.View
       
   254  * @augments wp.Backbone.View
       
   255  * @augments Backbone.View
       
   256  */
       
   257 var Button = wp.media.view.Button,
       
   258 	l10n = wp.media.view.l10n,
       
   259 	SelectModeToggle;
       
   260 
       
   261 SelectModeToggle = Button.extend({
       
   262 	initialize: function() {
       
   263 		Button.prototype.initialize.apply( this, arguments );
       
   264 		this.listenTo( this.controller, 'select:activate select:deactivate', this.toggleBulkEditHandler );
       
   265 		this.listenTo( this.controller, 'selection:action:done', this.back );
       
   266 	},
       
   267 
       
   268 	back: function () {
       
   269 		this.controller.deactivateMode( 'select' ).activateMode( 'edit' );
       
   270 	},
       
   271 
       
   272 	click: function() {
       
   273 		Button.prototype.click.apply( this, arguments );
       
   274 		if ( this.controller.isModeActive( 'select' ) ) {
       
   275 			this.back();
       
   276 		} else {
       
   277 			this.controller.deactivateMode( 'edit' ).activateMode( 'select' );
       
   278 		}
       
   279 	},
       
   280 
       
   281 	render: function() {
       
   282 		Button.prototype.render.apply( this, arguments );
       
   283 		this.$el.addClass( 'select-mode-toggle-button' );
       
   284 		return this;
       
   285 	},
       
   286 
       
   287 	toggleBulkEditHandler: function() {
       
   288 		var toolbar = this.controller.content.get().toolbar, children;
       
   289 
       
   290 		children = toolbar.$( '.media-toolbar-secondary > *, .media-toolbar-primary > *' );
       
   291 
       
   292 		// TODO: the Frame should be doing all of this.
       
   293 		if ( this.controller.isModeActive( 'select' ) ) {
       
   294 			this.model.set( 'text', l10n.cancelSelection );
       
   295 			children.not( '.media-button' ).hide();
       
   296 			this.$el.show();
       
   297 			toolbar.$( '.delete-selected-button' ).removeClass( 'hidden' );
       
   298 		} else {
       
   299 			this.model.set( 'text', l10n.bulkSelect );
       
   300 			this.controller.content.get().$el.removeClass( 'fixed' );
       
   301 			toolbar.$el.css( 'width', '' );
       
   302 			toolbar.$( '.delete-selected-button' ).addClass( 'hidden' );
       
   303 			children.not( '.spinner, .media-button' ).show();
       
   304 			this.controller.state().get( 'selection' ).reset();
       
   305 		}
       
   306 	}
       
   307 });
       
   308 
       
   309 module.exports = SelectModeToggle;
       
   310 
       
   311 },{}],8:[function(require,module,exports){
       
   312 /*globals wp, _ */
       
   313 
       
   314 /**
       
   315  * wp.media.view.EditImage.Details
       
   316  *
       
   317  * @class
       
   318  * @augments wp.media.view.EditImage
       
   319  * @augments wp.media.View
       
   320  * @augments wp.Backbone.View
       
   321  * @augments Backbone.View
       
   322  */
       
   323 var View = wp.media.View,
       
   324 	EditImage = wp.media.view.EditImage,
       
   325 	Details;
       
   326 
       
   327 Details = EditImage.extend({
       
   328 	initialize: function( options ) {
       
   329 		this.editor = window.imageEdit;
       
   330 		this.frame = options.frame;
       
   331 		this.controller = options.controller;
       
   332 		View.prototype.initialize.apply( this, arguments );
       
   333 	},
       
   334 
       
   335 	back: function() {
       
   336 		this.frame.content.mode( 'edit-metadata' );
       
   337 	},
       
   338 
       
   339 	save: function() {
       
   340 		this.model.fetch().done( _.bind( function() {
       
   341 			this.frame.content.mode( 'edit-metadata' );
       
   342 		}, this ) );
       
   343 	}
       
   344 });
       
   345 
       
   346 module.exports = Details;
       
   347 
       
   348 },{}],9:[function(require,module,exports){
       
   349 /*globals wp, _, jQuery */
       
   350 
       
   351 /**
       
   352  * wp.media.view.MediaFrame.EditAttachments
       
   353  *
       
   354  * A frame for editing the details of a specific media item.
       
   355  *
       
   356  * Opens in a modal by default.
       
   357  *
       
   358  * Requires an attachment model to be passed in the options hash under `model`.
       
   359  *
       
   360  * @class
       
   361  * @augments wp.media.view.Frame
       
   362  * @augments wp.media.View
       
   363  * @augments wp.Backbone.View
       
   364  * @augments Backbone.View
       
   365  * @mixes wp.media.controller.StateMachine
       
   366  */
       
   367 var Frame = wp.media.view.Frame,
       
   368 	MediaFrame = wp.media.view.MediaFrame,
       
   369 
       
   370 	$ = jQuery,
       
   371 	EditAttachments;
       
   372 
       
   373 EditAttachments = MediaFrame.extend({
       
   374 
       
   375 	className: 'edit-attachment-frame',
       
   376 	template:  wp.template( 'edit-attachment-frame' ),
       
   377 	regions:   [ 'title', 'content' ],
       
   378 
       
   379 	events: {
       
   380 		'click .left':  'previousMediaItem',
       
   381 		'click .right': 'nextMediaItem'
       
   382 	},
       
   383 
       
   384 	initialize: function() {
       
   385 		Frame.prototype.initialize.apply( this, arguments );
       
   386 
       
   387 		_.defaults( this.options, {
       
   388 			modal: true,
       
   389 			state: 'edit-attachment'
       
   390 		});
       
   391 
       
   392 		this.controller = this.options.controller;
       
   393 		this.gridRouter = this.controller.gridRouter;
       
   394 		this.library = this.options.library;
       
   395 
       
   396 		if ( this.options.model ) {
       
   397 			this.model = this.options.model;
       
   398 		}
       
   399 
       
   400 		this.bindHandlers();
       
   401 		this.createStates();
       
   402 		this.createModal();
       
   403 
       
   404 		this.title.mode( 'default' );
       
   405 		this.toggleNav();
       
   406 	},
       
   407 
       
   408 	bindHandlers: function() {
       
   409 		// Bind default title creation.
       
   410 		this.on( 'title:create:default', this.createTitle, this );
       
   411 
       
   412 		// Close the modal if the attachment is deleted.
       
   413 		this.listenTo( this.model, 'change:status destroy', this.close, this );
       
   414 
       
   415 		this.on( 'content:create:edit-metadata', this.editMetadataMode, this );
       
   416 		this.on( 'content:create:edit-image', this.editImageMode, this );
       
   417 		this.on( 'content:render:edit-image', this.editImageModeRender, this );
       
   418 		this.on( 'close', this.detach );
       
   419 	},
       
   420 
       
   421 	createModal: function() {
       
   422 		// Initialize modal container view.
       
   423 		if ( this.options.modal ) {
       
   424 			this.modal = new wp.media.view.Modal({
       
   425 				controller: this,
       
   426 				title:      this.options.title
       
   427 			});
       
   428 
       
   429 			this.modal.on( 'open', _.bind( function () {
       
   430 				$( 'body' ).on( 'keydown.media-modal', _.bind( this.keyEvent, this ) );
       
   431 			}, this ) );
       
   432 
       
   433 			// Completely destroy the modal DOM element when closing it.
       
   434 			this.modal.on( 'close', _.bind( function() {
       
   435 				this.modal.remove();
       
   436 				$( 'body' ).off( 'keydown.media-modal' ); /* remove the keydown event */
       
   437 				// Restore the original focus item if possible
       
   438 				$( 'li.attachment[data-id="' + this.model.get( 'id' ) +'"]' ).focus();
       
   439 				this.resetRoute();
       
   440 			}, this ) );
       
   441 
       
   442 			// Set this frame as the modal's content.
       
   443 			this.modal.content( this );
       
   444 			this.modal.open();
       
   445 		}
       
   446 	},
       
   447 
       
   448 	/**
       
   449 	 * Add the default states to the frame.
       
   450 	 */
       
   451 	createStates: function() {
       
   452 		this.states.add([
       
   453 			new wp.media.controller.EditAttachmentMetadata( { model: this.model } )
       
   454 		]);
       
   455 	},
       
   456 
       
   457 	/**
       
   458 	 * Content region rendering callback for the `edit-metadata` mode.
       
   459 	 *
       
   460 	 * @param {Object} contentRegion Basic object with a `view` property, which
       
   461 	 *                               should be set with the proper region view.
       
   462 	 */
       
   463 	editMetadataMode: function( contentRegion ) {
       
   464 		contentRegion.view = new wp.media.view.Attachment.Details.TwoColumn({
       
   465 			controller: this,
       
   466 			model:      this.model
       
   467 		});
       
   468 
       
   469 		/**
       
   470 		 * Attach a subview to display fields added via the
       
   471 		 * `attachment_fields_to_edit` filter.
       
   472 		 */
       
   473 		contentRegion.view.views.set( '.attachment-compat', new wp.media.view.AttachmentCompat({
       
   474 			controller: this,
       
   475 			model:      this.model
       
   476 		}) );
       
   477 
       
   478 		// Update browser url when navigating media details
       
   479 		if ( this.model ) {
       
   480 			this.gridRouter.navigate( this.gridRouter.baseUrl( '?item=' + this.model.id ) );
       
   481 		}
       
   482 	},
       
   483 
       
   484 	/**
       
   485 	 * Render the EditImage view into the frame's content region.
       
   486 	 *
       
   487 	 * @param {Object} contentRegion Basic object with a `view` property, which
       
   488 	 *                               should be set with the proper region view.
       
   489 	 */
       
   490 	editImageMode: function( contentRegion ) {
       
   491 		var editImageController = new wp.media.controller.EditImage( {
       
   492 			model: this.model,
       
   493 			frame: this
       
   494 		} );
       
   495 		// Noop some methods.
       
   496 		editImageController._toolbar = function() {};
       
   497 		editImageController._router = function() {};
       
   498 		editImageController._menu = function() {};
       
   499 
       
   500 		contentRegion.view = new wp.media.view.EditImage.Details( {
       
   501 			model: this.model,
       
   502 			frame: this,
       
   503 			controller: editImageController
       
   504 		} );
       
   505 	},
       
   506 
       
   507 	editImageModeRender: function( view ) {
       
   508 		view.on( 'ready', view.loadEditor );
       
   509 	},
       
   510 
       
   511 	toggleNav: function() {
       
   512 		this.$('.left').toggleClass( 'disabled', ! this.hasPrevious() );
       
   513 		this.$('.right').toggleClass( 'disabled', ! this.hasNext() );
       
   514 	},
       
   515 
       
   516 	/**
       
   517 	 * Rerender the view.
       
   518 	 */
       
   519 	rerender: function() {
       
   520 		// Only rerender the `content` region.
       
   521 		if ( this.content.mode() !== 'edit-metadata' ) {
       
   522 			this.content.mode( 'edit-metadata' );
       
   523 		} else {
       
   524 			this.content.render();
       
   525 		}
       
   526 
       
   527 		this.toggleNav();
       
   528 	},
       
   529 
       
   530 	/**
       
   531 	 * Click handler to switch to the previous media item.
       
   532 	 */
       
   533 	previousMediaItem: function() {
       
   534 		if ( ! this.hasPrevious() ) {
       
   535 			this.$( '.left' ).blur();
       
   536 			return;
       
   537 		}
       
   538 		this.model = this.library.at( this.getCurrentIndex() - 1 );
       
   539 		this.rerender();
       
   540 		this.$( '.left' ).focus();
       
   541 	},
       
   542 
       
   543 	/**
       
   544 	 * Click handler to switch to the next media item.
       
   545 	 */
       
   546 	nextMediaItem: function() {
       
   547 		if ( ! this.hasNext() ) {
       
   548 			this.$( '.right' ).blur();
       
   549 			return;
       
   550 		}
       
   551 		this.model = this.library.at( this.getCurrentIndex() + 1 );
       
   552 		this.rerender();
       
   553 		this.$( '.right' ).focus();
       
   554 	},
       
   555 
       
   556 	getCurrentIndex: function() {
       
   557 		return this.library.indexOf( this.model );
       
   558 	},
       
   559 
       
   560 	hasNext: function() {
       
   561 		return ( this.getCurrentIndex() + 1 ) < this.library.length;
       
   562 	},
       
   563 
       
   564 	hasPrevious: function() {
       
   565 		return ( this.getCurrentIndex() - 1 ) > -1;
       
   566 	},
       
   567 	/**
       
   568 	 * Respond to the keyboard events: right arrow, left arrow, except when
       
   569 	 * focus is in a textarea or input field.
       
   570 	 */
       
   571 	keyEvent: function( event ) {
       
   572 		if ( ( 'INPUT' === event.target.nodeName || 'TEXTAREA' === event.target.nodeName ) && ! ( event.target.readOnly || event.target.disabled ) ) {
       
   573 			return;
       
   574 		}
       
   575 
       
   576 		// The right arrow key
       
   577 		if ( 39 === event.keyCode ) {
       
   578 			this.nextMediaItem();
       
   579 		}
       
   580 		// The left arrow key
       
   581 		if ( 37 === event.keyCode ) {
       
   582 			this.previousMediaItem();
       
   583 		}
       
   584 	},
       
   585 
       
   586 	resetRoute: function() {
       
   587 		this.gridRouter.navigate( this.gridRouter.baseUrl( '' ) );
       
   588 	}
       
   589 });
       
   590 
       
   591 module.exports = EditAttachments;
       
   592 
       
   593 },{}],10:[function(require,module,exports){
       
   594 /*globals wp, _, Backbone */
       
   595 
   136 
   596 /**
   137 /**
   597  * wp.media.view.MediaFrame.Manage
   138  * wp.media.view.MediaFrame.Manage
   598  *
   139  *
   599  * A generic management frame workflow.
   140  * A generic management frame workflow.
   600  *
   141  *
   601  * Used in the media grid view.
   142  * Used in the media grid view.
       
   143  *
       
   144  * @memberOf wp.media.view.MediaFrame
   602  *
   145  *
   603  * @class
   146  * @class
   604  * @augments wp.media.view.MediaFrame
   147  * @augments wp.media.view.MediaFrame
   605  * @augments wp.media.view.Frame
   148  * @augments wp.media.view.Frame
   606  * @augments wp.media.View
   149  * @augments wp.media.View
   607  * @augments wp.Backbone.View
   150  * @augments wp.Backbone.View
   608  * @augments Backbone.View
   151  * @augments Backbone.View
   609  * @mixes wp.media.controller.StateMachine
   152  * @mixes wp.media.controller.StateMachine
   610  */
   153  */
   611 var MediaFrame = wp.media.view.MediaFrame,
   154 Manage = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.Manage.prototype */{
   612 	Library = wp.media.controller.Library,
   155 	/**
   613 
   156 	 * @constructs
   614 	$ = Backbone.$,
       
   615 	Manage;
       
   616 
       
   617 Manage = MediaFrame.extend({
       
   618 	/**
       
   619 	 * @global wp.Uploader
       
   620 	 */
   157 	 */
   621 	initialize: function() {
   158 	initialize: function() {
   622 		_.defaults( this.options, {
   159 		_.defaults( this.options, {
   623 			title:     '',
   160 			title:     '',
   624 			modal:     false,
   161 			modal:     false,
   631 		});
   168 		});
   632 
   169 
   633 		this.$body = $( document.body );
   170 		this.$body = $( document.body );
   634 		this.$window = $( window );
   171 		this.$window = $( window );
   635 		this.$adminBar = $( '#wpadminbar' );
   172 		this.$adminBar = $( '#wpadminbar' );
       
   173 		// Store the Add New button for later reuse in wp.media.view.UploaderInline.
       
   174 		this.$uploaderToggler = $( '.page-title-action' )
       
   175 			.attr( 'aria-expanded', 'false' )
       
   176 			.on( 'click', _.bind( this.addNewClickHandler, this ) );
       
   177 
   636 		this.$window.on( 'scroll resize', _.debounce( _.bind( this.fixPosition, this ), 15 ) );
   178 		this.$window.on( 'scroll resize', _.debounce( _.bind( this.fixPosition, this ), 15 ) );
   637 		$( document ).on( 'click', '.add-new-h2', _.bind( this.addNewClickHandler, this ) );
       
   638 
   179 
   639 		// Ensure core and media grid view UI is enabled.
   180 		// Ensure core and media grid view UI is enabled.
   640 		this.$el.addClass('wp-core-ui');
   181 		this.$el.addClass('wp-core-ui');
   641 
   182 
   642 		// Force the uploader off if the upload limit has been exceeded or
   183 		// Force the uploader off if the upload limit has been exceeded or
   670 
   211 
   671 		this.createStates();
   212 		this.createStates();
   672 		this.bindRegionModeHandlers();
   213 		this.bindRegionModeHandlers();
   673 		this.render();
   214 		this.render();
   674 		this.bindSearchHandler();
   215 		this.bindSearchHandler();
       
   216 
       
   217 		wp.media.frames.browse = this;
   675 	},
   218 	},
   676 
   219 
   677 	bindSearchHandler: function() {
   220 	bindSearchHandler: function() {
   678 		var search = this.$( '#media-search-input' ),
   221 		var search = this.$( '#media-search-input' ),
   679 			currentSearch = this.options.container.data( 'search' ),
       
   680 			searchView = this.browserView.toolbar.get( 'search' ).$el,
   222 			searchView = this.browserView.toolbar.get( 'search' ).$el,
   681 			listMode = this.$( '.view-list' ),
   223 			listMode = this.$( '.view-list' ),
   682 
   224 
   683 			input  = _.debounce( function (e) {
   225 			input  = _.throttle( function (e) {
   684 				var val = $( e.currentTarget ).val(),
   226 				var val = $( e.currentTarget ).val(),
   685 					url = '';
   227 					url = '';
   686 
   228 
   687 				if ( val ) {
   229 				if ( val ) {
   688 					url += '?search=' + val;
   230 					url += '?search=' + val;
       
   231 					this.gridRouter.navigate( this.gridRouter.baseUrl( url ), { replace: true } );
   689 				}
   232 				}
   690 				this.gridRouter.navigate( this.gridRouter.baseUrl( url ) );
       
   691 			}, 1000 );
   233 			}, 1000 );
   692 
   234 
   693 		// Update the URL when entering search string (at most once per second)
   235 		// Update the URL when entering search string (at most once per second)
   694 		search.on( 'input', _.bind( input, this ) );
   236 		search.on( 'input', _.bind( input, this ) );
   695 		searchView.val( currentSearch ).trigger( 'input' );
   237 
   696 
   238 		this.gridRouter
   697 		this.gridRouter.on( 'route:search', function () {
   239 			.on( 'route:search', function () {
   698 			var href = window.location.href;
   240 				var href = window.location.href;
   699 			if ( href.indexOf( 'mode=' ) > -1 ) {
   241 				if ( href.indexOf( 'mode=' ) > -1 ) {
   700 				href = href.replace( /mode=[^&]+/g, 'mode=list' );
   242 					href = href.replace( /mode=[^&]+/g, 'mode=list' );
   701 			} else {
   243 				} else {
   702 				href += href.indexOf( '?' ) > -1 ? '&mode=list' : '?mode=list';
   244 					href += href.indexOf( '?' ) > -1 ? '&mode=list' : '?mode=list';
   703 			}
   245 				}
   704 			href = href.replace( 'search=', 's=' );
   246 				href = href.replace( 'search=', 's=' );
   705 			listMode.prop( 'href', href );
   247 				listMode.prop( 'href', href );
   706 		} );
   248 			})
       
   249 			.on( 'route:reset', function() {
       
   250 				searchView.val( '' ).trigger( 'input' );
       
   251 			});
   707 	},
   252 	},
   708 
   253 
   709 	/**
   254 	/**
   710 	 * Create the default states for the frame.
   255 	 * Create the default states for the frame.
   711 	 */
   256 	 */
   782 	 * Click handler for the `Add New` button.
   327 	 * Click handler for the `Add New` button.
   783 	 */
   328 	 */
   784 	addNewClickHandler: function( event ) {
   329 	addNewClickHandler: function( event ) {
   785 		event.preventDefault();
   330 		event.preventDefault();
   786 		this.trigger( 'toggle:upload:attachment' );
   331 		this.trigger( 'toggle:upload:attachment' );
       
   332 
       
   333 		if ( this.uploader ) {
       
   334 			this.uploader.refresh();
       
   335 		}
   787 	},
   336 	},
   788 
   337 
   789 	/**
   338 	/**
   790 	 * Open the Edit Attachment modal.
   339 	 * Open the Edit Attachment modal.
   791 	 */
   340 	 */
   792 	openEditAttachmentModal: function( model ) {
   341 	openEditAttachmentModal: function( model ) {
   793 		// Create a new EditAttachment frame, passing along the library and the attachment model.
   342 		// Create a new EditAttachment frame, passing along the library and the attachment model.
   794 		wp.media( {
   343 		if ( wp.media.frames.edit ) {
   795 			frame:       'edit-attachments',
   344 			wp.media.frames.edit.open().trigger( 'refresh', model );
   796 			controller:  this,
   345 		} else {
   797 			library:     this.state().get('library'),
   346 			wp.media.frames.edit = wp.media( {
   798 			model:       model
   347 				frame:       'edit-attachments',
   799 		} );
   348 				controller:  this,
       
   349 				library:     this.state().get('library'),
       
   350 				model:       model
       
   351 			} );
       
   352 		}
   800 	},
   353 	},
   801 
   354 
   802 	/**
   355 	/**
   803 	 * Create an attachments browser view within the content region.
   356 	 * Create an attachments browser view within the content region.
   804 	 *
   357 	 *
   848 	},
   401 	},
   849 
   402 
   850 	startHistory: function() {
   403 	startHistory: function() {
   851 		// Verify pushState support and activate
   404 		// Verify pushState support and activate
   852 		if ( window.history && window.history.pushState ) {
   405 		if ( window.history && window.history.pushState ) {
       
   406 			if ( Backbone.History.started ) {
       
   407 				Backbone.history.stop();
       
   408 			}
   853 			Backbone.history.start( {
   409 			Backbone.history.start( {
   854 				root: window._wpMediaGridSettings.adminUrl,
   410 				root: window._wpMediaGridSettings.adminUrl,
   855 				pushState: true
   411 				pushState: true
   856 			} );
   412 			} );
   857 		}
   413 		}
   858 	}
   414 	}
   859 });
   415 });
   860 
   416 
   861 module.exports = Manage;
   417 module.exports = Manage;
   862 
   418 
   863 },{}]},{},[2]);
   419 
       
   420 /***/ }),
       
   421 /* 13 */
       
   422 /***/ (function(module, exports) {
       
   423 
       
   424 var Details = wp.media.view.Attachment.Details,
       
   425 	TwoColumn;
       
   426 
       
   427 /**
       
   428  * wp.media.view.Attachment.Details.TwoColumn
       
   429  *
       
   430  * A similar view to media.view.Attachment.Details
       
   431  * for use in the Edit Attachment modal.
       
   432  *
       
   433  * @memberOf wp.media.view.Attachment.Details
       
   434  *
       
   435  * @class
       
   436  * @augments wp.media.view.Attachment.Details
       
   437  * @augments wp.media.view.Attachment
       
   438  * @augments wp.media.View
       
   439  * @augments wp.Backbone.View
       
   440  * @augments Backbone.View
       
   441  */
       
   442 TwoColumn = Details.extend(/** @lends wp.media.view.Attachment.Details.TowColumn.prototype */{
       
   443 	template: wp.template( 'attachment-details-two-column' ),
       
   444 
       
   445 	initialize: function() {
       
   446 		this.controller.on( 'content:activate:edit-details', _.bind( this.editAttachment, this ) );
       
   447 
       
   448 		Details.prototype.initialize.apply( this, arguments );
       
   449 	},
       
   450 
       
   451 	editAttachment: function( event ) {
       
   452 		if ( event ) {
       
   453 			event.preventDefault();
       
   454 		}
       
   455 		this.controller.content.mode( 'edit-image' );
       
   456 	},
       
   457 
       
   458 	/**
       
   459 	 * Noop this from parent class, doesn't apply here.
       
   460 	 */
       
   461 	toggleSelectionHandler: function() {},
       
   462 
       
   463 	render: function() {
       
   464 		Details.prototype.render.apply( this, arguments );
       
   465 
       
   466 		wp.media.mixin.removeAllPlayers();
       
   467 		this.$( 'audio, video' ).each( function (i, elem) {
       
   468 			var el = wp.media.view.MediaDetails.prepareSrc( elem );
       
   469 			new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings );
       
   470 		} );
       
   471 	}
       
   472 });
       
   473 
       
   474 module.exports = TwoColumn;
       
   475 
       
   476 
       
   477 /***/ }),
       
   478 /* 14 */
       
   479 /***/ (function(module, exports) {
       
   480 
       
   481 /**
       
   482  * wp.media.view.MediaFrame.Manage.Router
       
   483  *
       
   484  * A router for handling the browser history and application state.
       
   485  *
       
   486  * @memberOf wp.media.view.MediaFrame.Manage
       
   487  *
       
   488  * @class
       
   489  * @augments Backbone.Router
       
   490  */
       
   491 var Router = Backbone.Router.extend(/** @lends wp.media.view.MediaFrame.Manage.Router.prototype */{
       
   492 	routes: {
       
   493 		'upload.php?item=:slug&mode=edit': 'editItem',
       
   494 		'upload.php?item=:slug':           'showItem',
       
   495 		'upload.php?search=:query':        'search',
       
   496 		'upload.php':                      'reset'
       
   497 	},
       
   498 
       
   499 	// Map routes against the page URL
       
   500 	baseUrl: function( url ) {
       
   501 		return 'upload.php' + url;
       
   502 	},
       
   503 
       
   504 	reset: function() {
       
   505 		var frame = wp.media.frames.edit;
       
   506 
       
   507 		if ( frame ) {
       
   508 			frame.close();
       
   509 		}
       
   510 	},
       
   511 
       
   512 	// Respond to the search route by filling the search field and trigggering the input event
       
   513 	search: function( query ) {
       
   514 		jQuery( '#media-search-input' ).val( query ).trigger( 'input' );
       
   515 	},
       
   516 
       
   517 	// Show the modal with a specific item
       
   518 	showItem: function( query ) {
       
   519 		var media = wp.media,
       
   520 			frame = media.frames.browse,
       
   521 			library = frame.state().get('library'),
       
   522 			item;
       
   523 
       
   524 		// Trigger the media frame to open the correct item
       
   525 		item = library.findWhere( { id: parseInt( query, 10 ) } );
       
   526 		item.set( 'skipHistory', true );
       
   527 
       
   528 		if ( item ) {
       
   529 			frame.trigger( 'edit:attachment', item );
       
   530 		} else {
       
   531 			item = media.attachment( query );
       
   532 			frame.listenTo( item, 'change', function( model ) {
       
   533 				frame.stopListening( item );
       
   534 				frame.trigger( 'edit:attachment', model );
       
   535 			} );
       
   536 			item.fetch();
       
   537 		}
       
   538 	},
       
   539 
       
   540 	// Show the modal in edit mode with a specific item.
       
   541 	editItem: function( query ) {
       
   542 		this.showItem( query );
       
   543 		wp.media.frames.edit.content.mode( 'edit-details' );
       
   544 	}
       
   545 });
       
   546 
       
   547 module.exports = Router;
       
   548 
       
   549 
       
   550 /***/ }),
       
   551 /* 15 */
       
   552 /***/ (function(module, exports) {
       
   553 
       
   554 var View = wp.media.View,
       
   555 	EditImage = wp.media.view.EditImage,
       
   556 	Details;
       
   557 
       
   558 /**
       
   559  * wp.media.view.EditImage.Details
       
   560  *
       
   561  * @memberOf wp.media.view.EditImage
       
   562  *
       
   563  * @class
       
   564  * @augments wp.media.view.EditImage
       
   565  * @augments wp.media.View
       
   566  * @augments wp.Backbone.View
       
   567  * @augments Backbone.View
       
   568  */
       
   569 Details = EditImage.extend(/** @lends wp.media.view.EditImage.Details.prototype */{
       
   570 	initialize: function( options ) {
       
   571 		this.editor = window.imageEdit;
       
   572 		this.frame = options.frame;
       
   573 		this.controller = options.controller;
       
   574 		View.prototype.initialize.apply( this, arguments );
       
   575 	},
       
   576 
       
   577 	back: function() {
       
   578 		this.frame.content.mode( 'edit-metadata' );
       
   579 	},
       
   580 
       
   581 	save: function() {
       
   582 		this.model.fetch().done( _.bind( function() {
       
   583 			this.frame.content.mode( 'edit-metadata' );
       
   584 		}, this ) );
       
   585 	}
       
   586 });
       
   587 
       
   588 module.exports = Details;
       
   589 
       
   590 
       
   591 /***/ }),
       
   592 /* 16 */
       
   593 /***/ (function(module, exports) {
       
   594 
       
   595 var Frame = wp.media.view.Frame,
       
   596 	MediaFrame = wp.media.view.MediaFrame,
       
   597 
       
   598 	$ = jQuery,
       
   599 	EditAttachments;
       
   600 
       
   601 /**
       
   602  * wp.media.view.MediaFrame.EditAttachments
       
   603  *
       
   604  * A frame for editing the details of a specific media item.
       
   605  *
       
   606  * Opens in a modal by default.
       
   607  *
       
   608  * Requires an attachment model to be passed in the options hash under `model`.
       
   609  *
       
   610  * @memberOf wp.media.view.MediaFrame
       
   611  *
       
   612  * @class
       
   613  * @augments wp.media.view.Frame
       
   614  * @augments wp.media.View
       
   615  * @augments wp.Backbone.View
       
   616  * @augments Backbone.View
       
   617  * @mixes wp.media.controller.StateMachine
       
   618  */
       
   619 EditAttachments = MediaFrame.extend(/** @lends wp.media.view.MediaFrame.EditAttachments.prototype */{
       
   620 
       
   621 	className: 'edit-attachment-frame',
       
   622 	template:  wp.template( 'edit-attachment-frame' ),
       
   623 	regions:   [ 'title', 'content' ],
       
   624 
       
   625 	events: {
       
   626 		'click .left':  'previousMediaItem',
       
   627 		'click .right': 'nextMediaItem'
       
   628 	},
       
   629 
       
   630 	initialize: function() {
       
   631 		Frame.prototype.initialize.apply( this, arguments );
       
   632 
       
   633 		_.defaults( this.options, {
       
   634 			modal: true,
       
   635 			state: 'edit-attachment'
       
   636 		});
       
   637 
       
   638 		this.controller = this.options.controller;
       
   639 		this.gridRouter = this.controller.gridRouter;
       
   640 		this.library = this.options.library;
       
   641 
       
   642 		if ( this.options.model ) {
       
   643 			this.model = this.options.model;
       
   644 		}
       
   645 
       
   646 		this.bindHandlers();
       
   647 		this.createStates();
       
   648 		this.createModal();
       
   649 
       
   650 		this.title.mode( 'default' );
       
   651 		this.toggleNav();
       
   652 	},
       
   653 
       
   654 	bindHandlers: function() {
       
   655 		// Bind default title creation.
       
   656 		this.on( 'title:create:default', this.createTitle, this );
       
   657 
       
   658 		this.on( 'content:create:edit-metadata', this.editMetadataMode, this );
       
   659 		this.on( 'content:create:edit-image', this.editImageMode, this );
       
   660 		this.on( 'content:render:edit-image', this.editImageModeRender, this );
       
   661 		this.on( 'refresh', this.rerender, this );
       
   662 		this.on( 'close', this.detach );
       
   663 
       
   664 		this.bindModelHandlers();
       
   665 		this.listenTo( this.gridRouter, 'route:search', this.close, this );
       
   666 	},
       
   667 
       
   668 	bindModelHandlers: function() {
       
   669 		// Close the modal if the attachment is deleted.
       
   670 		this.listenTo( this.model, 'change:status destroy', this.close, this );
       
   671 	},
       
   672 
       
   673 	createModal: function() {
       
   674 		// Initialize modal container view.
       
   675 		if ( this.options.modal ) {
       
   676 			this.modal = new wp.media.view.Modal({
       
   677 				controller: this,
       
   678 				title:      this.options.title
       
   679 			});
       
   680 
       
   681 			this.modal.on( 'open', _.bind( function () {
       
   682 				$( 'body' ).on( 'keydown.media-modal', _.bind( this.keyEvent, this ) );
       
   683 			}, this ) );
       
   684 
       
   685 			// Completely destroy the modal DOM element when closing it.
       
   686 			this.modal.on( 'close', _.bind( function() {
       
   687 				$( 'body' ).off( 'keydown.media-modal' ); /* remove the keydown event */
       
   688 				// Restore the original focus item if possible
       
   689 				$( 'li.attachment[data-id="' + this.model.get( 'id' ) +'"]' ).focus();
       
   690 				this.resetRoute();
       
   691 			}, this ) );
       
   692 
       
   693 			// Set this frame as the modal's content.
       
   694 			this.modal.content( this );
       
   695 			this.modal.open();
       
   696 		}
       
   697 	},
       
   698 
       
   699 	/**
       
   700 	 * Add the default states to the frame.
       
   701 	 */
       
   702 	createStates: function() {
       
   703 		this.states.add([
       
   704 			new wp.media.controller.EditAttachmentMetadata({
       
   705 				model:   this.model,
       
   706 				library: this.library
       
   707 			})
       
   708 		]);
       
   709 	},
       
   710 
       
   711 	/**
       
   712 	 * Content region rendering callback for the `edit-metadata` mode.
       
   713 	 *
       
   714 	 * @param {Object} contentRegion Basic object with a `view` property, which
       
   715 	 *                               should be set with the proper region view.
       
   716 	 */
       
   717 	editMetadataMode: function( contentRegion ) {
       
   718 		contentRegion.view = new wp.media.view.Attachment.Details.TwoColumn({
       
   719 			controller: this,
       
   720 			model:      this.model
       
   721 		});
       
   722 
       
   723 		/**
       
   724 		 * Attach a subview to display fields added via the
       
   725 		 * `attachment_fields_to_edit` filter.
       
   726 		 */
       
   727 		contentRegion.view.views.set( '.attachment-compat', new wp.media.view.AttachmentCompat({
       
   728 			controller: this,
       
   729 			model:      this.model
       
   730 		}) );
       
   731 
       
   732 		// Update browser url when navigating media details, except on load.
       
   733 		if ( this.model && ! this.model.get( 'skipHistory' ) ) {
       
   734 			this.gridRouter.navigate( this.gridRouter.baseUrl( '?item=' + this.model.id ) );
       
   735 		}
       
   736 	},
       
   737 
       
   738 	/**
       
   739 	 * Render the EditImage view into the frame's content region.
       
   740 	 *
       
   741 	 * @param {Object} contentRegion Basic object with a `view` property, which
       
   742 	 *                               should be set with the proper region view.
       
   743 	 */
       
   744 	editImageMode: function( contentRegion ) {
       
   745 		var editImageController = new wp.media.controller.EditImage( {
       
   746 			model: this.model,
       
   747 			frame: this
       
   748 		} );
       
   749 		// Noop some methods.
       
   750 		editImageController._toolbar = function() {};
       
   751 		editImageController._router = function() {};
       
   752 		editImageController._menu = function() {};
       
   753 
       
   754 		contentRegion.view = new wp.media.view.EditImage.Details( {
       
   755 			model: this.model,
       
   756 			frame: this,
       
   757 			controller: editImageController
       
   758 		} );
       
   759 
       
   760 		this.gridRouter.navigate( this.gridRouter.baseUrl( '?item=' + this.model.id + '&mode=edit' ) );
       
   761 
       
   762 	},
       
   763 
       
   764 	editImageModeRender: function( view ) {
       
   765 		view.on( 'ready', view.loadEditor );
       
   766 	},
       
   767 
       
   768 	toggleNav: function() {
       
   769 		this.$('.left').toggleClass( 'disabled', ! this.hasPrevious() );
       
   770 		this.$('.right').toggleClass( 'disabled', ! this.hasNext() );
       
   771 	},
       
   772 
       
   773 	/**
       
   774 	 * Rerender the view.
       
   775 	 */
       
   776 	rerender: function( model ) {
       
   777 		this.stopListening( this.model );
       
   778 
       
   779 		this.model = model;
       
   780 
       
   781 		this.bindModelHandlers();
       
   782 
       
   783 		// Only rerender the `content` region.
       
   784 		if ( this.content.mode() !== 'edit-metadata' ) {
       
   785 			this.content.mode( 'edit-metadata' );
       
   786 		} else {
       
   787 			this.content.render();
       
   788 		}
       
   789 
       
   790 		this.toggleNav();
       
   791 	},
       
   792 
       
   793 	/**
       
   794 	 * Click handler to switch to the previous media item.
       
   795 	 */
       
   796 	previousMediaItem: function() {
       
   797 		if ( ! this.hasPrevious() ) {
       
   798 			return;
       
   799 		}
       
   800 		this.trigger( 'refresh', this.library.at( this.getCurrentIndex() - 1 ) );
       
   801 		this.$( '.left' ).focus();
       
   802 	},
       
   803 
       
   804 	/**
       
   805 	 * Click handler to switch to the next media item.
       
   806 	 */
       
   807 	nextMediaItem: function() {
       
   808 		if ( ! this.hasNext() ) {
       
   809 			return;
       
   810 		}
       
   811 		this.trigger( 'refresh', this.library.at( this.getCurrentIndex() + 1 ) );
       
   812 		this.$( '.right' ).focus();
       
   813 	},
       
   814 
       
   815 	getCurrentIndex: function() {
       
   816 		return this.library.indexOf( this.model );
       
   817 	},
       
   818 
       
   819 	hasNext: function() {
       
   820 		return ( this.getCurrentIndex() + 1 ) < this.library.length;
       
   821 	},
       
   822 
       
   823 	hasPrevious: function() {
       
   824 		return ( this.getCurrentIndex() - 1 ) > -1;
       
   825 	},
       
   826 	/**
       
   827 	 * Respond to the keyboard events: right arrow, left arrow, except when
       
   828 	 * focus is in a textarea or input field.
       
   829 	 */
       
   830 	keyEvent: function( event ) {
       
   831 		if ( ( 'INPUT' === event.target.nodeName || 'TEXTAREA' === event.target.nodeName ) && ! ( event.target.readOnly || event.target.disabled ) ) {
       
   832 			return;
       
   833 		}
       
   834 
       
   835 		// The right arrow key
       
   836 		if ( 39 === event.keyCode ) {
       
   837 			this.nextMediaItem();
       
   838 		}
       
   839 		// The left arrow key
       
   840 		if ( 37 === event.keyCode ) {
       
   841 			this.previousMediaItem();
       
   842 		}
       
   843 	},
       
   844 
       
   845 	resetRoute: function() {
       
   846 		var searchTerm = this.controller.browserView.toolbar.get( 'search' ).$el.val(),
       
   847 			url = '' !== searchTerm ? '?search=' + searchTerm : '';
       
   848 		this.gridRouter.navigate( this.gridRouter.baseUrl( url ), { replace: true } );
       
   849 	}
       
   850 });
       
   851 
       
   852 module.exports = EditAttachments;
       
   853 
       
   854 
       
   855 /***/ }),
       
   856 /* 17 */
       
   857 /***/ (function(module, exports) {
       
   858 
       
   859 
       
   860 var Button = wp.media.view.Button,
       
   861 	l10n = wp.media.view.l10n,
       
   862 	SelectModeToggle;
       
   863 
       
   864 /**
       
   865  * wp.media.view.SelectModeToggleButton
       
   866  *
       
   867  * @memberOf wp.media.view
       
   868  *
       
   869  * @class
       
   870  * @augments wp.media.view.Button
       
   871  * @augments wp.media.View
       
   872  * @augments wp.Backbone.View
       
   873  * @augments Backbone.View
       
   874  */
       
   875 SelectModeToggle = Button.extend(/** @lends wp.media.view.SelectModeToggle.prototype */{
       
   876 	initialize: function() {
       
   877 		_.defaults( this.options, {
       
   878 			size : ''
       
   879 		} );
       
   880 
       
   881 		Button.prototype.initialize.apply( this, arguments );
       
   882 		this.controller.on( 'select:activate select:deactivate', this.toggleBulkEditHandler, this );
       
   883 		this.controller.on( 'selection:action:done', this.back, this );
       
   884 	},
       
   885 
       
   886 	back: function () {
       
   887 		this.controller.deactivateMode( 'select' ).activateMode( 'edit' );
       
   888 	},
       
   889 
       
   890 	click: function() {
       
   891 		Button.prototype.click.apply( this, arguments );
       
   892 		if ( this.controller.isModeActive( 'select' ) ) {
       
   893 			this.back();
       
   894 		} else {
       
   895 			this.controller.deactivateMode( 'edit' ).activateMode( 'select' );
       
   896 		}
       
   897 	},
       
   898 
       
   899 	render: function() {
       
   900 		Button.prototype.render.apply( this, arguments );
       
   901 		this.$el.addClass( 'select-mode-toggle-button' );
       
   902 		return this;
       
   903 	},
       
   904 
       
   905 	toggleBulkEditHandler: function() {
       
   906 		var toolbar = this.controller.content.get().toolbar, children;
       
   907 
       
   908 		children = toolbar.$( '.media-toolbar-secondary > *, .media-toolbar-primary > *' );
       
   909 
       
   910 		// TODO: the Frame should be doing all of this.
       
   911 		if ( this.controller.isModeActive( 'select' ) ) {
       
   912 			this.model.set( {
       
   913 				size: 'large',
       
   914 				text: l10n.cancelSelection
       
   915 			} );
       
   916 			children.not( '.spinner, .media-button' ).hide();
       
   917 			this.$el.show();
       
   918 			toolbar.$( '.delete-selected-button' ).removeClass( 'hidden' );
       
   919 		} else {
       
   920 			this.model.set( {
       
   921 				size: '',
       
   922 				text: l10n.bulkSelect
       
   923 			} );
       
   924 			this.controller.content.get().$el.removeClass( 'fixed' );
       
   925 			toolbar.$el.css( 'width', '' );
       
   926 			toolbar.$( '.delete-selected-button' ).addClass( 'hidden' );
       
   927 			children.not( '.media-button' ).show();
       
   928 			this.controller.state().get( 'selection' ).reset();
       
   929 		}
       
   930 	}
       
   931 });
       
   932 
       
   933 module.exports = SelectModeToggle;
       
   934 
       
   935 
       
   936 /***/ }),
       
   937 /* 18 */
       
   938 /***/ (function(module, exports) {
       
   939 
       
   940 var Button = wp.media.view.Button,
       
   941 	l10n = wp.media.view.l10n,
       
   942 	DeleteSelected;
       
   943 
       
   944 /**
       
   945  * wp.media.view.DeleteSelectedButton
       
   946  *
       
   947  * A button that handles bulk Delete/Trash logic
       
   948  *
       
   949  * @memberOf wp.media.view
       
   950  *
       
   951  * @class
       
   952  * @augments wp.media.view.Button
       
   953  * @augments wp.media.View
       
   954  * @augments wp.Backbone.View
       
   955  * @augments Backbone.View
       
   956  */
       
   957 DeleteSelected = Button.extend(/** @lends wp.media.view.DeleteSelectedButton.prototype */{
       
   958 	initialize: function() {
       
   959 		Button.prototype.initialize.apply( this, arguments );
       
   960 		if ( this.options.filters ) {
       
   961 			this.options.filters.model.on( 'change', this.filterChange, this );
       
   962 		}
       
   963 		this.controller.on( 'selection:toggle', this.toggleDisabled, this );
       
   964 	},
       
   965 
       
   966 	filterChange: function( model ) {
       
   967 		if ( 'trash' === model.get( 'status' ) ) {
       
   968 			this.model.set( 'text', l10n.untrashSelected );
       
   969 		} else if ( wp.media.view.settings.mediaTrash ) {
       
   970 			this.model.set( 'text', l10n.trashSelected );
       
   971 		} else {
       
   972 			this.model.set( 'text', l10n.deleteSelected );
       
   973 		}
       
   974 	},
       
   975 
       
   976 	toggleDisabled: function() {
       
   977 		this.model.set( 'disabled', ! this.controller.state().get( 'selection' ).length );
       
   978 	},
       
   979 
       
   980 	render: function() {
       
   981 		Button.prototype.render.apply( this, arguments );
       
   982 		if ( this.controller.isModeActive( 'select' ) ) {
       
   983 			this.$el.addClass( 'delete-selected-button' );
       
   984 		} else {
       
   985 			this.$el.addClass( 'delete-selected-button hidden' );
       
   986 		}
       
   987 		this.toggleDisabled();
       
   988 		return this;
       
   989 	}
       
   990 });
       
   991 
       
   992 module.exports = DeleteSelected;
       
   993 
       
   994 
       
   995 /***/ }),
       
   996 /* 19 */
       
   997 /***/ (function(module, exports) {
       
   998 
       
   999 var Button = wp.media.view.Button,
       
  1000 	DeleteSelected = wp.media.view.DeleteSelectedButton,
       
  1001 	DeleteSelectedPermanently;
       
  1002 
       
  1003 /**
       
  1004  * wp.media.view.DeleteSelectedPermanentlyButton
       
  1005  *
       
  1006  * When MEDIA_TRASH is true, a button that handles bulk Delete Permanently logic
       
  1007  *
       
  1008  * @memberOf wp.media.view
       
  1009  *
       
  1010  * @class
       
  1011  * @augments wp.media.view.DeleteSelectedButton
       
  1012  * @augments wp.media.view.Button
       
  1013  * @augments wp.media.View
       
  1014  * @augments wp.Backbone.View
       
  1015  * @augments Backbone.View
       
  1016  */
       
  1017 DeleteSelectedPermanently = DeleteSelected.extend(/** @lends wp.media.view.DeleteSelectedPermanentlyButton.prototype */{
       
  1018 	initialize: function() {
       
  1019 		DeleteSelected.prototype.initialize.apply( this, arguments );
       
  1020 		this.controller.on( 'select:activate', this.selectActivate, this );
       
  1021 		this.controller.on( 'select:deactivate', this.selectDeactivate, this );
       
  1022 	},
       
  1023 
       
  1024 	filterChange: function( model ) {
       
  1025 		this.canShow = ( 'trash' === model.get( 'status' ) );
       
  1026 	},
       
  1027 
       
  1028 	selectActivate: function() {
       
  1029 		this.toggleDisabled();
       
  1030 		this.$el.toggleClass( 'hidden', ! this.canShow );
       
  1031 	},
       
  1032 
       
  1033 	selectDeactivate: function() {
       
  1034 		this.toggleDisabled();
       
  1035 		this.$el.addClass( 'hidden' );
       
  1036 	},
       
  1037 
       
  1038 	render: function() {
       
  1039 		Button.prototype.render.apply( this, arguments );
       
  1040 		this.selectActivate();
       
  1041 		return this;
       
  1042 	}
       
  1043 });
       
  1044 
       
  1045 module.exports = DeleteSelectedPermanently;
       
  1046 
       
  1047 
       
  1048 /***/ })
       
  1049 /******/ ]);