Streamlining media, part I.
The main goal here is to rearrange the media components in a modularized structure to support more linear workflows. This is that structure using the pre-existing workflows, which will be improved over the course of the next few commits. This leaves a few pieces a bit rough around the edges: namely gallery editing and selecting a featured image. The fine print follows. ---- '''Styles''' * Tightened padding around the modal to optimize for a smaller default screen size. * Added a light dashed line surrounding the modal to provide a subtle cue for the persistent dropzone (which is evolving into a power user feature since we now have a dedicated `upload` state). * Add a size for `hero` buttons. * Remove transitions from frame subviews (e.g. menu, content, sidebar, toolbar). ---- '''Code''' `wp.media.controller.StateManager` * Don't fire `activate` and `deactivate` if attempting to switch to the current state. `wp.media.controller.State` * Add a base state class to bind default methods (as not all states will inherit from the `Library` state). * On `activate`, fire `activate()`, `menu()`, `content()`, `sidebar()`, and `toolbar()`. * The menu view is often a shared object (as its most common use case is switching between states). Assign the view to the state's `menu` attribute. * `menu()` automatically fetches the state's `menu` attribute, attaches the menu view to the frame, and attempts to select a menu item that matches the state's `id`. `wp.media.controller.Library` * Now inherits from `wp.media.controller.State`. `wp.media.controller.Upload` * A new state to improve the upload experience. * Displays a large dropzone when empty (a `UploaderInline` view). * When attachments are uploaded, displays management interface (a `library` state restricted to attachments uploaded during the current session). `wp.media.view.Frame` * In `menu()`, `content()`, `sidebar()`, and `toolbar()`, only change the view if it differs from the current view. Also, ensure `hide-*` classes are properly removed. * `wp.media.view.PriorityList` * A new container view used to sort and render child views by the `priority` property. * Used by `wp.media.view.Sidebar` and `wp.media.view.Menu`. * Next step: Use two instances to power `wp.media.view.Toolbar`. `wp.media.view.Menu` and `wp.media.view.MenuItem` * A new `PriorityList` view that renders a list of views used to switch between states. * `MenuItem` instances have `id` attributes that are tied directly to states. * Separators can be added as plain `Backbone.View` instances with the `separator` class. * Supports any type of `Backbone.View`. `media.view.Menu.Landing` * The landing menu for the 'insert media' workflow. * Includes an inactive link to an "Embed from URL" state. * Next steps: only use in select cases to allot for other workflows (such as featured images). `wp.media.view.AttachmentsBrowser` * A container to render an `Attachments` view with accompanying UI controls (similar to what the `Attachments` view was when it contained the `$list` property). * Currently only renders a `Search` view as a control. * Next steps: Add optional view counts (e.g. "21 images"), upload buttons, and collection filter UI. `wp.media.view.Attachments` * If the `Attachments` scroll buffer is not filled with `Attachment` views, continue loading more attachments. * Use `this.model` instead of `this.controller.state()` to allow `Attachments` views to have differing `edge` and `gutter` properties. * Add `edge()`, a method used to calculate the optimal dimensions for an attachment based on the current width of the `Attachments` container element. * `edge()` is currently only enabled on resize, as the relative positioning and CSS transforms used to center thumbnails are suboptimal when coupled with frequent resizing. * Next steps: For infinite scroll performance improvements, look into absolutely positioning attachment views and paging groups of attachment views. `wp.media.view.UploaderWindow` * Now generates a `$browser` element as the browse button (instead of a full `UploaderInline` view). Using a portable browse button prevents us from having to create a new `wp.Uploader` instance every time we want access to a browse button. `wp.media.view.UploaderInline` * No longer directly linked to the `UploaderWindow` view or its `wp.Uploader` instance. * Used as the default `upload` state view. `wp.media.view.Selection` * An interactive representation of the selected `Attachments`. * Based on the improved workflows, this is likely overkill. For simplicity's sake, will probably remove this in favor of `SelectionPreview`. ---- see #21390. git-svn-id: http://core.svn.wordpress.org/trunk@22362 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
a29e0190db
commit
92823b8635
|
@ -81,6 +81,14 @@ input[type="submit"]::-moz-focus-inner {
|
|||
padding: 0 8px 1px;
|
||||
}
|
||||
|
||||
.button.button-hero,
|
||||
.button-group.button-hero .button {
|
||||
font-size: 14px;
|
||||
height: 46px;
|
||||
line-height: 44px;
|
||||
padding: 0 36px;
|
||||
}
|
||||
|
||||
.button:active {
|
||||
outline: none;
|
||||
}
|
||||
|
@ -294,7 +302,7 @@ input[type="submit"]::-moz-focus-inner {
|
|||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
margin-top: 5px;
|
||||
margin: 5px 0;
|
||||
padding: 0.8em 1em;
|
||||
border-radius: 3px;
|
||||
|
||||
|
@ -314,3 +322,8 @@ input[type="submit"]::-moz-focus-inner {
|
|||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.dropdown-flip-y .dropdown {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
}
|
|
@ -3,10 +3,10 @@
|
|||
*/
|
||||
.media-modal {
|
||||
position: fixed;
|
||||
top: 80px;
|
||||
left: 60px;
|
||||
right: 60px;
|
||||
bottom: 60px;
|
||||
top: 60px;
|
||||
left: 40px;
|
||||
right: 40px;
|
||||
bottom: 40px;
|
||||
z-index: 125000;
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,15 @@
|
|||
z-index: 120000;
|
||||
}
|
||||
|
||||
.media-modal-backdrop div {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
border: 1px dashed rgba( 255, 255, 255, 0.5 );
|
||||
}
|
||||
|
||||
.media-modal-title,
|
||||
.media-modal-close {
|
||||
position: absolute;
|
||||
|
@ -38,7 +47,7 @@
|
|||
float: left;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
font-size: 1.4em;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.media-modal-close {
|
||||
|
@ -74,12 +83,23 @@
|
|||
.media-toolbar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 220px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
height: 50px;
|
||||
padding: 0 10px;
|
||||
border-bottom: 1px solid #dfdfdf;
|
||||
height: 60px;
|
||||
padding: 0 16px;
|
||||
border: 0 solid #dfdfdf;
|
||||
}
|
||||
|
||||
.media-frame > .media-toolbar {
|
||||
top: auto;
|
||||
left: 200px;
|
||||
bottom: 0;
|
||||
border-width: 1px 0 0 0;
|
||||
}
|
||||
|
||||
.media-frame.hide-toolbar > .media-toolbar {
|
||||
bottom: -61px;
|
||||
}
|
||||
|
||||
.media-toolbar-primary {
|
||||
|
@ -94,14 +114,14 @@
|
|||
.media-toolbar-primary > .media-button-group {
|
||||
margin-left: 10px;
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.media-toolbar-secondary > .media-button,
|
||||
.media-toolbar-secondary > .media-button-group {
|
||||
margin-right: 10px;
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,16 +130,21 @@
|
|||
.media-sidebar {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 219px;
|
||||
z-index: 50;
|
||||
right: 0;
|
||||
bottom: 61px;
|
||||
width: 247px;
|
||||
padding: 0 16px;
|
||||
z-index: 75;
|
||||
background: #f5f5f5;
|
||||
border-right: 1px solid #dfdfdf;
|
||||
border-left: 1px solid #dfdfdf;
|
||||
}
|
||||
|
||||
.hide-sidebar .media-sidebar {
|
||||
display: none;
|
||||
right: -280px;
|
||||
}
|
||||
|
||||
.hide-toolbar .media-sidebar {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.media-sidebar .sidebar-title {
|
||||
|
@ -146,32 +171,66 @@
|
|||
padding-top: 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Menu
|
||||
*/
|
||||
.media-menu {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: 199px;
|
||||
margin: 0;
|
||||
padding: 16px 0;
|
||||
z-index: 200;
|
||||
box-shadow: inset -6px 0 6px -6px rgba( 0, 0, 0, 0.4 );
|
||||
}
|
||||
|
||||
.media-menu li {
|
||||
position: relative;
|
||||
padding: 4px 20px;
|
||||
margin: 0;
|
||||
line-height: 18px;
|
||||
font-size: 14px;
|
||||
color: #21759B;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
.media-menu-item {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.media-menu li:hover {
|
||||
background: rgba( 0, 0, 0, 0.04 );
|
||||
}
|
||||
|
||||
.media-menu .active,
|
||||
.media-menu .active:hover {
|
||||
color: #333;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.media-menu .separator {
|
||||
height: 0;
|
||||
margin: 12px 20px;
|
||||
padding: 0;
|
||||
border-top: 1px solid #dfdfdf;
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frame
|
||||
*/
|
||||
|
||||
.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;
|
||||
-o-transition-property: left, right, top, bottom, margin;
|
||||
transition-property: left, right, top, bottom, margin;
|
||||
|
||||
-webkit-transition-duration: 0.2s;
|
||||
-moz-transition-duration: 0.2s;
|
||||
-ms-transition-duration: 0.2s;
|
||||
-o-transition-duration: 0.2s;
|
||||
transition-duration: 0.2s;
|
||||
.media-frame {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.media-frame .media-content {
|
||||
position: absolute;
|
||||
top: 51px;
|
||||
left: 220px;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
left: 200px;
|
||||
right: 280px;
|
||||
bottom: 61px;
|
||||
height: auto;
|
||||
width: auto;
|
||||
margin: 0;
|
||||
|
@ -179,7 +238,11 @@
|
|||
}
|
||||
|
||||
.media-frame.hide-sidebar .media-content {
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.media-frame.hide-toolbar .media-content {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.media-frame .media-toolbar .add-to-gallery {
|
||||
|
@ -198,6 +261,14 @@
|
|||
font-family: sans-serif;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attachments
|
||||
*/
|
||||
.attachments {
|
||||
margin: 0;
|
||||
padding-right: 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attachment
|
||||
*/
|
||||
|
@ -388,6 +459,28 @@
|
|||
border-radius: 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attachments Browser
|
||||
*/
|
||||
.media-frame .attachments-browser {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.attachments-browser .media-toolbar {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
.attachments-browser .attachments {
|
||||
position: absolute;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Progress Bar
|
||||
*/
|
||||
|
@ -445,10 +538,10 @@
|
|||
|
||||
.uploader-window-content {
|
||||
position: absolute;
|
||||
top: 30px;
|
||||
left: 30px;
|
||||
right: 30px;
|
||||
bottom: 30px;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
bottom: 10px;
|
||||
border: 1px dashed #fff;
|
||||
}
|
||||
|
||||
|
@ -463,7 +556,7 @@
|
|||
-o-transform: translateY( -50% );
|
||||
transform: translateY( -50% );
|
||||
|
||||
font-size: 18px;
|
||||
font-size: 20px;
|
||||
font-weight: 200;
|
||||
color: #fff;
|
||||
padding: 0;
|
||||
|
@ -485,8 +578,24 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.uploader-inline {
|
||||
display: none;
|
||||
.media-content.uploader-inline {
|
||||
margin: 20px;
|
||||
padding: 20px;
|
||||
border: 1px dashed #aaa;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.uploader-inline-content {
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.uploader-inline h3 {
|
||||
font-size: 20px;
|
||||
font-weight: 200;
|
||||
margin-bottom: 1.6em;
|
||||
}
|
||||
|
||||
.uploader-inline .media-progress-bar {
|
||||
|
@ -497,23 +606,85 @@
|
|||
display: block;
|
||||
}
|
||||
|
||||
.media-sidebar .uploader-inline {
|
||||
display: block;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
padding-top: 10px;
|
||||
text-align: center;
|
||||
border: 1px dashed #aaa;
|
||||
.uploader-inline .browser {
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
.media-sidebar .uploader-inline h3 {
|
||||
font-weight: 200;
|
||||
font-size: 16px;
|
||||
margin: 10px 0;
|
||||
/**
|
||||
* Selection
|
||||
*/
|
||||
|
||||
.media-selection {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 350px;
|
||||
height: 60px;
|
||||
padding: 0 0 0 16px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.media-selection .selection-info {
|
||||
display: inline-block;
|
||||
height: 60px;
|
||||
margin-right: 10px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.media-selection.empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.media-selection .count {
|
||||
display: block;
|
||||
padding-top: 12px;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.media-selection .clear-selection {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.media-selection .attachments {
|
||||
display: inline-block;
|
||||
height: 60px;
|
||||
margin-top: 5px;
|
||||
overflow: hidden;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.media-selection .selected.attachment {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.media-selection .details.attachment {
|
||||
box-shadow:
|
||||
0 0 0 1px #fff,
|
||||
0 0 0 3px #1e8cbe;
|
||||
}
|
||||
|
||||
.media-selection:after {
|
||||
content: '';
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 25px;
|
||||
background-image: -webkit-gradient(linear, right top, right top, from( rgba( 255, 255, 255, 1 ) ), to( rgba( 255, 255, 255, 0 ) ));
|
||||
background-image: -webkit-linear-gradient(right, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
|
||||
background-image: -moz-linear-gradient(right, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
|
||||
background-image: -o-linear-gradient(right, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
|
||||
background-image: linear-gradient(to left, rgba( 255, 255, 255, 1 ) , rgba( 255, 255, 255, 0 ) );
|
||||
}
|
||||
|
||||
.media-selection .attachment .filename {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -584,10 +755,6 @@
|
|||
* Attachment Details
|
||||
*/
|
||||
|
||||
.attachment-details {
|
||||
padding-top: 20px;
|
||||
}
|
||||
|
||||
.attachment-details-preview {
|
||||
cursor: default;
|
||||
}
|
||||
|
|
|
@ -83,15 +83,21 @@
|
|||
state: function( id ) {
|
||||
var previous;
|
||||
|
||||
if ( id ) {
|
||||
if ( previous = this.state() )
|
||||
previous.trigger('deactivate');
|
||||
this._state = id;
|
||||
return this.state().trigger('activate');
|
||||
}
|
||||
if ( ! id )
|
||||
return this._state ? this.get( this._state ) : null;
|
||||
|
||||
if ( this._state )
|
||||
return this.get( this._state );
|
||||
previous = this.state();
|
||||
|
||||
// Bail if we're trying to select the current state, or a state
|
||||
// that does not exist.
|
||||
if ( previous && id === previous.id || ! this.states.get( id ) )
|
||||
return;
|
||||
|
||||
if ( previous )
|
||||
previous.trigger('deactivate');
|
||||
|
||||
this._state = id;
|
||||
this.state().trigger('activate');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -107,9 +113,50 @@
|
|||
};
|
||||
});
|
||||
|
||||
|
||||
// wp.media.controller.State
|
||||
// ---------------------------
|
||||
media.controller.State = Backbone.Model.extend({
|
||||
initialize: function() {
|
||||
this.on( 'activate', this._activate, this );
|
||||
this.on( 'activate', this.activate, this );
|
||||
this.on( 'deactivate', this._deactivate, this );
|
||||
this.on( 'deactivate', this.deactivate, this );
|
||||
},
|
||||
|
||||
activate: function() {},
|
||||
_activate: function() {
|
||||
this.active = true;
|
||||
|
||||
this.menu();
|
||||
this.toolbar();
|
||||
this.sidebar();
|
||||
this.content();
|
||||
},
|
||||
|
||||
deactivate: function() {},
|
||||
_deactivate: function() {
|
||||
this.active = false;
|
||||
},
|
||||
|
||||
menu: function() {
|
||||
var menu = this.get('menu');
|
||||
|
||||
if ( ! menu )
|
||||
return;
|
||||
|
||||
this.frame.menu( menu );
|
||||
menu.select( this.id );
|
||||
},
|
||||
|
||||
toolbar: function() {},
|
||||
sidebar: function() {},
|
||||
content: function() {}
|
||||
});
|
||||
|
||||
// wp.media.controller.Library
|
||||
// ---------------------------
|
||||
media.controller.Library = Backbone.Model.extend({
|
||||
media.controller.Library = media.controller.State.extend({
|
||||
defaults: {
|
||||
id: 'library',
|
||||
multiple: false,
|
||||
|
@ -133,15 +180,10 @@
|
|||
if ( ! this.get('gutter') )
|
||||
this.set( 'gutter', 8 );
|
||||
|
||||
this.on( 'activate', this.activate, this );
|
||||
this.on( 'deactivate', this.deactivate, this );
|
||||
media.controller.State.prototype.initialize.apply( this, arguments );
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.toolbar();
|
||||
this.sidebar();
|
||||
this.content();
|
||||
|
||||
// If we're in a workflow that supports multiple attachments,
|
||||
// automatically select any uploading attachments.
|
||||
if ( this.get('multiple') )
|
||||
|
@ -153,6 +195,7 @@
|
|||
|
||||
deactivate: function() {
|
||||
var toolbar = this._postLibraryToolbar;
|
||||
|
||||
if ( toolbar )
|
||||
this.get('selection').off( 'add remove', toolbar.visibility, toolbar );
|
||||
|
||||
|
@ -184,30 +227,16 @@
|
|||
}) );
|
||||
|
||||
this.details();
|
||||
frame.sidebar().add({
|
||||
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: function() {
|
||||
var frame = this.frame;
|
||||
|
||||
// Content.
|
||||
frame.content( new media.view.Attachments({
|
||||
frame.content( new media.view.AttachmentsBrowser({
|
||||
controller: frame,
|
||||
collection: this.get('library'),
|
||||
// The single `Attachment` view to be used in the `Attachments` view.
|
||||
AttachmentView: media.view.Attachment.Library
|
||||
model: this
|
||||
}).render() );
|
||||
},
|
||||
|
||||
|
@ -255,6 +284,65 @@
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
// wp.media.controller.Upload
|
||||
// ---------------------------
|
||||
media.controller.Upload = media.controller.Library.extend({
|
||||
defaults: _.defaults({
|
||||
id: 'upload'
|
||||
}, media.controller.Library.prototype.defaults ),
|
||||
|
||||
initialize: function() {
|
||||
var library = this.get('library');
|
||||
|
||||
// If a `library` attribute isn't provided, create a new
|
||||
// `Attachments` collection that observes (and thereby receives
|
||||
// all uploading) attachments.
|
||||
if ( ! library ) {
|
||||
library = new Attachments();
|
||||
library.props.set({
|
||||
orderby: 'date',
|
||||
order: 'ASC'
|
||||
});
|
||||
library.observe( wp.Uploader.queue );
|
||||
this.set( 'library', library );
|
||||
}
|
||||
|
||||
media.controller.Library.prototype.initialize.apply( this, arguments );
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.get('library').on( 'add remove reset', this.refresh, this );
|
||||
media.controller.Library.prototype.activate.apply( this, arguments );
|
||||
this.refresh();
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
this.get('library').off( 'add remove reset', this.refresh, this );
|
||||
media.controller.Library.prototype.deactivate.apply( this, arguments );
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
this.frame.$el.toggleClass( 'hide-sidebar hide-toolbar', ! this.get('library').length );
|
||||
this.content();
|
||||
},
|
||||
|
||||
content: function() {
|
||||
var frame = this.frame,
|
||||
upload;
|
||||
|
||||
if ( this.get('library').length ) {
|
||||
media.controller.Library.prototype.content.apply( this, arguments );
|
||||
} else {
|
||||
upload = new media.view.UploaderInline({
|
||||
controller: frame
|
||||
}).render();
|
||||
|
||||
frame.content( upload );
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// wp.media.controller.Gallery
|
||||
// ---------------------------
|
||||
media.controller.Gallery = media.controller.Library.extend({
|
||||
|
@ -296,6 +384,7 @@
|
|||
this.frame.content( new media.view.Attachments({
|
||||
controller: this.frame,
|
||||
collection: this.get('library'),
|
||||
model: this,
|
||||
sortable: true,
|
||||
// The single `Attachment` view to be used in the `Attachments` view.
|
||||
AttachmentView: media.view.Attachment.Gallery
|
||||
|
@ -345,7 +434,7 @@
|
|||
|
||||
initialize: function() {
|
||||
_.defaults( this.options, {
|
||||
state: 'library',
|
||||
state: 'upload',
|
||||
title: '',
|
||||
selection: [],
|
||||
library: {},
|
||||
|
@ -361,12 +450,12 @@
|
|||
},
|
||||
|
||||
render: function() {
|
||||
var els = [ this.toolbar().el, this.sidebar().el, this.content().el ];
|
||||
var els = [ this.menu().el, this.content().el, this.sidebar().el, this.toolbar().el ];
|
||||
|
||||
if ( this.modal )
|
||||
this.modal.render();
|
||||
|
||||
// Detach any views that will be rebound to maintain event bidnings.
|
||||
// Detach any views that will be rebound to maintain event bindings.
|
||||
this.$el.children().filter( els ).detach();
|
||||
this.$el.empty().append( els );
|
||||
|
||||
|
@ -389,7 +478,12 @@
|
|||
},
|
||||
|
||||
createStates: function() {
|
||||
var options = this.options;
|
||||
var options = this.options,
|
||||
menus = {
|
||||
landing: new media.view.Menu.Landing({
|
||||
controller: this
|
||||
})
|
||||
};
|
||||
|
||||
// Create the default `states` collection.
|
||||
this.states = new Backbone.Collection();
|
||||
|
@ -404,7 +498,12 @@
|
|||
new media.controller.Library({
|
||||
selection: options.selection,
|
||||
library: media.query( options.library ),
|
||||
multiple: this.options.multiple
|
||||
multiple: this.options.multiple,
|
||||
menu: menus.landing
|
||||
}),
|
||||
new media.controller.Upload({
|
||||
multiple: this.options.multiple,
|
||||
menu: menus.landing
|
||||
}),
|
||||
new media.controller.Gallery({
|
||||
library: options.selection,
|
||||
|
@ -419,7 +518,7 @@
|
|||
|
||||
createSubviews: function() {
|
||||
// Initialize a stub view for each subview region.
|
||||
_.each(['toolbar','sidebar','content'], function( subview ) {
|
||||
_.each(['menu','content','sidebar','toolbar'], function( subview ) {
|
||||
this[ '_' + subview ] = new Backbone.View({
|
||||
tagName: 'div',
|
||||
className: 'media-' + subview
|
||||
|
@ -450,15 +549,21 @@
|
|||
_.extend( media.view.Frame.prototype, media.controller.StateMachine.prototype );
|
||||
|
||||
// Create methods to fetch and replace individual subviews.
|
||||
_.each(['toolbar','sidebar','content'], function( subview ) {
|
||||
_.each(['menu','content','sidebar','toolbar'], function( subview ) {
|
||||
media.view.Frame.prototype[ subview ] = function( view ) {
|
||||
var previous = this[ '_' + subview ];
|
||||
|
||||
if ( ! view )
|
||||
return previous;
|
||||
|
||||
if ( view === previous )
|
||||
return;
|
||||
|
||||
view.$el.addClass( 'media-' + subview );
|
||||
|
||||
// Remove the hide class.
|
||||
this.$el.removeClass( 'hide-' + subview );
|
||||
|
||||
if ( previous.destroy )
|
||||
previous.destroy();
|
||||
previous.undelegateEvents();
|
||||
|
@ -564,17 +669,12 @@
|
|||
var uploader;
|
||||
|
||||
this.controller = this.options.controller;
|
||||
this.inline = new media.view.UploaderInline({
|
||||
controller: this.controller,
|
||||
uploaderWindow: this
|
||||
}).render();
|
||||
|
||||
this.inline.$el.appendTo('body');
|
||||
this.$browser = $('<a href="#" class="browser" />').hide().appendTo('body');
|
||||
|
||||
uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
|
||||
container: this.inline.$el,
|
||||
dropzone: this.$el,
|
||||
browser: this.inline.$('.browser'),
|
||||
browser: this.$browser,
|
||||
params: {}
|
||||
});
|
||||
|
||||
|
@ -647,6 +747,9 @@
|
|||
initialize: function() {
|
||||
this.controller = this.options.controller;
|
||||
|
||||
if ( ! this.options.$browser )
|
||||
this.options.$browser = this.controller.uploader.$browser;
|
||||
|
||||
// Track uploading attachments.
|
||||
wp.Uploader.queue.on( 'add remove reset change:percent', this.renderUploadProgress, this );
|
||||
},
|
||||
|
@ -656,8 +759,17 @@
|
|||
},
|
||||
|
||||
render: function() {
|
||||
var $browser = this.options.$browser,
|
||||
$placeholder;
|
||||
|
||||
this.renderUploadProgress();
|
||||
this.$el.html( this.template( this.options ) );
|
||||
|
||||
$placeholder = this.$('.browser');
|
||||
$browser.text( $placeholder.text() );
|
||||
$browser[0].className = $placeholder[0].className;
|
||||
$placeholder.replaceWith( $browser.show() );
|
||||
|
||||
this.$bar = this.$('.media-progress-bar div');
|
||||
return this;
|
||||
},
|
||||
|
@ -679,7 +791,6 @@
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* wp.media.view.Toolbar
|
||||
*/
|
||||
|
@ -765,6 +876,12 @@
|
|||
controller = this.options.controller;
|
||||
|
||||
this.options.items = {
|
||||
selection: new media.view.Selection({
|
||||
controller: controller,
|
||||
collection: selection,
|
||||
priority: -40
|
||||
}).render(),
|
||||
|
||||
'create-new-gallery': {
|
||||
style: 'primary',
|
||||
text: l10n.createNewGallery,
|
||||
|
@ -777,7 +894,7 @@
|
|||
|
||||
'insert-into-post': new media.view.ButtonGroup({
|
||||
priority: 30,
|
||||
classes: 'dropdown-flip-x',
|
||||
classes: 'dropdown-flip-x dropdown-flip-y',
|
||||
buttons: [
|
||||
{
|
||||
text: l10n.insertIntoPost,
|
||||
|
@ -1033,19 +1150,19 @@
|
|||
});
|
||||
|
||||
/**
|
||||
* wp.media.view.Sidebar
|
||||
* wp.media.view.PriorityList
|
||||
*/
|
||||
media.view.Sidebar = Backbone.View.extend({
|
||||
|
||||
media.view.PriorityList = 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 });
|
||||
this.add( _.extend( {}, this.views, this.options.views ), { silent: true });
|
||||
delete this.views;
|
||||
delete this.options.views;
|
||||
|
||||
if ( ! this.options.silent )
|
||||
this.render();
|
||||
|
@ -1060,18 +1177,7 @@
|
|||
// 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 );
|
||||
|
||||
if ( this.controller.uploader ) {
|
||||
this.$el.append( this.controller.uploader.inline.$el );
|
||||
this.controller.uploader.refresh();
|
||||
}
|
||||
|
||||
this.$el.html( els );
|
||||
return this;
|
||||
},
|
||||
|
||||
|
@ -1089,6 +1195,9 @@
|
|||
return this;
|
||||
}
|
||||
|
||||
if ( ! (view instanceof Backbone.View) )
|
||||
view = this.toView( view, id, options );
|
||||
|
||||
view.controller = view.controller || this.controller;
|
||||
|
||||
this._views[ id ] = view;
|
||||
|
@ -1106,9 +1215,94 @@
|
|||
if ( ! options || ! options.silent )
|
||||
this.render();
|
||||
return this;
|
||||
},
|
||||
|
||||
toView: function( options ) {
|
||||
return new Backbone.View( options );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* wp.media.view.Menu
|
||||
*/
|
||||
media.view.Menu = media.view.PriorityList.extend({
|
||||
tagName: 'ul',
|
||||
className: 'media-menu',
|
||||
|
||||
toView: function( options, id ) {
|
||||
options = options || {};
|
||||
options.id = id;
|
||||
return new media.view.MenuItem( options ).render();
|
||||
},
|
||||
|
||||
select: function( id ) {
|
||||
var view = this.get( id );
|
||||
|
||||
if ( ! view )
|
||||
return;
|
||||
|
||||
this.deselect();
|
||||
view.$el.addClass('active');
|
||||
},
|
||||
|
||||
deselect: function() {
|
||||
this.$el.children().removeClass('active');
|
||||
}
|
||||
});
|
||||
|
||||
media.view.MenuItem = Backbone.View.extend({
|
||||
tagName: 'li',
|
||||
className: 'media-menu-item',
|
||||
|
||||
events: {
|
||||
'click': 'toState'
|
||||
},
|
||||
|
||||
toState: function() {
|
||||
this.controller.state( this.options.id );
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var options = this.options;
|
||||
|
||||
if ( options.text )
|
||||
this.$el.text( options.text );
|
||||
else if ( options.html )
|
||||
this.$el.html( options.html );
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
media.view.Menu.Landing = media.view.Menu.extend({
|
||||
views: {
|
||||
upload: {
|
||||
text: l10n.uploadFilesTitle,
|
||||
priority: 20
|
||||
},
|
||||
library: {
|
||||
text: l10n.mediaLibraryTitle,
|
||||
priority: 40
|
||||
},
|
||||
separateLibrary: new Backbone.View({
|
||||
className: 'separator',
|
||||
priority: 60
|
||||
}),
|
||||
embed: {
|
||||
text: l10n.embedFromUrlTitle,
|
||||
priority: 80
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.media.view.Sidebar
|
||||
*/
|
||||
media.view.Sidebar = media.view.PriorityList.extend({
|
||||
className: 'media-sidebar'
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.media.view.Attachment
|
||||
*/
|
||||
|
@ -1118,7 +1312,7 @@
|
|||
template: media.template('attachment'),
|
||||
|
||||
events: {
|
||||
'click .attachment-preview': 'toggleSelection',
|
||||
'mousedown .attachment-preview': 'toggleSelection',
|
||||
'change .describe': 'describe'
|
||||
},
|
||||
|
||||
|
@ -1322,29 +1516,47 @@
|
|||
|
||||
this.initSortable();
|
||||
|
||||
this.controller.state().on( 'change:edge change:gutter', this.css, this );
|
||||
_.bindAll( this, 'css' );
|
||||
this.model.on( 'change:edge change:gutter', this.css, this );
|
||||
this._resizeCss = _.debounce( _.bind( this.css, this ), this.refreshSensitivity );
|
||||
$(window).on( 'resize.attachments', this._resizeCss );
|
||||
this.css();
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.collection.off( 'add remove reset', null, this );
|
||||
this.controller.state().off( 'change:edge change:gutter', this.css, this );
|
||||
this.model.off( 'change:edge change:gutter', this.css, this );
|
||||
$(window).off( 'resize.attachments', this._resizeCss );
|
||||
},
|
||||
|
||||
css: function() {
|
||||
var $css = $( '#' + this.el.id + '-css' ),
|
||||
state = this.controller.state();
|
||||
var $css = $( '#' + this.el.id + '-css' );
|
||||
|
||||
if ( $css.length )
|
||||
$css.remove();
|
||||
|
||||
media.view.Attachments.$head().append( this.template({
|
||||
id: this.el.id,
|
||||
edge: state.get('edge'),
|
||||
gutter: state.get('gutter')
|
||||
edge: this.edge(),
|
||||
gutter: this.model.get('gutter')
|
||||
}) );
|
||||
},
|
||||
|
||||
edge: function() {
|
||||
var edge = this.model.get('edge'),
|
||||
gutter, width, columns;
|
||||
|
||||
if ( ! this.$el.is(':visible') )
|
||||
return edge;
|
||||
|
||||
|
||||
gutter = this.model.get('gutter') * 2;
|
||||
width = this.$el.width() - gutter;
|
||||
columns = Math.ceil( width / ( edge + gutter ) );
|
||||
edge = Math.floor( ( width - ( columns * gutter ) ) / columns );
|
||||
return edge;
|
||||
},
|
||||
|
||||
initSortable: function() {
|
||||
var collection = this.collection,
|
||||
from;
|
||||
|
@ -1393,7 +1605,7 @@
|
|||
render: function() {
|
||||
// If there are no elements, load some.
|
||||
if ( ! this.collection.length ) {
|
||||
this.collection.more();
|
||||
this.collection.more().done( this.scroll );
|
||||
this.$el.empty();
|
||||
return this;
|
||||
}
|
||||
|
@ -1410,6 +1622,7 @@
|
|||
// Then, trigger the scroll event to check if we're within the
|
||||
// threshold to query for additional attachments.
|
||||
this.scroll();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
@ -1441,7 +1654,7 @@
|
|||
return;
|
||||
|
||||
if ( this.el.scrollHeight < this.el.scrollTop + ( this.el.clientHeight * this.options.refreshThreshold ) ) {
|
||||
this.collection.more();
|
||||
this.collection.more().done( this.scroll );
|
||||
}
|
||||
}
|
||||
}, {
|
||||
|
@ -1482,6 +1695,54 @@
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* wp.media.view.AttachmentsBrowser
|
||||
*/
|
||||
media.view.AttachmentsBrowser = Backbone.View.extend({
|
||||
tagName: 'div',
|
||||
className: 'attachments-browser',
|
||||
|
||||
initialize: function() {
|
||||
this.controller = this.options.controller;
|
||||
|
||||
_.defaults( this.options, {
|
||||
search: true,
|
||||
upload: false,
|
||||
total: true
|
||||
});
|
||||
|
||||
this.toolbar = new media.view.Toolbar({
|
||||
controller: this.controller
|
||||
});
|
||||
|
||||
if ( this.options.search ) {
|
||||
this.toolbar.add( 'search', new media.view.Search({
|
||||
controller: this.controller,
|
||||
model: this.collection.props,
|
||||
priority: -40
|
||||
}) );
|
||||
}
|
||||
|
||||
this.attachments = new media.view.Attachments({
|
||||
controller: this.controller,
|
||||
collection: this.collection,
|
||||
model: this.model,
|
||||
sortable: this.options.sortable,
|
||||
// The single `Attachment` view to be used in the `Attachments` view.
|
||||
AttachmentView: media.view.Attachment.Library
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.toolbar.$el.detach();
|
||||
this.attachments.$el.detach();
|
||||
this.$el.html([ this.toolbar.render().el, this.attachments.render().el ]);
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.media.view.SelectionPreview
|
||||
*/
|
||||
|
@ -1533,6 +1794,83 @@
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.media.view.Selection
|
||||
*/
|
||||
media.view.Selection = Backbone.View.extend({
|
||||
tagName: 'div',
|
||||
className: 'media-selection',
|
||||
template: media.template('media-selection'),
|
||||
|
||||
events: {
|
||||
'click .clear-selection': 'clear'
|
||||
},
|
||||
|
||||
initialize: function() {
|
||||
_.defaults( this.options, {
|
||||
clearable: true
|
||||
});
|
||||
|
||||
this.controller = this.options.controller;
|
||||
this.attachments = new media.view.Attachments({
|
||||
controller: this.controller,
|
||||
collection: this.collection,
|
||||
sortable: true,
|
||||
model: new Backbone.Model({
|
||||
edge: 40,
|
||||
gutter: 5
|
||||
}),
|
||||
|
||||
// The single `Attachment` view to be used in the `Attachments` view.
|
||||
AttachmentView: media.view.Attachment.Selection
|
||||
});
|
||||
|
||||
this.collection.on( 'add remove reset', this.refresh, this );
|
||||
},
|
||||
|
||||
destroy: function() {
|
||||
this.collection.off( 'add remove reset', this.refresh, this );
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.attachments.$el.detach();
|
||||
this.attachments.render();
|
||||
|
||||
this.$el.html( this.template( this.options ) );
|
||||
|
||||
this.$('.selection-view').replaceWith( this.attachments.$el );
|
||||
this.refresh();
|
||||
return this;
|
||||
},
|
||||
|
||||
refresh: function() {
|
||||
// If the selection hasn't been rendered, bail.
|
||||
if ( ! this.$el.children().length )
|
||||
return;
|
||||
|
||||
// If nothing is selected, display nothing.
|
||||
this.$el.toggleClass( 'empty', ! this.collection.length );
|
||||
this.$('.count').text( this.collection.length + ' ' + l10n.selected );
|
||||
},
|
||||
|
||||
clear: function( event ) {
|
||||
event.preventDefault();
|
||||
this.collection.clear();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* wp.media.view.Attachment.Selection
|
||||
*/
|
||||
media.view.Attachment.Selection = media.view.Attachment.extend({
|
||||
// On click, just select the model, instead of removing the model from
|
||||
// the selection.
|
||||
toggleSelection: function() {
|
||||
this.controller.state().get('selection').single( this.model );
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* wp.media.view.Settings
|
||||
|
|
|
@ -1300,7 +1300,9 @@ function wp_print_media_templates( $attachment ) {
|
|||
<h3 class="media-modal-title"><%- title %></h3>
|
||||
<a class="media-modal-close" href="" title="<?php esc_attr_e('Close'); ?>">×</a>
|
||||
</div>
|
||||
<div class="media-modal-backdrop"></div>
|
||||
<div class="media-modal-backdrop">
|
||||
<div></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-uploader-window">
|
||||
|
@ -1310,15 +1312,11 @@ function wp_print_media_templates( $attachment ) {
|
|||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-uploader-inline">
|
||||
<h3><?php _e( 'Drop files here' ); ?></h3>
|
||||
<!--<span><?php _ex( 'or', 'Uploader: Drop files here - or - Select Files' ); ?></span>-->
|
||||
<a href="#" class="browser button-secondary"><?php _e( 'Select Files' ); ?></a>
|
||||
<div class="media-progress-bar"><div></div></div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-sidebar">
|
||||
<h2 class="sidebar-title"><%- title %></h2>
|
||||
<div class="sidebar-content"></div>
|
||||
<div class="uploader-inline-content">
|
||||
<h3><?php _e( 'Drop files anywhere to upload' ); ?></h3>
|
||||
<a href="#" class="browser button button-hero"><?php _e( 'Select Files' ); ?></a>
|
||||
<div class="media-progress-bar"><div></div></div>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-attachment">
|
||||
|
@ -1360,6 +1358,7 @@ function wp_print_media_templates( $attachment ) {
|
|||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-attachment-details">
|
||||
<h3><?php _e('Edit Attachment Details'); ?></h3>
|
||||
<div class="attachment-preview attachment-details-preview type-<%- type %> subtype-<%- subtype %> <%- orientation %>">
|
||||
<% if ( uploading ) { %>
|
||||
<div class="media-progress-bar"><div></div></div>
|
||||
|
@ -1392,6 +1391,16 @@ function wp_print_media_templates( $attachment ) {
|
|||
<% } %>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-media-selection">
|
||||
<div class="selection-info">
|
||||
<span class="count"></span>
|
||||
<% if ( clearable ) { %>
|
||||
<a class="clear-selection" href="#"><?php _e('Clear'); ?></a>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="selection-view"></div>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-media-selection-preview">
|
||||
<div class="selected-img selected-count-<%- count %>">
|
||||
<% if ( thumbnail ) { %>
|
||||
|
@ -1486,7 +1495,7 @@ function wp_print_media_templates( $attachment ) {
|
|||
<script type="text/html" id="tmpl-attachments-css">
|
||||
<style type="text/css" id="<%- id %>-css">
|
||||
#<%- id %> {
|
||||
padding: <%- gutter %>px;
|
||||
padding: 0 <%- gutter %>px;
|
||||
}
|
||||
|
||||
#<%- id %> .attachment {
|
||||
|
|
|
@ -327,12 +327,20 @@ function wp_default_scripts( &$scripts ) {
|
|||
'search' => __( 'Search' ),
|
||||
'cancel' => __( 'Cancel' ),
|
||||
'addImages' => __( 'Add images' ),
|
||||
'selected' => __( 'selected' ),
|
||||
|
||||
// Upload
|
||||
'uploadFilesTitle' => __( 'Upload Files' ),
|
||||
'selectFiles' => __( 'Select files' ),
|
||||
|
||||
// Library
|
||||
'mediaLibraryTitle' => __( 'Media Library' ),
|
||||
'createNewGallery' => __( 'Create a new gallery' ),
|
||||
'insertIntoPost' => __( 'Insert into post' ),
|
||||
'addToGallery' => __( 'Add to gallery' ),
|
||||
'mediaLibraryTitle' => __( 'Media Library' ),
|
||||
'createNewGallery' => __( 'Create a new gallery' ),
|
||||
'insertIntoPost' => __( 'Insert into post' ),
|
||||
'addToGallery' => __( 'Add to gallery' ),
|
||||
|
||||
// Embed
|
||||
'embedFromUrlTitle' => __( 'Embed From URL' ),
|
||||
|
||||
// Gallery
|
||||
'createGalleryTitle' => __( 'Create Gallery' ),
|
||||
|
|
Loading…
Reference in New Issue