[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/js/ -> media-grid.js (source)

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


Generated : Tue Sep 8 08:20:28 2026 Cross-referenced by PHPXref