Caption editing in the media modal library.

* Adds a `describe` option to the workflow controller to support inline caption editing.
* For images, descriptions are mapped to the `caption` attribute.
* For other media items, descriptions are mapped to the `title` attribute.
* Descriptions are saved when the textarea's `change` event fires (i.e. when the textarea is blurred).

fixes #21807, see #21390.


git-svn-id: http://core.svn.wordpress.org/trunk@22173 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
Daryl Koopersmith 2012-10-10 23:32:48 +00:00
parent d71143817e
commit 1daa774b27
8 changed files with 113 additions and 25 deletions

View File

@ -53,7 +53,8 @@ $core_actions_post = array(
'menu-locations-save', 'menu-quick-search', 'meta-box-order', 'get-permalink', 'menu-locations-save', 'menu-quick-search', 'meta-box-order', 'get-permalink',
'sample-permalink', 'inline-save', 'inline-save-tax', 'find_posts', 'widgets-order', 'sample-permalink', 'inline-save', 'inline-save-tax', 'find_posts', 'widgets-order',
'save-widget', 'set-post-thumbnail', 'date_format', 'time_format', 'wp-fullscreen-save-post', 'save-widget', 'set-post-thumbnail', 'date_format', 'time_format', 'wp-fullscreen-save-post',
'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment', 'query-attachments', 'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment',
'query-attachments', 'save-attachment',
); );
// Register core Ajax calls. // Register core Ajax calls.

View File

@ -1820,3 +1820,33 @@ function wp_ajax_query_attachments() {
wp_send_json_success( $posts ); wp_send_json_success( $posts );
} }
/**
* Save attachment attributes.
*
* @since 3.5.0
*/
function wp_ajax_save_attachment() {
if ( ! isset( $_REQUEST['id'] ) || ! isset( $_REQUEST['changes'] ) )
wp_send_json_error();
if ( ! $id = absint( $_REQUEST['id'] ) )
wp_send_json_error();
if ( ! current_user_can( 'edit_post', $id ) )
wp_send_json_error();
$changes = $_REQUEST['changes'];
$args = array();
if ( $changes['title'] )
$args['post_title'] = $changes['title'];
if ( $changes['caption'] )
$args['post_excerpt'] = $changes['caption'];
if ( $args )
wp_update_post( array_merge( $args, array( 'ID' => $id ) ) );
wp_send_json_success();
}

View File

@ -104,7 +104,8 @@ var tb_position;
workflow = workflows[ id ] = wp.media( _.defaults( options || {}, { workflow = workflows[ id ] = wp.media( _.defaults( options || {}, {
title: wp.media.view.l10n.insertMedia, title: wp.media.view.l10n.insertMedia,
multiple: true multiple: true,
describe: true
} ) ); } ) );
workflow.on( 'update:insert', function( selection ) { workflow.on( 'update:insert', function( selection ) {

View File

@ -246,16 +246,9 @@
.attachment { .attachment {
position: relative; position: relative;
float: left; float: left;
width: 199px;
height: 199px;
padding: 0; padding: 0;
margin: 0 10px 20px; margin: 0 10px 20px;
box-shadow:
inset 0 0 15px rgba( 0, 0, 0, 0.1 ),
inset 0 0 0 1px rgba( 0, 0, 0, 0.05 );
background: #eee;
cursor: pointer;
color: #464646; color: #464646;
-webkit-user-select: none; -webkit-user-select: none;
@ -281,12 +274,15 @@
} }
.attachment-preview { .attachment-preview {
position: absolute; position: relative;
top: 0; width: 199px;
left: 0; height: 199px;
right: 0;
bottom: 0;
overflow: hidden; overflow: hidden;
box-shadow:
inset 0 0 15px rgba( 0, 0, 0, 0.1 ),
inset 0 0 0 1px rgba( 0, 0, 0, 0.05 );
background: #eee;
cursor: pointer;
} }
.attachment .icon, .attachment .icon,
@ -390,6 +386,18 @@
display: block; display: block;
} }
.attachment .describe {
position: relative;
display: block;
width: 100%;
height: 66px;
margin: -1px 0 0;
padding: 8px;
font-size: 12px;
resize: none;
border-radius: 0;
}
/* Square crop with overflow visible on hover. */ /* Square crop with overflow visible on hover. */
/* /*

View File

@ -639,7 +639,8 @@ window.wp = window.wp || {};
selection: this.attachments.models, selection: this.attachments.models,
title: mceview.l10n.editGallery, title: mceview.l10n.editGallery,
editing: true, editing: true,
multiple: true multiple: true,
describe: true
}); });
// Create a single-use workflow. If the workflow is closed, // Create a single-use workflow. If the workflow is closed,

View File

@ -174,7 +174,7 @@ window.wp = window.wp || {};
*/ */
Attachment = media.model.Attachment = Backbone.Model.extend({ Attachment = media.model.Attachment = Backbone.Model.extend({
sync: function( method, model, options ) { sync: function( method, model, options ) {
// Overload the read method so Attachment.fetch() functions correctly. // Overload the `read` request so Attachment.fetch() functions correctly.
if ( 'read' === method ) { if ( 'read' === method ) {
options = options || {}; options = options || {};
options.context = this; options.context = this;
@ -184,13 +184,35 @@ window.wp = window.wp || {};
}); });
return media.ajax( options ); return media.ajax( options );
// Otherwise, fall back to Backbone.sync() // Overload the `update` request so properties can be saved.
} else { } else if ( 'update' === method ) {
return Backbone.sync.apply( this, arguments ); options = options || {};
options.context = this;
// Set the action and ID.
options.data = _.extend( options.data || {}, {
action: 'save-attachment',
id: this.id
});
// Record the values of the changed attributes.
if ( options.changes ) {
_.each( options.changes, function( value, key ) {
options.changes[ key ] = this.get( key );
}, this );
options.data.changes = options.changes;
delete options.changes;
}
return media.ajax( options );
} }
}, },
parse: function( resp, xhr ) { parse: function( resp, xhr ) {
if ( ! resp )
return resp;
// Convert date strings into Date objects. // Convert date strings into Date objects.
resp.date = new Date( resp.date ); resp.date = new Date( resp.date );
resp.modified = new Date( resp.modified ); resp.modified = new Date( resp.modified );

View File

@ -385,9 +385,10 @@
template: media.template('attachment'), template: media.template('attachment'),
events: { events: {
'click': 'toggleSelection', 'click .attachment-preview': 'toggleSelection',
'mouseenter': 'shrink', 'mouseenter .attachment-preview': 'shrink',
'mouseleave': 'expand' 'mouseleave .attachment-preview': 'expand',
'change .describe': 'describe'
}, },
buttons: {}, buttons: {},
@ -415,7 +416,8 @@
filename: '' filename: ''
}); });
options.buttons = this.buttons; options.buttons = this.buttons;
options.describe = this.controller.get('describe');
if ( 'image' === options.type ) if ( 'image' === options.type )
_.extend( options, this.crop() ); _.extend( options, this.crop() );
@ -533,6 +535,13 @@
width: 199, width: 199,
height: 199 height: 199
}); });
},
describe: function( event ) {
if ( 'image' === this.model.get('type') )
this.model.save( 'caption', event.target.value );
else
this.model.save( 'title', event.target.value );
} }
}); });
@ -817,7 +826,7 @@
template: media.template('attachments'), template: media.template('attachments'),
events: { events: {
'keyup input': 'search' 'keyup .search': 'search'
}, },
initialize: function() { initialize: function() {

View File

@ -1345,7 +1345,23 @@ function wp_print_media_templates( $attachment ) {
<a class="close" href="#">&times;</a> <a class="close" href="#">&times;</a>
<% } %> <% } %>
</div> </div>
<div class="describe"></div> <% if ( describe ) { %>
<% if ( 'image' === type ) { %>
<textarea class="describe"
placeholder="<?php esc_attr_e('Describe this image&hellip;'); ?>"
><%- caption %></textarea>
<% } else { %>
<textarea class="describe"
<% if ( 'video' === type ) { %>
placeholder="<?php esc_attr_e('Describe this video&hellip;'); ?>"
<% } else if ( 'audio' === type ) { %>
placeholder="<?php esc_attr_e('Describe this audio file&hellip;'); ?>"
<% } else { %>
placeholder="<?php esc_attr_e('Describe this media file&hellip;'); ?>"
<% } %>
><%- title %></textarea>
<% } %>
<% } %>
</script> </script>
<script type="text/html" id="tmpl-media-selection-preview"> <script type="text/html" id="tmpl-media-selection-preview">