Introduce Edit Image (single mode) in the media modal and use it to edit images inserted in the editor. Adds new feature: replace an image in the editor. Props gcorne, see #24409.
Built from https://develop.svn.wordpress.org/trunk@27050 git-svn-id: http://core.svn.wordpress.org/trunk@26924 1a063a9b-81f0-0310-95a4-ce76da25c4cd
This commit is contained in:
parent
9172107539
commit
33eedc570b
|
@ -228,7 +228,6 @@ final class _WP_Editors {
|
|||
'paste',
|
||||
'tabfocus',
|
||||
'textcolor',
|
||||
'image',
|
||||
'fullscreen',
|
||||
'wordpress',
|
||||
'wpeditimage',
|
||||
|
|
|
@ -86,6 +86,10 @@
|
|||
color: #a9a9a9;
|
||||
}
|
||||
|
||||
.media-frame .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Enable draggable on IE10 touch events until it's rolled into jQuery UI core */
|
||||
.ui-sortable,
|
||||
.ui-draggable {
|
||||
|
@ -1411,7 +1415,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* Embed from URL
|
||||
* Embed from URL and Image Details
|
||||
*/
|
||||
.embed-url {
|
||||
display: block;
|
||||
|
@ -1452,6 +1456,10 @@
|
|||
overflow: auto;
|
||||
}
|
||||
|
||||
.image-details .embed-image-settings {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.media-embed .thumbnail {
|
||||
max-width: 100%;
|
||||
max-height: 200px;
|
||||
|
@ -1484,6 +1492,10 @@
|
|||
clear: both;
|
||||
}
|
||||
|
||||
.media-embed .setting .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.media-embed .setting span {
|
||||
display: block;
|
||||
width: 200px;
|
||||
|
@ -1926,4 +1938,4 @@
|
|||
.media-frame .spinner {
|
||||
background-image: url('../images/spinner-2x.gif');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -86,6 +86,10 @@
|
|||
color: #a9a9a9;
|
||||
}
|
||||
|
||||
.media-frame .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Enable draggable on IE10 touch events until it's rolled into jQuery UI core */
|
||||
.ui-sortable,
|
||||
.ui-draggable {
|
||||
|
@ -1411,7 +1415,7 @@
|
|||
}
|
||||
|
||||
/**
|
||||
* Embed from URL
|
||||
* Embed from URL and Image Details
|
||||
*/
|
||||
.embed-url {
|
||||
display: block;
|
||||
|
@ -1452,6 +1456,10 @@
|
|||
overflow: auto;
|
||||
}
|
||||
|
||||
.image-details .embed-image-settings {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.media-embed .thumbnail {
|
||||
max-width: 100%;
|
||||
max-height: 200px;
|
||||
|
@ -1484,6 +1492,10 @@
|
|||
clear: both;
|
||||
}
|
||||
|
||||
.media-embed .setting .hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.media-embed .setting span {
|
||||
display: block;
|
||||
width: 200px;
|
||||
|
@ -1926,4 +1938,4 @@
|
|||
.media-frame .spinner {
|
||||
background-image: url('../images/spinner-2x.gif');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -2,7 +2,7 @@
|
|||
window.wp = window.wp || {};
|
||||
|
||||
(function($){
|
||||
var Attachment, Attachments, Query, compare, l10n, media;
|
||||
var Attachment, Attachments, Query, PostImage, compare, l10n, media;
|
||||
|
||||
/**
|
||||
* wp.media( attributes )
|
||||
|
@ -30,6 +30,8 @@ window.wp = window.wp || {};
|
|||
frame = new MediaFrame.Select( attributes );
|
||||
} else if ( 'post' === attributes.frame && MediaFrame.Post ) {
|
||||
frame = new MediaFrame.Post( attributes );
|
||||
} else if ( 'image' === attributes.frame && MediaFrame.ImageDetails ) {
|
||||
frame = new MediaFrame.ImageDetails( attributes );
|
||||
}
|
||||
|
||||
delete attributes.frame;
|
||||
|
@ -339,6 +341,121 @@ window.wp = window.wp || {};
|
|||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.media.model.Attachment
|
||||
*
|
||||
* @constructor
|
||||
* @augments Backbone.Model
|
||||
*
|
||||
**/
|
||||
PostImage = media.model.PostImage = Backbone.Model.extend({
|
||||
|
||||
initialize: function( attributes ) {
|
||||
this.attachment = false;
|
||||
|
||||
if ( attributes.attachment_id ) {
|
||||
this.attachment = media.model.Attachment.get( attributes.attachment_id );
|
||||
this.dfd = this.attachment.fetch();
|
||||
this.bindAttachmentListeners();
|
||||
}
|
||||
|
||||
// keep url in sync with changes to the type of link
|
||||
this.on( 'change:link', this.updateLinkUrl, this );
|
||||
this.on( 'change:size', this.updateSize, this );
|
||||
|
||||
this.setLinkTypeFromUrl();
|
||||
|
||||
},
|
||||
|
||||
bindAttachmentListeners: function() {
|
||||
this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl );
|
||||
},
|
||||
|
||||
changeAttachment: function( attachment, props ) {
|
||||
this.stopListening( this.attachment );
|
||||
this.attachment = attachment;
|
||||
this.bindAttachmentListeners();
|
||||
|
||||
this.set( 'attachment_id', this.attachment.get( 'id' ) );
|
||||
this.set( 'caption', this.attachment.get( 'caption' ) );
|
||||
this.set( 'alt', this.attachment.get( 'alt' ) );
|
||||
this.set( 'size', props.get( 'size' ) );
|
||||
this.set( 'align', props.get( 'align' ) );
|
||||
this.set( 'link', props.get( 'link' ) );
|
||||
this.updateLinkUrl();
|
||||
this.updateSize();
|
||||
},
|
||||
|
||||
setLinkTypeFromUrl: function() {
|
||||
var linkUrl = this.get( 'linkUrl' ),
|
||||
type;
|
||||
|
||||
if ( ! linkUrl ) {
|
||||
this.set( 'link', 'none' );
|
||||
return;
|
||||
}
|
||||
|
||||
// default to custom if there is a linkUrl
|
||||
type = 'custom';
|
||||
|
||||
if ( this.attachment ) {
|
||||
if ( this.attachment.get( 'url' ) === linkUrl ) {
|
||||
type = 'file';
|
||||
} else if ( this.attachment.get( 'link' ) === linkUrl ) {
|
||||
type = 'post';
|
||||
}
|
||||
} else {
|
||||
if ( this.get( 'url' ) === linkUrl ) {
|
||||
type = 'file';
|
||||
}
|
||||
}
|
||||
|
||||
this.set( 'link', type );
|
||||
|
||||
},
|
||||
|
||||
|
||||
updateLinkUrl: function() {
|
||||
var link = this.get( 'link' ),
|
||||
url;
|
||||
|
||||
switch( link ) {
|
||||
case 'file':
|
||||
if ( this.attachment ) {
|
||||
url = this.attachment.get( 'url' );
|
||||
} else {
|
||||
url = this.get( 'url' );
|
||||
}
|
||||
this.set( 'linkUrl', url );
|
||||
break;
|
||||
case 'post':
|
||||
this.set( 'linkUrl', this.attachment.get( 'link' ) );
|
||||
break;
|
||||
case 'none':
|
||||
this.set( 'linkUrl', '' );
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
updateSize: function() {
|
||||
var size;
|
||||
|
||||
if ( ! this.attachment ) {
|
||||
return;
|
||||
}
|
||||
|
||||
size = this.attachment.get( 'sizes' )[ this.get( 'size' ) ];
|
||||
this.set( 'url', size.url );
|
||||
this.set( 'width', size.width );
|
||||
this.set( 'height', size.height );
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.media.model.Attachments
|
||||
*
|
||||
|
@ -1170,4 +1287,4 @@ window.wp = window.wp || {};
|
|||
window.wp = null;
|
||||
});
|
||||
|
||||
}(jQuery));
|
||||
}(jQuery));
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -980,6 +980,107 @@
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
media.controller.ImageDetails = media.controller.State.extend({
|
||||
|
||||
defaults: _.defaults({
|
||||
id: 'image-details',
|
||||
toolbar: 'image-details',
|
||||
title: l10n.imageDetailsTitle,
|
||||
content: 'image-details',
|
||||
menu: 'image-details',
|
||||
router: false,
|
||||
attachment: false,
|
||||
priority: 60,
|
||||
editing: false
|
||||
}, media.controller.Library.prototype.defaults ),
|
||||
|
||||
initialize: function( options ) {
|
||||
this.image = options.image;
|
||||
media.controller.State.prototype.initialize.apply( this, arguments );
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.media.controller.ReplaceImage
|
||||
*
|
||||
* Replace a selected single image
|
||||
*
|
||||
**/
|
||||
media.controller.ReplaceImage = media.controller.Library.extend({
|
||||
defaults: _.defaults({
|
||||
id: 'replace-image',
|
||||
filterable: 'uploaded',
|
||||
multiple: false,
|
||||
toolbar: 'replace',
|
||||
title: l10n.replaceImageTitle,
|
||||
priority: 60,
|
||||
syncSelection: false
|
||||
}, media.controller.Library.prototype.defaults ),
|
||||
|
||||
initialize: function( options ) {
|
||||
var library, comparator;
|
||||
|
||||
this.image = options.image;
|
||||
|
||||
// If we haven't been provided a `library`, create a `Selection`.
|
||||
if ( ! this.get('library') ) {
|
||||
this.set( 'library', media.query({ type: 'image' }) );
|
||||
}
|
||||
/**
|
||||
* call 'initialize' directly on the parent class
|
||||
*/
|
||||
media.controller.Library.prototype.initialize.apply( this, arguments );
|
||||
|
||||
library = this.get('library');
|
||||
comparator = library.comparator;
|
||||
|
||||
// Overload the library's comparator to push items that are not in
|
||||
// the mirrored query to the front of the aggregate collection.
|
||||
library.comparator = function( a, b ) {
|
||||
var aInQuery = !! this.mirroring.get( a.cid ),
|
||||
bInQuery = !! this.mirroring.get( b.cid );
|
||||
|
||||
if ( ! aInQuery && bInQuery ) {
|
||||
return -1;
|
||||
} else if ( aInQuery && ! bInQuery ) {
|
||||
return 1;
|
||||
} else {
|
||||
return comparator.apply( this, arguments );
|
||||
}
|
||||
};
|
||||
|
||||
// Add all items in the selection to the library, so any featured
|
||||
// images that are not initially loaded still appear.
|
||||
library.observe( this.get('selection') );
|
||||
},
|
||||
|
||||
activate: function() {
|
||||
this.updateSelection();
|
||||
/**
|
||||
* call 'activate' directly on the parent class
|
||||
*/
|
||||
media.controller.Library.prototype.activate.apply( this, arguments );
|
||||
},
|
||||
|
||||
deactivate: function() {
|
||||
/**
|
||||
* call 'deactivate' directly on the parent class
|
||||
*/
|
||||
media.controller.Library.prototype.deactivate.apply( this, arguments );
|
||||
},
|
||||
|
||||
updateSelection: function() {
|
||||
var selection = this.get('selection'),
|
||||
attachment = this.image.attachment;
|
||||
|
||||
selection.reset( attachment ? [ attachment ] : [] );
|
||||
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
|
||||
/**
|
||||
* wp.media.controller.Embed
|
||||
*
|
||||
|
@ -1924,8 +2025,157 @@
|
|||
}
|
||||
}) );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
media.view.MediaFrame.ImageDetails = media.view.MediaFrame.Select.extend({
|
||||
defaults: {
|
||||
id: 'image',
|
||||
url: '',
|
||||
menu: 'image-details',
|
||||
content: 'image-details',
|
||||
toolbar: 'image-details',
|
||||
type: 'link',
|
||||
title: l10n.imageDetailsTitle,
|
||||
priority: 120
|
||||
},
|
||||
|
||||
initialize: function( options ) {
|
||||
this.image = new media.model.PostImage( options.metadata );
|
||||
this.options.selection = new media.model.Selection( this.image.attachment, { multiple: false } );
|
||||
media.view.MediaFrame.Select.prototype.initialize.apply( this, arguments );
|
||||
},
|
||||
|
||||
bindHandlers: function() {
|
||||
media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments );
|
||||
this.on( 'menu:create:image-details', this.createMenu, this );
|
||||
this.on( 'content:render:image-details', this.renderImageDetailsContent, this );
|
||||
this.on( 'menu:render:image-details', this.renderMenu, this );
|
||||
this.on( 'toolbar:render:image-details', this.renderImageDetailsToolbar, this );
|
||||
// override the select toolbar
|
||||
this.on( 'toolbar:render:replace', this.renderReplaceImageToolbar, this );
|
||||
},
|
||||
|
||||
createStates: function() {
|
||||
this.states.add([
|
||||
new media.controller.ImageDetails({
|
||||
image: this.image,
|
||||
editable: false,
|
||||
menu: 'image-details'
|
||||
}),
|
||||
new media.controller.ReplaceImage({
|
||||
id: 'replace-image',
|
||||
library: media.query( { type: 'image' } ),
|
||||
image: this.image,
|
||||
multiple: false,
|
||||
title: l10n.imageReplaceTitle,
|
||||
menu: 'image-details',
|
||||
toolbar: 'replace',
|
||||
priority: 80,
|
||||
displaySettings: true
|
||||
})
|
||||
]);
|
||||
},
|
||||
|
||||
renderImageDetailsContent: function() {
|
||||
var view = new media.view.ImageDetails({
|
||||
controller: this,
|
||||
model: this.state().image,
|
||||
attachment: this.state().image.attachment
|
||||
}).render();
|
||||
|
||||
this.content.set( view );
|
||||
|
||||
},
|
||||
|
||||
renderMenu: function( view ) {
|
||||
var lastState = this.lastState(),
|
||||
previous = lastState && lastState.id,
|
||||
frame = this;
|
||||
|
||||
view.set({
|
||||
cancel: {
|
||||
text: l10n.imageDetailsCancel,
|
||||
priority: 20,
|
||||
click: function() {
|
||||
if ( previous ) {
|
||||
frame.setState( previous );
|
||||
} else {
|
||||
frame.close();
|
||||
}
|
||||
}
|
||||
},
|
||||
separateCancel: new media.View({
|
||||
className: 'separator',
|
||||
priority: 40
|
||||
})
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
renderImageDetailsToolbar: function() {
|
||||
this.toolbar.set( new media.view.Toolbar({
|
||||
controller: this,
|
||||
items: {
|
||||
select: {
|
||||
style: 'primary',
|
||||
text: l10n.update,
|
||||
priority: 80,
|
||||
|
||||
click: function() {
|
||||
var controller = this.controller,
|
||||
state = controller.state();
|
||||
|
||||
controller.close();
|
||||
|
||||
// not sure if we want to use wp.media.string.image which will create a shortcode or
|
||||
// perhaps wp.html.string to at least to build the <img />
|
||||
state.trigger( 'update', controller.image.toJSON() );
|
||||
|
||||
// Restore and reset the default state.
|
||||
controller.setState( controller.options.state );
|
||||
controller.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}) );
|
||||
},
|
||||
|
||||
renderReplaceImageToolbar: function() {
|
||||
this.toolbar.set( new media.view.Toolbar({
|
||||
controller: this,
|
||||
items: {
|
||||
replace: {
|
||||
style: 'primary',
|
||||
text: l10n.replace,
|
||||
priority: 80,
|
||||
|
||||
click: function() {
|
||||
var controller = this.controller,
|
||||
state = controller.state(),
|
||||
selection = state.get( 'selection' ),
|
||||
attachment = selection.single();
|
||||
|
||||
controller.close();
|
||||
|
||||
controller.image.changeAttachment( attachment, state.display( attachment ) );
|
||||
|
||||
// not sure if we want to use wp.media.string.image which will create a shortcode or
|
||||
// perhaps wp.html.string to at least to build the <img />
|
||||
state.trigger( 'replace', controller.image.toJSON() );
|
||||
|
||||
// Restore and reset the default state.
|
||||
controller.setState( controller.options.state );
|
||||
controller.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}) );
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* wp.media.view.Modal
|
||||
*
|
||||
|
@ -4555,7 +4805,7 @@
|
|||
attachment = this.options.attachment;
|
||||
|
||||
if ( 'none' === linkTo || 'embed' === linkTo || ( ! attachment && 'custom' !== linkTo ) ) {
|
||||
$input.hide();
|
||||
$input.addClass( 'hidden' );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -4571,7 +4821,7 @@
|
|||
$input.prop( 'readonly', 'custom' !== linkTo );
|
||||
}
|
||||
|
||||
$input.show();
|
||||
$input.removeClass( 'hidden' );
|
||||
|
||||
// If the input is visible, focus and select its contents.
|
||||
if ( $input.is(':visible') ) {
|
||||
|
@ -4932,4 +5182,50 @@
|
|||
this.$('img').attr( 'src', this.model.get('url') );
|
||||
}
|
||||
});
|
||||
}(jQuery));
|
||||
|
||||
media.view.ImageDetails = media.view.Settings.AttachmentDisplay.extend({
|
||||
className: 'image-details',
|
||||
template: media.template('image-details'),
|
||||
|
||||
initialize: function() {
|
||||
// used in AttachmentDisplay.prototype.updateLinkTo
|
||||
this.options.attachment = this.model.attachment;
|
||||
media.view.Settings.AttachmentDisplay.prototype.initialize.apply( this, arguments );
|
||||
},
|
||||
|
||||
prepare: function() {
|
||||
var attachment = false;
|
||||
|
||||
if ( this.model.attachment ) {
|
||||
attachment = this.model.attachment.toJSON();
|
||||
}
|
||||
return _.defaults({
|
||||
model: this.model.toJSON(),
|
||||
attachment: attachment
|
||||
}, this.options );
|
||||
},
|
||||
|
||||
|
||||
render: function() {
|
||||
var self = this,
|
||||
args = arguments;
|
||||
if ( this.model.attachment && 'pending' === this.model.dfd.state() ) {
|
||||
// should instead show a spinner when the attachment is new and then add a listener that updates on change
|
||||
this.model.dfd.done( function() {
|
||||
media.view.Settings.AttachmentDisplay.prototype.render.apply( self, args );
|
||||
self.resetFocus();
|
||||
} );
|
||||
} else {
|
||||
media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments );
|
||||
setTimeout( function() { self.resetFocus(); }, 10 );
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
resetFocus: function() {
|
||||
this.$( '.caption textarea' ).focus();
|
||||
this.$( '.embed-image-settings' ).scrollTop( 0 );
|
||||
}
|
||||
});
|
||||
}(jQuery));
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -101,6 +101,176 @@ tinymce.PluginManager.add( 'wpeditimage', function( editor ) {
|
|||
});
|
||||
}
|
||||
|
||||
function extractImageData( imageNode ) {
|
||||
var classes, metadata, captionBlock, caption;
|
||||
|
||||
// default attributes
|
||||
metadata = {
|
||||
attachment_id: false,
|
||||
url: false,
|
||||
height: '',
|
||||
width: '',
|
||||
size: 'none',
|
||||
caption: '',
|
||||
alt: '',
|
||||
align: 'none',
|
||||
link: false,
|
||||
linkUrl: ''
|
||||
};
|
||||
|
||||
metadata.url = editor.dom.getAttrib( imageNode, 'src' );
|
||||
metadata.alt = editor.dom.getAttrib( imageNode, 'alt' );
|
||||
metadata.width = parseInt( editor.dom.getAttrib( imageNode, 'width' ), 10 );
|
||||
metadata.height = parseInt( editor.dom.getAttrib( imageNode, 'height' ), 10 );
|
||||
|
||||
//TODO: probably should capture attributes on both the <img /> and the <a /> so that they can be restored when the image and/or caption are updated
|
||||
// maybe use getAttribs()
|
||||
|
||||
// extract meta data from classes (candidate for turning into a method)
|
||||
classes = imageNode.className.split( ' ' );
|
||||
tinymce.each( classes, function( name ) {
|
||||
|
||||
if ( /^wp-image/.test( name ) ) {
|
||||
metadata.attachment_id = parseInt( name.replace( 'wp-image-', '' ), 10 );
|
||||
}
|
||||
|
||||
if ( /^align/.test( name ) ) {
|
||||
metadata.align = name.replace( 'align', '' );
|
||||
}
|
||||
|
||||
if ( /^size/.test( name ) ) {
|
||||
metadata.size = name.replace( 'size-', '' );
|
||||
}
|
||||
} );
|
||||
|
||||
|
||||
// extract caption
|
||||
captionBlock = editor.dom.getParents( imageNode, '.wp-caption' );
|
||||
|
||||
if ( captionBlock.length ) {
|
||||
captionBlock = captionBlock[0];
|
||||
|
||||
classes = captionBlock.className.split( ' ' );
|
||||
tinymce.each( classes, function( name ) {
|
||||
if ( /^align/.test( name ) ) {
|
||||
metadata.align = name.replace( 'align', '' );
|
||||
}
|
||||
} );
|
||||
caption = editor.dom.select( 'dd.wp-caption-dd', captionBlock );
|
||||
if ( caption.length ) {
|
||||
caption = caption[0];
|
||||
// need to do some more thinking about this
|
||||
metadata.caption = editor.serializer.serialize( caption )
|
||||
.replace( /<br[^>]*>/g, '$&\n' ).replace( /^<p>/, '' ).replace( /<\/p>$/, '' );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// extract linkTo
|
||||
if ( imageNode.parentNode.nodeName === 'A' ) {
|
||||
metadata.linkUrl = editor.dom.getAttrib( imageNode.parentNode, 'href' );
|
||||
}
|
||||
|
||||
return metadata;
|
||||
|
||||
}
|
||||
|
||||
function updateImage( imageNode, imageData ) {
|
||||
var className, width, node, html, captionNode, nodeToReplace, uid;
|
||||
|
||||
if ( imageData.caption ) {
|
||||
|
||||
html = createImageAndLink( imageData, 'html' );
|
||||
|
||||
width = imageData.width + 10;
|
||||
className = 'align' + imageData.align;
|
||||
|
||||
//TODO: shouldn't add the id attribute if it isn't an attachment
|
||||
|
||||
// should create a new function for genrating the caption markup
|
||||
html = '<dl id="'+ imageData.attachment_id +'" class="wp-caption '+ className +'" style="width: '+ width +'px">' +
|
||||
'<dt class="wp-caption-dt">'+ html + '</dt><dd class="wp-caption-dd">'+ imageData.caption +'</dd></dl>';
|
||||
|
||||
node = editor.dom.create( 'div', { 'class': 'mceTemp', draggable: 'true' }, html );
|
||||
} else {
|
||||
node = createImageAndLink( imageData, 'node' );
|
||||
}
|
||||
|
||||
nodeToReplace = imageNode;
|
||||
|
||||
captionNode = editor.dom.getParent( imageNode, '.mceTemp' );
|
||||
|
||||
if ( captionNode ) {
|
||||
nodeToReplace = captionNode;
|
||||
} else {
|
||||
if ( imageNode.parentNode.nodeName === 'A' ) {
|
||||
nodeToReplace = imageNode.parentNode;
|
||||
}
|
||||
}
|
||||
// uniqueId isn't super exciting, so maybe we want to use something else
|
||||
uid = editor.dom.uniqueId( 'wp_' );
|
||||
editor.dom.setAttrib( node, 'data-wp-replace-id', uid );
|
||||
editor.dom.replace( node, nodeToReplace );
|
||||
|
||||
// find the updated node
|
||||
node = editor.dom.select( '[data-wp-replace-id="' + uid + '"]' )[0];
|
||||
|
||||
editor.dom.setAttrib( node, 'data-wp-replace-id', '' );
|
||||
|
||||
if ( node.nodeName === 'IMG' ) {
|
||||
editor.selection.select( node );
|
||||
} else {
|
||||
editor.selection.select( editor.dom.select( 'img', node )[0] );
|
||||
}
|
||||
editor.nodeChanged();
|
||||
|
||||
}
|
||||
|
||||
function createImageAndLink( imageData, mode ) {
|
||||
var classes = [],
|
||||
props;
|
||||
|
||||
mode = mode ? mode : 'node';
|
||||
|
||||
|
||||
if ( ! imageData.caption ) {
|
||||
classes.push( 'align' + imageData.align );
|
||||
}
|
||||
|
||||
if ( imageData.attachment_id ) {
|
||||
classes.push( 'wp-image-' + imageData.attachment_id );
|
||||
if ( imageData.size ) {
|
||||
classes.push( 'size-' + imageData.size );
|
||||
}
|
||||
}
|
||||
|
||||
props = {
|
||||
src: imageData.url,
|
||||
width: imageData.width,
|
||||
height: imageData.height,
|
||||
alt: imageData.alt
|
||||
};
|
||||
|
||||
if ( classes.length ) {
|
||||
props['class'] = classes.join( ' ' );
|
||||
}
|
||||
|
||||
if ( imageData.linkUrl ) {
|
||||
if ( mode === 'node' ) {
|
||||
return editor.dom.create( 'a', { href: imageData.linkUrl }, editor.dom.createHTML( 'img', props ) );
|
||||
} else if ( mode === 'html' ) {
|
||||
return editor.dom.createHTML( 'a', { href: imageData.linkUrl }, editor.dom.createHTML( 'img', props ) );
|
||||
}
|
||||
} else {
|
||||
if ( mode === 'node' ) {
|
||||
return editor.dom.create( 'img', props );
|
||||
} else if ( mode === 'html' ) {
|
||||
return editor.dom.createHTML( 'img', props );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
editor.on( 'init', function() {
|
||||
var dom = editor.dom;
|
||||
|
||||
|
@ -452,6 +622,40 @@ tinymce.PluginManager.add( 'wpeditimage', function( editor ) {
|
|||
}
|
||||
});
|
||||
|
||||
editor.on( 'mousedown', function( e ) {
|
||||
var imageNode, frame, callback;
|
||||
if ( e.target.nodeName === 'IMG' && editor.selection.getNode() === e.target ) {
|
||||
// Don't trigger on right-click
|
||||
if ( e.button !== 2 ) {
|
||||
|
||||
// Don't attempt to edit placeholders
|
||||
if ( editor.dom.hasClass( e.target, 'mceItem' ) || '1' === editor.dom.getAttrib( e.target, 'data-mce-placeholder' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
imageNode = e.target;
|
||||
|
||||
frame = wp.media({
|
||||
frame: 'image',
|
||||
state: 'image-details',
|
||||
metadata: extractImageData( imageNode )
|
||||
} );
|
||||
|
||||
callback = function( imageData ) {
|
||||
updateImage( imageNode, imageData );
|
||||
editor.focus();
|
||||
};
|
||||
|
||||
frame.state('image-details').on( 'update', callback );
|
||||
frame.state('replace-image').on( 'replace', callback );
|
||||
|
||||
frame.open();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
} );
|
||||
|
||||
editor.wpSetImgCaption = function( content ) {
|
||||
return parseShortcode( content );
|
||||
};
|
||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -500,6 +500,117 @@ function wp_print_media_templates() {
|
|||
}
|
||||
</style>
|
||||
</script>
|
||||
|
||||
<script type="text/html" id="tmpl-image-details">
|
||||
<?php // reusing .media-embed to pick up the styles for now ?>
|
||||
<div class="media-embed">
|
||||
<div class="embed-image-settings">
|
||||
<div class="thumbnail">
|
||||
<img src="{{ data.model.url }}" draggable="false" />
|
||||
</div>
|
||||
|
||||
<div class="setting url">
|
||||
<?php // might want to make the url editable if it isn't an attachment ?>
|
||||
<input type="text" disabled="disabled" value="{{ data.model.url }}" />
|
||||
</div>
|
||||
|
||||
<?php
|
||||
/** This filter is documented in wp-admin/includes/media.php */
|
||||
if ( ! apply_filters( 'disable_captions', '' ) ) : ?>
|
||||
<label class="setting caption">
|
||||
<span><?php _e('Caption'); ?></span>
|
||||
<textarea data-setting="caption">{{ data.model.caption }}</textarea>
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
|
||||
<label class="setting alt-text">
|
||||
<span><?php _e('Alt Text'); ?></span>
|
||||
<input type="text" data-setting="alt" value="{{ data.model.alt }}" />
|
||||
</label>
|
||||
|
||||
<div class="setting align">
|
||||
<span><?php _e('Align'); ?></span>
|
||||
<div class="button-group button-large" data-setting="align">
|
||||
<button class="button" value="left">
|
||||
<?php esc_attr_e('Left'); ?>
|
||||
</button>
|
||||
<button class="button" value="center">
|
||||
<?php esc_attr_e('Center'); ?>
|
||||
</button>
|
||||
<button class="button" value="right">
|
||||
<?php esc_attr_e('Right'); ?>
|
||||
</button>
|
||||
<button class="button active" value="none">
|
||||
<?php esc_attr_e('None'); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="setting link-to">
|
||||
<span><?php _e('Link To'); ?></span>
|
||||
|
||||
<# if ( data.attachment ) { #>
|
||||
<div class="button-group button-large" data-setting="link">
|
||||
<button class="button" value="file">
|
||||
<?php esc_attr_e('Media File'); ?>
|
||||
</button>
|
||||
<button class="button" value="post">
|
||||
<?php esc_attr_e('Attachment Page'); ?>
|
||||
</button>
|
||||
<button class="button" value="custom">
|
||||
<?php esc_attr_e('Custom URL'); ?>
|
||||
</button>
|
||||
<button class="button active" value="none">
|
||||
<?php esc_attr_e('None'); ?>
|
||||
</button>
|
||||
</div>
|
||||
<input type="text" class="link-to-custom" data-setting="linkUrl" />
|
||||
|
||||
<# } else { #>
|
||||
<div class="button-group button-large" data-setting="link">
|
||||
<button class="button" value="file">
|
||||
<?php esc_attr_e('Image URL'); ?>
|
||||
</button>
|
||||
<button class="button" value="custom">
|
||||
<?php esc_attr_e('Custom URL'); ?>
|
||||
</button>
|
||||
<button class="button active" value="none">
|
||||
<?php esc_attr_e('None'); ?>
|
||||
</button>
|
||||
</div>
|
||||
<input type="text" class="link-to-custom" data-setting="linkUrl" />
|
||||
|
||||
<# } #>
|
||||
</div>
|
||||
|
||||
<# if ( data.attachment ) { #>
|
||||
<div class="setting size">
|
||||
<span><?php _e('Size'); ?></span>
|
||||
<div class="button-group button-large" data-setting="size">
|
||||
<?php
|
||||
/** This filter is documented in wp-admin/includes/media.php */
|
||||
$sizes = apply_filters( 'image_size_names_choose', array(
|
||||
'thumbnail' => __('Thumbnail'),
|
||||
'medium' => __('Medium'),
|
||||
'large' => __('Large'),
|
||||
'full' => __('Full Size'),
|
||||
) );
|
||||
|
||||
foreach ( $sizes as $value => $name ) : ?>
|
||||
<#
|
||||
var size = data.attachment.sizes['<?php echo esc_js( $value ); ?>'];
|
||||
if ( size ) { #>
|
||||
<button class="button" value="<?php echo esc_attr( $value ); ?>">
|
||||
<?php echo esc_html( $name ); ?>
|
||||
</button>
|
||||
<# } #>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<# } #>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</script>
|
||||
<?php
|
||||
|
||||
/**
|
||||
|
|
|
@ -1967,6 +1967,8 @@ function wp_enqueue_media( $args = array() ) {
|
|||
'search' => __( 'Search' ),
|
||||
'select' => __( 'Select' ),
|
||||
'cancel' => __( 'Cancel' ),
|
||||
'update' => __( 'Update' ),
|
||||
'replace' => __( 'Replace' ),
|
||||
/* translators: This is a would-be plural string used in the media manager.
|
||||
If there is not a word you can use in your language to avoid issues with the
|
||||
lack of plural support here, turn it into "selected: %d" then translate it.
|
||||
|
@ -2005,6 +2007,12 @@ function wp_enqueue_media( $args = array() ) {
|
|||
'addToGallery' => __( 'Add to gallery' ),
|
||||
'addToGalleryTitle' => __( 'Add to Gallery' ),
|
||||
'reverseOrder' => __( 'Reverse order' ),
|
||||
|
||||
|
||||
// Edit Image
|
||||
'imageDetailsTitle' => __( 'Image Details' ),
|
||||
'imageReplaceTitle' => __( 'Replace Image' ),
|
||||
'imageDetailsCancel' => __( 'Cancel Edit' )
|
||||
);
|
||||
|
||||
$settings = apply_filters( 'media_view_settings', $settings, $post );
|
||||
|
|
Loading…
Reference in New Issue