WordPress.org

Make WordPress Core

Ticket #24716: 24716.38.diff

File 24716.38.diff, 7.5 KB (added by adamsilverstein, 3 years ago)

routing, keyboard

  • src/wp-admin/upload.php

     
    2424        wp_enqueue_media(); 
    2525        wp_enqueue_script( 'media-grid' ); 
    2626        wp_enqueue_script( 'media' ); 
     27        wp_localize_script( 'media-grid', 'mediaGridSettings', array( 'adminUrl' => parse_url( self_admin_url(), PHP_URL_PATH )  ) ); 
    2728 
    2829        require_once( ABSPATH . 'wp-admin/admin-header.php' ); 
    2930        include( ABSPATH . 'wp-admin/admin-footer.php' ); 
  • src/wp-includes/js/media-grid.js

     
    1 /* global _wpMediaViewsL10n, setUserSetting, deleteUserSetting, MediaElementPlayer */ 
     1/* global _wpMediaViewsL10n, setUserSetting, deleteUserSetting, MediaElementPlayer, mediaGridSettings*/ 
    22(function($, _, Backbone, wp) { 
    33        var media = wp.media, l10n; 
    44 
     
    9191                 * @global wp.Uploader 
    9292                 */ 
    9393                initialize: function() { 
     94                        var self = this; 
    9495                        _.defaults( this.options, { 
    9596                                title:     l10n.mediaLibraryTitle, 
    9697                                modal:     false, 
     
    140141                        this.createStates(); 
    141142                        this.bindHandlers(); 
    142143                        this.render(); 
     144 
     145                        // Set up the Backbone router after a brief delay 
     146                        _.delay( function(){ 
     147                                wp.media.mediarouter = new media.view.Frame.Router( self ); 
     148                                // Verify pushState support and activate 
     149                                if ( window.history && window.history.pushState ) { 
     150                                        Backbone.history.start({ 
     151                                                root: mediaGridSettings.adminUrl, 
     152                                                pushState: true 
     153                                        }); 
     154                                } 
     155                        }, 250); 
     156 
     157                        // Update the URL when entering search string (at most once per second) 
     158                        $( '#media-search-input' ).on( 'input', _.debounce( function() { 
     159                                var $val = $( this ).val(); 
     160                                wp.media.mediarouter.navigate( wp.media.mediarouter.baseUrl( ( '' == $val ) ? '' : ( '?search=' + $val ) ) ); 
     161                        }, 1000 ) ); 
    143162                }, 
    144163 
    145164                createSelection: function() { 
     
    218237                 * Open the Edit Attachment modal. 
    219238                 */ 
    220239                editAttachment: function( model ) { 
    221                         var library = this.state().get('library'); 
     240                        var self    = this, 
     241                                library = this.state().get('library'); 
    222242 
    223243                        // Create a new EditAttachment frame, passing along the library and the attachment model. 
    224                         this.editAttachmentFrame = new media.view.Frame.EditAttachment({ 
     244                        this.editAttachmentFrame = new media.view.Frame.EditAttachments({ 
    225245                                library:        library, 
    226246                                model:          model 
    227247                        }); 
     
    229249                        // Listen to events on the edit attachment frame for triggering pagination callback handlers. 
    230250                        this.listenTo( this.editAttachmentFrame, 'edit:attachment:next', this.editNextAttachment ); 
    231251                        this.listenTo( this.editAttachmentFrame, 'edit:attachment:previous', this.editPreviousAttachment ); 
     252                        // Listen to keyboard events on the modal 
     253                        $( 'body' ).on( 'keydown.media-modal', function( e ) { 
     254                                self.editAttachmentFrame.keyEvent( e ); 
     255                        } ); 
    232256                }, 
    233257 
    234258                /** 
     
    300324        }); 
    301325 
    302326        /** 
     327         * A router for handling the browser history and application state 
     328         */ 
     329        media.view.Frame.Router = Backbone.Router.extend({ 
     330 
     331                mediaFrame: '', 
     332 
     333                initialize: function( mediaFrame ){ 
     334                        this.mediaFrame = mediaFrame; 
     335                }, 
     336 
     337                routes: { 
     338                        'upload.php?item=:slug':    'showitem', 
     339                        'upload.php?search=:query': 'search', 
     340                        ':default':                 'defaultRoute' 
     341                }, 
     342 
     343                // Map routes against the page URL 
     344                baseUrl: function( url ) { 
     345                        return 'upload.php' + url; 
     346                }, 
     347 
     348                // Respond to the search route by filling the search field and trigggering the input event 
     349                search: function( query ) { 
     350                        // Ensure modal closed, see back button 
     351                        this.closeModal(); 
     352                        $( '#media-search-input' ).val( query ).trigger( 'input' ); 
     353                }, 
     354 
     355                // Show the modal with a specific item 
     356                showitem: function( query ) { 
     357                        var library = this.mediaFrame.state().get('library'); 
     358 
     359                        // Remove existing modal if present 
     360                        this.closeModal(); 
     361                        // Trigger the media frame to open the correct item 
     362                        this.mediaFrame.trigger( 'edit:attachment', library.findWhere( { id: parseInt( query, 10 ) } ) ); 
     363                }, 
     364 
     365                // Close the modal if set up 
     366                closeModal: function() { 
     367                        if ( 'undefined' !== typeof this.mediaFrame.editAttachmentFrame ) { 
     368                                this.mediaFrame.editAttachmentFrame.modal.close(); 
     369                        } 
     370                }, 
     371 
     372                // Default route: make sure the modal and search are reset 
     373                defaultRoute: function() { 
     374                        this.closeModal(); 
     375                        $( '#media-search-input' ).val( '' ).trigger( 'input' ); 
     376                } 
     377        }); 
     378 
     379        /** 
    303380         * A frame for editing the details of a specific media item. 
    304381         * 
    305382         * Opens in a modal by default. 
     
    306383         * 
    307384         * Requires an attachment model to be passed in the options hash under `model`. 
    308385         */ 
    309         media.view.Frame.EditAttachment = media.view.Frame.extend({ 
     386        media.view.Frame.EditAttachments = media.view.Frame.extend({ 
    310387 
    311388                className: 'edit-attachment-frame', 
    312389                template: media.template( 'edit-attachment-frame' ), 
     
    328405                                state: 'edit-attachment' 
    329406                        }); 
    330407 
     408                        this.library = this.options.library; 
     409                        if ( this.options.model ) { 
     410                                this.model = this.options.model; 
     411                        } else { 
     412                                this.model = this.library.at( 0 ); 
     413                        } 
     414 
    331415                        this.createStates(); 
    332416 
    333417                        this.on( 'content:render:edit-metadata', this.editMetadataContent, this ); 
     
    334418                        this.on( 'content:render:edit-image', this.editImageContentUgh, this ); 
    335419 
    336420                        // Only need a tab to Edit Image for images. 
    337                         if ( this.model.get( 'type' ) === 'image' ) { 
     421                        if ( 'undefined' !== typeof this.model && this.model.get( 'type' ) === 'image' ) { 
    338422                                this.on( 'router:create', this.createRouter, this ); 
    339423                                this.on( 'router:render', this.browseRouter, this ); 
    340424                        } 
     
    352436                                // Completely destroy the modal DOM element when closing it. 
    353437                                this.modal.close = function() { 
    354438                                        self.modal.remove(); 
     439                                        $( 'body' ).off( 'keydown.media-modal' ); /* remove the keydown event */ 
     440                                        // Reset the browser URL 
     441                                        self.resetRoute(); 
    355442                                }; 
    356443 
    357444                                this.modal.content( this ); 
     
    391478                                model:      this.model 
    392479                        }); 
    393480                        this.content.set( view ); 
     481                        // Update browser url when navigating media details 
     482                        wp.media.mediarouter.navigate( wp.media.mediarouter.baseUrl( '?item=' + this.model.id ) ); 
    394483                }, 
    395484 
    396485                /** 
     
    461550                                return; 
    462551                        this.modal.close(); 
    463552                        this.trigger( 'edit:attachment:next', this.model ); 
     553                }, 
     554 
     555                getCurrentIndex: function() { 
     556                        return this.library.indexOf( this.model ); 
     557                }, 
     558 
     559                hasNext: function() { 
     560                        return ( this.getCurrentIndex() + 1 ) < this.library.length; 
     561                }, 
     562 
     563                hasPrevious: function() { 
     564                        return ( this.getCurrentIndex() - 1 ) > -1; 
     565                }, 
     566                /** 
     567                 * Respond to the keyboard events: right arrow, left arrow, escape. 
     568                 */ 
     569                keyEvent: function( event ) { 
     570                        var $target = $( event.target ); 
     571                        // Pressing the escape key routes back to main url 
     572                        if ( event.keyCode === 27 ) { 
     573                                this.resetRoute(); 
     574                                return event; 
     575                        } 
     576                        //Don't go left/right if we are in a textarea or input field 
     577                        if ( $target.is( 'input' ) || $target.is( 'textarea' ) ) { 
     578                                return event; 
     579                        } 
     580                        // The right arrow key 
     581                        if ( event.keyCode === 39 ) { 
     582                                if ( ! this.hasNext ) { return; } 
     583                                _.debounce( this.nextMediaItem(), 250 ); 
     584                        } 
     585                        // The left arrow key 
     586                        if ( event.keyCode === 37 ) { 
     587                                if ( ! this.hasPrevious ) { return; } 
     588                                _.debounce( this.previousMediaItem(), 250 ); 
     589                        } 
     590                }, 
     591 
     592                resetRoute: function() { 
     593                        wp.media.mediarouter.navigate( wp.media.mediarouter.baseUrl( '' ) ); 
     594                        return; 
    464595                } 
    465596        }); 
    466597