diff --git a/wp-admin/includes/meta-boxes.php b/wp-admin/includes/meta-boxes.php
index 2aee5aa2d0..51e38b60cb 100644
--- a/wp-admin/includes/meta-boxes.php
+++ b/wp-admin/includes/meta-boxes.php
@@ -1018,7 +1018,8 @@ function post_thumbnail_meta_box( $post ) {
var $element = $('#select-featured-image'),
$thumbnailId = $element.find('input[name="thumbnail_id"]'),
title = '',
- workflow, selection, setFeaturedImage;
+ update = '',
+ frame, selection, setFeaturedImage;
setFeaturedImage = function( thumbnailId ) {
$element.find('img').remove();
@@ -1029,41 +1030,52 @@ function post_thumbnail_meta_box( $post ) {
$element.on( 'click', '.choose, img', function( event ) {
event.preventDefault();
- if ( ! workflow ) {
- workflow = wp.media({
+ if ( ! frame ) {
+ frame = wp.media({
title: title,
library: {
type: 'image'
}
});
- selection = workflow.state().get('selection');
+ frame.toolbar( new wp.media.view.Toolbar({
+ controller: frame,
+ items: {
+ update: {
+ style: 'primary',
+ text: update,
+ priority: 40,
- selection.on( 'add', function( model ) {
- var sizes = model.get('sizes'),
- size;
+ click: function() {
+ var selection = frame.state().get('selection'),
+ model = selection.first(),
+ sizes = model.get('sizes'),
+ size;
- setFeaturedImage( model.id );
+ setFeaturedImage( model.id );
- // @todo: might need a size hierarchy equivalent.
- if ( sizes )
- size = sizes['post-thumbnail'] || sizes.medium;
+ // @todo: might need a size hierarchy equivalent.
+ if ( sizes )
+ size = sizes['post-thumbnail'] || sizes.medium;
- // @todo: Need a better way of accessing full size
- // data besides just calling toJSON().
- size = size || model.toJSON();
+ // @todo: Need a better way of accessing full size
+ // data besides just calling toJSON().
+ size = size || model.toJSON();
- workflow.close();
- selection.clear();
+ frame.close();
+ selection.clear();
- $( '', {
- src: size.url,
- width: size.width
- }).prependTo( $element );
- });
+ $( '
', {
+ src: size.url,
+ width: size.width
+ }).prependTo( $element );
+ }
+ }
+ }
+ }) );
}
- workflow.open();
+ frame.open();
});
$element.on( 'click', '.remove', function( event ) {
diff --git a/wp-includes/css/media-views.css b/wp-includes/css/media-views.css
index 0f22658c48..1f3e92cc57 100644
--- a/wp-includes/css/media-views.css
+++ b/wp-includes/css/media-views.css
@@ -72,9 +72,12 @@
* Toolbar
*/
.media-toolbar {
- position: relative;
- z-index: 50;
- height: 60px;
+ position: absolute;
+ top: 0;
+ left: 220px;
+ right: 0;
+ z-index: 100;
+ height: 50px;
padding: 0 10px;
border-bottom: 1px solid #dfdfdf;
}
@@ -91,22 +94,64 @@
.media-toolbar-primary > .media-button-group {
margin-left: 10px;
float: left;
- margin-top: 16px;
+ margin-top: 10px;
}
.media-toolbar-secondary > .media-button,
.media-toolbar-secondary > .media-button-group {
margin-right: 10px;
float: left;
- margin-top: 16px;
+ margin-top: 10px;
+}
+
+/**
+ * Sidebar
+ */
+.media-sidebar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ width: 219px;
+ z-index: 50;
+ background: #f5f5f5;
+ border-right: 1px solid #dfdfdf;
+}
+
+.hide-sidebar .media-sidebar {
+ display: none;
+}
+
+.media-sidebar .sidebar-title {
+ font-weight: 200;
+ font-size: 20px;
+ margin: 0;
+ padding: 12px 10px 10px;
+ line-height: 28px;
+ /*border-bottom: 1px solid #dfdfdf;*/
+}
+
+.media-sidebar .sidebar-content {
+ padding: 0 10px;
+}
+
+.media-sidebar .search {
+ display: block;
+ width: 100%;
+}
+
+.media-sidebar .selection-preview {
+ display: block;
+ padding-top: 5px;
}
/**
* Frame
*/
-.media-frame .attachments,
-.media-frame .media-toolbar {
+.media-frame .media-content,
+.media-frame .media-toolbar,
+.media-frame .media-sidebar {
-webkit-transition-property: left, right, top, bottom, margin;
-moz-transition-property: left, right, top, bottom, margin;
-ms-transition-property: left, right, top, bottom, margin;
@@ -120,35 +165,41 @@
transition-duration: 0.2s;
}
-.media-frame .attachments {
+.media-frame .media-content {
position: absolute;
- top: 61px;
- left: 0;
+ top: 51px;
+ left: 220px;
right: 0;
bottom: 0;
height: auto;
width: auto;
+ overflow: auto;
}
-.media-frame.hide-toolbar .attachments {
- top: 0;
-}
-
-.media-frame .media-toolbar {
- margin-top: 0;
-}
-
-.media-frame.hide-toolbar .media-toolbar {
- margin-top: -61px;
+.media-frame.hide-sidebar .media-content {
+ left: 0;
}
.media-frame .media-toolbar .add-to-gallery {
display: none;
}
+
+/**
+ * Search
+ */
+.media-frame .search {
+ margin-top: 11px;
+ padding: 4px;
+ line-height: 18px;
+ font-size: 13px;
+ color: #464646;
+ font-family: sans-serif;
+}
+
/**
* Attachments
*/
-.attachments {
+/*.attachments {
position: relative;
width: 100%;
height: 100%;
@@ -173,16 +224,6 @@
font-weight: 200;
}
-.attachments-header .search {
- float: right;
- margin-top: 11px;
- padding: 4px;
- line-height: 18px;
- font-size: 13px;
- color: #464646;
- font-family: sans-serif;
-}
-
.attachments ul {
position: absolute;
top: 50px;
@@ -191,7 +232,7 @@
bottom: 0;
overflow: auto;
margin: 0 0 20px;
-}
+}*/
/**
* Attachment
@@ -401,7 +442,6 @@
bottom: 0;
background: rgba( 0, 86, 132, 0.9 );
- /*z-index: -200;*/
z-index: 250000;
display: none;
text-align: center;
@@ -414,10 +454,6 @@
transition: opacity 250ms;
}
-/*.drag-over .uploader-window {
- z-index: 250000;
-}*/
-
.uploader-window-content {
position: absolute;
top: 30px;
diff --git a/wp-includes/js/media-views.js b/wp-includes/js/media-views.js
index c994d76119..4efd28c715 100644
--- a/wp-includes/js/media-views.js
+++ b/wp-includes/js/media-views.js
@@ -113,7 +113,8 @@
defaults: {
id: 'library',
multiple: false,
- describe: false
+ describe: false,
+ title: l10n.mediaLibrary
},
initialize: function() {
@@ -130,25 +131,41 @@
var frame = this.frame,
toolbar;
+ // Toolbar.
toolbar = this._postLibraryToolbar = new media.view.Toolbar.PostLibrary({
controller: frame,
- selection: this.get('selection')
+ state: this
});
frame.toolbar( toolbar );
this.get('selection').on( 'add remove', toolbar.visibility, toolbar );
+ // Sidebar.
+ frame.sidebar( new media.view.Sidebar({
+ controller: frame,
+ views: {
+ search: new media.view.Search({
+ controller: frame,
+ model: this.get('library').props,
+ priority: 20
+ }),
+
+ selection: new media.view.SelectionPreview({
+ controller: frame,
+ collection: this.get('selection'),
+ priority: 40
+ })
+ }
+ }) );
+
+ // Content.
frame.content( new media.view.Attachments({
- directions: this.get('multiple') ? l10n.selectMediaMultiple : l10n.selectMediaSingular,
controller: frame,
collection: this.get('library'),
// The single `Attachment` view to be used in the `Attachments` view.
AttachmentView: media.view.Attachment.Library
}).render() );
- if ( ! this.get('selection').length )
- frame.$el.addClass('hide-toolbar');
-
// If we're in a workflow that supports multiple attachments,
// automatically select any uploading attachments.
if ( this.get('multiple') )
@@ -173,7 +190,8 @@
defaults: {
id: 'gallery',
multiple: true,
- describe: true
+ describe: true,
+ title: l10n.createGallery
},
initialize: function() {
@@ -186,14 +204,19 @@
activate: function() {
var frame = this.frame;
+ // Toolbar.
frame.toolbar( new media.view.Toolbar.Gallery({
controller: frame,
- editing: this.get('editing'),
- selection: this.get('selection')
+ state: this
}) );
+ // Sidebar.
+ frame.sidebar( new media.view.Sidebar({
+ controller: frame
+ }).render() );
+
+ // Content.
frame.content( new media.view.Attachments({
- directions: 'Gallery time!',
controller: frame,
collection: this.get('selection'),
sortable: true,
@@ -245,7 +268,7 @@
},
render: function() {
- var els = [ this.sidebar().el, this.toolbar().el, this.content().el ];
+ var els = [ this.toolbar().el, this.sidebar().el, this.content().el ];
if ( this.modal )
this.modal.render();
@@ -634,16 +657,11 @@
// ---------------------------------
media.view.Toolbar.PostLibrary = media.view.Toolbar.extend({
initialize: function() {
- var selection = this.options.selection,
+ var state = this.options.state,
+ selection = state.get('selection'),
controller = this.options.controller;
this.options.items = {
- 'selection-preview': new media.view.SelectionPreview({
- controller: controller,
- collection: selection,
- priority: -40
- }),
-
'create-new-gallery': {
style: 'primary',
text: l10n.createNewGallery,
@@ -662,7 +680,7 @@
text: l10n.insertIntoPost,
click: function() {
controller.close();
- controller.state().trigger( 'insert', selection );
+ state.trigger( 'insert', selection );
selection.clear();
}
},
@@ -698,16 +716,16 @@
};
media.view.Toolbar.prototype.initialize.apply( this, arguments );
+ this.visibility();
},
visibility: function() {
- var selection = this.options.selection,
+ var state = this.options.state,
+ selection = state.get('selection'),
controller = this.options.controller,
count = selection.length,
showGallery;
- controller.$el.toggleClass( 'hide-toolbar', ! count );
-
// Check if every attachment in the selection is an image.
showGallery = count > 1 && selection.all( function( attachment ) {
return 'image' === attachment.get('type');
@@ -718,6 +736,8 @@
_.each( insert.buttons, function( button ) {
button.model.set( 'style', showGallery ? '' : 'primary' );
});
+
+ _.first( insert.buttons ).model.set( 'disabled', ! count );
}
});
@@ -725,8 +745,9 @@
// -----------------------------
media.view.Toolbar.Gallery = media.view.Toolbar.extend({
initialize: function() {
- var editing = this.options.editing,
- selection = this.options.selection,
+ var state = this.options.state,
+ editing = state.get('editing'),
+ selection = state.get('selection'),
controller = this.options.controller;
this.options.items = {
@@ -736,7 +757,7 @@
priority: 40,
click: function() {
controller.close();
- controller.state().trigger( 'update', selection );
+ state.trigger( 'update', selection );
selection.clear();
controller.state('library');
}
@@ -769,9 +790,10 @@
},
defaults: {
- text: '',
- style: '',
- size: 'large'
+ text: '',
+ style: '',
+ size: 'large',
+ disabled: false
},
initialize: function() {
@@ -796,17 +818,19 @@
},
render: function() {
- var classes = [ 'button', this.className ];
+ var classes = [ 'button', this.className ],
+ model = this.model.toJSON();
- if ( this.model.get('style') )
- classes.push( 'button-' + this.model.get('style') );
+ if ( model.style )
+ classes.push( 'button-' + model.style );
- if ( this.model.get('size') )
- classes.push( 'button-' + this.model.get('size') );
+ if ( model.size )
+ classes.push( 'button-' + model.size );
classes = _.uniq( classes.concat( this.options.classes ) );
this.el.className = classes.join(' ');
+ this.$el.attr( 'disabled', model.disabled );
// Detach the dropdown.
if ( this.options.dropdown )
@@ -822,7 +846,7 @@
click: function( event ) {
event.preventDefault();
- if ( this.options.click )
+ if ( this.options.click && ! this.model.get('disabled') )
this.options.click.apply( this, arguments );
}
});
@@ -854,6 +878,70 @@
}
});
+ /**
+ * wp.media.view.Sidebar
+ */
+ media.view.Sidebar = Backbone.View.extend({
+ tagName: 'div',
+ className: 'media-sidebar',
+ template: media.template('sidebar'),
+
+ initialize: function() {
+ this.controller = this.options.controller;
+ this._views = {};
+
+ if ( this.options.views )
+ this.add( this.options.views, { silent: true }).render();
+ },
+
+ render: function() {
+ var els = _( this._views ).chain().sortBy( function( view ) {
+ return view.options.priority || 10;
+ }).pluck('el').value();
+
+ // Make sure to detach the elements we want to reuse.
+ // Otherwise, `jQuery.html()` will unbind their events.
+ $( els ).detach();
+
+ this.$el.html( this.template({
+ title: this.controller.state().get('title') || '',
+ uploader: this.controller.options.uploader
+ }) );
+
+ this.$('.sidebar-content').html( els );
+
+ return this;
+ },
+
+ add: function( id, view, options ) {
+ // Accept an object with an `id` : `view` mapping.
+ if ( _.isObject( id ) ) {
+ _.each( id, function( view, id ) {
+ this.add( id, view, options );
+ }, this );
+ return this;
+ }
+
+ view.controller = view.controller || this.controller;
+
+ this._views[ id ] = view;
+ if ( ! options || ! options.silent )
+ this.render();
+ return this;
+ },
+
+ get: function( id ) {
+ return this._views[ id ];
+ },
+
+ remove: function( id, options ) {
+ delete this._views[ id ];
+ if ( ! options || ! options.silent )
+ this.render();
+ return this;
+ }
+ });
+
/**
* wp.media.view.Attachment
*/
@@ -1068,12 +1156,11 @@
* wp.media.view.Attachments
*/
media.view.Attachments = Backbone.View.extend({
- tagName: 'div',
+ tagName: 'ul',
className: 'attachments',
- template: media.template('attachments'),
events: {
- 'keyup .search': 'search'
+ 'scroll': 'scroll'
},
initialize: function() {
@@ -1092,13 +1179,10 @@
}, this );
}, this );
- this.collection.on( 'reset', this.refresh, this );
-
- this.$list = $('