Ticket #21390: 21390.2.diff

File 21390.2.diff, 58.4 KB (added by koopersmith, 6 months ago)
Line 
1Index: wp-admin/js/custom-background.js
2===================================================================
3--- wp-admin/js/custom-background.js    (revision 22995)
4+++ wp-admin/js/custom-background.js    (working copy)
5@@ -37,8 +37,8 @@
6                                }
7                        });
8 
9-                       frame.toolbar.on( 'activate:select', function() {
10-                               frame.toolbar.view().set({
11+                       frame.on( 'toolbar:render:select', function( view ) {
12+                               view.set({
13                                        select: {
14                                                style: 'primary',
15                                                text:  $el.data('update'),
16Index: wp-admin/js/custom-header.js
17===================================================================
18--- wp-admin/js/custom-header.js        (revision 22995)
19+++ wp-admin/js/custom-header.js        (working copy)
20@@ -24,8 +24,8 @@
21                                }
22                        });
23 
24-                       frame.toolbar.on( 'activate:select', function() {
25-                               frame.toolbar.view().set({
26+                       frame.on( 'toolbar:render:select', function( view ) {
27+                               view.set({
28                                        select: {
29                                                style: 'primary',
30                                                text:  $el.data('update'),
31Index: wp-includes/css/media-views-rtl.css
32===================================================================
33--- wp-includes/css/media-views-rtl.css (revision 22995)
34+++ wp-includes/css/media-views-rtl.css (working copy)
35@@ -226,30 +226,6 @@
36 }
37 
38 /**
39- * Selection Preview
40- */
41-.selected-img {
42-       float: right;
43-       margin-right: 0;
44-       margin-left: 14px;
45-}
46-
47-.selection-preview img {
48-       float: right;
49-       margin-left: 0;
50-       margin-right: 1px;
51-}
52-
53-.selection-preview .count {
54-       right: auto;
55-       left: 0;
56-}
57-
58-.selection-preview .clear-selection {
59-       float: right;
60-}
61-
62-/**
63  * Attachment Details
64  */
65 .attachment-info .thumbnail {
66Index: wp-includes/css/media-views.css
67===================================================================
68--- wp-includes/css/media-views.css     (revision 22995)
69+++ wp-includes/css/media-views.css     (working copy)
70@@ -80,10 +80,10 @@
71  */
72 .media-modal {
73        position: fixed;
74-       top: 60px;
75-       left: 40px;
76-       right: 40px;
77-       bottom: 40px;
78+       top: 30px;
79+       left: 30px;
80+       right: 30px;
81+       bottom: 30px;
82        z-index: 160000;
83 }
84 
85@@ -94,42 +94,24 @@
86        right: 0;
87        bottom: 0;
88        background: #000;
89-       opacity: 0.8;
90+       opacity: 0.7;
91        z-index: 159900;
92 }
93 
94-.media-modal-backdrop div,
95-.uploader-window-content {
96+.media-modal-close {
97        position: absolute;
98-       top: 10px;
99-       left: 10px;
100-       right: 10px;
101-       bottom: 10px;
102-       border: 1px dashed rgba( 255, 255, 255, 0.5 );
103+       top: 7px;
104+       right: 7px;
105+       width: 30px;
106+       height: 30px;
107+       z-index: 1000;
108 }
109-
110-.media-modal-title {
111-       position: absolute;
112-       top: -40px;
113-       left: 0;
114-       height: 40px;
115-       padding: 0;
116-       margin: 0;
117-
118-       line-height: 40px;
119-       color: #fff;
120-       font-size: 16px;
121-       font-weight: 200;
122-       text-shadow: 0 0 16px rgba( 0, 0, 0, 0.6 );
123-}
124-
125-.media-modal-close {
126-       position: absolute;
127-       top: -27px;
128-       right: 0;
129+.media-modal-close span {
130+       display: block;
131+       margin: 8px auto 0;
132+       width: 15px;
133        height: 15px;
134-       width: 15px;
135-       background-position: -80px 0;
136+       background-position: -100px 0;
137 }
138 
139 .media-modal-close:active {
140@@ -165,18 +147,6 @@
141        border: 0 solid #dfdfdf;
142 }
143 
144-.media-frame-toolbar > .media-toolbar {
145-       top: auto;
146-       left: 200px;
147-       bottom: 0;
148-       border-width: 1px 0 0 0;
149-       box-shadow: 0 -4px 4px -4px rgba( 0, 0, 0, 0.1 );
150-}
151-
152-.hide-toolbar .media-frame-toolbar > .media-toolbar {
153-       bottom: -61px;
154-}
155-
156 .media-toolbar-primary {
157        float: right;
158 }
159@@ -238,11 +208,6 @@
160        width: 100%;
161 }
162 
163-.media-sidebar .selection-preview {
164-       display: block;
165-       padding-top: 5px;
166-}
167-
168 .media-sidebar h3 {
169        position: relative;
170        font-weight: bold;
171@@ -361,11 +326,10 @@
172        position: absolute;
173        top: 0;
174        left: 0;
175+       right: 0;
176        bottom: 0;
177-       width: 199px;
178        margin: 0;
179        padding: 16px 0;
180-       z-index: 200;
181        border-right: 1px solid #d9d9d9;
182        box-shadow: inset -6px 0 6px -6px rgba( 0, 0, 0, 0.2 );
183        -webkit-user-select: none;
184@@ -374,7 +338,8 @@
185        user-select: none;
186 }
187 
188-.media-menu li {
189+.media-menu > a {
190+       display: block;
191        position: relative;
192        padding: 4px 20px;
193        margin: 0;
194@@ -382,14 +347,16 @@
195        font-size: 14px;
196        color: #21759B;
197        text-shadow: 0 1px 0 #fff;
198+       text-decoration: none;
199 }
200 
201-.media-menu-item {
202-       cursor: pointer;
203+.media-menu > a:hover {
204+       color: #21759B;
205+       background: rgba( 0, 0, 0, 0.04 );
206 }
207 
208-.media-menu li:hover {
209-       background: rgba( 0, 0, 0, 0.04 );
210+.media-menu > a:active {
211+       outline: none;
212 }
213 
214 .media-menu .active,
215@@ -407,6 +374,63 @@
216 }
217 
218 /**
219+ * Menu
220+ */
221+.media-router {
222+       position: relative;
223+       padding: 0 6px;
224+       margin: 0;
225+       clear: both;
226+       -webkit-user-select: none;
227+       -moz-user-select: none;
228+       -ms-user-select: none;
229+       user-select: none;
230+}
231+
232+.media-router > a {
233+       position: relative;
234+       float: left;
235+       padding: 2px 10px;
236+       margin: 0;
237+       height: 18px;
238+       line-height: 18px;
239+       font-size: 14px;
240+       border-right: 1px solid #dfdfdf;
241+       text-shadow: 0 1px 0 #fff;
242+       text-decoration: none;
243+}
244+
245+.media-router > a:last-child {
246+       border-right: 0;
247+}
248+
249+.media-router > a:active {
250+       outline: none;
251+}
252+
253+.media-router .active,
254+.media-router .active:hover {
255+       color: #333;
256+}
257+
258+.media-router .active:after {
259+       content: '';
260+       display: block;
261+       margin: -100px auto 0;
262+       width: 7px;
263+       height: 7px;
264+       background: #fff;
265+       box-shadow: 1px 1px 1px rgba( 0, 0, 0, 0.2 );
266+       z-index: 300;
267+
268+       -webkit-transform: rotate( 45deg ) translate( 75px, 75px );
269+       -moz-transform:    rotate( 45deg ) translate( 75px, 75px );
270+       -ms-transform:     rotate( 45deg ) translate( 75px, 75px );
271+       -o-transform:      rotate( 45deg ) translate( 75px, 75px );
272+       transform:         rotate( 45deg ) translate( 75px, 75px );
273+}
274+
275+/**
276  * Frame
277  */
278 .media-frame {
279@@ -418,11 +442,40 @@
280        bottom: 0;
281 }
282 
283-.media-frame .region-content {
284+.media-frame-menu {
285        position: absolute;
286        top: 0;
287+       left: 0;
288+       bottom: 0;
289+       width: 199px;
290+       z-index: 150;
291+}
292+
293+.media-frame-title {
294+       position: absolute;
295+       top: 0;
296        left: 200px;
297        right: 0;
298+       height: 45px;
299+       z-index: 200;
300+}
301+
302+.media-frame-router {
303+       position: absolute;
304+       top: 45px;
305+       left: 200px;
306+       right: 0;
307+       height: 30px;
308+       z-index: 200;
309+       border-bottom: 1px solid #dfdfdf;
310+       box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
311+}
312+
313+.media-frame-content {
314+       position: absolute;
315+       top: 75px;
316+       left: 200px;
317+       right: 0;
318        bottom: 61px;
319        height: auto;
320        width: auto;
321@@ -430,14 +483,62 @@
322        overflow: auto;
323 }
324 
325-.media-frame.hide-toolbar .region-content {
326+.media-frame-toolbar {
327+       position: absolute;
328+       left: 200px;
329+       right: 0;
330        bottom: 0;
331+       height: 60px;
332+       z-index: 100;
333+       border: 0 solid #dfdfdf;
334+       border-width: 1px 0 0 0;
335+       box-shadow: 0 -4px 4px -4px rgba( 0, 0, 0, 0.1 );
336 }
337 
338+.media-frame.hide-menu .media-frame-title,
339+.media-frame.hide-menu .media-frame-router,
340+.media-frame.hide-menu .media-frame-toolbar,
341+.media-frame.hide-menu .media-frame-content {
342+       left: 0;
343+}
344+
345+.media-frame.hide-menu .media-frame-menu {
346+       left: -200px;
347+}
348+
349+.media-frame.hide-toolbar .media-frame-content {
350+       bottom: 0;
351+}
352+
353+.media-frame.hide-toolbar .media-frame-toolbar {
354+       bottom: -61px;
355+}
356+
357+.media-frame.hide-router .media-frame-content {
358+       top: 45px;
359+}
360+
361+.media-frame.hide-router .media-frame-router {
362+       display: none;
363+}
364+
365+.media-frame.hide-router .media-frame-title {
366+       border-bottom: 1px solid #dfdfdf;
367+       box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
368+}
369+
370 .media-frame .media-toolbar .add-to-gallery {
371        display: none;
372 }
373 
374+.media-frame-title h1 {
375+       padding: 0 16px;
376+       font-size: 22px;
377+       font-weight: 200;
378+       line-height: 45px;
379+       margin: 0;
380+}
381+
382 /**
383  * Iframes
384  */
385@@ -721,6 +822,9 @@
386  * Attachments Browser
387  */
388 .media-frame .attachments-browser {
389+       position: relative;
390+       width: 100%;
391+       height: 100%;
392        overflow: hidden;
393 }
394 
395@@ -903,7 +1007,12 @@
396 }
397 
398 .uploader-window-content {
399-       border-color: #fff;
400+       position: absolute;
401+       top: 10px;
402+       left: 10px;
403+       right: 10px;
404+       bottom: 10px;
405+       border: 1px dashed #fff;
406 }
407 
408 .uploader-window h3 {
409@@ -956,6 +1065,10 @@
410        margin: 4em 0;
411 }
412 
413+.uploader-inline .has-upload-message .upload-ui {
414+       margin: 0 0 4em;
415+}
416+
417 .uploader-inline h3 {
418        font-size: 20px;
419        line-height: 28px;
420@@ -963,6 +1076,12 @@
421        margin-bottom: 1.6em;
422 }
423 
424+.uploader-inline .has-upload-message .upload-instructions {
425+       font-size: 14px;
426+       color: #464646;
427+       font-weight: normal;
428+}
429+
430 .uploader-inline .drop-instructions {
431        display: none;
432 }
433@@ -1058,7 +1177,7 @@
434        vertical-align: top;
435 }
436 
437-.media-selection .attachment img {
438+.media-selection .attachment .icon {
439        width: 50%;
440 }
441 
442@@ -1098,69 +1217,6 @@
443 }
444 
445 /**
446- * Selection Preview
447- */
448-.selection-preview {
449-       position: relative;
450-       height: 60px;
451-       overflow: hidden;
452-}
453-
454-.selected-img {
455-       float: left;
456-       position: relative;
457-       margin-right: 14px;
458-}
459-
460-.selection-preview img {
461-       max-width: 40px;
462-       max-height: 40px;
463-       float: left;
464-       margin-top: 6px;
465-       margin-left: 1px;
466-       border: 2px solid white;
467-       box-shadow:
468-           0 0 0 1px #ccc,
469-           3px 3px 0 0 #fff,
470-           3px 3px 0 1px #ccc,
471-           6px 6px 0 0 #fff,
472-           6px 6px 0 1px #ccc;
473-}
474-
475-.selection-preview .selected-count-1 img {
476-       margin-top: 8px;
477-       box-shadow: 0 0 0 1px #ccc;
478-}
479-
480-.selection-preview .selected-count-2 img {
481-       margin-top: 7px;
482-       box-shadow:
483-           0 0 0 1px #ccc,
484-           3px 3px 0 0 #fff,
485-           3px 3px 0 1px #ccc;
486-}
487-
488-.selection-preview .count {
489-       position: absolute;
490-       bottom: 0;
491-       right: 0;
492-       height: 16px;
493-       min-width: 8px;
494-       padding: 0 4px;
495-       font-size: 12px;
496-       text-align: center;
497-       font-weight: bold;
498-       color: #999;
499-       background: #fff;
500-       box-shadow: -1px -1px 2px -1px rgba( 0, 0, 0, 0.2 );
501-}
502-
503-.selection-preview .clear-selection {
504-       float: left;
505-       line-height: 60px;
506-}
507-
508-/**
509  * Spinner
510  */
511 .media-sidebar .settings-save-status {
512@@ -1296,21 +1352,17 @@
513 .embed-url {
514        display: block;
515        position: relative;
516-       height: 75px;
517-       padding: 16px 16px;
518+       height: 40px;
519+       padding: 0 16px 16px;
520        margin: 0;
521-       z-index: 50;
522+       z-index: 250;
523+       background: #fff;
524        border-bottom: 1px solid #dfdfdf;
525        box-shadow: 0 4px 4px -4px rgba( 0, 0, 0, 0.1 );
526        font-size: 18px;
527        font-weight: 200;
528 }
529 
530-.embed-url span {
531-       display: block;
532-       padding: 4px 0 6px 2px;
533-}
534-
535 .media-frame .embed-url input {
536        font-size: 18px;
537        padding: 12px 14px;
538@@ -1323,7 +1375,7 @@
539 .embed-image-settings {
540        position: absolute;
541        background: #f5f5f5;
542-       top: 108px;
543+       top: 57px;
544        left: 0;
545        right: 0;
546        bottom: 0;
547@@ -1387,32 +1439,7 @@
548  * Responsive layout
549  */
550 @media only screen and (max-width: 900px) {
551-       .media-modal {
552-               bottom: 20px;
553-               left: 20px;
554-               right: 20px;
555-               top: 40px;
556-       }
557-
558-       .media-modal-title {
559-               height: 30px;
560-               line-height: 30px;
561-               top: -30px;
562-       }
563-
564-       .media-modal-close {
565-               top: -23px;
566-       }
567-
568-       .media-modal-backdrop div,
569-       .uploader-window-content {
570-               top: 5px;
571-               left: 5px;
572-               right: 5px;
573-               bottom: 5px;
574-       }
575-
576-       .media-menu {
577+       .media-frame-menu {
578                width: 139px;
579        }
580 
581@@ -1420,8 +1447,8 @@
582                padding: 4px 10px;
583        }
584 
585-       .media-frame .region-content,
586-       .media-frame-toolbar > .media-toolbar {
587+       .media-frame-content,
588+       .media-frame-toolbar {
589                left: 140px;
590        }
591 
592Index: wp-includes/js/media-editor.js
593===================================================================
594--- wp-includes/js/media-editor.js      (revision 22995)
595+++ wp-includes/js/media-editor.js      (working copy)
596@@ -384,7 +384,7 @@
597 
598                        workflow = workflows[ id ] = wp.media( _.defaults( options || {}, {
599                                frame:    'post',
600-                               state:    'upload',
601+                               state:    'insert',
602                                title:    wp.media.view.l10n.addMedia,
603                                multiple: true
604                        } ) );
605@@ -408,11 +408,13 @@
606                        }, this );
607 
608                        workflow.state('embed').on( 'select', function() {
609-                               var embed = workflow.state().toJSON();
610+                               var state = workflow.state(),
611+                                       type = state.get('type'),
612+                                       embed = state.props.toJSON();
613 
614                                embed.url = embed.url || '';
615 
616-                               if ( 'link' === embed.type ) {
617+                               if ( 'link' === type ) {
618                                        _.defaults( embed, {
619                                                title:   embed.url,
620                                                linkUrl: embed.url
621@@ -420,7 +422,7 @@
622 
623                                        this.send.link( embed );
624 
625-                               } else if ( 'image' === embed.type ) {
626+                               } else if ( 'image' === type ) {
627                                        _.defaults( embed, {
628                                                title:   embed.url,
629                                                linkUrl: '',
630Index: wp-includes/js/media-views.js
631===================================================================
632--- wp-includes/js/media-views.js       (revision 22995)
633+++ wp-includes/js/media-views.js       (working copy)
634@@ -68,65 +68,71 @@
635         * wp.media.controller.Region
636         */
637        media.controller.Region = function( options ) {
638-               _.extend( this, _.pick( options || {}, 'id', 'controller', 'selector' ) );
639-
640-               this.on( 'activate:empty', this.empty, this );
641-               this.mode('empty');
642+               _.extend( this, _.pick( options || {}, 'id', 'view', 'selector' ) );
643        };
644 
645        // Use Backbone's self-propagating `extend` inheritance method.
646        media.controller.Region.extend = Backbone.Model.extend;
647 
648-       _.extend( media.controller.Region.prototype, Backbone.Events, {
649-               trigger: (function() {
650-                       var eventSplitter = /\s+/,
651-                               trigger = Backbone.Events.trigger;
652+       _.extend( media.controller.Region.prototype, {
653+               mode: function( mode ) {
654+                       if ( ! mode )
655+                               return this._mode;
656 
657-                       return function( events ) {
658-                               var mode = ':' + this._mode,
659-                                       modeEvents = events.split( eventSplitter ).join( mode ) + mode;
660-
661-                               trigger.apply( this, arguments );
662-                               trigger.apply( this, [ modeEvents ].concat( _.rest( arguments ) ) );
663+                       // Bail if we're trying to change to the current mode.
664+                       if ( mode === this._mode )
665                                return this;
666-                       };
667-               }()),
668 
669-               mode: function( mode ) {
670-                       if ( mode ) {
671-                               this.trigger( 'deactivate', this );
672-                               this._mode = mode;
673-                               return this.trigger( 'activate', this );
674-                       }
675-                       return this._mode;
676+                       this.trigger('deactivate');
677+                       this._mode = mode;
678+                       this.render( mode );
679+                       this.trigger('activate');
680+                       return this;
681                },
682 
683-               view: function( view ) {
684-                       var previous = this._view,
685-                               mode = this._mode,
686-                               id = this.id;
687+               render: function( mode ) {
688+                       // If no mode is provided, just re-render the current mode.
689+                       // If the provided mode isn't active, perform a full switch.
690+                       if ( mode && mode !== this._mode )
691+                               return this.mode( mode );
692 
693-                       // If no argument is provided, return the current view.
694-                       if ( ! view )
695-                               return previous;
696+                       var set = { view: null },
697+                               view;
698 
699-                       // If we're attempting to switch to the current view, bail.
700-                       if ( view === previous )
701+                       this.trigger( 'create', set );
702+                       view = set.view;
703+                       this.trigger( 'render', view );
704+                       if ( view )
705+                               this.set( view );
706+                       return this;
707+               },
708+
709+               get: function() {
710+                       return this.view.views.first( this.selector );
711+               },
712+
713+               set: function( views, options ) {
714+                       if ( options )
715+                               options.add = false;
716+                       return this.view.views.set( this.selector, views, options );
717+               },
718+
719+               trigger: function( event ) {
720+                       var base;
721+                       if ( ! this._mode )
722                                return;
723 
724-                       // Add classes to the new view.
725-                       if ( id )
726-                               view.$el.addClass( 'region-' + id );
727+                       var args = _.toArray( arguments );
728+                       base = this.id + ':' + event;
729 
730-                       if ( mode )
731-                               view.$el.addClass( 'mode-' + mode );
732+                       // Trigger `region:action:mode` event.
733+                       args[0] = base + ':' + this._mode;
734+                       this.view.trigger.apply( this.view, args );
735 
736-                       this.controller.views.set( this.selector, view );
737-                       this._view = view;
738-               },
739-
740-               empty: function() {
741-                       this.view( new media.View() );
742+                       // Trigger `region:action` event.
743+                       args[0] = base;
744+                       this.view.trigger.apply( this.view, args );
745+                       return this;
746                }
747        });
748 
749@@ -208,31 +214,86 @@
750        // wp.media.controller.State
751        // ---------------------------
752        media.controller.State = Backbone.Model.extend({
753-               initialize: function() {
754-                       this.on( 'activate', this._activate, this );
755+               constructor: function() {
756+                       this.on( 'activate', this._preActivate, this );
757                        this.on( 'activate', this.activate, this );
758+                       this.on( 'activate', this._postActivate, this );
759                        this.on( 'deactivate', this._deactivate, this );
760                        this.on( 'deactivate', this.deactivate, this );
761                        this.on( 'reset', this.reset, this );
762+                       this.on( 'ready', this._ready, this );
763+                       this.on( 'ready', this.ready, this );
764+
765+                       this.on( 'change:menu', this._updateMenu, this );
766+
767+                       Backbone.Model.apply( this, arguments );
768                },
769 
770+               ready: function() {},
771                activate: function() {},
772-               _activate: function() {
773+               deactivate: function() {},
774+               reset: function() {},
775+
776+               _ready: function() {
777+                       this._updateMenu();
778+               },
779+
780+               _preActivate: function() {
781                        this.active = true;
782+               },
783 
784-                       this.menu();
785-                       this.toolbar();
786-                       this.content();
787+               _postActivate: function() {
788+                       this.on( 'change:menu', this._menu, this );
789+                       this.on( 'change:titleMode', this._title, this );
790+                       this.on( 'change:content', this._content, this );
791+                       this.on( 'change:toolbar', this._toolbar, this );
792+
793+                       this.frame.on( 'title:render:default', this._renderTitle, this );
794+
795+                       this._title();
796+                       this._menu();
797+                       this._toolbar();
798+                       this._content();
799+                       this._router();
800                },
801 
802-               deactivate: function() {},
803+
804                _deactivate: function() {
805                        this.active = false;
806+
807+                       this.frame.off( 'title:render:default', this._renderTitle, this );
808+
809+                       this.off( 'change:menu', this._menu, this );
810+                       this.off( 'change:titleMode', this._title, this );
811+                       this.off( 'change:content', this._content, this );
812+                       this.off( 'change:toolbar', this._toolbar, this );
813                },
814 
815-               reset: function() {},
816+               _title: function() {
817+                       this.frame.title.render( this.get('titleMode') || 'default' );
818+               },
819 
820-               menu: function() {
821+               _renderTitle: function( view ) {
822+                       view.$el.text( this.get('title') || '' );
823+               },
824+
825+               _router: function() {
826+                       var router = this.frame.router,
827+                               mode = this.get('router'),
828+                               view;
829+
830+                       this.frame.$el.toggleClass( 'hide-router', ! mode );
831+                       if ( ! mode )
832+                               return;
833+
834+                       this.frame.router.render( mode );
835+
836+                       view = router.get();
837+                       if ( view.select )
838+                               view.select( this.frame.content.mode() );
839+               },
840+
841+               _menu: function() {
842                        var menu = this.frame.menu,
843                                mode = this.get('menu'),
844                                view;
845@@ -240,20 +301,48 @@
846                        if ( ! mode )
847                                return;
848 
849-                       if ( menu.mode() !== mode )
850-                               menu.mode( mode );
851+                       menu.mode( mode );
852 
853-                       view = menu.view();
854+                       view = menu.get();
855                        if ( view.select )
856                                view.select( this.id );
857+               },
858+
859+               _updateMenu: function() {
860+                       var previous = this.previous('menu'),
861+                               menu = this.get('menu');
862+
863+                       if ( previous )
864+                               this.frame.off( 'menu:render:' + previous, this._renderMenu, this );
865+
866+                       if ( menu )
867+                               this.frame.on( 'menu:render:' + menu, this._renderMenu, this );
868+               },
869+
870+               _renderMenu: function( view ) {
871+                       var menuItem = this.get('menuItem'),
872+                               title = this.get('title'),
873+                               priority = this.get('priority');
874+
875+                       if ( ! menuItem && title ) {
876+                               menuItem = { text: title };
877+
878+                               if ( priority )
879+                                       menuItem.priority = priority;
880+                       }
881+
882+                       if ( ! menuItem )
883+                               return;
884+
885+                       view.set( this.id, menuItem );
886                }
887        });
888 
889        _.each(['toolbar','content'], function( region ) {
890-               media.controller.State.prototype[ region ] = function() {
891+               media.controller.State.prototype[ '_' + region ] = function() {
892                        var mode = this.get( region );
893                        if ( mode )
894-                               this.frame[ region ].mode( mode );
895+                               this.frame[ region ].render( mode );
896                };
897        });
898 
899@@ -264,13 +353,20 @@
900                        id:         'library',
901                        multiple:   false,
902                        describe:   false,
903-                       toolbar:    'main-attachments',
904+                       toolbar:    'select',
905                        sidebar:    'settings',
906-                       content:    'browse',
907+                       content:    'upload',
908+                       router:     'browse',
909                        searchable: true,
910                        filterable: false,
911-                       uploads:    true,
912-                       sortable:   true
913+                       sortable:   true,
914+                       title:      l10n.mediaLibraryTitle,
915+
916+                       // Uses a user setting to override the content mode.
917+                       contentUserSetting: true,
918+
919+                       // Sync the selection from the last state when 'multiple' matches.
920+                       syncLastSelection: true
921                },
922 
923                initialize: function() {
924@@ -290,31 +386,36 @@
925                                this.set( 'gutter', 8 );
926 
927                        this.resetDisplays();
928-
929-                       media.controller.State.prototype.initialize.apply( this, arguments );
930                },
931 
932                activate: function() {
933                        var library = this.get('library'),
934                                selection = this.get('selection');
935 
936+                       if ( this.get('syncLastSelection') ) {
937+                               this.getLastSelection();
938+                       }
939+
940                        this._excludeStateLibrary();
941                        this.buildComposite();
942                        this.on( 'change:library change:exclude', this.buildComposite, this );
943                        this.on( 'change:excludeState', this._excludeState, this );
944 
945-                       // If we're in a workflow that supports multiple attachments,
946-                       // automatically select any uploading attachments.
947-                       if ( this.get('multiple') )
948-                               wp.Uploader.queue.on( 'add', this.selectUpload, this );
949+                       wp.Uploader.queue.on( 'add', this.uploading, this );
950 
951                        selection.on( 'add remove reset', this.refreshSelection, this );
952 
953-                       this.refresh();
954                        this.on( 'insert', this._insertDisplaySettings, this );
955+
956+                       if ( this.get('contentUserSetting') ) {
957+                               this.frame.on( 'content:activate', this.saveContentMode, this );
958+                               this.set( 'content', getUserSetting( 'libraryContent', this.get('content') ) );
959+                       }
960                },
961 
962                deactivate: function() {
963+                       this.frame.off( 'content:activate', this.saveContentMode, this );
964+
965                        // Unbind all event handlers that use this state as the context
966                        // from the selection.
967                        this.get('selection').off( null, null, this );
968@@ -332,11 +433,6 @@
969                        this.resetDisplays();
970                },
971 
972-               refresh: function() {
973-                       this.content();
974-                       this.refreshSelection();
975-               },
976-
977                resetDisplays: function() {
978                        this._displays = [];
979                        this._defaultDisplaySettings = {
980@@ -371,21 +467,49 @@
981                        setUserSetting( 'urlbutton', display.link );
982                },
983 
984+               getLastSelection: function() {
985+                       var selection = this.get('selection'),
986+                               lastState = this.frame.lastState(),
987+                               lastSelection = lastState && lastState.get('selection');
988+
989+                       if ( ! lastSelection || lastSelection.multiple !== selection.multiple )
990+                               return;
991+
992+                       selection.reset( lastSelection.toArray() ).single( lastSelection.single() );
993+               },
994+
995                refreshSelection: function() {
996                        var selection = this.get('selection'),
997                                mode = this.frame.content.mode();
998 
999-                       this.frame.toolbar.view().refresh();
1000+                       this.frame.toolbar.get().refresh();
1001                        this.trigger( 'refresh:selection', this, selection );
1002 
1003                        if ( ! selection.length && 'browse' !== mode && 'upload' !== mode )
1004-                               this.content();
1005+                               this.frame.content.render();
1006                },
1007 
1008-               selectUpload: function( attachment ) {
1009-                       this.get('selection').add( attachment );
1010+               uploading: function( attachment ) {
1011+                       var content = this.frame.content;
1012+
1013+                       // If the uploader was selected, navigate to the browser.
1014+                       if ( 'upload' === content.mode() )
1015+                               this.frame.content.mode('browse');
1016+
1017+                       // If we're in a workflow that supports multiple attachments,
1018+                       // automatically select any uploading attachments.
1019+                       if ( this.get('multiple') )
1020+                               this.get('selection').add( attachment );
1021                },
1022 
1023+               saveContentMode: function() {
1024+                       // Only track the browse router on library states.
1025+                       if ( 'browse' !== this.get('router') )
1026+                               return;
1027+
1028+                       setUserSetting( 'libraryContent', this.frame.content.mode() );
1029+               },
1030+
1031                buildComposite: function() {
1032                        var original = this.get('_library'),
1033                                exclude = this.get('exclude'),
1034@@ -448,42 +572,6 @@
1035                }
1036        });
1037 
1038-
1039-       // wp.media.controller.Upload
1040-       // ---------------------------
1041-       media.controller.Upload = media.controller.State.extend({
1042-               defaults: _.defaults({
1043-                       id:      'upload',
1044-                       content: 'upload',
1045-                       toolbar: 'empty',
1046-                       uploads: true,
1047-
1048-                       // The state to navigate to when files are uploading.
1049-                       libraryState: 'library'
1050-               }, media.controller.State.prototype.defaults ),
1051-
1052-               initialize: function() {
1053-                       media.controller.State.prototype.initialize.apply( this, arguments );
1054-               },
1055-
1056-               activate: function() {
1057-                       wp.Uploader.queue.on( 'add', this.uploading, this );
1058-                       media.controller.State.prototype.activate.apply( this, arguments );
1059-               },
1060-
1061-               deactivate: function() {
1062-                       wp.Uploader.queue.off( null, null, this );
1063-                       media.controller.State.prototype.deactivate.apply( this, arguments );
1064-               },
1065-
1066-               uploading: function( attachment ) {
1067-                       var library = this.get('libraryState');
1068-
1069-                       this.frame.state( library ).get('selection').add( attachment );
1070-                       this.frame.setState( library );
1071-               }
1072-       });
1073-
1074        // wp.media.controller.Gallery
1075        // ---------------------------
1076        media.controller.Gallery = media.controller.Library.extend({
1077@@ -496,7 +584,9 @@
1078                        sortable:   true,
1079                        searchable: false,
1080                        toolbar:    'gallery-edit',
1081-                       content:    'browse'
1082+                       content:    'browse',
1083+                       title:      l10n.editGalleryTitle,
1084+                       priority:   60
1085                },
1086 
1087                initialize: function() {
1088@@ -519,7 +609,7 @@
1089                        // Watch for uploaded attachments.
1090                        this.get('library').observe( wp.Uploader.queue );
1091 
1092-                       this.frame.content.on( 'activate:browse', this.gallerySettings, this );
1093+                       this.frame.on( 'content:render:browse', this.gallerySettings, this );
1094 
1095                        media.controller.Library.prototype.activate.apply( this, arguments );
1096                },
1097@@ -528,21 +618,19 @@
1098                        // Stop watching for uploaded attachments.
1099                        this.get('library').unobserve( wp.Uploader.queue );
1100 
1101-                       this.frame.content.off( null, null, this );
1102+                       this.frame.off( 'content:render:browse', this.gallerySettings, this );
1103+
1104                        media.controller.Library.prototype.deactivate.apply( this, arguments );
1105                },
1106 
1107-               gallerySettings: function() {
1108-                       var library = this.get('library'),
1109-                               browser;
1110+               gallerySettings: function( browser ) {
1111+                       var library = this.get('library');
1112 
1113-                       if ( ! library )
1114+                       if ( ! library || ! browser )
1115                                return;
1116 
1117                        library.gallery = library.gallery || new Backbone.Model();
1118 
1119-                       browser = this.frame.content.view();
1120-
1121                        browser.sidebar.set({
1122                                gallery: new media.view.Settings.Gallery({
1123                                        controller: this,
1124@@ -570,7 +658,9 @@
1125                        filterable: 'uploaded',
1126                        multiple:   false,
1127                        menu:       'main',
1128-                       toolbar:    'featured-image'
1129+                       toolbar:    'featured-image',
1130+                       title:      l10n.featuredImageTitle,
1131+                       priority:   60
1132                }, media.controller.Library.prototype.defaults ),
1133 
1134                initialize: function() {
1135@@ -629,7 +719,10 @@
1136                        menu:    'main',
1137                        content: 'embed',
1138                        toolbar: 'main-embed',
1139-                       type:    'link'
1140+                       type:    'link',
1141+
1142+                       title:    l10n.fromUrlTitle,
1143+                       priority: 120
1144                },
1145 
1146                // The amount of time used when debouncing the scan.
1147@@ -637,9 +730,9 @@
1148 
1149                initialize: function() {
1150                        this.debouncedScan = _.debounce( _.bind( this.scan, this ), this.sensitivity );
1151-                       this.on( 'change:url', this.debouncedScan, this );
1152+                       this.props = new Backbone.Model({ url: '' });
1153+                       this.props.on( 'change:url', this.debouncedScan, this );
1154                        this.on( 'scan', this.scanImage, this );
1155-                       media.controller.State.prototype.initialize.apply( this, arguments );
1156                },
1157 
1158                scan: function() {
1159@@ -652,11 +745,11 @@
1160                scanImage: function( attributes ) {
1161                        var frame = this.frame,
1162                                state = this,
1163-                               url = this.get('url'),
1164+                               url = this.props.get('url'),
1165                                image = new Image();
1166 
1167                        image.onload = function() {
1168-                               if ( state !== frame.state() || url !== state.get('url') )
1169+                               if ( state !== frame.state() || url !== state.props.get('url') )
1170                                        return;
1171 
1172                                state.set({
1173@@ -670,14 +763,10 @@
1174                },
1175 
1176                reset: function() {
1177-                       _.each( _.difference( _.keys( this.attributes ), _.keys( this.defaults ) ), function( key ) {
1178-                               this.unset( key );
1179-                       }, this );
1180+                       this.props = new Backbone.Model({ url: '' });
1181 
1182-                       this.set( 'url', '' );
1183-
1184                        if ( this.id === this.frame.state().id )
1185-                               this.frame.toolbar.view().refresh();
1186+                               this.frame.toolbar.get().refresh();
1187                }
1188        });
1189 
1190@@ -1022,9 +1111,13 @@
1191                // The constructor for the `Views` manager.
1192                Views: media.Views,
1193 
1194-               constructor: function() {
1195+               constructor: function( options ) {
1196                        this.views = new this.Views( this, this.views );
1197                        this.on( 'ready', this.ready, this );
1198+
1199+                       if ( options && options.controller )
1200+                               this.controller = options.controller;
1201+
1202                        Backbone.View.apply( this, arguments );
1203                },
1204 
1205@@ -1097,9 +1190,9 @@
1206                        // Initialize regions.
1207                        _.each( this.regions, function( region ) {
1208                                this[ region ] = new media.controller.Region({
1209-                                       controller: this,
1210-                                       id:         region,
1211-                                       selector:   '.media-frame-' + region
1212+                                       view:     this,
1213+                                       id:       region,
1214+                                       selector: '.media-frame-' + region
1215                                });
1216                        }, this );
1217                },
1218@@ -1113,6 +1206,7 @@
1219                        // Ensure states have a reference to the frame.
1220                        this.states.on( 'add', function( model ) {
1221                                model.frame = this;
1222+                               model.trigger('ready');
1223                        }, this );
1224                },
1225 
1226@@ -1131,7 +1225,7 @@
1227        media.view.MediaFrame = media.view.Frame.extend({
1228                className: 'media-frame',
1229                template:  media.template('media-frame'),
1230-               regions:   ['menu','content','toolbar'],
1231+               regions:   ['menu','title','content','toolbar','router'],
1232 
1233                initialize: function() {
1234                        media.view.Frame.prototype.initialize.apply( this, arguments );
1235@@ -1173,6 +1267,10 @@
1236                        }
1237 
1238                        this.on( 'attach', _.bind( this.views.ready, this.views ), this );
1239+
1240+                       // Bind default title creation.
1241+                       this.on( 'title:create:default', this.createTitle, this );
1242+                       this.title.mode('default');
1243                },
1244 
1245                render: function() {
1246@@ -1183,6 +1281,31 @@
1247                        return media.view.Frame.prototype.render.apply( this, arguments );
1248                },
1249 
1250+               createTitle: function( title ) {
1251+                       title.view = new media.View({
1252+                               controller: this,
1253+                               tagName: 'h1'
1254+                       });
1255+               },
1256+
1257+               createMenu: function( menu ) {
1258+                       menu.view = new media.view.Menu({
1259+                               controller: this
1260+                       });
1261+               },
1262+
1263+               createToolbar: function( toolbar ) {
1264+                       menu.view = new media.view.Toolbar({
1265+                               controller: this
1266+                       });
1267+               },
1268+
1269+               createRouter: function( router ) {
1270+                       router.view = new media.view.Router({
1271+                               controller: this
1272+                       });
1273+               },
1274+
1275                createIframeStates: function( options ) {
1276                        var settings = media.view.settings,
1277                                tabs = settings.tabs,
1278@@ -1208,22 +1331,25 @@
1279                                }, options ) );
1280                        }, this );
1281 
1282-                       this.content.on( 'activate:iframe', this.iframeContent, this );
1283-                       this.menu.on( 'activate:main', this.iframeMenu, this );
1284+                       this.on( 'content:create:iframe', this.iframeContent, this );
1285+                       this.on( 'menu:render:main', this.iframeMenu, this );
1286                        this.on( 'open', this.hijackThickbox, this );
1287                        this.on( 'close', this.restoreThickbox, this );
1288                },
1289 
1290-               iframeContent: function() {
1291+               iframeContent: function( content ) {
1292                        this.$el.addClass('hide-toolbar');
1293-                       this.content.view( new media.view.Iframe({
1294+                       content.view = new media.view.Iframe({
1295                                controller: this
1296-                       }).render() );
1297+                       });
1298                },
1299 
1300-               iframeMenu: function() {
1301+               iframeMenu: function( view ) {
1302                        var views = {};
1303 
1304+                       if ( ! view )
1305+                               return;
1306+
1307                        _.each( media.view.settings.tabs, function( title, id ) {
1308                                views[ 'iframe:' + id ] = {
1309                                        text: this.state( 'iframe:' + id ).get('title'),
1310@@ -1231,7 +1357,7 @@
1311                                };
1312                        }, this );
1313 
1314-                       this.menu.view().set( views );
1315+                       view.set( views );
1316                },
1317 
1318                hijackThickbox: function() {
1319@@ -1305,83 +1431,76 @@
1320                                new media.controller.Library({
1321                                        selection: options.selection,
1322                                        library:   media.query( options.library ),
1323-                                       multiple:  this.options.multiple,
1324+                                       multiple:  options.multiple,
1325                                        menu:      'main',
1326-                                       toolbar:   'select'
1327-                               }),
1328-
1329-                               new media.controller.Upload({
1330-                                       menu: 'main'
1331+                                       title:     options.title,
1332+                                       priority:  20
1333                                })
1334                        ]);
1335                },
1336 
1337                bindHandlers: function() {
1338-                       this.menu.on( 'activate:main', this.mainMenu, this );
1339-                       this.content.on( 'activate:browse', this.browseContent, this );
1340-                       this.content.on( 'activate:upload', this.uploadContent, this );
1341-                       this.toolbar.on( 'activate:select', this.selectToolbar, this );
1342+                       this.on( 'menu:create:main', this.createMenu, this );
1343+                       this.on( 'router:create:browse', this.createRouter, this );
1344+                       this.on( 'router:render:browse', this.browseRouter, this );
1345+                       this.on( 'content:create:browse', this.browseContent, this );
1346+                       this.on( 'content:render:upload', this.uploadContent, this );
1347+                       this.on( 'toolbar:create:select', this.createSelectToolbar, this );
1348 
1349                        this.on( 'refresh:selection', this.refreshSelectToolbar, this );
1350                },
1351 
1352-               mainMenu: function( options ) {
1353-                       this.menu.view( new media.view.Menu({
1354-                               controller: this,
1355-                               silent:     options && options.silent,
1356-
1357-                               views: {
1358-                                       upload: {
1359-                                               text: l10n.uploadFilesTitle,
1360-                                               priority: 20
1361-                                       },
1362-                                       library: {
1363-                                               text: l10n.mediaLibraryTitle,
1364-                                               priority: 40
1365-                                       }
1366+               // Routers
1367+               browseRouter: function( view ) {
1368+                       view.set({
1369+                               upload: {
1370+                                       text:     l10n.uploadFilesTitle,
1371+                                       priority: 20
1372+                               },
1373+                               browse: {
1374+                                       text:     l10n.mediaLibraryTitle,
1375+                                       priority: 40
1376                                }
1377-                       }) );
1378+                       });
1379                },
1380 
1381                // Content
1382-               browseContent: function() {
1383+               browseContent: function( content ) {
1384                        var state = this.state();
1385 
1386                        this.$el.removeClass('hide-toolbar');
1387 
1388                        // Browse our library of attachments.
1389-                       this.content.view( new media.view.AttachmentsBrowser({
1390+                       content.view = new media.view.AttachmentsBrowser({
1391                                controller: this,
1392                                collection: state.get('library'),
1393                                selection:  state.get('selection'),
1394                                model:      state,
1395                                sortable:   state.get('sortable'),
1396                                search:     state.get('searchable'),
1397-                               uploads:    state.get('uploads'),
1398                                filters:    state.get('filterable'),
1399                                display:    state.get('displaySettings'),
1400 
1401                                AttachmentView: state.get('AttachmentView')
1402-                       }) );
1403+                       });
1404                },
1405 
1406                uploadContent: function() {
1407-                       this.$el.addClass('hide-toolbar');
1408-
1409-                       this.content.view( new media.view.UploaderInline({
1410+                       this.$el.removeClass('hide-toolbar');
1411+                       this.content.set( new media.view.UploaderInline({
1412                                controller: this
1413                        }) );
1414                },
1415 
1416                // Toolbars
1417-               selectToolbar: function( options ) {
1418+               createSelectToolbar: function( toolbar, options ) {
1419                        options = _.defaults( options || {}, {
1420                                event:  'select',
1421                                silent: false,
1422                                state:  false
1423                        });
1424 
1425-                       this.toolbar.view( new media.view.Toolbar({
1426+                       toolbar.view = new media.view.Toolbar({
1427                                controller: this,
1428                                silent:     options.silent,
1429 
1430@@ -1402,7 +1521,7 @@
1431                                                }
1432                                        }
1433                                }
1434-                       }) );
1435+                       });
1436                },
1437 
1438                refreshSelectToolbar: function() {
1439@@ -1411,7 +1530,7 @@
1440                        if ( ! selection || 'select' !== this.toolbar.mode() )
1441                                return;
1442 
1443-                       this.toolbar.view().get('select').model.set( 'disabled', ! selection.length );
1444+                       this.toolbar.get().get('select').model.set( 'disabled', ! selection.length );
1445                }
1446        });
1447 
1448@@ -1430,16 +1549,10 @@
1449                },
1450 
1451                createStates: function() {
1452-                       var options = this.options;
1453-
1454-                       // Add the default states.
1455-                       this.states.add([
1456-                               // Main states.
1457-                               new media.controller.Library({
1458-                                       selection:  options.selection,
1459-                                       library:    media.query( options.library ),
1460+                       var options = this.options,
1461+                               selection = options.selection,
1462+                               library = {
1463                                        editable:   true,
1464-                                       filterable: 'all',
1465                                        multiple:   this.options.multiple,
1466                                        menu:       'main',
1467 
1468@@ -1448,12 +1561,37 @@
1469                                        // Update user settings when users adjust the
1470                                        // attachment display settings.
1471                                        displayUserSettings: true
1472-                               }),
1473+                               };
1474 
1475-                               new media.controller.Upload({
1476-                                       menu: 'main'
1477-                               }),
1478+                       // Add the default states.
1479+                       this.states.add([
1480+                               // Main states.
1481+                               new media.controller.Library( _.defaults({
1482+                                       id:         'insert',
1483+                                       title:      l10n.insertMediaTitle,
1484+                                       priority:   20,
1485+                                       toolbar:    'main-insert',
1486+                                       filterable: 'all',
1487+                                       library:    media.query( options.library ),
1488+                                       selection:  selection
1489+                               }, library ) ),
1490 
1491+                               new media.controller.Library( _.defaults({
1492+                                       id:         'gallery',
1493+                                       title:      l10n.createGalleryTitle,
1494+                                       priority:   40,
1495+                                       toolbar:    'main-gallery',
1496+                                       filterable: 'uploaded',
1497+
1498+                                       library:  media.query( _.defaults({
1499+                                               type: 'image'
1500+                                       }, options.library ) ),
1501+
1502+                                       selection: new media.model.Selection( selection.models, {
1503+                                               multiple: selection.multiple
1504+                                       })
1505+                               }, library ) ),
1506+
1507                                // Embed states.
1508                                new media.controller.Embed(),
1509 
1510@@ -1471,13 +1609,9 @@
1511                                        multiple:     true,
1512                                        menu:         'gallery',
1513                                        toolbar:      'gallery-add',
1514-                                       excludeState: 'gallery-edit'
1515-                               }),
1516-
1517-                               new media.controller.Upload({
1518-                                       id:           'gallery-upload',
1519-                                       menu:         'gallery',
1520-                                       libraryState: 'gallery-edit'
1521+                                       excludeState: 'gallery-edit',
1522+                                       title:        l10n.addToGalleryTitle,
1523+                                       priority:     100
1524                                })
1525                        ]);
1526 
1527@@ -1492,9 +1626,13 @@
1528 
1529                bindHandlers: function() {
1530                        media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
1531+                       this.on( 'menu:create:gallery', this.createMenu, this );
1532+                       this.on( 'toolbar:create:main-insert', this.createSelectionToolbar, this );
1533+                       this.on( 'toolbar:create:main-gallery', this.createSelectionToolbar, this );
1534 
1535                        var handlers = {
1536                                        menu: {
1537+                                               'main':    'mainMenu',
1538                                                'gallery': 'galleryMenu'
1539                                        },
1540 
1541@@ -1504,7 +1642,8 @@
1542                                        },
1543 
1544                                        toolbar: {
1545-                                               'main-attachments': 'mainAttachmentsToolbar',
1546+                                               'main-insert':      'mainInsertToolbar',
1547+                                               'main-gallery':     'mainGalleryToolbar',
1548                                                'main-embed':       'mainEmbedToolbar',
1549                                                'featured-image':   'featuredImageToolbar',
1550                                                'gallery-edit':     'galleryEditToolbar',
1551@@ -1514,70 +1653,42 @@
1552 
1553                        _.each( handlers, function( regionHandlers, region ) {
1554                                _.each( regionHandlers, function( callback, handler ) {
1555-                                       this[ region ].on( 'activate:' + handler, this[ callback ], this );
1556+                                       this.on( region + ':render:' + handler, this[ callback ], this );
1557                                }, this );
1558                        }, this );
1559                },
1560 
1561                // Menus
1562-               mainMenu: function() {
1563-                       media.view.MediaFrame.Select.prototype.mainMenu.call( this, { silent: true });
1564-
1565-                       this.menu.view().set({
1566+               mainMenu: function( view ) {
1567+                       view.set({
1568                                'library-separator': new media.View({
1569                                        className: 'separator',
1570-                                       priority: 60
1571-                               }),
1572-                               'embed': {
1573-                                       text: l10n.fromUrlTitle,
1574-                                       priority: 80
1575-                               }
1576+                                       priority: 100
1577+                               })
1578                        });
1579-
1580-                       if ( media.view.settings.post.featuredImageId ) {
1581-                               this.menu.view().set( 'featured-image', {
1582-                                       text: l10n.featuredImageTitle,
1583-                                       priority: 100
1584-                               });
1585-                       }
1586                },
1587 
1588-               galleryMenu: function() {
1589+               galleryMenu: function( view ) {
1590                        var lastState = this.lastState(),
1591                                previous = lastState && lastState.id,
1592                                frame = this;
1593 
1594-                       this.menu.view( new media.view.Menu({
1595-                               controller: this,
1596-                               views: {
1597-                                       cancel: {
1598-                                               text:     l10n.cancelGalleryTitle,
1599-                                               priority: 20,
1600-                                               click:    function() {
1601-                                                       if ( previous )
1602-                                                               frame.setState( previous );
1603-                                                       else
1604-                                                               frame.close();
1605-                                               }
1606-                                       },
1607-                                       separateCancel: new media.View({
1608-                                               className: 'separator',
1609-                                               priority: 40
1610-                                       }),
1611-                                       'gallery-edit': {
1612-                                               text: l10n.editGalleryTitle,
1613-                                               priority: 60
1614-                                       },
1615-                                       'gallery-upload': {
1616-                                               text: l10n.uploadImagesTitle,
1617-                                               priority: 80
1618-                                       },
1619-                                       'gallery-library': {
1620-                                               text: l10n.mediaLibraryTitle,
1621-                                               priority: 100
1622+                       view.set({
1623+                               cancel: {
1624+                                       text:     l10n.cancelGalleryTitle,
1625+                                       priority: 20,
1626+                                       click:    function() {
1627+                                               if ( previous )
1628+                                                       frame.setState( previous );
1629+                                               else
1630+                                                       frame.close();
1631                                        }
1632-                               }
1633-                       }) );
1634+                               },
1635+                               separateCancel: new media.View({
1636+                                       className: 'separator',
1637+                                       priority: 40
1638+                               })
1639+                       });
1640                },
1641 
1642                // Content
1643@@ -1587,7 +1698,7 @@
1644                                model:      this.state()
1645                        }).render();
1646 
1647-                       this.content.view( view );
1648+                       this.content.set( view );
1649                        view.url.focus();
1650                },
1651 
1652@@ -1617,37 +1728,62 @@
1653                        });
1654 
1655                        // Browse our library of attachments.
1656-                       this.content.view( view );
1657+                       this.content.set( view );
1658                },
1659 
1660-               // Sidebars
1661-               onSidebarGallerySettings: function( options ) {
1662-                       var library = this.state().get('library');
1663+               // Toolbars
1664+               createSelectionToolbar: function( toolbar ) {
1665+                       toolbar.view = new media.view.Toolbar.Selection({
1666+                               controller: this,
1667+                               editable:   this.state().get('editable')
1668+                       });
1669+               },
1670 
1671-                       if ( ! library )
1672-                               return;
1673+               mainInsertToolbar: function( view ) {
1674+                       var controller = this;
1675 
1676-                       library.gallery = library.gallery || new Backbone.Model();
1677+                       view.button = 'insert';
1678+                       view.set( 'insert', {
1679+                               style:    'primary',
1680+                               priority: 80,
1681+                               text:     l10n.insertIntoPost,
1682 
1683-                       this.sidebar.view().set({
1684-                               gallery: new media.view.Settings.Gallery({
1685-                                       controller: this,
1686-                                       model:      library.gallery,
1687-                                       priority:   40
1688-                               }).render()
1689-                       }, options );
1690+                               click: function() {
1691+                                       var state = controller.state(),
1692+                                               selection = state.get('selection');
1693+
1694+                                       controller.close();
1695+                                       state.trigger( 'insert', selection ).reset();
1696+                               }
1697+                       });
1698                },
1699 
1700-               // Toolbars
1701-               mainAttachmentsToolbar: function() {
1702-                       this.toolbar.view( new media.view.Toolbar.Insert({
1703-                               controller: this,
1704-                               editable:   this.state().get('editable')
1705-                       }) );
1706+               mainGalleryToolbar: function( view ) {
1707+                       var controller = this;
1708+
1709+                       view.button = 'gallery';
1710+                       view.set( 'gallery', {
1711+                               style:    'primary',
1712+                               text:     l10n.createNewGallery,
1713+                               priority: 60,
1714+
1715+                               click: function() {
1716+                                       var selection = controller.state().get('selection'),
1717+                                               edit = controller.state('gallery-edit'),
1718+                                               models = selection.where({ type: 'image' });
1719+
1720+                                       edit.set( 'library', new media.model.Selection( models, {
1721+                                               props:    selection.props.toJSON(),
1722+                                               multiple: true
1723+                                       }) );
1724+
1725+                                       this.controller.setState('gallery-edit');
1726+                               }
1727+                       });
1728                },
1729 
1730                featuredImageToolbar: function() {
1731-                       this.toolbar.view( new media.view.Toolbar.Select({
1732+                       this.toolbar.set( new media.view.Toolbar.Select({
1733                                controller: this,
1734                                text:       l10n.setFeaturedImage,
1735                                state:      this.options.state || 'upload'
1736@@ -1655,7 +1791,7 @@
1737                },
1738 
1739                mainEmbedToolbar: function() {
1740-                       this.toolbar.view( new media.view.Toolbar.Embed({
1741+                       this.toolbar.set( new media.view.Toolbar.Embed({
1742                                controller: this
1743                        }) );
1744 
1745@@ -1664,7 +1800,7 @@
1746 
1747                galleryEditToolbar: function() {
1748                        var editing = this.state().get('editing');
1749-                       this.toolbar.view( new media.view.Toolbar({
1750+                       this.toolbar.set( new media.view.Toolbar({
1751                                controller: this,
1752                                items: {
1753                                        insert: {
1754@@ -1689,7 +1825,7 @@
1755                },
1756 
1757                galleryAddToolbar: function() {
1758-                       this.toolbar.view( new media.view.Toolbar({
1759+                       this.toolbar.set( new media.view.Toolbar({
1760                                controller: this,
1761                                items: {
1762                                        insert: {
1763@@ -1704,7 +1840,7 @@
1764 
1765                                                        edit.get('library').add( state.get('selection').models );
1766                                                        state.trigger('reset');
1767-                                                       controller.state('gallery-edit');
1768+                                                       controller.setState('gallery-edit');
1769                                                }
1770                                        }
1771                                }
1772@@ -1729,8 +1865,6 @@
1773                },
1774 
1775                initialize: function() {
1776-                       this.controller = this.options.controller;
1777-
1778                        _.defaults( this.options, {
1779                                container: document.body,
1780                                title:     '',
1781@@ -1838,8 +1972,6 @@
1782                initialize: function() {
1783                        var uploader;
1784 
1785-                       this.controller = this.options.controller;
1786-
1787                        this.$browser = $('<a href="#" class="browser" />').hide().appendTo('body');
1788 
1789                        uploader = this.options.uploader = _.defaults( this.options.uploader || {}, {
1790@@ -1906,7 +2038,10 @@
1791                template:  media.template('uploader-inline'),
1792 
1793                initialize: function() {
1794-                       this.controller = this.options.controller;
1795+                       _.defaults( this.options, {
1796+                               message: '',
1797+                               status:  true
1798+                       });
1799 
1800                        if ( ! this.options.$browser && this.controller.uploader )
1801                                this.options.$browser = this.controller.uploader.$browser;
1802@@ -1914,9 +2049,11 @@
1803                        if ( _.isUndefined( this.options.postId ) )
1804                                this.options.postId = media.view.settings.post.id;
1805 
1806-                       this.views.set( '.upload-inline-status', new media.view.UploaderStatus({
1807-                               controller: this.controller
1808-                       }) );
1809+                       if ( this.options.status ) {
1810+                               this.views.set( '.upload-inline-status', new media.view.UploaderStatus({
1811+                                       controller: this.controller
1812+                               }) );
1813+                       }
1814                },
1815 
1816                ready: function() {
1817@@ -1951,8 +2088,6 @@
1818                },
1819 
1820                initialize: function() {
1821-                       this.controller = this.options.controller;
1822-
1823                        this.queue = wp.Uploader.queue;
1824                        this.queue.on( 'add remove reset', this.visibility, this );
1825                        this.queue.on( 'add remove reset change:percent', this.progress, this );
1826@@ -2060,8 +2195,6 @@
1827                className: 'media-toolbar',
1828 
1829                initialize: function() {
1830-                       this.controller = this.options.controller;
1831-
1832                        this._views     = {};
1833                        this.$primary   = $('<div class="media-toolbar-primary" />').prependTo( this.$el );
1834                        this.$secondary = $('<div class="media-toolbar-secondary" />').prependTo( this.$el );
1835@@ -2199,50 +2332,32 @@
1836        // ---------------------------
1837        media.view.Toolbar.Embed = media.view.Toolbar.Select.extend({
1838                initialize: function() {
1839-                       var controller = this.options.controller;
1840-
1841                        _.defaults( this.options, {
1842                                text: l10n.insertIntoPost
1843                        });
1844 
1845                        media.view.Toolbar.Select.prototype.initialize.apply( this, arguments );
1846-                       controller.on( 'change:url', this.refresh, this );
1847+                       this.controller.state().props.on( 'change:url', this.refresh, this );
1848                },
1849 
1850                refresh: function() {
1851-                       var url = this.controller.state().get('url');
1852+                       var url = this.controller.state().props.get('url');
1853                        this.get('select').model.set( 'disabled', ! url || /^https?:\/\/$/.test(url) );
1854                }
1855        });
1856 
1857-       // wp.media.view.Toolbar.Insert
1858-       // ----------------------------
1859-       media.view.Toolbar.Insert = media.view.Toolbar.extend({
1860+       // wp.media.view.Toolbar.Selection
1861+       // -------------------------------
1862+       media.view.Toolbar.Selection = media.view.Toolbar.extend({
1863+               button: 'insert',
1864+
1865                initialize: function() {
1866-                       var controller = this.options.controller,
1867-                               selection = controller.state().get('selection'),
1868-                               selectionToLibrary;
1869+                       var controller = this.controller;
1870 
1871-                       selectionToLibrary = function( state, filter ) {
1872-                               return function() {
1873-                                       var controller = this.controller,
1874-                                               selection = controller.state().get('selection'),
1875-                                               edit = controller.state( state ),
1876-                                               models = filter ? filter( selection ) : selection.models;
1877-
1878-                                       edit.set( 'library', new media.model.Selection( models, {
1879-                                               props:    selection.props.toJSON(),
1880-                                               multiple: true
1881-                                       }) );
1882-
1883-                                       this.controller.setState( state );
1884-                               };
1885-                       };
1886-
1887                        this.options.items = _.defaults( this.options.items || {}, {
1888                                selection: new media.view.Selection({
1889                                        controller: controller,
1890-                                       collection: selection,
1891+                                       collection: controller.state().get('selection'),
1892                                        priority:   -40,
1893 
1894                                        // If the selection is editable, pass the callback to
1895@@ -2250,26 +2365,7 @@
1896                                        editable: this.options.editable && function() {
1897                                                this.controller.content.mode('edit-selection');
1898                                        }
1899-                               }).render(),
1900-
1901-                               insert: {
1902-                                       style:    'primary',
1903-                                       priority: 80,
1904-                                       text:     l10n.insertIntoPost,
1905-
1906-                                       click: function() {
1907-                                               controller.close();
1908-                                               controller.state().trigger( 'insert', selection ).reset();
1909-                                       }
1910-                               },
1911-
1912-                               gallery: {
1913-                                       text:     l10n.createNewGallery,
1914-                                       priority: 40,
1915-                                       click:    selectionToLibrary('gallery-edit', function( selection ) {
1916-                                               return selection.where({ type: 'image' });
1917-                                       })
1918-                               }
1919+                               }).render()
1920                        });
1921 
1922                        media.view.Toolbar.prototype.initialize.apply( this, arguments );
1923@@ -2277,14 +2373,12 @@
1924 
1925                refresh: function() {
1926                        var selection = this.controller.state().get('selection'),
1927-                               count = selection.length;
1928+                               button = this.get( this.button );
1929 
1930-                       this.get('insert').model.set( 'disabled', ! selection.length );
1931+                       if ( ! button )
1932+                               return;
1933 
1934-                       // Check if any attachment in the selection is an image.
1935-                       this.get('gallery').$el.toggle( count > 1 && selection.any( function( attachment ) {
1936-                               return 'image' === attachment.get('type');
1937-                       }) );
1938+                       button.model.set( 'disabled', ! selection.length );
1939                }
1940        });
1941 
1942@@ -2388,8 +2482,7 @@
1943                tagName:   'div',
1944 
1945                initialize: function() {
1946-                       this.controller = this.options.controller;
1947-                       this._views     = {};
1948+                       this._views = {};
1949 
1950                        this.set( _.extend( {}, this._views, this.options.views ), { silent: true });
1951                        delete this.options.views;
1952@@ -2457,23 +2550,94 @@
1953                }
1954        });
1955 
1956+       /**
1957+        * wp.media.view.MenuItem
1958+        */
1959+       media.view.MenuItem = media.View.extend({
1960+               tagName:   'a',
1961+               className: 'media-menu-item',
1962 
1963+               attributes: {
1964+                       href: '#'
1965+               },
1966+
1967+               events: {
1968+                       'click': '_click'
1969+               },
1970+
1971+               _click: function( event ) {
1972+                       var clickOverride = this.options.click;
1973+
1974+                       event.preventDefault();
1975+
1976+                       if ( clickOverride )
1977+                               clickOverride.call( this );
1978+                       else
1979+                               this.click();
1980+               },
1981+
1982+               click: function() {
1983+                       var state = this.options.state;
1984+                       if ( state )
1985+                               this.controller.setState( state );
1986+               },
1987+
1988+               render: function() {
1989+                       var options = this.options;
1990+
1991+                       if ( options.text )
1992+                               this.$el.text( options.text );
1993+                       else if ( options.html )
1994+                               this.$el.html( options.html );
1995+
1996+                       return this;
1997+               }
1998+       });
1999+
2000        /**
2001         * wp.media.view.Menu
2002         */
2003        media.view.Menu = media.view.PriorityList.extend({
2004-               tagName:   'ul',
2005+               tagName:   'div',
2006                className: 'media-menu',
2007+               property:  'state',
2008+               ItemView:  media.view.MenuItem,
2009+               region:    'menu',
2010 
2011-               toView: function( options, state ) {
2012+               toView: function( options, id ) {
2013                        options = options || {};
2014-                       options.state = options.state || state;
2015-                       return new media.view.MenuItem( options ).render();
2016+                       options[ this.property ] = options[ this.property ] || id;
2017+                       return new this.ItemView( options ).render();
2018                },
2019 
2020-               select: function( state ) {
2021-                       var view = this.get( state );
2022+               ready: function() {
2023+                       media.view.PriorityList.prototype.ready.apply( this, arguments );
2024+                       this.visibility();
2025+               },
2026 
2027+               set: function() {
2028+                       media.view.PriorityList.prototype.set.apply( this, arguments );
2029+                       this.visibility();
2030+               },
2031+
2032+               unset: function() {
2033+                       media.view.PriorityList.prototype.unset.apply( this, arguments );
2034+                       this.visibility();
2035+               },
2036+
2037+               visibility: function() {
2038+                       var region = this.region,
2039+                               view = this.controller[ region ].get(),
2040+                               views = this.views.get(),
2041+                               hide = ! views || views.length < 2;
2042+
2043+                       if ( this === view )
2044+                               this.controller.$el.toggleClass( 'hide-' + region, hide );
2045+               },
2046+
2047+               select: function( id ) {
2048+                       var view = this.get( id );
2049+
2050                        if ( ! view )
2051                                return;
2052 
2053@@ -2486,35 +2650,40 @@
2054                }
2055        });
2056 
2057-       media.view.MenuItem = media.View.extend({
2058-               tagName:   'li',
2059-               className: 'media-menu-item',
2060+       /**
2061+        * wp.media.view.RouterItem
2062+        */
2063+       media.view.RouterItem = media.view.MenuItem.extend({
2064+               click: function() {
2065+                       var contentMode = this.options.contentMode;
2066+                       if ( contentMode )
2067+                               this.controller.content.mode( contentMode );
2068+               }
2069+       });
2070 
2071-               events: {
2072-                       'click': 'click'
2073-               },
2074+       /**
2075+        * wp.media.view.Router
2076+        */
2077+       media.view.Router = media.view.Menu.extend({
2078+               tagName:   'div',
2079+               className: 'media-router',
2080+               property:  'contentMode',
2081+               ItemView:  media.view.RouterItem,
2082+               region:    'router',
2083 
2084-               click: function() {
2085-                       var options = this.options;
2086-
2087-                       if ( options.click )
2088-                               options.click.call( this );
2089-                       else if ( options.state )
2090-                               this.controller.setState( options.state );
2091+               initialize: function() {
2092+                       this.controller.on( 'content:render', this.update, this );
2093+                       media.view.Menu.prototype.initialize.apply( this, arguments );
2094                },
2095 
2096-               render: function() {
2097-                       var options = this.options;
2098-
2099-                       if ( options.text )
2100-                               this.$el.text( options.text );
2101-                       else if ( options.html )
2102-                               this.$el.html( options.html );
2103-
2104-                       return this;
2105+               update: function() {
2106+                       var mode = this.controller.content.mode();
2107+                       if ( mode )
2108+                               this.select( mode );
2109                }
2110        });
2111 
2112+
2113        /**
2114         * wp.media.view.Sidebar
2115         */
2116@@ -2546,8 +2715,6 @@
2117                initialize: function() {
2118                        var selection = this.options.selection;
2119 
2120-                       this.controller = this.options.controller;
2121-
2122                        this.model.on( 'change:sizes change:uploading change:caption change:title', this.render, this );
2123                        this.model.on( 'change:percent', this.progress, this );
2124 
2125@@ -2838,7 +3005,6 @@
2126                },
2127 
2128                initialize: function() {
2129-                       this.controller = this.options.controller;
2130                        this.el.id = _.uniqueId('__attachments-view-');
2131 
2132                        _.defaults( this.options, {
2133@@ -3200,12 +3366,9 @@
2134                className: 'attachments-browser',
2135 
2136                initialize: function() {
2137-                       this.controller = this.options.controller;
2138-
2139                        _.defaults( this.options, {
2140                                filters: false,
2141                                search:  true,
2142-                               uploads: false,
2143                                display: false,
2144 
2145                                AttachmentView: media.view.Attachment.Library
2146@@ -3290,7 +3453,9 @@
2147                        this.removeContent();
2148 
2149                        this.uploader = new media.view.UploaderInline({
2150-                               controller: this.controller
2151+                               controller: this.controller,
2152+                               status:     false,
2153+                               message:    l10n.noItemsFound
2154                        });
2155 
2156                        this.views.add( this.uploader );
2157@@ -3322,7 +3487,7 @@
2158 
2159                        this.views.add( sidebar );
2160 
2161-                       if ( options.uploads && this.controller.uploader ) {
2162+                       if ( this.controller.uploader ) {
2163                                sidebar.set( 'uploads', new media.view.UploaderStatus({
2164                                        controller: this.controller,
2165                                        priority:   40
2166@@ -3373,57 +3538,6 @@
2167        });
2168 
2169        /**
2170-        * wp.media.view.SelectionPreview
2171-        */
2172-       media.view.SelectionPreview = media.View.extend({
2173-               tagName:   'div',
2174-               className: 'selection-preview',
2175-               template:  media.template('media-selection-preview'),
2176-
2177-               events: {
2178-                       'click .clear-selection': 'clear'
2179-               },
2180-
2181-               initialize: function() {
2182-                       _.defaults( this.options, {
2183-                               clearable: true
2184-                       });
2185-
2186-                       this.controller = this.options.controller;
2187-                       this.collection.on( 'add change:url remove', this.render, this );
2188-                       this.render();
2189-               },
2190-
2191-               render: function() {
2192-                       var options = _.clone( this.options ),
2193-                               last, sizes, amount;
2194-
2195-                       // If nothing is selected, display nothing.
2196-                       if ( ! this.collection.length ) {
2197-                               this.$el.empty();
2198-                               return this;
2199-                       }
2200-
2201-                       options.count = this.collection.length;
2202-                       last  = this.collection.last();
2203-                       sizes = last.get('sizes');
2204-
2205-                       if ( 'image' === last.get('type') )
2206-                               options.thumbnail = ( sizes && sizes.thumbnail ) ? sizes.thumbnail.url : last.get('url');
2207-                       else
2208-                               options.thumbnail =  last.get('icon');
2209-
2210-                       this.$el.html( this.template( options ) );
2211-                       return this;
2212-               },
2213-
2214-               clear: function( event ) {
2215-                       event.preventDefault();
2216-                       this.collection.reset();
2217-               }
2218-       });
2219-
2220-       /**
2221         * wp.media.view.Selection
2222         */
2223        media.view.Selection = media.View.extend({
2224@@ -3442,7 +3556,6 @@
2225                                clearable: true
2226                        });
2227 
2228-                       this.controller = this.options.controller;
2229                        this.attachments = new media.view.Attachments({
2230                                controller: this.controller,
2231                                collection: this.collection,
2232@@ -3768,12 +3881,10 @@
2233        media.view.Iframe = media.View.extend({
2234                className: 'media-iframe',
2235 
2236-               initialize: function() {
2237-                       this.controller = this.options.controller;
2238-               },
2239-
2240                render: function() {
2241+                       this.views.detach();
2242                        this.$el.html( '<iframe src="' + this.controller.state().get('src') + '" />' );
2243+                       this.views.render();
2244                        return this;
2245                }
2246        });
2247@@ -3785,11 +3896,9 @@
2248                className: 'media-embed',
2249 
2250                initialize: function() {
2251-                       this.controller = this.options.controller;
2252-
2253                        this.url = new media.view.EmbedUrl({
2254                                controller: this.controller,
2255-                               model:      this.model
2256+                               model:      this.model.props
2257                        }).render();
2258 
2259                        this._settings = new media.View();
2260@@ -3826,7 +3935,7 @@
2261 
2262                        this.settings( new constructor({
2263                                controller: this.controller,
2264-                               model:      this.model,
2265+                               model:      this.model.props,
2266                                priority:   40
2267                        }) );
2268                }
2269@@ -3846,15 +3955,13 @@
2270                },
2271 
2272                initialize: function() {
2273-                       this.label = this.make( 'span', null, this.options.label || l10n.url );
2274                        this.input = this.make( 'input', {
2275                                type:  'text',
2276                                value: this.model.get('url') || ''
2277                        });
2278 
2279-                       this.$label = $( this.label );
2280                        this.$input = $( this.input );
2281-                       this.$el.append([ this.label, this.input ]);
2282+                       this.$el.append( this.input );
2283 
2284                        this.model.on( 'change:url', this.render, this );
2285                },
2286Index: wp-includes/media.php
2287===================================================================
2288--- wp-includes/media.php       (revision 22995)
2289+++ wp-includes/media.php       (working copy)
2290@@ -1467,9 +1467,11 @@
2291 
2292                // Library
2293                'mediaLibraryTitle'  => __( 'Media Library' ),
2294+               'insertMediaTitle'   => __( 'Insert Media' ),
2295                'createNewGallery'   => __( 'Create a new gallery' ),
2296                'returnToLibrary'    => __( '&#8592; Return to library' ),
2297                'allMediaItems'      => __( 'All media items' ),
2298+               'noItemsFound'       => __( 'No items found.' ),
2299                'insertIntoPost'     => $hier ? __( 'Insert into page' ) : __( 'Insert into post' ),
2300                'uploadedToThisPost' => $hier ? __( 'Uploaded to this page' ) : __( 'Uploaded to this post' ),
2301                'warnDelete' =>      __( "You are about to permanently delete this item.\n  'Cancel' to stop, 'OK' to delete." ),
2302@@ -1489,6 +1491,7 @@
2303                'updateGallery'      => __( 'Update gallery' ),
2304                'continueEditing'    => __( 'Continue editing' ),
2305                'addToGallery'       => __( 'Add to gallery' ),
2306+               'addToGalleryTitle'  => __( 'Add to Gallery' ),
2307                'reverseOrder'       => __( 'Reverse order' ),
2308        );
2309 
2310@@ -1517,6 +1520,8 @@
2311        ?>
2312        <script type="text/html" id="tmpl-media-frame">
2313                <div class="media-frame-menu"></div>
2314+               <div class="media-frame-title"></div>
2315+               <div class="media-frame-router"></div>
2316                <div class="media-frame-content"></div>
2317                <div class="media-frame-toolbar"></div>
2318                <div class="media-frame-uploader"></div>
2319@@ -1524,13 +1529,10 @@
2320 
2321        <script type="text/html" id="tmpl-media-modal">
2322                <div class="media-modal wp-core-ui">
2323-                       <h3 class="media-modal-title">{{ data.title }}</h3>
2324-                       <a class="media-modal-close media-modal-icon" href="#" title="<?php esc_attr_e('Close'); ?>"></a>
2325+                       <a class="media-modal-close" href="#" title="<?php esc_attr_e('Close'); ?>"><span class="media-modal-icon"></span></a>
2326                        <div class="media-modal-content"></div>
2327                </div>
2328-               <div class="media-modal-backdrop">
2329-                       <div></div>
2330-               </div>
2331+               <div class="media-modal-backdrop"></div>
2332        </script>
2333 
2334        <script type="text/html" id="tmpl-uploader-window">
2335@@ -1540,16 +1542,20 @@
2336        </script>
2337 
2338        <script type="text/html" id="tmpl-uploader-inline">
2339-               <div class="uploader-inline-content">
2340+               <# var messageClass = data.message ? 'has-upload-message' : 'no-upload-message'; #>
2341+               <div class="uploader-inline-content {{ messageClass }}">
2342+               <# if ( data.message ) { #>
2343+                       <h3 class="upload-message">{{ data.message }}</h3>
2344+               <# } #>
2345                <?php if ( ! _device_can_upload() ) : ?>
2346-                       <h3><?php _e('The web browser on your device cannot be used to upload files. You may be able to use the <a href="http://wordpress.org/extend/mobile/">native app for your device</a> instead.'); ?></h3>
2347+                       <h3 class="upload-instructions"><?php _e('The web browser on your device cannot be used to upload files. You may be able to use the <a href="http://wordpress.org/extend/mobile/">native app for your device</a> instead.'); ?></h3>
2348                <?php elseif ( is_multisite() && ! is_upload_space_available() ) : ?>
2349-                       <h3><?php _e( 'Upload Limit Exceeded' ); ?></h3>
2350+                       <h3 class="upload-instructions"><?php _e( 'Upload Limit Exceeded' ); ?></h3>
2351                        <?php do_action( 'upload_ui_over_quota' ); ?>
2352 
2353                <?php else : ?>
2354                        <div class="upload-ui">
2355-                               <h3 class="drop-instructions"><?php _e( 'Drop files anywhere to upload' ); ?></h3>
2356+                               <h3 class="upload-instructions drop-instructions"><?php _e( 'Drop files anywhere to upload' ); ?></h3>
2357                                <a href="#" class="browser button button-hero"><?php _e( 'Select Files' ); ?></a>
2358                        </div>
2359 
2360@@ -1744,19 +1750,6 @@
2361                <div class="selection-view"></div>
2362        </script>
2363 
2364-       <script type="text/html" id="tmpl-media-selection-preview">
2365-               <div class="selected-img selected-count-{{ data.count }}">
2366-                       <# if ( data.thumbnail ) { #>
2367-                               <img src="{{ data.thumbnail }}" draggable="false" />
2368-                       <# } #>
2369-
2370-                       <span class="count">{{ data.count }}</span>
2371-               </div>
2372-               <# if ( data.clearable ) { #>
2373-                       <a class="clear-selection" href="#"><?php _e('Clear selection'); ?></a>
2374-               <# } #>
2375-       </script>
2376-
2377        <script type="text/html" id="tmpl-attachment-display-settings">
2378                <h3><?php _e('Attachment Display Settings'); ?></h3>
2379