diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css index 541f4880d9..5c0ddbcf70 100644 --- a/src/wp-includes/css/media-views.css +++ b/src/wp-includes/css/media-views.css @@ -729,6 +729,17 @@ -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; + opacity: 1; + -webkit-transition: opacity 250ms; + transition: opacity 250ms; +} + +.media-frame.mode-select .attachment { + opacity: 0.65; +} + +.media-frame.mode-select .attachment.selected { + opacity: 1; } .attachment:focus { @@ -741,6 +752,15 @@ outline: none; } +.media-frame.mode-grid .attachment:focus { + -webkit-box-shadow: + inset 0 0 0 6px #f1f1f1, + inset 0 0 1px 7px #5b9dd9; + box-shadow: + inset 0 0 0 6px #f1f1f1, + inset 0 0 1px 7px #5b9dd9; +} + .selected.attachment { -webkit-box-shadow: inset 0 0 0 5px #fff, @@ -750,6 +770,15 @@ inset 0 0 0 7px #ccc; } +.media-frame.mode-grid .selected.attachment { + -webkit-box-shadow: + inset 0 0 0 6px #f1f1f1, + inset 0 0 0 7px #ccc; + box-shadow: + inset 0 0 0 6px #f1f1f1, + inset 0 0 0 7px #ccc; +} + .attachment-preview { position: relative; -webkit-box-shadow: @@ -922,8 +951,7 @@ } .selected.attachment:focus, -.attachment.details, -.media-frame.mode-grid .selected.attachment { +.attachment.details { -webkit-box-shadow: inset 0 0 0 3px #fff, inset 0 0 0 7px #1e8cbe; @@ -932,6 +960,15 @@ inset 0 0 0 7px #1e8cbe; } +.media-frame.mode-grid .selected.attachment:focus { + -webkit-box-shadow: + inset 0 0 0 3px #f1f1f1, + inset 0 0 0 7px #1e8cbe; + box-shadow: + inset 0 0 0 3px #f1f1f1, + inset 0 0 0 7px #1e8cbe; +} + .attachment.details .check, .attachment.selected .check:focus, .media-frame.mode-grid .attachment.selected .check { @@ -944,14 +981,6 @@ 0 0 0 2px #1e8cbe; } -.media-frame.mode-grid .attachment .check { - display: block; -} - -.media-frame.mode-grid .attachment .check div { - background-position: 21px 0; -} - .attachment.details .check div, .media-frame.mode-grid .attachment.selected .check div { background-position: -21px 0; @@ -997,7 +1026,7 @@ .attachments-browser .media-toolbar-primary > .media-button-group, .attachments-browser .media-toolbar-secondary > .media-button, .attachments-browser .media-toolbar-secondary > .media-button-group { - margin-top: 10px; + margin: 11px 0; } .attachments-browser .attachments, @@ -2453,7 +2482,6 @@ /* Regions we don't use at all */ .media-frame.mode-grid .media-frame-title, -.media-frame.mode-grid .media-frame-toolbar, .media-frame.mode-grid .media-frame-router, .media-frame.mode-grid .media-frame-menu { display: none; @@ -2488,6 +2516,10 @@ padding: 2px; } +.media-frame.mode-select .attachments { + padding: 2px; +} + /** * Copied styles from the Add theme toolbar. * @@ -2511,6 +2543,14 @@ border: none; } +.media-frame.mode-select .attachments-browser .media-toolbar.fixed { + position: fixed; + top: 28px; + left: 182px; + right: 20px; + width: auto; +} + .media-frame.mode-grid input[type="search"] { margin: 1px; padding: 3px 5px; @@ -2539,6 +2579,10 @@ margin-top: 15px; } +.attachments-browser .media-toolbar-secondary > .select-mode-toggle-button { + margin-right: 10px; +} + .media-frame.mode-grid .attachments-browser { padding: 0; } diff --git a/src/wp-includes/js/media-grid.js b/src/wp-includes/js/media-grid.js index 2df661b091..3aa13f7696 100644 --- a/src/wp-includes/js/media-grid.js +++ b/src/wp-includes/js/media-grid.js @@ -62,10 +62,13 @@ multiple: 'add', state: 'library', uploader: true, - mode: [ 'grid' ] + mode: [ 'grid', 'edit' ] }); - $(document).on( 'click', '.add-new-h2', _.bind( this.addNewClickHandler, this ) ); + this.$window = $( window ); + this.$adminBar = $( '#wpadminbar' ); + this.$window.on( 'scroll', _.debounce( _.bind( this.fixPosition, this ), 15 ) ); + $( document ).on( 'click', '.add-new-h2', _.bind( this.addNewClickHandler, this ) ); // Ensure core and media grid view UI is enabled. this.$el.addClass('wp-core-ui'); @@ -96,6 +99,8 @@ // Call 'initialize' directly on the parent class. media.view.MediaFrame.prototype.initialize.apply( this, arguments ); + this.on( 'all', function () { console.log( arguments ); } ); + // Append the frame view directly the supplied container. this.$el.appendTo( this.options.container ); @@ -130,6 +135,7 @@ multiple: options.multiple, title: options.title, content: 'browse', + toolbar: 'select', contentUserSetting: false, filterable: 'all' }) @@ -146,6 +152,21 @@ this.on( 'edit:attachment', this.openEditAttachmentModal, this ); }, + fixPosition: function() { + var $browser; + if ( ! this.isModeActive( 'select' ) ) { + return; + } + + $browser = this.$('.attachments-browser'); + + if ( $browser.offset().top < this.$window.scrollTop() + this.$adminBar.height() ) { + $browser.find('.media-toolbar').addClass( 'fixed' ); + } else { + $browser.find('.media-toolbar').removeClass( 'fixed' ); + } + }, + /** * Click handler for the `Add New` button. */ @@ -542,126 +563,60 @@ } }); - /** - * Controller for bulk selection. - */ - media.view.BulkSelection = media.View.extend({ - className: 'bulk-select', - - initialize: function() { - this.model = new Backbone.Model({ - currentAction: '' - - }); - - this.views.add( new media.view.Label({ - value: l10n.bulkActionsLabel, - attributes: { - 'for': 'bulk-select-dropdown' - } - }) ); - - this.views.add( - new media.view.BulkSelectionActionDropdown({ - controller: this - }) - ); - - this.views.add( - new media.view.BulkSelectionActionButton({ - disabled: true, - text: l10n.apply, - controller: this - }) - ); - } - }); - - /** - * Bulk Selection dropdown view. - * - * @constructor - * @augments wp.media.View - * @augments wp.Backbone.View - * @augments Backbone.View - */ - media.view.BulkSelectionActionDropdown = media.View.extend({ - tagName: 'select', - id: 'bulk-select-dropdown', - + media.view.SelectModeToggleButton = media.view.Button.extend({ initialize: function() { media.view.Button.prototype.initialize.apply( this, arguments ); - this.listenTo( this.controller.controller.state().get( 'selection' ), 'add remove reset', _.bind( this.enabled, this ) ); - this.$el.append( $('').val( '' ).html( l10n.bulkActions ) ) - .append( $('').val( 'delete' ).html( l10n.deletePermanently ) ); - this.$el.prop( 'disabled', true ); - this.$el.on( 'change', _.bind( this.changeHandler, this ) ); + this.listenTo( this.controller, 'select:activate select:deactivate', this.toggleBulkEditHandler ); }, - /** - * Change handler for the dropdown. - * - * Sets the bulk selection controller's currentAction. - */ - changeHandler: function() { - this.controller.model.set( { 'currentAction': this.$el.val() } ); - }, - - /** - * Enable or disable the dropdown if attachments have been selected. - */ - enabled: function() { - var disabled = ! this.controller.controller.state().get('selection').length; - this.$el.prop( 'disabled', disabled ); - } - }); - - /** - * Bulk Selection dropdown view. - * - * @constructor - * - * @augments wp.media.view.Button - * @augments wp.media.View - * @augments wp.Backbone.View - * @augments Backbone.View - */ - media.view.BulkSelectionActionButton = media.view.Button.extend({ - tagName: 'button', - - initialize: function() { - media.view.Button.prototype.initialize.apply( this, arguments ); - - this.listenTo( this.controller.model, 'change', this.enabled, this ); - this.listenTo( this.controller.controller.state().get( 'selection' ), 'add remove reset', _.bind( this.enabled, this ) ); - }, - /** - * Button click handler. - */ click: function() { - var selection = this.controller.controller.state().get('selection'); media.view.Button.prototype.click.apply( this, arguments ); - - if ( 'delete' === this.controller.model.get( 'currentAction' ) ) { - // Currently assumes delete is the only action - if ( confirm( l10n.warnBulkDelete ) ) { - while ( selection.length > 0 ) { - selection.at(0).destroy(); - } - } + if ( this.controller.isModeActive( 'select' ) ) { + this.controller.deactivateMode( 'select' ).activateMode( 'edit' ); + } else { + this.controller.deactivateMode( 'edit' ).activateMode( 'select' ); } - - this.enabled(); }, - /** - * Enable or disable the button depending if a bulk action is selected - * in the bulk select dropdown, and if attachments have been selected. - */ - enabled: function() { - var currentAction = this.controller.model.get( 'currentAction' ), - selection = this.controller.controller.state().get('selection'), - disabled = ! currentAction || ! selection.length; - this.$el.prop( 'disabled', disabled ); + + render: function() { + media.view.Button.prototype.render.apply( this, arguments ); + this.$el.addClass( 'select-mode-toggle-button' ); + return this; + }, + + toggleBulkEditHandler: function() { + var toolbar = this.controller.content.get().toolbar, children; + + children = toolbar.$( '.media-toolbar-secondary > *, .media-toolbar-primary > *'); + + if ( this.controller.isModeActive( 'select' ) ) { + this.model.set( 'text', l10n.cancelSelection ); + children.not( '.delete-selected-button' ).hide(); + toolbar.$( '.select-mode-toggle-button' ).show(); + toolbar.$( '.delete-selected-button' ).removeClass( 'hidden' ); + } else { + this.model.set( 'text', l10n.bulkSelect ); + toolbar.$( '.delete-selected-button' ).addClass( 'hidden' ); + children.not( '.spinner, .delete-selected-button' ).show(); + this.controller.state().get( 'selection' ).reset(); + } + } + }); + + media.view.DeleteSelectedButton = media.view.Button.extend({ + initialize: function() { + media.view.Button.prototype.initialize.apply( this, arguments ); + this.listenTo( this.controller, 'selection:toggle', this.toggleDisabled ); + }, + + toggleDisabled: function() { + this.$el.attr( 'disabled', ! this.controller.state().get( 'selection' ).length ); + }, + + render: function() { + media.view.Button.prototype.render.apply( this, arguments ); + this.$el.addClass( 'delete-selected-button hidden' ); + return this; } }); diff --git a/src/wp-includes/js/media-views.js b/src/wp-includes/js/media-views.js index 3e90761046..2945df3541 100644 --- a/src/wp-includes/js/media-views.js +++ b/src/wp-includes/js/media-views.js @@ -1792,7 +1792,7 @@ deactivateMode: function( mode ) { // Bail if the mode isn't active. if ( ! this.isModeActive( mode ) ) { - return; + return this; } this.activeModes.remove( this.activeModes.where( { id: mode } ) ); this.$el.removeClass( 'mode-' + mode ); @@ -4821,12 +4821,18 @@ // In the grid view, bubble up an edit:attachment event to the controller. if ( this.controller.isModeActive( 'grid' ) ) { - // Pass the current target to restore focus when closing - this.controller.trigger( 'edit:attachment', this.model, event.currentTarget ); + if ( this.controller.isModeActive( 'edit' ) ) { + // Pass the current target to restore focus when closing + this.controller.trigger( 'edit:attachment', this.model, event.currentTarget ); - // Don't scroll the view and don't attempt to submit anything. - event.stopPropagation(); - return; + // Don't scroll the view and don't attempt to submit anything. + event.stopPropagation(); + return; + } + + if ( this.controller.isModeActive( 'select' ) ) { + method = 'toggle'; + } } if ( event.shiftKey ) { @@ -4839,6 +4845,8 @@ method: method }); + this.controller.trigger( 'selection:toggle' ); + // Don't scroll the view and don't attempt to submit anything. event.stopPropagation(); }, @@ -5784,12 +5792,6 @@ priority: -90 }).render() ); - // BulkSelection is a
with subviews, including screen reader text - this.toolbar.set( 'bulkSelection', new media.view.BulkSelection({ - controller: this.controller, - priority: -70 - }).render() ); - // DateFilter is a