angelovcom.net

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

media-grid.js (29533B)


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