<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[28993] trunk/src: Media grid, round 2.</title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://core.trac.wordpress.org/changeset/28993">28993</a></dd>
<dt>Author</dt> <dd>helen</dd>
<dt>Date</dt> <dd>2014-07-04 03:38:33 +0000 (Fri, 04 Jul 2014)</dd>
</dl>
<h3>Log Message</h3>
<pre>Media grid, round 2. Expect much more to come.
* Instead of a sidebar for details, utilize a modal. The modal experience allows for a larger preview, editing images, audio/video previews, and previous/next navigation, like the theme browser. Think of it as an attachment browser.
* Show some details in the grid view to more easily distinguish items.
props ericlewis, wonderboymusic, JerrySarcastic. see <a href="http://core.trac.wordpress.org/ticket/24716">#24716</a>.</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpadminuploadphp">trunk/src/wp-admin/upload.php</a></li>
<li><a href="#trunksrcwpincludescssmediaviewscss">trunk/src/wp-includes/css/media-views.css</a></li>
<li><a href="#trunksrcwpincludesjsmediaaudiovideojs">trunk/src/wp-includes/js/media-audiovideo.js</a></li>
<li><a href="#trunksrcwpincludesjsmediagridjs">trunk/src/wp-includes/js/media-grid.js</a></li>
<li><a href="#trunksrcwpincludesjsmediaviewsjs">trunk/src/wp-includes/js/media-views.js</a></li>
<li><a href="#trunksrcwpincludesmediatemplatephp">trunk/src/wp-includes/media-template.php</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpadminuploadphp"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-admin/upload.php (28992 => 28993)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-admin/upload.php 2014-07-04 02:17:22 UTC (rev 28992)
+++ trunk/src/wp-admin/upload.php 2014-07-04 03:38:33 UTC (rev 28993)
</span><span class="lines">@@ -24,16 +24,8 @@
</span><span class="cx"> wp_enqueue_media();
</span><span class="cx"> wp_enqueue_script( 'media-grid' );
</span><span class="cx"> wp_enqueue_script( 'media' );
</span><del>-
</del><ins>+
</ins><span class="cx"> require_once( ABSPATH . 'wp-admin/admin-header.php' );
</span><del>- ?><div class="view-switch media-grid-view-switch">
- <a href="<?php echo esc_url( add_query_arg( 'mode', 'list', $_SERVER['REQUEST_URI'] ) ) ?>" class="view-list">
- <img id="view-switch-list" src="<?php echo includes_url( 'images/blank.gif' ) ?>" width="20" height="20" title="List View" alt="List View"/>
- </a>
- <a href="<?php echo esc_url( add_query_arg( 'mode', 'grid', $_SERVER['REQUEST_URI'] ) ) ?>" class="view-grid current">
- <img id="view-switch-excerpt" src="<?php echo includes_url( 'images/blank.gif' ) ?>" width="20" height="20" title="Grid View" alt="Grid View"/>
- </a>
- </div><?php
</del><span class="cx"> include( ABSPATH . 'wp-admin/admin-footer.php' );
</span><span class="cx"> exit;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunksrcwpincludescssmediaviewscss"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/css/media-views.css (28992 => 28993)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/css/media-views.css 2014-07-04 02:17:22 UTC (rev 28992)
+++ trunk/src/wp-includes/css/media-views.css 2014-07-04 03:38:33 UTC (rev 28993)
</span><span class="lines">@@ -750,6 +750,30 @@
</span><span class="cx"> max-height: 100%;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+.attachment-preview.type-audio .thumbnail,
+.attachment-preview.type-video .thumbnail {
+ z-index: 1;
+ margin: 5%;
+ max-width: 90%;
+ max-height: 90%;
+}
+
+.media-frame-content .attachment-preview.type-audio .icon,
+.media-frame-content .attachment-preview.type-video .icon {
+ z-index: 2;
+ background: #f1f1f1;
+ position: relative;
+ padding: 0;
+ top: 15%;
+ left: auto;
+ right: auto;
+}
+
+.attachment-preview.type-audio .filename,
+.attachment-preview.type-video .filename {
+ z-index: 3;
+}
+
</ins><span class="cx"> .attachment-preview .thumbnail:after {
</span><span class="cx"> content: '';
</span><span class="cx"> display: block;
</span><span class="lines">@@ -909,6 +933,22 @@
</span><span class="cx"> border-radius: 0;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+.attachment .data-fields {
+ margin: 5px 0 0;
+}
+
+.attachment .data-field {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ display: block;
+ line-height: 19px;
+ height: 19px;
+ text-align: left;
+ width: 90%;
+ margin: 0 5%;
+}
+
</ins><span class="cx"> /**
</span><span class="cx"> * Attachments Browser
</span><span class="cx"> */
</span><span class="lines">@@ -924,6 +964,10 @@
</span><span class="cx"> height: 50px;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+.attachments-browser.hide-sidebar .media-toolbar {
+ right: 0;
+}
+
</ins><span class="cx"> .attachments-browser .media-toolbar-primary > .media-button,
</span><span class="cx"> .attachments-browser .media-toolbar-primary > .media-button-group,
</span><span class="cx"> .attachments-browser .media-toolbar-secondary > .media-button,
</span><span class="lines">@@ -942,6 +986,92 @@
</span><span class="cx"> outline: none;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+.inline-toolbar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ display: none;
+ z-index: 100;
+}
+
+.inline-toolbar .remove {
+ display: none;
+}
+
+.active-video .inline-toolbar .remove {
+ display: inline-block;
+}
+
+.attachment:hover .inline-toolbar {
+ display: block;
+}
+
+.inline-toolbar div,
+.inline-toolbar .inline-media-control {
+ display: inline-block;
+ margin-top: 4px;
+ margin-left: 4px;
+ padding: 2px;
+ width: 20px;
+ height: 20px;
+ box-shadow: 0 1px 3px rgba(0,0,0,0.5);
+ background-color: #000;
+ background-color: rgba(0,0,0,0.9);
+ cursor: pointer;
+ color: white;
+ font-size: 20px;
+}
+
+.ie8 .inline-toolbar div,
+.ie7 .inline-toolbar div {
+ display: inline;
+ padding: 0;
+}
+
+.inline-media-control span {
+ display: block;
+ width: 16px;
+ height: 16px;
+ margin: 2px;
+ background: url(/wp-includes/js/mediaelement/controls.png) 0 0 no-repeat;
+}
+
+.inline-media-control.active span {
+ margin: 2px;
+ background-position: 0 -16px;
+}
+
+.inline-media-control.paused span {
+ margin: 2px;
+ background-position: 0 0;
+}
+
+audio#inline-media-node {
+ display: none;
+}
+
+video#inline-media-node {
+ position: relative;
+ z-index: 5;
+ top: 0;
+ left: 0;
+}
+
+.inline-video-wrap {
+ width: 100%;
+ height: auto;
+ position: absolute;
+ z-index: 5;
+ background: #000;
+ padding: 10px 0 5px;
+ top: 0;
+ left: 0;
+}
+
+.attachments-browser.hide-sidebar .attachments {
+ right: 0;
+}
+
</ins><span class="cx"> .attachments-browser .instructions {
</span><span class="cx"> display: inline-block;
</span><span class="cx"> margin-top: 16px;
</span><span class="lines">@@ -2388,11 +2518,11 @@
</span><span class="cx"> line-height: 29px;
</span><span class="cx"> }
</span><span class="cx">
</span><del>-.media-grid-view-switch {
- position: fixed;
- right: 10px;
- top: 44px;
- z-index: 300;
</del><ins>+.media-grid-view .view-switch {
+ display: inline-block;
+ float: none;
+ margin-top: 13px;
+ vertical-align: middle;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -2427,7 +2557,221 @@
</span><span class="cx"> display: none;
</span><span class="cx"> }
</span><span class="cx">
</span><ins>+/**
+ * Copied styles from the Add theme toolbar.
+ *
+ * This should be OOCSS'd so both use a shared selector.
+ */
+.media-grid-view .media-toolbar {
+ background: #fff;
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
+ box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ color: #555;
+ display: inline-block;
+ font-size: 13px;
+ padding: 0 20px;
+ position: relative;
+ width: 100%;
+}
+
+/**
+ * The left and right buttons are copied from the expanded theme details modal.
+ *
+ * This should be OOCSS'd so both use a shared selector.
+ */
+.edit-attachment-frame .edit-media-header .left,
+.edit-attachment-frame .edit-media-header .right {
+ cursor: pointer;
+ color: #777;
+ background-color: transparent;
+ height: 48px;
+ width: 54px;
+ float: left;
+ text-align: center;
+ border: 0;
+ border-right: 1px solid #ddd;
+}
+
+.edit-attachment-frame .edit-media-header .right:before,
+.edit-attachment-frame .edit-media-header .left:before {
+ font: normal 20px/50px 'dashicons' !important;
+ display: inline;
+ font-weight: 300;
+}
+
+
+.edit-attachment-frame .edit-media-header .left:before {
+ content: '\f340';
+}
+
+.edit-attachment-frame .edit-media-header .right:before {
+ content: '\f344';
+}
+
+.edit-attachment-frame .edit-media-header .left.disabled,
+.edit-attachment-frame .edit-media-header .right.disabled,
+.edit-attachment-frame .edit-media-header .left.disabled:hover,
+.edit-attachment-frame .edit-media-header .right.disabled:hover {
+ color: #ccc;
+ background: inherit;
+ cursor: inherit;
+}
+
+.edit-attachment-frame .edit-media-header .close:hover,
+.edit-attachment-frame .edit-media-header .right:hover,
+.edit-attachment-frame .edit-media-header .left:hover,
+.edit-attachment-frame .edit-media-header .close:focus,
+.edit-attachment-frame .edit-media-header .right:focus,
+.edit-attachment-frame .edit-media-header .left:focus {
+ background: #0074a2;
+ color: #fff;
+}
+
+.edit-attachment-frame .media-frame-content,
+.edit-attachment-frame .media-frame-router {
+ left: 0;
+}
+
+/* Hiding this for the moment instead of removing it from the template. */
+.edit-attachment-frame h3 {
+ display: none;
+}
+
+.edit-attachment-frame .attachment-details {
+ position: absolute;
+ overflow: auto;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: 0;
+}
+
+.edit-attachment-frame .attachment-info {
+ border-bottom: 0;
+ border-right: 1px solid #ddd;
+ bottom: 0;
+ position: absolute;
+ top: 0;
+ left: 0;
+ margin-bottom: 0;
+ padding: 2% 4%;
+ right: 50%;
+}
+
+.edit-attachment-frame .attachment-info .thumbnail {
+ max-width: none;
+ max-height: none;
+}
+
+.edit-attachment-frame .attachment-info .thumbnail-image img {
+ margin: 0;
+}
+
+.edit-attachment-frame .attachment-info .thumbnail-image:after {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+}
+
+.edit-attachment-frame .attachment-info .thumbnail img {
+ max-width: none;
+ max-height: 50%;
+}
+
+.edit-attachment-frame .attachment-info .details {
+ float: none;
+}
+
+.edit-attachment-frame .wp-media-wrapper {
+ margin-top: 20px;
+}
+
+.edit-attachment-frame .attachment-fields {
+ bottom: 0;
+ padding: 2% 4%;
+ position: absolute;
+ top: 0;
+ left: 50%;
+ right: 0;
+}
+
+.edit-attachment-frame .attachment-fields .setting {
+ display: block;
+ float: left;
+ width: 100%;
+ margin: 1px 0;
+}
+
+.edit-attachment-frame .attachment-fields .setting label {
+ display: block;
+}
+
+.edit-attachment-frame .attachment-fields .setting .link-to-custom {
+ margin: 3px 0;
+}
+
+.edit-attachment-frame .attachment-fields .setting .name {
+ min-width: 30%;
+ margin-right: 4%;
+ font-size: 12px;
+ text-align: right;
+}
+
+.edit-attachment-frame .attachment-fields .setting select {
+ max-width: 65%;
+}
+
+.edit-attachment-frame .attachment-fields .setting input[type="checkbox"],
+.edit-attachment-frame .attachment-fields .field input[type="checkbox"] {
+ width: 16px;
+ float: none;
+ margin: 8px 3px 0;
+ padding: 0;
+}
+
+.edit-attachment-frame .attachment-fields .setting span {
+ float: left;
+ min-height: 22px;
+ padding-top: 8px;
+ line-height: 16px;
+ font-weight: normal;
+ color: #666;
+}
+
+.edit-attachment-frame .attachment-fields .setting input[type="text"],
+.edit-attachment-frame .attachment-fields .setting input[type="password"],
+.edit-attachment-frame .attachment-fields .setting input[type="number"],
+.edit-attachment-frame .attachment-fields .setting input[type="search"],
+.edit-attachment-frame .attachment-fields .setting input[type="email"],
+.edit-attachment-frame .attachment-fields .setting input[type="url"],
+.edit-attachment-frame .attachment-fields .setting textarea,
+.edit-attachment-frame .attachment-fields .setting .value {
+ margin: 1px;
+ width: 65%;
+ float: right;
+ padding: 6px 8px;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+.edit-attachment-frame .attachment-fields .setting textarea {
+ height: 62px;
+ resize: vertical;
+}
+
+.edit-attachment-frame .attachment-fields select {
+ margin-top: 3px;
+}
+
+.media-grid-view.hide-router .media-frame-title {
+ box-shadow: none;
+}
+
</ins><span class="cx"> .media-grid-view .media-frame-content {
</span><ins>+ background-color: transparent;
</ins><span class="cx"> bottom: 40px;
</span><span class="cx"> }
</span><span class="cx"> @media screen and (max-width: 782px) {
</span></span></pre></div>
<a id="trunksrcwpincludesjsmediaaudiovideojs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/media-audiovideo.js (28992 => 28993)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/media-audiovideo.js 2014-07-04 02:17:22 UTC (rev 28992)
+++ trunk/src/wp-includes/js/media-audiovideo.js 2014-07-04 03:38:33 UTC (rev 28993)
</span><span class="lines">@@ -26,6 +26,17 @@
</span><span class="cx"> }
</span><span class="cx"> },
</span><span class="cx">
</span><ins>+ removeAllPlayers: function() {
+ var p;
+
+ if ( window.mejs && window.mejs.players ) {
+ for ( p in window.mejs.players ) {
+ window.mejs.players[p].pause();
+ this.removePlayer( window.mejs.players[p] );
+ }
+ }
+ },
+
</ins><span class="cx"> /**
</span><span class="cx"> * Pauses the current object's instances of MediaElementPlayer
</span><span class="cx"> */
</span></span></pre></div>
<a id="trunksrcwpincludesjsmediagridjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/media-grid.js (28992 => 28993)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/media-grid.js 2014-07-04 02:17:22 UTC (rev 28992)
+++ trunk/src/wp-includes/js/media-grid.js 2014-07-04 03:38:33 UTC (rev 28993)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-(function( $, _, Backbone, wp ) {
</del><ins>+(function($, _, Backbone, wp) {
</ins><span class="cx"> var media = wp.media, l10n;
</span><span class="cx">
</span><span class="cx"> // Link any localized strings.
</span><span class="lines">@@ -10,6 +10,96 @@
</span><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /**
</span><ins>+ * A state for editing (cropping, etc.) an image.
+ *
+ * @constructor
+ * @augments wp.media.controller.State
+ * @augments Backbone.Model
+ */
+ media.controller.EditImageNoFrame = media.controller._State.extend({
+ defaults: {
+ id: 'edit-attachment',
+ title: l10n.editImage,
+ // Region mode defaults.
+ menu: false,
+ router: 'edit-metadata',
+ content: 'edit-metadata',
+ toolbar: 'toolbar',
+
+ url: ''
+ },
+
+ initialize: function() {
+ media.controller._State.prototype.initialize.apply( this, arguments );
+ },
+
+ activate: function() {
+ this.listenTo( this.frame, 'toolbar:render:edit-image', this.toolbar );
+ },
+
+ _postActivate: function() {
+ this._content();
+ this._router();
+ },
+
+ deactivate: function() {
+ this.stopListening( this.frame );
+ },
+
+ toolbar: function() {
+ var frame = this.frame,
+ lastState = frame.lastState(),
+ previous = lastState && lastState.id;
+
+ frame.toolbar.set( new media.view.Toolbar({
+ controller: frame,
+ items: {
+ back: {
+ style: 'primary',
+ text: l10n.back,
+ priority: 20,
+ click: function() {
+ if ( previous ) {
+ frame.setState( previous );
+ } else {
+ frame.close();
+ }
+ }
+ }
+ }
+ }) );
+ },
+
+ /**
+ * @access private
+ */
+ _router: function() {
+ var router = this.frame.router,
+ mode = this.get('router'),
+ view;
+
+ this.frame.$el.toggleClass( 'hide-router', ! mode );
+ if ( ! mode ) {
+ return;
+ }
+
+ this.frame.router.render( mode );
+
+ view = router.get();
+ if ( view && view.select ) {
+ view.select( this.frame.content.mode() );
+ }
+ },
+
+ _content: function() {
+ var mode = this.get( 'content' );
+ if ( mode ) {
+ this.frame[ 'content' ].render( mode );
+ }
+ }
+ });
+
+ /**
</ins><span class="cx"> * wp.media.view.MediaFrame.Manage
</span><span class="cx"> *
</span><span class="cx"> * A generic management frame workflow.
</span><span class="lines">@@ -36,7 +126,8 @@
</span><span class="cx"> library: {},
</span><span class="cx"> multiple: false,
</span><span class="cx"> state: 'library',
</span><del>- uploader: true
</del><ins>+ uploader: true,
+ mode: [ 'grid', 'edit' ]
</ins><span class="cx"> });
</span><span class="cx">
</span><span class="cx"> // Ensure core and media grid view UI is enabled.
</span><span class="lines">@@ -111,18 +202,59 @@
</span><span class="cx"> router: false,
</span><span class="cx"> content: 'browse',
</span><span class="cx"> filterable: 'mime-types'
</span><del>- }),
-
- new media.controller.EditImage( { model: options.editImage } )
</del><ins>+ })
</ins><span class="cx"> ]);
</span><span class="cx"> },
</span><span class="cx">
</span><span class="cx"> bindHandlers: function() {
</span><span class="cx"> this.on( 'content:create:browse', this.browseContent, this );
</span><span class="cx"> this.on( 'content:render:edit-image', this.editImageContent, this );
</span><ins>+
+ // Handle a frame-level event for editing an attachment.
+ this.on( 'edit:attachment', this.editAttachment, this );
+ this.on( 'edit:attachment:next', this.editNextAttachment, this );
+ this.on( 'edit:attachment:previous', this.editPreviousAttachment, this );
</ins><span class="cx"> },
</span><span class="cx">
</span><ins>+ editPreviousAttachment: function( currentModel ) {
+ var library = this.state().get('library'),
+ currentModelIndex = library.indexOf( currentModel );
+ this.trigger( 'edit:attachment', library.at( currentModelIndex - 1 ) );
+ },
+
+ editNextAttachment: function( currentModel ) {
+ var library = this.state().get('library'),
+ currentModelIndex = library.indexOf( currentModel );
+ this.trigger( 'edit:attachment', library.at( currentModelIndex + 1 ) );
+ },
+
</ins><span class="cx"> /**
</span><ins>+ * Open the Edit Attachment modal.
+ */
+ editAttachment: function( model ) {
+ var library = this.state().get('library'), hasPrevious, hasNext;
+ if ( library.indexOf( model ) > 0 ) {
+ hasPrevious = true;
+ }
+ else {
+ hasPrevious = false;
+ }
+ if ( library.indexOf( model ) < library.length - 1 ) {
+ hasNext = true;
+ }
+ else {
+ hasNext = false;
+ }
+
+ new media.view.Frame.EditAttachment({
+ hasPrevious: hasPrevious,
+ hasNext: hasNext,
+ model: model,
+ gridController: this
+ });
+ },
+
+ /**
</ins><span class="cx"> * Content
</span><span class="cx"> *
</span><span class="cx"> * @param {Object} content
</span><span class="lines">@@ -143,6 +275,7 @@
</span><span class="cx"> display: state.get('displaySettings'),
</span><span class="cx"> dragInfo: state.get('dragInfo'),
</span><span class="cx"> bulkEdit: true,
</span><ins>+ sidebar: false,
</ins><span class="cx">
</span><span class="cx"> suggestedWidth: state.get('suggestedWidth'),
</span><span class="cx"> suggestedHeight: state.get('suggestedHeight'),
</span><span class="lines">@@ -162,5 +295,194 @@
</span><span class="cx">
</span><span class="cx"> }
</span><span class="cx"> });
</span><del>-
-}( jQuery, _, Backbone, wp ));
</del><span class="cx">\ No newline at end of file
</span><ins>+
+ media.view.Attachment.Details.TwoColumn = media.view.Attachment.Details.extend({
+ template: wp.template( 'attachment-details-two-column' ),
+
+ initialize: function() {
+ this.$el.attr('aria-label', this.model.attributes.title).attr('aria-checked', false);
+ this.model.on( 'change:sizes change:uploading', this.render, this );
+ this.model.on( 'change:title', this._syncTitle, this );
+ this.model.on( 'change:caption', this._syncCaption, this );
+ this.model.on( 'change:percent', this.progress, this );
+
+ // Update the selection.
+ this.model.on( 'add', this.select, this );
+ this.model.on( 'remove', this.deselect, this );
+ },
+
+ render: function() {
+ media.view.Attachment.Details.prototype.render.apply( this, arguments );
+
+ media.mixin.removeAllPlayers();
+ $( 'audio, video', this.$el ).each( function (i, elem) {
+ var el = media.view.MediaDetails.prepareSrc( elem );
+ new MediaElementPlayer( el, media.mixin.mejsSettings );
+ } );
+ }
+ });
+
+ /**
+ * A frame for editing the details of a specific media item.
+ *
+ * Opens in a modal by default.
+ *
+ * Requires an attachment model to be passed in the options hash under `model`.
+ */
+ media.view.Frame.EditAttachment = media.view.Frame.extend({
+
+ className: 'edit-attachment-frame',
+ template: media.template( 'edit-attachment-frame' ),
+ regions: [ 'router', 'content' ],
+
+ events: {
+ 'click': 'collapse',
+ 'click .delete-media-item': 'deleteMediaItem',
+ 'click .left': 'previousMediaItem',
+ 'click .right': 'nextMediaItem'
+ },
+
+ initialize: function( options ) {
+ var self = this;
+ media.view.Frame.prototype.initialize.apply( this, arguments );
+
+ _.defaults( this.options, {
+ modal: true,
+ state: 'edit-attachment'
+ });
+
+ this.createStates();
+
+ this.on( 'content:render:edit-metadata', this.editMetadataContent, this );
+ this.on( 'content:render:edit-image', this.editImageContentUgh, this );
+
+ // Only need a tab to Edit Image for images.
+ if ( this.model.get( 'type' ) === 'image' ) {
+ this.on( 'router:create', this.createRouter, this );
+ this.on( 'router:render', this.browseRouter, this );
+ }
+
+ // Initialize modal container view.
+ if ( this.options.modal ) {
+ this.modal = new media.view.Modal({
+ controller: this,
+ title: this.options.title
+ });
+
+ // Completely destroy the modal DOM element when closing it.
+ this.modal.close = function() {
+ self.modal.remove();
+ };
+
+ this.modal.content( this );
+ this.modal.open();
+ }
+ },
+
+ /**
+ * Add the default states to the frame.
+ */
+ createStates: function() {
+ this.states.add([
+ new media.controller.EditImageNoFrame( { model: this.model } )
+ ]);
+ },
+
+ /**
+ * @returns {wp.media.view.MediaFrame} Returns itself to allow chaining
+ */
+ render: function() {
+ // Activate the default state if no active state exists.
+ if ( ! this.state() && this.options.state ) {
+ this.setState( this.options.state );
+ }
+ /**
+ * call 'render' directly on the parent class
+ */
+ return media.view.Frame.prototype.render.apply( this, arguments );
+ },
+
+ /**
+ * Content region rendering callback for the `edit-metadata` mode.
+ */
+ editMetadataContent: function() {
+ var view = new media.view.Attachment.Details.TwoColumn({
+ controller: this,
+ model: this.model
+ });
+ this.content.set( view );
+ },
+
+ /**
+ * For some reason the view doesn't exist in the DOM yet, don't have the
+ * patience to track this down right now.
+ */
+ editImageContentUgh: function() {
+ _.defer( _.bind( this.editImageContent, this ) );
+ },
+
+ /**
+ * Render the EditImage view into the frame's content region.
+ */
+ editImageContent: function() {
+ var view = new media.view.EditImage( { model: this.model, controller: this } ).render();
+
+ this.content.set( view );
+
+ // after creating the wrapper view, load the actual editor via an ajax call
+ view.loadEditor();
+ },
+
+ /**
+ * Create the router view.
+ *
+ * @param {Object} router
+ * @this wp.media.controller.Region
+ */
+ createRouter: function( router ) {
+ router.view = new media.view.Router({
+ controller: this
+ });
+ },
+
+ /**
+ * Router rendering callback.
+ *
+ * @param media.view.Router view Instantiated in this.createRouter()
+ */
+ browseRouter: function( view ) {
+ view.set({
+ 'edit-metadata': {
+ text: 'Edit Metadata',
+ priority: 20
+ },
+ 'edit-image': {
+ text: 'Edit Image',
+ priority: 40
+ }
+ });
+ },
+
+ /**
+ * Click handler to switch to the previous media item.
+ */
+ previousMediaItem: function() {
+ if ( ! this.options.hasPrevious )
+ return;
+ this.modal.close();
+ this.options.gridController.trigger( 'edit:attachment:previous', this.model );
+ },
+
+ /**
+ * Click handler to switch to the next media item.
+ */
+ nextMediaItem: function() {
+ if ( ! this.options.hasNext )
+ return;
+ this.modal.close();
+ this.options.gridController.trigger( 'edit:attachment:next', this.model );
+ }
+
+ });
+
+}(jQuery, _, Backbone, wp));
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunksrcwpincludesjsmediaviewsjs"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/js/media-views.js (28992 => 28993)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/js/media-views.js 2014-07-04 02:17:22 UTC (rev 28992)
+++ trunk/src/wp-includes/js/media-views.js 2014-07-04 03:38:33 UTC (rev 28993)
</span><span class="lines">@@ -337,16 +337,11 @@
</span><span class="cx"> });
</span><span class="cx">
</span><span class="cx"> /**
</span><del>- * wp.media.controller.State
- *
- * A state is a step in a workflow that when set will trigger the controllers
- * for the regions to be updated as specified in the frame. This is the base
- * class that the various states used in wp.media extend.
- *
- * @constructor
- * @augments Backbone.Model
</del><ins>+ * A more abstracted state, because media.controller.State expects
+ * specific regions (menu, title, etc.) to exist on the frame, which do not
+ * exist in media.view.Frame.EditAttachment.
</ins><span class="cx"> */
</span><del>- media.controller.State = Backbone.Model.extend({
</del><ins>+ media.controller._State = Backbone.Model.extend({
</ins><span class="cx"> constructor: function() {
</span><span class="cx"> this.on( 'activate', this._preActivate, this );
</span><span class="cx"> this.on( 'activate', this.activate, this );
</span><span class="lines">@@ -354,13 +349,11 @@
</span><span class="cx"> this.on( 'deactivate', this._deactivate, this );
</span><span class="cx"> this.on( 'deactivate', this.deactivate, this );
</span><span class="cx"> this.on( 'reset', this.reset, this );
</span><del>- this.on( 'ready', this._ready, this );
</del><span class="cx"> this.on( 'ready', this.ready, this );
</span><span class="cx"> /**
</span><span class="cx"> * Call parent constructor with passed arguments
</span><span class="cx"> */
</span><span class="cx"> Backbone.Model.apply( this, arguments );
</span><del>- this.on( 'change:menu', this._updateMenu, this );
</del><span class="cx"> },
</span><span class="cx">
</span><span class="cx"> /**
</span><span class="lines">@@ -382,18 +375,58 @@
</span><span class="cx"> /**
</span><span class="cx"> * @access private
</span><span class="cx"> */
</span><del>- _ready: function() {
- this._updateMenu();
</del><ins>+ _preActivate: function() {
+ this.active = true;
</ins><span class="cx"> },
</span><span class="cx"> /**
</span><span class="cx"> * @access private
</span><span class="cx"> */
</span><del>- _preActivate: function() {
- this.active = true;
</del><ins>+ _postActivate: function() {},
+ /**
+ * @access private
+ */
+ _deactivate: function() {
+ this.active = false;
+ }
+ });
+
+ /**
+ * wp.media.controller.State
+ *
+ * A state is a step in a workflow that when set will trigger the controllers
+ * for the regions to be updated as specified in the frame. This is the base
+ * class that the various states used in wp.media extend.
+ *
+ * @constructor
+ * @augments Backbone.Model
+ */
+ media.controller.State = media.controller._State.extend({
+ constructor: function() {
+ this.on( 'activate', this._preActivate, this );
+ this.on( 'activate', this.activate, this );
+ this.on( 'activate', this._postActivate, this );
+ this.on( 'deactivate', this._deactivate, this );
+ this.on( 'deactivate', this.deactivate, this );
+ this.on( 'reset', this.reset, this );
+ this.on( 'ready', this._ready, this );
+ this.on( 'ready', this.ready, this );
+ /**
+ * Call parent constructor with passed arguments
+ */
+ Backbone.Model.apply( this, arguments );
+ this.on( 'change:menu', this._updateMenu, this );
</ins><span class="cx"> },
</span><ins>+
</ins><span class="cx"> /**
</span><span class="cx"> * @access private
</span><span class="cx"> */
</span><ins>+ _ready: function() {
+ this._updateMenu();
+ },
+
+ /**
+ * @access private
+ */
</ins><span class="cx"> _postActivate: function() {
</span><span class="cx"> this.on( 'change:menu', this._menu, this );
</span><span class="cx"> this.on( 'change:titleMode', this._title, this );
</span><span class="lines">@@ -1758,7 +1791,8 @@
</span><span class="cx"> _.defaults( this.options, {
</span><span class="cx"> title: '',
</span><span class="cx"> modal: true,
</span><del>- uploader: true
</del><ins>+ uploader: true,
+ mode: ['select']
</ins><span class="cx"> });
</span><span class="cx">
</span><span class="cx"> // Ensure core UI is enabled.
</span><span class="lines">@@ -4530,7 +4564,7 @@
</span><span class="cx"> var selection = this.options.selection;
</span><span class="cx">
</span><span class="cx"> this.$el.attr('aria-label', this.model.attributes.title).attr('aria-checked', false);
</span><del>- this.model.on( 'change:sizes change:uploading', this.render, this );
</del><ins>+ this.model.on( 'change', this.render, this );
</ins><span class="cx"> this.model.on( 'change:title', this._syncTitle, this );
</span><span class="cx"> this.model.on( 'change:caption', this._syncCaption, this );
</span><span class="cx"> this.model.on( 'change:percent', this.progress, this );
</span><span class="lines">@@ -4583,7 +4617,7 @@
</span><span class="cx"> compat: false,
</span><span class="cx"> alt: '',
</span><span class="cx"> description: ''
</span><del>- });
</del><ins>+ }, this.options );
</ins><span class="cx">
</span><span class="cx"> options.buttons = this.buttons;
</span><span class="cx"> options.describe = this.controller.state().get('describe');
</span><span class="lines">@@ -4633,11 +4667,17 @@
</span><span class="cx"> */
</span><span class="cx"> toggleSelectionHandler: function( event ) {
</span><span class="cx"> var method;
</span><del>-
</del><span class="cx"> // Catch enter and space events
</span><span class="cx"> if ( 'keydown' === event.type && 13 !== event.keyCode && 32 !== event.keyCode ) {
</span><span class="cx"> return;
</span><span class="cx"> }
</span><ins>+
+ // In the grid view, bubble up an edit:attachment event to the controller.
+ if ( _.contains( this.controller.options.mode, 'grid' ) ) {
+ this.controller.trigger( 'edit:attachment', this.model );
+ return;
+ }
+
</ins><span class="cx"> if ( event.shiftKey ) {
</span><span class="cx"> method = 'between';
</span><span class="cx"> } else if ( event.ctrlKey || event.metaKey ) {
</span><span class="lines">@@ -5168,10 +5208,11 @@
</span><span class="cx"> */
</span><span class="cx"> createAttachmentView: function( attachment ) {
</span><span class="cx"> var view = new this.options.AttachmentView({
</span><del>- controller: this.controller,
- model: attachment,
- collection: this.collection,
- selection: this.options.selection
</del><ins>+ controller: this.controller,
+ model: attachment,
+ collection: this.collection,
+ selection: this.options.selection,
+ showAttachmentFields: this.options.showAttachmentFields
</ins><span class="cx"> });
</span><span class="cx">
</span><span class="cx"> return this._viewsByCid[ attachment.cid ] = view;
</span><span class="lines">@@ -5468,7 +5509,6 @@
</span><span class="cx"> }
</span><span class="cx"> });
</span><span class="cx">
</span><del>-
</del><span class="cx"> /**
</span><span class="cx"> * wp.media.view.AttachmentsBrowser
</span><span class="cx"> *
</span><span class="lines">@@ -5486,13 +5526,18 @@
</span><span class="cx"> filters: false,
</span><span class="cx"> search: true,
</span><span class="cx"> display: false,
</span><del>-
</del><ins>+ sidebar: true,
+ showAttachmentFields: getUserSetting( 'showAttachmentFields', [ 'title', 'uploadedTo', 'dateFormatted', 'mime' ] ),
</ins><span class="cx"> AttachmentView: media.view.Attachment.Library
</span><span class="cx"> });
</span><span class="cx">
</span><span class="cx"> this.createToolbar();
</span><span class="cx"> this.updateContent();
</span><del>- this.createSidebar();
</del><ins>+ if ( this.options.sidebar ) {
+ this.createSidebar();
+ } else {
+ this.$el.addClass( 'hide-sidebar' );
+ }
</ins><span class="cx">
</span><span class="cx"> this.collection.on( 'add remove reset', this.updateContent, this );
</span><span class="cx"> },
</span><span class="lines">@@ -5517,6 +5562,20 @@
</span><span class="cx">
</span><span class="cx"> this.views.add( this.toolbar );
</span><span class="cx">
</span><ins>+ // Feels odd to bring the global media library switcher into the Attachment
+ // browser view. Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar );
+ // which the controller can tap into and add this view?
+ if ( _.contains( this.controller.options.mode, 'grid' ) ) {
+ var libraryViewSwitcherConstructor = media.View.extend({
+ className: 'view-switch media-grid-view-switch',
+ template: media.template( 'media-library-view-switcher')
+ });
+ this.toolbar.set( 'libraryViewSwitcher', new libraryViewSwitcherConstructor({
+ controller: this.controller,
+ priority: -90
+ }).render() );
+ }
+
</ins><span class="cx"> filters = this.options.filters;
</span><span class="cx"> if ( 'uploaded' === filters ) {
</span><span class="cx"> FiltersConstructor = media.view.AttachmentFilters.Uploaded;
</span><span class="lines">@@ -5611,11 +5670,12 @@
</span><span class="cx"> this.removeContent();
</span><span class="cx">
</span><span class="cx"> this.attachments = new media.view.Attachments({
</span><del>- controller: this.controller,
- collection: this.collection,
- selection: this.options.selection,
- model: this.model,
- sortable: this.options.sortable,
</del><ins>+ controller: this.controller,
+ collection: this.collection,
+ selection: this.options.selection,
+ model: this.model,
+ sortable: this.options.sortable,
+ showAttachmentFields: this.options.showAttachmentFields,
</ins><span class="cx">
</span><span class="cx"> // The single `Attachment` view to be used in the `Attachments` view.
</span><span class="cx"> AttachmentView: this.options.AttachmentView
</span></span></pre></div>
<a id="trunksrcwpincludesmediatemplatephp"></a>
<div class="modfile"><h4>Modified: trunk/src/wp-includes/media-template.php (28992 => 28993)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/src/wp-includes/media-template.php 2014-07-04 02:17:22 UTC (rev 28992)
+++ trunk/src/wp-includes/media-template.php 2014-07-04 03:38:33 UTC (rev 28993)
</span><span class="lines">@@ -220,6 +220,15 @@
</span><span class="cx"> </div>
</span><span class="cx"> </script>
</span><span class="cx">
</span><ins>+ <script type="text/html" id="tmpl-media-library-view-switcher">
+ <a href="<?php echo esc_url( add_query_arg( 'mode', 'list', $_SERVER['REQUEST_URI'] ) ) ?>" class="view-list">
+ <img id="view-switch-list" src="<?php echo includes_url( 'images/blank.gif' ) ?>" width="20" height="20" title="List View" alt="List View"/>
+ </a>
+ <a href="<?php echo esc_url( add_query_arg( 'mode', 'grid', $_SERVER['REQUEST_URI'] ) ) ?>" class="view-grid current">
+ <img id="view-switch-excerpt" src="<?php echo includes_url( 'images/blank.gif' ) ?>" width="20" height="20" title="Grid View" alt="Grid View"/>
+ </a>
+ </script>
+
</ins><span class="cx"> <script type="text/html" id="tmpl-uploader-status">
</span><span class="cx"> <h3><?php _e( 'Uploading' ); ?></h3>
</span><span class="cx"> <a class="upload-dismiss-errors" href="#"><?php _e('Dismiss Errors'); ?></a>
</span><span class="lines">@@ -241,7 +250,128 @@
</span><span class="cx"> <span class="upload-error-message">{{ data.message }}</span>
</span><span class="cx"> </script>
</span><span class="cx">
</span><ins>+ <script type="text/html" id="tmpl-edit-attachment-frame">
+ <div class="edit-media-header">
+ <button class="left dashicons dashicons-no<# if ( ! data.hasPrevious ) { #> disabled <# } #>"><span class="screen-reader-text"><?php _e( 'Edit previous media item' ); ?></span></button>
+ <button class="right dashicons dashicons-no<# if ( ! data.hasNext ) { #> disabled <# } #>"><span class="screen-reader-text"><?php _e( 'Edit next media item' ); ?></span></button>
+ </div>
+ <div class="media-frame-router"></div>
+ <div class="media-frame-content"></div>
+ <div class="media-frame-toolbar"></div>
+ </script>
+
+ <script type="text/html" id="tmpl-attachment-details-two-column">
+ <h3>
+ <?php _e('Attachment Details'); ?>
+
+ <span class="settings-save-status">
+ <span class="spinner"></span>
+ <span class="saved"><?php esc_html_e('Saved.'); ?></span>
+ </span>
+ </h3>
+ <div class="attachment-info">
+ <div class="thumbnail thumbnail-{{ data.type }}">
+ <# if ( data.uploading ) { #>
+ <div class="media-progress-bar"><div></div></div>
+ <# } else if ( 'image' === data.type ) { #>
+ <img src="{{ data.sizes.full.url }}" draggable="false" />
+ <# } else { #>
+ <img src="{{ data.icon }}" class="icon" draggable="false" />
+ <# } #>
+ </div>
+ <div class="details">
+ <div class="filename">{{ data.filename }}</div>
+ <div class="uploaded">{{ data.dateFormatted }}</div>
+
+ <div class="file-size">{{ data.filesizeHumanReadable }}</div>
+ <# if ( 'image' === data.type && ! data.uploading ) { #>
+ <# if ( data.width && data.height ) { #>
+ <div class="dimensions">{{ data.width }} × {{ data.height }}</div>
+ <# } #>
+
+ <# if ( data.can.save ) { #>
+ <a class="edit-attachment" href="{{ data.editLink }}&image-editor" target="_blank"><?php _e( 'Edit Image' ); ?></a>
+ <a class="refresh-attachment" href="#"><?php _e( 'Refresh' ); ?></a>
+ <# } #>
+ <# } #>
+
+ <# if ( data.fileLength ) { #>
+ <div class="file-length"><?php _e( 'Length:' ); ?> {{ data.fileLength }}</div>
+ <# } #>
+
+ <# if ( ! data.uploading && data.can.remove ) { #>
+ <?php if ( MEDIA_TRASH ): ?>
+ <a class="trash-attachment" href="#"><?php _e( 'Trash' ); ?></a>
+ <?php else: ?>
+ <a class="delete-attachment" href="#"><?php _e( 'Delete Permanently' ); ?></a>
+ <?php endif; ?>
+ <# } #>
+
+ <div class="compat-meta">
+ <# if ( data.compat && data.compat.meta ) { #>
+ {{{ data.compat.meta }}}
+ <# } #>
+ </div>
+ </div>
+ <# if ( 'audio' === data.type ) { #>
+ <div class="wp-media-wrapper">
+ <audio style="visibility: hidden" controls class="wp-audio-shortcode" width="100%" preload="none">
+ <source type="{{ data.mime }}" src="{{ data.url }}"/>
+ </audio>
+ </div>
+ <# } else if ( 'video' === data.type ) { #>
+ <div style="max-width: 100%; width: {{ data.width }}px" class="wp-media-wrapper">
+ <video controls class="wp-video-shortcode" preload="metadata"
+ width="{{ data.width }}" height="{{ data.height }}"
+ <# if ( data.image && data.image.src !== data.icon ) { #>poster="{{ data.image.src }}"<# } #>>
+ <source type="{{ data.mime }}" src="{{ data.url }}"/>
+ </video>
+ </div>
+ <# } #>
+ </div>
+ <div class="attachment-fields">
+ <label class="setting" data-setting="url">
+ <span class="name"><?php _e('URL'); ?></span>
+ <input type="text" value="{{ data.url }}" readonly />
+ </label>
+ <# var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly'; #>
+ <label class="setting" data-setting="title">
+ <span class="name"><?php _e('Title'); ?></span>
+ <input type="text" value="{{ data.title }}" {{ maybeReadOnly }} />
+ </label>
+ <label class="setting" data-setting="caption">
+ <span class="name"><?php _e('Caption'); ?></span>
+ <textarea {{ maybeReadOnly }}>{{ data.caption }}</textarea>
+ </label>
+ <# if ( 'image' === data.type ) { #>
+ <label class="setting" data-setting="alt">
+ <span class="name"><?php _e('Alt Text'); ?></span>
+ <input type="text" value="{{ data.alt }}" {{ maybeReadOnly }} />
+ </label>
+ <# } #>
+ <label class="setting" data-setting="description">
+ <span class="name"><?php _e('Description'); ?></span>
+ <textarea {{ maybeReadOnly }}>{{ data.description }}</textarea>
+ </label>
+ <label class="setting">
+ <span class="name"><?php _e( 'Uploaded By' ); ?></span>
+ <span class="value">{{ data.authorName }}</span>
+ </label>
+ <# if ( data.uploadedTo ) { #>
+ <label class="setting">
+ <span class="name"><?php _e('Uploaded To'); ?></span>
+ <span class="value"><a href="{{ data.uploadedToLink }}">{{ data.uploadedToTitle }}</a></span>
+ </label>
+ <# } #>
+ </div>
+ </script>
+
</ins><span class="cx"> <script type="text/html" id="tmpl-attachment">
</span><ins>+ <# if ( _.contains( data.controller.options.mode, 'grid' ) ) { #>
+ <div class="inline-toolbar">
+ <div class="dashicons dashicons-edit edit edit-media"></div>
+ </div>
+ <# } #>
</ins><span class="cx"> <div class="attachment-preview type-{{ data.type }} subtype-{{ data.subtype }} {{ data.orientation }}">
</span><span class="cx"> <# if ( data.uploading ) { #>
</span><span class="cx"> <div class="media-progress-bar"><div></div></div>
</span><span class="lines">@@ -251,13 +381,15 @@
</span><span class="cx"> <img src="{{ data.size.url }}" draggable="false" alt="" />
</span><span class="cx"> </div>
</span><span class="cx"> </div>
</span><del>- <# } else { #>
</del><ins>+ <# } else {
+ if ( data.thumb && data.thumb.src && data.thumb.src !== data.icon ) {
+ #><img src="{{ data.thumb.src }}" class="thumbnail" draggable="false" /><#
+ } #>
</ins><span class="cx"> <img src="{{ data.icon }}" class="icon" draggable="false" />
</span><span class="cx"> <div class="filename">
</span><span class="cx"> <div>{{ data.filename }}</div>
</span><span class="cx"> </div>
</span><span class="cx"> <# } #>
</span><del>-
</del><span class="cx"> <# if ( data.buttons.close ) { #>
</span><span class="cx"> <a class="close media-modal-icon" href="#" title="<?php esc_attr_e('Remove'); ?>"></a>
</span><span class="cx"> <# } #>
</span><span class="lines">@@ -268,8 +400,8 @@
</span><span class="cx"> </div>
</span><span class="cx"> <#
</span><span class="cx"> var maybeReadOnly = data.can.save || data.allowLocalEdits ? '' : 'readonly';
</span><del>- if ( data.describe ) { #>
- <# if ( 'image' === data.type ) { #>
</del><ins>+ if ( data.describe ) {
+ if ( 'image' === data.type ) { #>
</ins><span class="cx"> <input type="text" value="{{ data.caption }}" class="describe" data-setting="caption"
</span><span class="cx"> placeholder="<?php esc_attr_e('Caption this image…'); ?>" {{ maybeReadOnly }} />
</span><span class="cx"> <# } else { #>
</span><span class="lines">@@ -281,8 +413,31 @@
</span><span class="cx"> <# } else { #>
</span><span class="cx"> placeholder="<?php esc_attr_e('Describe this media file…'); ?>"
</span><span class="cx"> <# } #> {{ maybeReadOnly }} />
</span><del>- <# } #>
</del><ins>+ <# }
+ }
+
+ if ( _.contains( data.controller.options.mode, 'grid' ) ) { #>
+ <div class="data-fields">
+ <# _.each( data.showAttachmentFields, function( field ) { #>
+ <div class="data-field data-{{ field }}"><#
+ if ( 'uploadedTo' === field ) {
+ if ( data[field] ) {
+ #><?php _e( 'Uploaded To:' ) ?><#
+ } else {
+ #><?php _e( 'Unattached' ) ?><#
+ }
+ } else if ( 'title' === field && ! data[ field ] ) {
+ #><?php _e( '(No title)' ) ?><#
+ }
+
+ if ( data[ field ] ) {
+ #>{{ data[ field ] }}<#
+ }
+ #></div>
+ <# }); #>
+ </div>
</ins><span class="cx"> <# } #>
</span><ins>+
</ins><span class="cx"> </script>
</span><span class="cx">
</span><span class="cx"> <script type="text/html" id="tmpl-attachment-details">
</span></span></pre>
</div>
</div>
</body>
</html>