You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

858 lines
23 KiB

  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){
  2. /**
  3. * wp.media.controller.EditAttachmentMetadata
  4. *
  5. * A state for editing an attachment's metadata.
  6. *
  7. * @class
  8. * @augments wp.media.controller.State
  9. * @augments Backbone.Model
  10. */
  11. var l10n = wp.media.view.l10n,
  12. EditAttachmentMetadata;
  13. EditAttachmentMetadata = wp.media.controller.State.extend({
  14. defaults: {
  15. id: 'edit-attachment',
  16. // Title string passed to the frame's title region view.
  17. title: l10n.attachmentDetails,
  18. // Region mode defaults.
  19. content: 'edit-metadata',
  20. menu: false,
  21. toolbar: false,
  22. router: false
  23. }
  24. });
  25. module.exports = EditAttachmentMetadata;
  26. },{}],2:[function(require,module,exports){
  27. var media = wp.media;
  28. media.controller.EditAttachmentMetadata = require( './controllers/edit-attachment-metadata.js' );
  29. media.view.MediaFrame.Manage = require( './views/frame/manage.js' );
  30. media.view.Attachment.Details.TwoColumn = require( './views/attachment/details-two-column.js' );
  31. media.view.MediaFrame.Manage.Router = require( './routers/manage.js' );
  32. media.view.EditImage.Details = require( './views/edit-image-details.js' );
  33. media.view.MediaFrame.EditAttachments = require( './views/frame/edit-attachments.js' );
  34. media.view.SelectModeToggleButton = require( './views/button/select-mode-toggle.js' );
  35. media.view.DeleteSelectedButton = require( './views/button/delete-selected.js' );
  36. media.view.DeleteSelectedPermanentlyButton = require( './views/button/delete-selected-permanently.js' );
  37. },{"./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){
  38. /**
  39. * wp.media.view.MediaFrame.Manage.Router
  40. *
  41. * A router for handling the browser history and application state.
  42. *
  43. * @class
  44. * @augments Backbone.Router
  45. */
  46. var Router = Backbone.Router.extend({
  47. routes: {
  48. 'upload.php?item=:slug': 'showItem',
  49. 'upload.php?search=:query': 'search'
  50. },
  51. // Map routes against the page URL
  52. baseUrl: function( url ) {
  53. return 'upload.php' + url;
  54. },
  55. // Respond to the search route by filling the search field and trigggering the input event
  56. search: function( query ) {
  57. jQuery( '#media-search-input' ).val( query ).trigger( 'input' );
  58. },
  59. // Show the modal with a specific item
  60. showItem: function( query ) {
  61. var media = wp.media,
  62. library = media.frame.state().get('library'),
  63. item;
  64. // Trigger the media frame to open the correct item
  65. item = library.findWhere( { id: parseInt( query, 10 ) } );
  66. if ( item ) {
  67. media.frame.trigger( 'edit:attachment', item );
  68. } else {
  69. item = media.attachment( query );
  70. media.frame.listenTo( item, 'change', function( model ) {
  71. media.frame.stopListening( item );
  72. media.frame.trigger( 'edit:attachment', model );
  73. } );
  74. item.fetch();
  75. }
  76. }
  77. });
  78. module.exports = Router;
  79. },{}],4:[function(require,module,exports){
  80. /**
  81. * wp.media.view.Attachment.Details.TwoColumn
  82. *
  83. * A similar view to media.view.Attachment.Details
  84. * for use in the Edit Attachment modal.
  85. *
  86. * @class
  87. * @augments wp.media.view.Attachment.Details
  88. * @augments wp.media.view.Attachment
  89. * @augments wp.media.View
  90. * @augments wp.Backbone.View
  91. * @augments Backbone.View
  92. */
  93. var Details = wp.media.view.Attachment.Details,
  94. TwoColumn;
  95. TwoColumn = Details.extend({
  96. template: wp.template( 'attachment-details-two-column' ),
  97. editAttachment: function( event ) {
  98. event.preventDefault();
  99. this.controller.content.mode( 'edit-image' );
  100. },
  101. /**
  102. * Noop this from parent class, doesn't apply here.
  103. */
  104. toggleSelectionHandler: function() {},
  105. render: function() {
  106. Details.prototype.render.apply( this, arguments );
  107. wp.media.mixin.removeAllPlayers();
  108. this.$( 'audio, video' ).each( function (i, elem) {
  109. var el = wp.media.view.MediaDetails.prepareSrc( elem );
  110. new window.MediaElementPlayer( el, wp.media.mixin.mejsSettings );
  111. } );
  112. }
  113. });
  114. module.exports = TwoColumn;
  115. },{}],5:[function(require,module,exports){
  116. /**
  117. * wp.media.view.DeleteSelectedPermanentlyButton
  118. *
  119. * When MEDIA_TRASH is true, a button that handles bulk Delete Permanently logic
  120. *
  121. * @class
  122. * @augments wp.media.view.DeleteSelectedButton
  123. * @augments wp.media.view.Button
  124. * @augments wp.media.View
  125. * @augments wp.Backbone.View
  126. * @augments Backbone.View
  127. */
  128. var Button = wp.media.view.Button,
  129. DeleteSelected = wp.media.view.DeleteSelectedButton,
  130. DeleteSelectedPermanently;
  131. DeleteSelectedPermanently = DeleteSelected.extend({
  132. initialize: function() {
  133. DeleteSelected.prototype.initialize.apply( this, arguments );
  134. this.controller.on( 'select:activate', this.selectActivate, this );
  135. this.controller.on( 'select:deactivate', this.selectDeactivate, this );
  136. },
  137. filterChange: function( model ) {
  138. this.canShow = ( 'trash' === model.get( 'status' ) );
  139. },
  140. selectActivate: function() {
  141. this.toggleDisabled();
  142. this.$el.toggleClass( 'hidden', ! this.canShow );
  143. },
  144. selectDeactivate: function() {
  145. this.toggleDisabled();
  146. this.$el.addClass( 'hidden' );
  147. },
  148. render: function() {
  149. Button.prototype.render.apply( this, arguments );
  150. this.selectActivate();
  151. return this;
  152. }
  153. });
  154. module.exports = DeleteSelectedPermanently;
  155. },{}],6:[function(require,module,exports){
  156. /**
  157. * wp.media.view.DeleteSelectedButton
  158. *
  159. * A button that handles bulk Delete/Trash logic
  160. *
  161. * @class
  162. * @augments wp.media.view.Button
  163. * @augments wp.media.View
  164. * @augments wp.Backbone.View
  165. * @augments Backbone.View
  166. */
  167. var Button = wp.media.view.Button,
  168. l10n = wp.media.view.l10n,
  169. DeleteSelected;
  170. DeleteSelected = Button.extend({
  171. initialize: function() {
  172. Button.prototype.initialize.apply( this, arguments );
  173. if ( this.options.filters ) {
  174. this.options.filters.model.on( 'change', this.filterChange, this );
  175. }
  176. this.controller.on( 'selection:toggle', this.toggleDisabled, this );
  177. },
  178. filterChange: function( model ) {
  179. if ( 'trash' === model.get( 'status' ) ) {
  180. this.model.set( 'text', l10n.untrashSelected );
  181. } else if ( wp.media.view.settings.mediaTrash ) {
  182. this.model.set( 'text', l10n.trashSelected );
  183. } else {
  184. this.model.set( 'text', l10n.deleteSelected );
  185. }
  186. },
  187. toggleDisabled: function() {
  188. this.model.set( 'disabled', ! this.controller.state().get( 'selection' ).length );
  189. },
  190. render: function() {
  191. Button.prototype.render.apply( this, arguments );
  192. if ( this.controller.isModeActive( 'select' ) ) {
  193. this.$el.addClass( 'delete-selected-button' );
  194. } else {
  195. this.$el.addClass( 'delete-selected-button hidden' );
  196. }
  197. this.toggleDisabled();
  198. return this;
  199. }
  200. });
  201. module.exports = DeleteSelected;
  202. },{}],7:[function(require,module,exports){
  203. /**
  204. * wp.media.view.SelectModeToggleButton
  205. *
  206. * @class
  207. * @augments wp.media.view.Button
  208. * @augments wp.media.View
  209. * @augments wp.Backbone.View
  210. * @augments Backbone.View
  211. */
  212. var Button = wp.media.view.Button,
  213. l10n = wp.media.view.l10n,
  214. SelectModeToggle;
  215. SelectModeToggle = Button.extend({
  216. initialize: function() {
  217. _.defaults( this.options, {
  218. size : ''
  219. } );
  220. Button.prototype.initialize.apply( this, arguments );
  221. this.controller.on( 'select:activate select:deactivate', this.toggleBulkEditHandler, this );
  222. this.controller.on( 'selection:action:done', this.back, this );
  223. },
  224. back: function () {
  225. this.controller.deactivateMode( 'select' ).activateMode( 'edit' );
  226. },
  227. click: function() {
  228. Button.prototype.click.apply( this, arguments );
  229. if ( this.controller.isModeActive( 'select' ) ) {
  230. this.back();
  231. } else {
  232. this.controller.deactivateMode( 'edit' ).activateMode( 'select' );
  233. }
  234. },
  235. render: function() {
  236. Button.prototype.render.apply( this, arguments );
  237. this.$el.addClass( 'select-mode-toggle-button' );
  238. return this;
  239. },
  240. toggleBulkEditHandler: function() {
  241. var toolbar = this.controller.content.get().toolbar, children;
  242. children = toolbar.$( '.media-toolbar-secondary > *, .media-toolbar-primary > *' );
  243. // TODO: the Frame should be doing all of this.
  244. if ( this.controller.isModeActive( 'select' ) ) {
  245. this.model.set( {
  246. size: 'large',
  247. text: l10n.cancelSelection
  248. } );
  249. children.not( '.spinner, .media-button' ).hide();
  250. this.$el.show();
  251. toolbar.$( '.delete-selected-button' ).removeClass( 'hidden' );
  252. } else {
  253. this.model.set( {
  254. size: '',
  255. text: l10n.bulkSelect
  256. } );
  257. this.controller.content.get().$el.removeClass( 'fixed' );
  258. toolbar.$el.css( 'width', '' );
  259. toolbar.$( '.delete-selected-button' ).addClass( 'hidden' );
  260. children.not( '.media-button' ).show();
  261. this.controller.state().get( 'selection' ).reset();
  262. }
  263. }
  264. });
  265. module.exports = SelectModeToggle;
  266. },{}],8:[function(require,module,exports){
  267. /**
  268. * wp.media.view.EditImage.Details
  269. *
  270. * @class
  271. * @augments wp.media.view.EditImage
  272. * @augments wp.media.View
  273. * @augments wp.Backbone.View
  274. * @augments Backbone.View
  275. */
  276. var View = wp.media.View,
  277. EditImage = wp.media.view.EditImage,
  278. Details;
  279. Details = EditImage.extend({
  280. initialize: function( options ) {
  281. this.editor = window.imageEdit;
  282. this.frame = options.frame;
  283. this.controller = options.controller;
  284. View.prototype.initialize.apply( this, arguments );
  285. },
  286. back: function() {
  287. this.frame.content.mode( 'edit-metadata' );
  288. },
  289. save: function() {
  290. this.model.fetch().done( _.bind( function() {
  291. this.frame.content.mode( 'edit-metadata' );
  292. }, this ) );
  293. }
  294. });
  295. module.exports = Details;
  296. },{}],9:[function(require,module,exports){
  297. /**
  298. * wp.media.view.MediaFrame.EditAttachments
  299. *
  300. * A frame for editing the details of a specific media item.
  301. *
  302. * Opens in a modal by default.
  303. *
  304. * Requires an attachment model to be passed in the options hash under `model`.
  305. *
  306. * @class
  307. * @augments wp.media.view.Frame
  308. * @augments wp.media.View
  309. * @augments wp.Backbone.View
  310. * @augments Backbone.View
  311. * @mixes wp.media.controller.StateMachine
  312. */
  313. var Frame = wp.media.view.Frame,
  314. MediaFrame = wp.media.view.MediaFrame,
  315. $ = jQuery,
  316. EditAttachments;
  317. EditAttachments = MediaFrame.extend({
  318. className: 'edit-attachment-frame',
  319. template: wp.template( 'edit-attachment-frame' ),
  320. regions: [ 'title', 'content' ],
  321. events: {
  322. 'click .left': 'previousMediaItem',
  323. 'click .right': 'nextMediaItem'
  324. },
  325. initialize: function() {
  326. Frame.prototype.initialize.apply( this, arguments );
  327. _.defaults( this.options, {
  328. modal: true,
  329. state: 'edit-attachment'
  330. });
  331. this.controller = this.options.controller;
  332. this.gridRouter = this.controller.gridRouter;
  333. this.library = this.options.library;
  334. if ( this.options.model ) {
  335. this.model = this.options.model;
  336. }
  337. this.bindHandlers();
  338. this.createStates();
  339. this.createModal();
  340. this.title.mode( 'default' );
  341. this.toggleNav();
  342. },
  343. bindHandlers: function() {
  344. // Bind default title creation.
  345. this.on( 'title:create:default', this.createTitle, this );
  346. // Close the modal if the attachment is deleted.
  347. this.listenTo( this.model, 'change:status destroy', this.close, this );
  348. this.on( 'content:create:edit-metadata', this.editMetadataMode, this );
  349. this.on( 'content:create:edit-image', this.editImageMode, this );
  350. this.on( 'content:render:edit-image', this.editImageModeRender, this );
  351. this.on( 'close', this.detach );
  352. },
  353. createModal: function() {
  354. // Initialize modal container view.
  355. if ( this.options.modal ) {
  356. this.modal = new wp.media.view.Modal({
  357. controller: this,
  358. title: this.options.title
  359. });
  360. this.modal.on( 'open', _.bind( function () {
  361. $( 'body' ).on( 'keydown.media-modal', _.bind( this.keyEvent, this ) );
  362. }, this ) );
  363. // Completely destroy the modal DOM element when closing it.
  364. this.modal.on( 'close', _.bind( function() {
  365. this.modal.remove();
  366. $( 'body' ).off( 'keydown.media-modal' ); /* remove the keydown event */
  367. // Restore the original focus item if possible
  368. $( 'li.attachment[data-id="' + this.model.get( 'id' ) +'"]' ).focus();
  369. this.resetRoute();
  370. }, this ) );
  371. // Set this frame as the modal's content.
  372. this.modal.content( this );
  373. this.modal.open();
  374. }
  375. },
  376. /**
  377. * Add the default states to the frame.
  378. */
  379. createStates: function() {
  380. this.states.add([
  381. new wp.media.controller.EditAttachmentMetadata( { model: this.model } )
  382. ]);
  383. },
  384. /**
  385. * Content region rendering callback for the `edit-metadata` mode.
  386. *
  387. * @param {Object} contentRegion Basic object with a `view` property, which
  388. * should be set with the proper region view.
  389. */
  390. editMetadataMode: function( contentRegion ) {
  391. contentRegion.view = new wp.media.view.Attachment.Details.TwoColumn({
  392. controller: this,
  393. model: this.model
  394. });
  395. /**
  396. * Attach a subview to display fields added via the
  397. * `attachment_fields_to_edit` filter.
  398. */
  399. contentRegion.view.views.set( '.attachment-compat', new wp.media.view.AttachmentCompat({
  400. controller: this,
  401. model: this.model
  402. }) );
  403. // Update browser url when navigating media details
  404. if ( this.model ) {
  405. this.gridRouter.navigate( this.gridRouter.baseUrl( '?item=' + this.model.id ) );
  406. }
  407. },
  408. /**
  409. * Render the EditImage view into the frame's content region.
  410. *
  411. * @param {Object} contentRegion Basic object with a `view` property, which
  412. * should be set with the proper region view.
  413. */
  414. editImageMode: function( contentRegion ) {
  415. var editImageController = new wp.media.controller.EditImage( {
  416. model: this.model,
  417. frame: this
  418. } );
  419. // Noop some methods.
  420. editImageController._toolbar = function() {};
  421. editImageController._router = function() {};
  422. editImageController._menu = function() {};
  423. contentRegion.view = new wp.media.view.EditImage.Details( {
  424. model: this.model,
  425. frame: this,
  426. controller: editImageController
  427. } );
  428. },
  429. editImageModeRender: function( view ) {
  430. view.on( 'ready', view.loadEditor );
  431. },
  432. toggleNav: function() {
  433. this.$('.left').toggleClass( 'disabled', ! this.hasPrevious() );
  434. this.$('.right').toggleClass( 'disabled', ! this.hasNext() );
  435. },
  436. /**
  437. * Rerender the view.
  438. */
  439. rerender: function() {
  440. // Only rerender the `content` region.
  441. if ( this.content.mode() !== 'edit-metadata' ) {
  442. this.content.mode( 'edit-metadata' );
  443. } else {
  444. this.content.render();
  445. }
  446. this.toggleNav();
  447. },
  448. /**
  449. * Click handler to switch to the previous media item.
  450. */
  451. previousMediaItem: function() {
  452. if ( ! this.hasPrevious() ) {
  453. this.$( '.left' ).blur();
  454. return;
  455. }
  456. this.model = this.library.at( this.getCurrentIndex() - 1 );
  457. this.rerender();
  458. this.$( '.left' ).focus();
  459. },
  460. /**
  461. * Click handler to switch to the next media item.
  462. */
  463. nextMediaItem: function() {
  464. if ( ! this.hasNext() ) {
  465. this.$( '.right' ).blur();
  466. return;
  467. }
  468. this.model = this.library.at( this.getCurrentIndex() + 1 );
  469. this.rerender();
  470. this.$( '.right' ).focus();
  471. },
  472. getCurrentIndex: function() {
  473. return this.library.indexOf( this.model );
  474. },
  475. hasNext: function() {
  476. return ( this.getCurrentIndex() + 1 ) < this.library.length;
  477. },
  478. hasPrevious: function() {
  479. return ( this.getCurrentIndex() - 1 ) > -1;
  480. },
  481. /**
  482. * Respond to the keyboard events: right arrow, left arrow, except when
  483. * focus is in a textarea or input field.
  484. */
  485. keyEvent: function( event ) {
  486. if ( ( 'INPUT' === event.target.nodeName || 'TEXTAREA' === event.target.nodeName ) && ! ( event.target.readOnly || event.target.disabled ) ) {
  487. return;
  488. }
  489. // The right arrow key
  490. if ( 39 === event.keyCode ) {
  491. this.nextMediaItem();
  492. }
  493. // The left arrow key
  494. if ( 37 === event.keyCode ) {
  495. this.previousMediaItem();
  496. }
  497. },
  498. resetRoute: function() {
  499. this.gridRouter.navigate( this.gridRouter.baseUrl( '' ) );
  500. }
  501. });
  502. module.exports = EditAttachments;
  503. },{}],10:[function(require,module,exports){
  504. /**
  505. * wp.media.view.MediaFrame.Manage
  506. *
  507. * A generic management frame workflow.
  508. *
  509. * Used in the media grid view.
  510. *
  511. * @class
  512. * @augments wp.media.view.MediaFrame
  513. * @augments wp.media.view.Frame
  514. * @augments wp.media.View
  515. * @augments wp.Backbone.View
  516. * @augments Backbone.View
  517. * @mixes wp.media.controller.StateMachine
  518. */
  519. var MediaFrame = wp.media.view.MediaFrame,
  520. Library = wp.media.controller.Library,
  521. $ = Backbone.$,
  522. Manage;
  523. Manage = MediaFrame.extend({
  524. /**
  525. * @global wp.Uploader
  526. */
  527. initialize: function() {
  528. _.defaults( this.options, {
  529. title: '',
  530. modal: false,
  531. selection: [],
  532. library: {}, // Options hash for the query to the media library.
  533. multiple: 'add',
  534. state: 'library',
  535. uploader: true,
  536. mode: [ 'grid', 'edit' ]
  537. });
  538. this.$body = $( document.body );
  539. this.$window = $( window );
  540. this.$adminBar = $( '#wpadminbar' );
  541. this.$window.on( 'scroll resize', _.debounce( _.bind( this.fixPosition, this ), 15 ) );
  542. $( document ).on( 'click', '.page-title-action', _.bind( this.addNewClickHandler, this ) );
  543. // Ensure core and media grid view UI is enabled.
  544. this.$el.addClass('wp-core-ui');
  545. // Force the uploader off if the upload limit has been exceeded or
  546. // if the browser isn't supported.
  547. if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) {
  548. this.options.uploader = false;
  549. }
  550. // Initialize a window-wide uploader.
  551. if ( this.options.uploader ) {
  552. this.uploader = new wp.media.view.UploaderWindow({
  553. controller: this,
  554. uploader: {
  555. dropzone: document.body,
  556. container: document.body
  557. }
  558. }).render();
  559. this.uploader.ready();
  560. $('body').append( this.uploader.el );
  561. this.options.uploader = false;
  562. }
  563. this.gridRouter = new wp.media.view.MediaFrame.Manage.Router();
  564. // Call 'initialize' directly on the parent class.
  565. MediaFrame.prototype.initialize.apply( this, arguments );
  566. // Append the frame view directly the supplied container.
  567. this.$el.appendTo( this.options.container );
  568. this.createStates();
  569. this.bindRegionModeHandlers();
  570. this.render();
  571. this.bindSearchHandler();
  572. },
  573. bindSearchHandler: function() {
  574. var search = this.$( '#media-search-input' ),
  575. currentSearch = this.options.container.data( 'search' ),
  576. searchView = this.browserView.toolbar.get( 'search' ).$el,
  577. listMode = this.$( '.view-list' ),
  578. input = _.debounce( function (e) {
  579. var val = $( e.currentTarget ).val(),
  580. url = '';
  581. if ( val ) {
  582. url += '?search=' + val;
  583. }
  584. this.gridRouter.navigate( this.gridRouter.baseUrl( url ) );
  585. }, 1000 );
  586. // Update the URL when entering search string (at most once per second)
  587. search.on( 'input', _.bind( input, this ) );
  588. searchView.val( currentSearch ).trigger( 'input' );
  589. this.gridRouter.on( 'route:search', function () {
  590. var href = window.location.href;
  591. if ( href.indexOf( 'mode=' ) > -1 ) {
  592. href = href.replace( /mode=[^&]+/g, 'mode=list' );
  593. } else {
  594. href += href.indexOf( '?' ) > -1 ? '&mode=list' : '?mode=list';
  595. }
  596. href = href.replace( 'search=', 's=' );
  597. listMode.prop( 'href', href );
  598. } );
  599. },
  600. /**
  601. * Create the default states for the frame.
  602. */
  603. createStates: function() {
  604. var options = this.options;
  605. if ( this.options.states ) {
  606. return;
  607. }
  608. // Add the default states.
  609. this.states.add([
  610. new Library({
  611. library: wp.media.query( options.library ),
  612. multiple: options.multiple,
  613. title: options.title,
  614. content: 'browse',
  615. toolbar: 'select',
  616. contentUserSetting: false,
  617. filterable: 'all',
  618. autoSelect: false
  619. })
  620. ]);
  621. },
  622. /**
  623. * Bind region mode activation events to proper handlers.
  624. */
  625. bindRegionModeHandlers: function() {
  626. this.on( 'content:create:browse', this.browseContent, this );
  627. // Handle a frame-level event for editing an attachment.
  628. this.on( 'edit:attachment', this.openEditAttachmentModal, this );
  629. this.on( 'select:activate', this.bindKeydown, this );
  630. this.on( 'select:deactivate', this.unbindKeydown, this );
  631. },
  632. handleKeydown: function( e ) {
  633. if ( 27 === e.which ) {
  634. e.preventDefault();
  635. this.deactivateMode( 'select' ).activateMode( 'edit' );
  636. }
  637. },
  638. bindKeydown: function() {
  639. this.$body.on( 'keydown.select', _.bind( this.handleKeydown, this ) );
  640. },
  641. unbindKeydown: function() {
  642. this.$body.off( 'keydown.select' );
  643. },
  644. fixPosition: function() {
  645. var $browser, $toolbar;
  646. if ( ! this.isModeActive( 'select' ) ) {
  647. return;
  648. }
  649. $browser = this.$('.attachments-browser');
  650. $toolbar = $browser.find('.media-toolbar');
  651. // Offset doesn't appear to take top margin into account, hence +16
  652. if ( ( $browser.offset().top + 16 ) < this.$window.scrollTop() + this.$adminBar.height() ) {
  653. $browser.addClass( 'fixed' );
  654. $toolbar.css('width', $browser.width() + 'px');
  655. } else {
  656. $browser.removeClass( 'fixed' );
  657. $toolbar.css('width', '');
  658. }
  659. },
  660. /**
  661. * Click handler for the `Add New` button.
  662. */
  663. addNewClickHandler: function( event ) {
  664. event.preventDefault();
  665. this.trigger( 'toggle:upload:attachment' );
  666. if ( this.uploader ) {
  667. this.uploader.refresh();
  668. }
  669. },
  670. /**
  671. * Open the Edit Attachment modal.
  672. */
  673. openEditAttachmentModal: function( model ) {
  674. // Create a new EditAttachment frame, passing along the library and the attachment model.
  675. wp.media( {
  676. frame: 'edit-attachments',
  677. controller: this,
  678. library: this.state().get('library'),
  679. model: model
  680. } );
  681. },
  682. /**
  683. * Create an attachments browser view within the content region.
  684. *
  685. * @param {Object} contentRegion Basic object with a `view` property, which
  686. * should be set with the proper region view.
  687. * @this wp.media.controller.Region
  688. */
  689. browseContent: function( contentRegion ) {
  690. var state = this.state();
  691. // Browse our library of attachments.
  692. this.browserView = contentRegion.view = new wp.media.view.AttachmentsBrowser({
  693. controller: this,
  694. collection: state.get('library'),
  695. selection: state.get('selection'),
  696. model: state,
  697. sortable: state.get('sortable'),
  698. search: state.get('searchable'),
  699. filters: state.get('filterable'),
  700. date: state.get('date'),
  701. display: state.get('displaySettings'),
  702. dragInfo: state.get('dragInfo'),
  703. sidebar: 'errors',
  704. suggestedWidth: state.get('suggestedWidth'),
  705. suggestedHeight: state.get('suggestedHeight'),
  706. AttachmentView: state.get('AttachmentView'),
  707. scrollElement: document
  708. });
  709. this.browserView.on( 'ready', _.bind( this.bindDeferred, this ) );
  710. this.errors = wp.Uploader.errors;
  711. this.errors.on( 'add remove reset', this.sidebarVisibility, this );
  712. },
  713. sidebarVisibility: function() {
  714. this.browserView.$( '.media-sidebar' ).toggle( !! this.errors.length );
  715. },
  716. bindDeferred: function() {
  717. if ( ! this.browserView.dfd ) {
  718. return;
  719. }
  720. this.browserView.dfd.done( _.bind( this.startHistory, this ) );
  721. },
  722. startHistory: function() {
  723. // Verify pushState support and activate
  724. if ( window.history && window.history.pushState ) {
  725. Backbone.history.start( {
  726. root: window._wpMediaGridSettings.adminUrl,
  727. pushState: true
  728. } );
  729. }
  730. }
  731. });
  732. module.exports = Manage;
  733. },{}]},{},[2]);