mirror of
https://github.com/WordPress/WordPress.git
synced 2024-12-28 20:17:45 +01:00
459 lines
13 KiB
JavaScript
459 lines
13 KiB
JavaScript
|
/*globals _, wp, jQuery */
|
||
|
|
||
|
/**
|
||
|
* wp.media.view.AttachmentsBrowser
|
||
|
*
|
||
|
* @class
|
||
|
* @augments wp.media.View
|
||
|
* @augments wp.Backbone.View
|
||
|
* @augments Backbone.View
|
||
|
*
|
||
|
* @param {object} options
|
||
|
* @param {object} [options.filters=false] Which filters to show in the browser's toolbar.
|
||
|
* Accepts 'uploaded' and 'all'.
|
||
|
* @param {object} [options.search=true] Whether to show the search interface in the
|
||
|
* browser's toolbar.
|
||
|
* @param {object} [options.date=true] Whether to show the date filter in the
|
||
|
* browser's toolbar.
|
||
|
* @param {object} [options.display=false] Whether to show the attachments display settings
|
||
|
* view in the sidebar.
|
||
|
* @param {bool|string} [options.sidebar=true] Whether to create a sidebar for the browser.
|
||
|
* Accepts true, false, and 'errors'.
|
||
|
*/
|
||
|
var View = require( '../view.js' ),
|
||
|
Library = require( '../attachment/library.js' ),
|
||
|
Toolbar = require( '../toolbar.js' ),
|
||
|
Spinner = require( '../spinner.js' ),
|
||
|
Search = require( '../search.js' ),
|
||
|
Label = require( '../label.js' ),
|
||
|
Uploaded = require( '../attachment-filters/uploaded.js' ),
|
||
|
All = require( '../attachment-filters/all.js' ),
|
||
|
DateFilter = require( '../attachment-filters/date.js' ),
|
||
|
UploaderInline = require( '../uploader/inline.js' ),
|
||
|
Attachments = require( '../attachments.js' ),
|
||
|
Sidebar = require( '../sidebar.js' ),
|
||
|
UploaderStatus = require( '../uploader/status.js' ),
|
||
|
Details = require( '../attachment/details.js' ),
|
||
|
AttachmentCompat = require( '../attachment-compat.js' ),
|
||
|
AttachmentDisplay = require( '../settings/attachment-display.js' ),
|
||
|
mediaTrash = wp.media.view.settings.mediaTrash,
|
||
|
l10n = wp.media.view.l10n,
|
||
|
$ = jQuery,
|
||
|
AttachmentsBrowser;
|
||
|
|
||
|
AttachmentsBrowser = View.extend({
|
||
|
tagName: 'div',
|
||
|
className: 'attachments-browser',
|
||
|
|
||
|
initialize: function() {
|
||
|
_.defaults( this.options, {
|
||
|
filters: false,
|
||
|
search: true,
|
||
|
date: true,
|
||
|
display: false,
|
||
|
sidebar: true,
|
||
|
AttachmentView: Library
|
||
|
});
|
||
|
|
||
|
this.listenTo( this.controller, 'toggle:upload:attachment', _.bind( this.toggleUploader, this ) );
|
||
|
this.controller.on( 'edit:selection', this.editSelection );
|
||
|
this.createToolbar();
|
||
|
if ( this.options.sidebar ) {
|
||
|
this.createSidebar();
|
||
|
}
|
||
|
this.createUploader();
|
||
|
this.createAttachments();
|
||
|
this.updateContent();
|
||
|
|
||
|
if ( ! this.options.sidebar || 'errors' === this.options.sidebar ) {
|
||
|
this.$el.addClass( 'hide-sidebar' );
|
||
|
|
||
|
if ( 'errors' === this.options.sidebar ) {
|
||
|
this.$el.addClass( 'sidebar-for-errors' );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this.collection.on( 'add remove reset', this.updateContent, this );
|
||
|
},
|
||
|
|
||
|
editSelection: function( modal ) {
|
||
|
modal.$( '.media-button-backToLibrary' ).focus();
|
||
|
},
|
||
|
|
||
|
/**
|
||
|
* @returns {wp.media.view.AttachmentsBrowser} Returns itself to allow chaining
|
||
|
*/
|
||
|
dispose: function() {
|
||
|
this.options.selection.off( null, null, this );
|
||
|
View.prototype.dispose.apply( this, arguments );
|
||
|
return this;
|
||
|
},
|
||
|
|
||
|
createToolbar: function() {
|
||
|
var LibraryViewSwitcher, Filters, toolbarOptions;
|
||
|
|
||
|
toolbarOptions = {
|
||
|
controller: this.controller
|
||
|
};
|
||
|
|
||
|
if ( this.controller.isModeActive( 'grid' ) ) {
|
||
|
toolbarOptions.className = 'media-toolbar wp-filter';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @member {wp.media.view.Toolbar}
|
||
|
*/
|
||
|
this.toolbar = new Toolbar( toolbarOptions );
|
||
|
|
||
|
this.views.add( this.toolbar );
|
||
|
|
||
|
this.toolbar.set( 'spinner', new Spinner({
|
||
|
priority: -60
|
||
|
}) );
|
||
|
|
||
|
if ( -1 !== $.inArray( this.options.filters, [ 'uploaded', 'all' ] ) ) {
|
||
|
// "Filters" will return a <select>, need to render
|
||
|
// screen reader text before
|
||
|
this.toolbar.set( 'filtersLabel', new Label({
|
||
|
value: l10n.filterByType,
|
||
|
attributes: {
|
||
|
'for': 'media-attachment-filters'
|
||
|
},
|
||
|
priority: -80
|
||
|
}).render() );
|
||
|
|
||
|
if ( 'uploaded' === this.options.filters ) {
|
||
|
this.toolbar.set( 'filters', new Uploaded({
|
||
|
controller: this.controller,
|
||
|
model: this.collection.props,
|
||
|
priority: -80
|
||
|
}).render() );
|
||
|
} else {
|
||
|
Filters = new All({
|
||
|
controller: this.controller,
|
||
|
model: this.collection.props,
|
||
|
priority: -80
|
||
|
});
|
||
|
|
||
|
this.toolbar.set( 'filters', Filters.render() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Feels odd to bring the global media library switcher into the Attachment
|
||
|
// browser view. Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
|
||
|
// which the controller can tap into and add this view?
|
||
|
if ( this.controller.isModeActive( 'grid' ) ) {
|
||
|
LibraryViewSwitcher = View.extend({
|
||
|
className: 'view-switch media-grid-view-switch',
|
||
|
template: wp.template( 'media-library-view-switcher')
|
||
|
});
|
||
|
|
||
|
this.toolbar.set( 'libraryViewSwitcher', new LibraryViewSwitcher({
|
||
|
controller: this.controller,
|
||
|
priority: -90
|
||
|
}).render() );
|
||
|
|
||
|
// DateFilter is a <select>, screen reader text needs to be rendered before
|
||
|
this.toolbar.set( 'dateFilterLabel', new Label({
|
||
|
value: l10n.filterByDate,
|
||
|
attributes: {
|
||
|
'for': 'media-attachment-date-filters'
|
||
|
},
|
||
|
priority: -75
|
||
|
}).render() );
|
||
|
this.toolbar.set( 'dateFilter', new DateFilter({
|
||
|
controller: this.controller,
|
||
|
model: this.collection.props,
|
||
|
priority: -75
|
||
|
}).render() );
|
||
|
|
||
|
// BulkSelection is a <div> with subviews, including screen reader text
|
||
|
this.toolbar.set( 'selectModeToggleButton', new wp.media.view.SelectModeToggleButton({
|
||
|
text: l10n.bulkSelect,
|
||
|
controller: this.controller,
|
||
|
priority: -70
|
||
|
}).render() );
|
||
|
|
||
|
this.toolbar.set( 'deleteSelectedButton', new wp.media.view.DeleteSelectedButton({
|
||
|
filters: Filters,
|
||
|
style: 'primary',
|
||
|
disabled: true,
|
||
|
text: mediaTrash ? l10n.trashSelected : l10n.deleteSelected,
|
||
|
controller: this.controller,
|
||
|
priority: -60,
|
||
|
click: function() {
|
||
|
var changed = [], removed = [], self = this,
|
||
|
selection = this.controller.state().get( 'selection' ),
|
||
|
library = this.controller.state().get( 'library' );
|
||
|
|
||
|
if ( ! selection.length ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( ! mediaTrash && ! confirm( l10n.warnBulkDelete ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( mediaTrash &&
|
||
|
'trash' !== selection.at( 0 ).get( 'status' ) &&
|
||
|
! confirm( l10n.warnBulkTrash ) ) {
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
selection.each( function( model ) {
|
||
|
if ( ! model.get( 'nonces' )['delete'] ) {
|
||
|
removed.push( model );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ( mediaTrash && 'trash' === model.get( 'status' ) ) {
|
||
|
model.set( 'status', 'inherit' );
|
||
|
changed.push( model.save() );
|
||
|
removed.push( model );
|
||
|
} else if ( mediaTrash ) {
|
||
|
model.set( 'status', 'trash' );
|
||
|
changed.push( model.save() );
|
||
|
removed.push( model );
|
||
|
} else {
|
||
|
model.destroy({wait: true});
|
||
|
}
|
||
|
} );
|
||
|
|
||
|
if ( changed.length ) {
|
||
|
selection.remove( removed );
|
||
|
|
||
|
$.when.apply( null, changed ).then( function() {
|
||
|
library._requery( true );
|
||
|
self.controller.trigger( 'selection:action:done' );
|
||
|
} );
|
||
|
} else {
|
||
|
this.controller.trigger( 'selection:action:done' );
|
||
|
}
|
||
|
}
|
||
|
}).render() );
|
||
|
|
||
|
if ( mediaTrash ) {
|
||
|
this.toolbar.set( 'deleteSelectedPermanentlyButton', new wp.media.view.DeleteSelectedPermanentlyButton({
|
||
|
filters: Filters,
|
||
|
style: 'primary',
|
||
|
disabled: true,
|
||
|
text: l10n.deleteSelected,
|
||
|
controller: this.controller,
|
||
|
priority: -55,
|
||
|
click: function() {
|
||
|
var removed = [], selection = this.controller.state().get( 'selection' );
|
||
|
|
||
|
if ( ! selection.length || ! confirm( l10n.warnBulkDelete ) ) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
selection.each( function( model ) {
|
||
|
if ( ! model.get( 'nonces' )['delete'] ) {
|
||
|
removed.push( model );
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
model.destroy();
|
||
|
} );
|
||
|
|
||
|
selection.remove( removed );
|
||
|
this.controller.trigger( 'selection:action:done' );
|
||
|
}
|
||
|
}).render() );
|
||
|
}
|
||
|
|
||
|
} else if ( this.options.date ) {
|
||
|
// DateFilter is a <select>, screen reader text needs to be rendered before
|
||
|
this.toolbar.set( 'dateFilterLabel', new Label({
|
||
|
value: l10n.filterByDate,
|
||
|
attributes: {
|
||
|
'for': 'media-attachment-date-filters'
|
||
|
},
|
||
|
priority: -75
|
||
|
}).render() );
|
||
|
this.toolbar.set( 'dateFilter', new DateFilter({
|
||
|
controller: this.controller,
|
||
|
model: this.collection.props,
|
||
|
priority: -75
|
||
|
}).render() );
|
||
|
}
|
||
|
|
||
|
if ( this.options.search ) {
|
||
|
// Search is an input, screen reader text needs to be rendered before
|
||
|
this.toolbar.set( 'searchLabel', new Label({
|
||
|
value: l10n.searchMediaLabel,
|
||
|
attributes: {
|
||
|
'for': 'media-search-input'
|
||
|
},
|
||
|
priority: 60
|
||
|
}).render() );
|
||
|
this.toolbar.set( 'search', new Search({
|
||
|
controller: this.controller,
|
||
|
model: this.collection.props,
|
||
|
priority: 60
|
||
|
}).render() );
|
||
|
}
|
||
|
|
||
|
if ( this.options.dragInfo ) {
|
||
|
this.toolbar.set( 'dragInfo', new View({
|
||
|
el: $( '<div class="instructions">' + l10n.dragInfo + '</div>' )[0],
|
||
|
priority: -40
|
||
|
}) );
|
||
|
}
|
||
|
|
||
|
if ( this.options.suggestedWidth && this.options.suggestedHeight ) {
|
||
|
this.toolbar.set( 'suggestedDimensions', new View({
|
||
|
el: $( '<div class="instructions">' + l10n.suggestedDimensions + ' ' + this.options.suggestedWidth + ' × ' + this.options.suggestedHeight + '</div>' )[0],
|
||
|
priority: -40
|
||
|
}) );
|
||
|
}
|
||
|
},
|
||
|
|
||
|
updateContent: function() {
|
||
|
var view = this,
|
||
|
noItemsView;
|
||
|
|
||
|
if ( this.controller.isModeActive( 'grid' ) ) {
|
||
|
noItemsView = view.attachmentsNoResults;
|
||
|
} else {
|
||
|
noItemsView = view.uploader;
|
||
|
}
|
||
|
|
||
|
if ( ! this.collection.length ) {
|
||
|
this.toolbar.get( 'spinner' ).show();
|
||
|
this.dfd = this.collection.more().done( function() {
|
||
|
if ( ! view.collection.length ) {
|
||
|
noItemsView.$el.removeClass( 'hidden' );
|
||
|
} else {
|
||
|
noItemsView.$el.addClass( 'hidden' );
|
||
|
}
|
||
|
view.toolbar.get( 'spinner' ).hide();
|
||
|
} );
|
||
|
} else {
|
||
|
noItemsView.$el.addClass( 'hidden' );
|
||
|
view.toolbar.get( 'spinner' ).hide();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
createUploader: function() {
|
||
|
this.uploader = new UploaderInline({
|
||
|
controller: this.controller,
|
||
|
status: false,
|
||
|
message: this.controller.isModeActive( 'grid' ) ? '' : l10n.noItemsFound,
|
||
|
canClose: this.controller.isModeActive( 'grid' )
|
||
|
});
|
||
|
|
||
|
this.uploader.hide();
|
||
|
this.views.add( this.uploader );
|
||
|
},
|
||
|
|
||
|
toggleUploader: function() {
|
||
|
if ( this.uploader.$el.hasClass( 'hidden' ) ) {
|
||
|
this.uploader.show();
|
||
|
} else {
|
||
|
this.uploader.hide();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
createAttachments: function() {
|
||
|
this.attachments = new Attachments({
|
||
|
controller: this.controller,
|
||
|
collection: this.collection,
|
||
|
selection: this.options.selection,
|
||
|
model: this.model,
|
||
|
sortable: this.options.sortable,
|
||
|
scrollElement: this.options.scrollElement,
|
||
|
idealColumnWidth: this.options.idealColumnWidth,
|
||
|
|
||
|
// The single `Attachment` view to be used in the `Attachments` view.
|
||
|
AttachmentView: this.options.AttachmentView
|
||
|
});
|
||
|
|
||
|
// Add keydown listener to the instance of the Attachments view
|
||
|
this.attachments.listenTo( this.controller, 'attachment:keydown:arrow', this.attachments.arrowEvent );
|
||
|
this.attachments.listenTo( this.controller, 'attachment:details:shift-tab', this.attachments.restoreFocus );
|
||
|
|
||
|
this.views.add( this.attachments );
|
||
|
|
||
|
|
||
|
if ( this.controller.isModeActive( 'grid' ) ) {
|
||
|
this.attachmentsNoResults = new View({
|
||
|
controller: this.controller,
|
||
|
tagName: 'p'
|
||
|
});
|
||
|
|
||
|
this.attachmentsNoResults.$el.addClass( 'hidden no-media' );
|
||
|
this.attachmentsNoResults.$el.html( l10n.noMedia );
|
||
|
|
||
|
this.views.add( this.attachmentsNoResults );
|
||
|
}
|
||
|
},
|
||
|
|
||
|
createSidebar: function() {
|
||
|
var options = this.options,
|
||
|
selection = options.selection,
|
||
|
sidebar = this.sidebar = new Sidebar({
|
||
|
controller: this.controller
|
||
|
});
|
||
|
|
||
|
this.views.add( sidebar );
|
||
|
|
||
|
if ( this.controller.uploader ) {
|
||
|
sidebar.set( 'uploads', new UploaderStatus({
|
||
|
controller: this.controller,
|
||
|
priority: 40
|
||
|
}) );
|
||
|
}
|
||
|
|
||
|
selection.on( 'selection:single', this.createSingle, this );
|
||
|
selection.on( 'selection:unsingle', this.disposeSingle, this );
|
||
|
|
||
|
if ( selection.single() ) {
|
||
|
this.createSingle();
|
||
|
}
|
||
|
},
|
||
|
|
||
|
createSingle: function() {
|
||
|
var sidebar = this.sidebar,
|
||
|
single = this.options.selection.single();
|
||
|
|
||
|
sidebar.set( 'details', new Details({
|
||
|
controller: this.controller,
|
||
|
model: single,
|
||
|
priority: 80
|
||
|
}) );
|
||
|
|
||
|
sidebar.set( 'compat', new AttachmentCompat({
|
||
|
controller: this.controller,
|
||
|
model: single,
|
||
|
priority: 120
|
||
|
}) );
|
||
|
|
||
|
if ( this.options.display ) {
|
||
|
sidebar.set( 'display', new AttachmentDisplay({
|
||
|
controller: this.controller,
|
||
|
model: this.model.display( single ),
|
||
|
attachment: single,
|
||
|
priority: 160,
|
||
|
userSettings: this.model.get('displayUserSettings')
|
||
|
}) );
|
||
|
}
|
||
|
|
||
|
// Show the sidebar on mobile
|
||
|
if ( this.model.id === 'insert' ) {
|
||
|
sidebar.$el.addClass( 'visible' );
|
||
|
}
|
||
|
},
|
||
|
|
||
|
disposeSingle: function() {
|
||
|
var sidebar = this.sidebar;
|
||
|
sidebar.unset('details');
|
||
|
sidebar.unset('compat');
|
||
|
sidebar.unset('display');
|
||
|
// Hide the sidebar on mobile
|
||
|
sidebar.$el.removeClass( 'visible' );
|
||
|
}
|
||
|
});
|
||
|
|
||
|
module.exports = AttachmentsBrowser;
|