Ask your WordPress questions! Pay money and get answers fast! (more info)

who can customise existing js? WordPress

  • SOLVED

I've changed the code for handling images in the visual and text editors to use the html5 format:

[code]
<figure>
<img ... </img>
<figcaption></figcaption>
</figure>
[code]

... which means the js for the existing wpeditimage needs to be adjusted to maintain functionality.

I've no idea what effort is needed here: details on request and estimates welcome.

best regards
andrewsan

Answers (1)

2013-03-26

webGP answers:

Hello!

Try add the code below into your functions.php file:

add_filter('image_send_to_editor', 'cutom_img_wrapper', 99, 8);

// We are only working with the $html argument, but you can play with all of them
function cutom_img_wrapper($html, $id, $caption, $title, $align, $url, $size, $alt)
{

$new_html = preg_replace("/\<div(.*)\>(.*)\<\/div\>/iU", "<figure $1>$2</figure>", $html);
$html = ($new_html == $html) ? '<figure class="align' . $align . '">' . $html . '</figure>' : $new_html;

return $html;
}

function custom_caption_shortcode($attr, $content = null)
{


if(preg_match('#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches))
{
$content = $matches[1];
$attr['caption'] = trim($matches[2]);
}

if($output != '')
return $output;

extract(shortcode_atts(array(
'id' => '',
'align' => 'alignnone',
'width' => '',
'caption' => ''
), $attr));

if(1 > (int) $width || empty($caption))
return $content;

if($id)
$id = 'id="' . $id . '" ';

return do_shortcode($content) . '<figcaption class="wp-caption">' . $caption . '</figcaption>';
}

add_shortcode('wp_caption', 'custom_caption_shortcode');
add_shortcode('caption', 'custom_caption_shortcode');


andrewsan comments:

hallo WebGP - thanks for the fast reply ...

in functions.php I have:
removed the wp-autop filter in content and excerpts;
removed the filter image_add_caption and replaced with new_ ;
removed core caption shortcodes for caption and wpcaption and replaced with customised.

This gives me control over html formats in both visual and text editor:
here's an example of the underlying code for the vsual editor after loading an image via the visual editor:

[code]
body id="tinymce" class="mceContentBody content post-type-post wp-editor" contenteditable="true" onload="window.parent.tinyMCE.get('content').onLoad.dispatch();" dir="ltr">

<p>
[caption id="attachment_1751" align="alignleft" width="512"]

</p>
<figure id="attachment_1751 " class="abc">

<img class="alignsize-large wp-image-1751" width="512" height="427" data-mce-src="http://.../wp-content/uploads/2013/03/lotus.png" src="http://.../wp-content/uploads/2013/03/lotus.png" alt="x" _moz_resizing="true"></img>

<figcaption class="abc">
caption text goes here
</figcaption>

</figure>
<p>

caption text is duplicated here [/caption]
</p>

</body>
[/code]

So far, so good: by using the html5 figure description for images-plus-captions, life will be easier in the long term.

However, in the short term there are two issues to fix:

1 - permanently get rid of: the utterly irrelevant square bracket caption id; and the equally useless duplicated caption text and the closing caption in square brackets.

2 - now that the image-plus-caption is described with an html5 figure statement, the js - which formerly wrote a mceTemp div, followed by dl, dt, dd - is redundant and thus the functionality for the Editor to use the pop-up to re-align an image is
broken: this needs re-defining.

Both issues can be fixed via correct js in a new version of wpeditimage.js

interesting for you?

best regards
Andrewsan





webGP comments:

Ok, could you send me all of your filters, that I can put them into my theme and look into code?


andrewsan comments:

thanks webGP ... here's the code for functions.php:

[code]
/*
* replace standard WP image handling with consistent image preparation in html5 format
* Author: Andrew Sanderson
* Author URI: andrewsan.com
*/

remove_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );
add_filter( 'image_send_to_editor', 'new_image_add_caption', 20, 8 );
function new_image_add_caption( $html, $id, $caption, $title, $align, $url, $size, $alt = '' ) {

if ( empty($caption) || apply_filters( 'disable_captions', '' ) )
return '<figure id="' . $id . '" class="frame-' . $align . '-' . $size . '">' . $html . '</figure>';

$id = ( 0 < (int) $id ) ? 'attachment_' . $id : '';

if ( ! preg_match( '/width=["\']([0-9]+)/', $html, $matches ) )
return $html;

$width = $matches[1];

$caption = str_replace( array("\r\n", "\r"), "\n", $caption);
$caption = preg_replace_callback( '/<[a-zA-Z0-9]+(?: [^<>]+>)*/', '_cleanup_image_add_caption', $caption );
// convert any remaining line breaks to <br>
$caption = preg_replace( '/[ \n\t]*\n[ \t]*/', '<br />', $caption );

$html = preg_replace( '/(class=["\'][^\'"]*)align(none|left|right|center)\s?/', '$1', $html );
if ( empty($align) )
$align = 'none';

$shcode = ' . $html . ';

return '<figure id="' . $id . ' " class="frame-' . $align . '-' . $size . '">' . $html . '<figcaption class="caption-' . $align . '-' . $size . '">' . $caption . '</figcaption></figure>';
}
/* image handling ends*/


/**
* The Caption shortcode. Copied from core, with markup modifications.
*
* Author: Kailey Lampert
* Author URI: kaileylampert.com
* Allows a plugin to replace the content that would otherwise be returned. The
* filter is 'img_caption_shortcode' and passes an empty string, the attr
* parameter and the content parameter values.
*
* The supported attributes for the shortcode are 'id', 'align', 'width', and
* 'caption'.
*
* @since 2.6.0
*
* @param array $attr Attributes attributed to the shortcode.
* @param string $content Optional. Shortcode content.
* @return string
*/

add_action('init', 'remove_core_caption_shortcodes');
function remove_core_caption_shortcodes() {
remove_shortcode('wp_caption', 'img_caption_shortcode');
remove_shortcode('caption', 'img_caption_shortcode');
}


add_action('init', 'new_caption_shortcodes', 11, 4);
function new_caption_shortcodes() {
add_shortcode('wp_caption', 'new_img_caption_shortcode');
add_shortcode('caption', 'new_img_caption_shortcode');

}

function new_img_caption_shortcode($attr, $content = null) {
// New-style shortcode with the caption inside the shortcode with the link and image tags.
if ( ! isset( $attr['caption'] ) ) {
if ( preg_match( '#((?:<a [^>]+>\s*)?<img [^>]+>(?:\s*</a>)?)(.*)#is', $content, $matches ) ) {
$content = $matches[1];
$attr['caption'] = trim( $matches[2] );
}
}

// Allow plugins/themes to override the default caption template.
$output = apply_filters('img_caption_shortcode', '', $attr, $content);
if ( $output != '' )
return $output;

extract(shortcode_atts(array(
'id' => '',
'align' => '',
'size' => '',
'width' => '',
'caption' => ''
), $attr));

if ( 1 > (int) $width || empty($caption) )
return $content;

if ( $id ) $id = 'id="' . esc_attr($id) . '" ';

// extract the size name from the image class
preg_match( '/size-([^\s]*) /', $content, $matches );
$size = $matches[1];

// remove height/width attribs from img
$content = preg_replace( '/ width="(\d*)" height="(\d*)"/', '', $content );

$content = preg_replace( '/(class=["\'][^\'"]*)(none|left|right|center)\s?/', '$1', $content );
if ( empty($align) )
$align = 'none';

return '<figure ' . $id . 'class="frame-' . $align . '-'. $size .'">' . do_shortcode( $content ) . ' ' . $caption . '</figure>';
}

// remove height/width attribs from img
add_filter( 'image_send_to_editor', 'new_image_send_to_editor', 21, 8 );
function new_image_send_to_editor( $html, $id, $caption, $title, $align, $url, $size, $alt ) {
// careful, removing width causes the [caption] to get stripped out if you switch between the text and visual editors
if ( empty( $caption ) )
$html = preg_replace( '/ width="(\d*)" height="(\d*)"/', '', $html );
return $html;
}

// make "Link To" always be "none" by default
add_filter( 'pre_option_image_default_link_type', 'always_return_none' );
function always_return_none() {
return 'none';
}
/* caption shortcode ends */


/**
* Author: Kailey Lampert
* Author URI: kaileylampert.com
*
* The markup around captions that you see in TinyMCE/Visual editor
* By default, we get something like:
* div » dl.wp-caption alignnone » dt.wp-caption-dt » img.size-medium wp-image-999
* is added by a WP TinyMCE plugin, wpEditImage
*
* To customize this, we must first turn off that plugin:
*/
add_filter('tiny_mce_plugins', 'ct_tiny_mce_plugins' );
function ct_tiny_mce_plugins( $plugins ) {
if ( false !== ( $key = array_search('wpeditimage', $plugins ) ) )
unset( $plugins[ $key ] );
return $plugins;
}

/**
* Next, we re-add our nearly identical version, but with our markup edits:
* This version produces markup like:
* div » figure.wp-caption alignnone » img.size-medium wp-image-999
*
*/
add_filter( 'mce_external_plugins', 'ct_mce_external_plugins', 11 );
function ct_mce_external_plugins( $plugin_array ) {
$plugin_array[ 'wpeditimage2' ] = get_bloginfo( 'template_url' ) . '/js/editor_plugin_src.js';
return $plugin_array;
}

[/code]


andrewsan comments:

... and here's the current version of a new js for wpeditimage:

[code]
(function() {
tinymce.create('tinymce.plugins.wpEditImage2', {
url: '',
editor: {},

init: function(ed, url) {
var t = this, mouse = {};

t.url = url;
t.editor = ed;
t._createButtons();

ed.addCommand('WP_EditImage', t._editImage);

ed.onInit.add(function(ed) {
ed.dom.events.add(ed.getBody(), 'mousedown', function(e) {
var parent;

if ( e.target.nodeName == 'IMG' && ( parent = ed.dom.getParent(e.target, 'div.mceTemp') ) ) {
if ( tinymce.isGecko )
ed.selection.select(parent);
else if ( tinymce.isWebKit )
ed.dom.events.prevent(e);
}
});

// when pressing Return inside a caption move the caret to a new parapraph under it
ed.dom.events.add(ed.getBody(), 'keydown', function(e) {
var n, DL, DIV, P, content;

if ( e.keyCode == 13 ) {
n = ed.selection.getNode();
DL = ed.dom.getParent(n, 'figure.wp-caption');

if ( DL )
DIV = ed.dom.getParent(DL, 'div.mceTemp');

if ( DIV ) {
ed.dom.events.cancel(e);
P = ed.dom.create('p', {}, '\uFEFF');
ed.dom.insertAfter( P, DIV );
ed.selection.setCursorLocation(P, 0);
return false;
}
}
});

// iOS6 doesn't show the buttons properly on click, show them on 'touchstart'
if ( 'ontouchstart' in window ) {
ed.dom.events.add(ed.getBody(), 'touchstart', function(e){
t._showButtons(e);
});
}
});

// resize the caption <dl> when the image is soft-resized by the user
ed.onMouseUp.add(function(ed, e) {
if ( tinymce.isWebKit || tinymce.isOpera )
return;

if ( mouse.x && (e.clientX != mouse.x || e.clientY != mouse.y) ) {
var n = ed.selection.getNode();

if ( 'IMG' == n.nodeName ) {
window.setTimeout(function(){
var DL = ed.dom.getParent(n, 'figure.wp-caption'), width;

if ( n.width != mouse.img_w || n.height != mouse.img_h )
n.className = n.className.replace(/size-[^ "']+/, '');

if ( DL ) {
width = ed.dom.getAttrib(n, 'width') || n.width;
width = parseInt(width, 10);
ed.dom.setStyle(DL, 'width', 10 + width);
ed.execCommand('mceRepaint');
}
}, 100);
}
}
mouse = {};
});

// show editimage buttons
ed.onMouseDown.add(function(ed, e){
t._showButtons(e);
});

ed.onBeforeSetContent.add(function(ed, o) {
o.content = ed.wpSetImgCaption(o.content);
});

ed.onPostProcess.add(function(ed, o) {
if (o.get)
o.content = ed.wpGetImgCaption(o.content);
});

ed.wpSetImgCaption = function(content) {
return t._do_shcode(content);
};

ed.wpGetImgCaption = function(content) {
return t._get_shcode(content);
};

// When inserting content, if the caret is inside a caption create new paragraph under
// and move the caret there
ed.onBeforeExecCommand.add(function(ed, cmd, ui, val) {
var node, p;

if ( cmd == 'mceInsertContent' ) {
node = ed.dom.getParent(ed.selection.getNode(), 'div.mceTemp');

if ( !node )
return;

p = ed.dom.create('p');
ed.dom.insertAfter( p, node );
ed.selection.setCursorLocation(p, 0);
}
});
},

_do_shcode : function(content) {
return content.replace(/(?:<p>)?\[(?:wp_)?caption([^\]]+)\]([\s\S]+?)\[\/(?:wp_)?caption\](?:<\/p>)?/g, function(a,b,c){
var id, cls, w, cap, div_cls, img, trim = tinymce.trim;

id = b.match(/id=['"]([^'"]*)['"] ?/);
if ( id )
b = b.replace(id[0], '');

cls = b.match(/align=['"]([^'"]*)['"] ?/);
if ( cls )
b = b.replace(cls[0], '');

w = b.match(/width=['"]([0-9]*)['"] ?/);
if ( w )
b = b.replace(w[0], '');

c = trim(c);
img = c.match(/((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)([\s\S]*)/i);

if ( img && img[2] ) {
cap = trim( img[2] );
img = trim( img[1] );
} else {
// old captions shortcode style
cap = trim(b).replace(/caption=['"]/, '').replace(/['"]$/, '');
img = c;
}

id = ( id && id[1] ) ? id[1] : '';
cls = ( cls && cls[1] ) ? cls[1] : 'alignnone';
w = ( w && w[1] ) ? w[1] : '';

if ( !w || !cap )
return c;

div_cls = 'mceTemp';
if ( cls == 'aligncenter' )
div_cls += ' mceIEcenter';

return '<div class="'+div_cls+'"><figure id="'+id+'" class="wp-caption '+cls+'" style="width: '+( 10 + parseInt(w) )+
'px">'+img+'<figcaption class="wp-caption-dd">'+cap+'</figcaption></figure></div>';
});
},

_get_shcode : function(content) {
return content.replace(/<div (?:id="attachment_|class="mceTemp)[^>]*>([\s\S]+?)<\/div>/g, function(a, b){
var ret = b.replace(/<figure ([^>]+)>\s*([\s\S]+?)\s*<figcaption [^>]+>([\s\S]*?)<\/figcaption>\s*<\/figure>/gi, function(a,b,c,cap){
var id, cls, w;

w = c.match(/width="([0-9]*)"/);
w = ( w && w[1] ) ? w[1] : '';

if ( !w || !cap )
return c;

id = b.match(/id="([^"]*)"/);
id = ( id && id[1] ) ? id[1] : '';

cls = b.match(/class="([^"]*)"/);
cls = ( cls && cls[1] ) ? cls[1] : '';
cls = cls.match(/align[a-z]+/) || 'alignnone';

cap = cap.replace(/\r\n|\r/g, '\n').replace(/<[a-zA-Z0-9]+( [^<>]+)?>/g, function(a){
// no line breaks inside HTML tags
return a.replace(/[\r\n\t]+/, ' ');
});

// convert remaining line breaks to <br>
cap = cap.replace(/\s*\n\s*/g, '<br />');

return '[caption id="'+id+'" align="'+cls+'" width="'+w+'"]'+c+' '+cap+'[/caption]';
});

if ( ret.indexOf('[caption') !== 0 ) {
// the caption html seems brocken, try to find the image that may be wrapped in a link
// and may be followed by <p> with the caption text.
ret = b.replace(/[\s\S]*?((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)(<p>[\s\S]*<\/p>)?[\s\S]*/gi, '<p>$1</p>$2');
}

return ret;
});
},

_createButtons : function() {
var t = this, ed = tinymce.activeEditor, DOM = tinymce.DOM, editButton, dellButton, isRetina;

if ( DOM.get('wp_editbtns') )
return;

isRetina = ( window.devicePixelRatio && window.devicePixelRatio > 1 ) || // WebKit, Opera
( window.matchMedia && window.matchMedia('(min-resolution:130dpi)').matches ); // Firefox, IE10, Opera

DOM.add(document.body, 'div', {
id : 'wp_editbtns',
style : 'display:none;'
});

editButton = DOM.add('wp_editbtns', 'img', {
src : isRetina ? t.url+'/img/image-2x.png' : t.url+'/img/image.png',
id : 'wp_editimgbtn',
width : '24',
height : '24',
title : ed.getLang('wpeditimage2.edit_img')
});

tinymce.dom.Event.add(editButton, 'mousedown', function(e) {
t._editImage();
ed.plugins.wordpress._hideButtons();
});

dellButton = DOM.add('wp_editbtns', 'img', {
src : isRetina ? t.url+'/img/delete-2x.png' : t.url+'/img/delete.png',
id : 'wp_delimgbtn',
width : '24',
height : '24',
title : ed.getLang('wpeditimage2.del_img')
});

tinymce.dom.Event.add(dellButton, 'mousedown', function(e) {
var ed = tinymce.activeEditor, el = ed.selection.getNode(), parent;

if ( el.nodeName == 'IMG' && ed.dom.getAttrib(el, 'class').indexOf('mceItem') == -1 ) {
if ( (parent = ed.dom.getParent(el, 'div')) && ed.dom.hasClass(parent, 'mceTemp') ) {
ed.dom.remove(parent);
} else {
if ( el.parentNode.nodeName == 'A' && el.parentNode.childNodes.length == 1 )
el = el.parentNode;

if ( el.parentNode.nodeName == 'P' && el.parentNode.childNodes.length == 1 )
el = el.parentNode;

ed.dom.remove(el);
}

ed.execCommand('mceRepaint');
return false;
}
ed.plugins.wordpress._hideButtons();
});
},

_editImage : function() {
var ed = tinymce.activeEditor, url = this.url, el = ed.selection.getNode(), vp, H, W, cls = el.className;

if ( cls.indexOf('mceItem') != -1 || cls.indexOf('wpGallery') != -1 || el.nodeName != 'IMG' )
return;

vp = tinymce.DOM.getViewPort();
H = 680 < (vp.h - 70) ? 680 : vp.h - 70;
W = 650 < vp.w ? 650 : vp.w;

ed.windowManager.open({
file: url + '/editimage.html',
width: W+'px',
height: H+'px',
inline: true
});
},

_showButtons : function(e) {
var ed = this.editor, target = e.target;

if ( target.nodeName != 'IMG' ) {
if ( target.firstChild && target.firstChild.nodeName == 'IMG' && target.childNodes.length == 1 ) {
target = target.firstChild;
} else {
ed.plugins.wordpress._hideButtons();
return;
}
}

if ( ed.dom.getAttrib(target, 'class').indexOf('mceItem') == -1 ) {
mouse = {
x: e.clientX,
y: e.clientY,
img_w: target.clientWidth,
img_h: target.clientHeight
};

if ( e.type == 'touchstart' ) {
ed.selection.select(target);
ed.dom.events.cancel(e);
}

ed.plugins.wordpress._hideButtons();
ed.plugins.wordpress._showButtons(target, 'wp_editbtns');
}
},

getInfo : function() {
return {
longname : 'Edit Image',
author : 'WordPress',
authorurl : 'http://wordpress.org',
infourl : '',
version : "1.0"
};
}
});

tinymce.PluginManager.add('wpeditimage2', tinymce.plugins.wpEditImage2);
})();

[/code]

... comments to follow ...


andrewsan comments:

OK ... so now I've got the js open in an editor so that I can see line numbers, and the comments are:

(please bear in mind I've no idea about js, so my understanding of what is going on may be completely off the wall ...

at line 19: looks like we're setting up a reference to a div called mceTemp;
but that no longer exists - we need to refer to the html5 figure statement here

lines 27 to 46: yes we need the 'create a new paragraph' function, but the parents and nodes all need adjusting to html5 figure format

lines 48 to 54: no idea at all !!!

lines 56 to 81: - soft re-sizing: does this mean when a user changes the alignment via the po-up? if yes, this functionality definitely wanted

lines 83 to 103: the editimage buttons show up at present, but clicking on the edit one creates an error message ...
(sub-folder img under file js contaions the button images - do you need those?)

lines 105 to 121: refers to the mceTemp node which doesn't exist any more ...

lines 123 to 165 - now we're getting to the heart of the matter:

the trim and replace stuff takes out of the html I've lovingly created somestuff I need - there's no placeholder for the image size attribute in the class statements (definitely wanted and preferred because pixel definitions suck in a responsive world)

the reference to mceTemp and mceIEcenter is irrelevant

lines 167 to 204: once again, the size attribute is not present in the clas sstatement (it's needed);
and the return contaions that ghastly 'caption-in-square-brackets-stuff' plus a duplicate copy of the caption text (I've created that via the functions.php) and adds a closing caption-in-square-brackets.
I need to get rid of all that junk.

lines 206 to 262: create buttons - fine, don't see anything to grumble about here

lines 264 to end: seems OK, too


is the scope of the thing clear?
pls shout loud if I've got something seriously wrong ...

best regards
andrewsan





webGP comments:

I changed your js file and i think it's ok now, but you have to check. Below is new code file:



(function() {
tinymce.create('tinymce.plugins.wpEditImage2', {
url: '',
editor: {},

init: function(ed, url) {
var t = this, mouse = {};

t.url = url;
t.editor = ed;
t._createButtons();

ed.addCommand('WP_EditImage', t._editImage);

ed.onInit.add(function(ed) {
ed.dom.events.add(ed.getBody(), 'mousedown', function(e) {
var parent;

if ( e.target.nodeName == 'IMG' && ( parent = ed.dom.getParent(e.target, 'div.mceTemp') ) ) {
if ( tinymce.isGecko )
ed.selection.select(parent);
else if ( tinymce.isWebKit )
ed.dom.events.prevent(e);
}
});

// when pressing Return inside a caption move the caret to a new parapraph under it
ed.dom.events.add(ed.getBody(), 'keydown', function(e) {
var n, DL, DIV, P, content;

if ( e.keyCode == 13 ) {
n = ed.selection.getNode();
DL = ed.dom.getParent(n, 'figure.wp-caption');

if ( DL )
DIV = ed.dom.getParent(DL, 'div.mceTemp');

if ( DIV ) {
ed.dom.events.cancel(e);
P = ed.dom.create('p', {}, '\uFEFF');
ed.dom.insertAfter( P, DIV );
ed.selection.setCursorLocation(P, 0);
return false;
}
}
});

// iOS6 doesn't show the buttons properly on click, show them on 'touchstart'
if ( 'ontouchstart' in window ) {
ed.dom.events.add(ed.getBody(), 'touchstart', function(e){
t._showButtons(e);
});
}
});

// resize the caption <dl> when the image is soft-resized by the user
ed.onMouseUp.add(function(ed, e) {
if ( tinymce.isWebKit || tinymce.isOpera )
return;

if ( mouse.x && (e.clientX != mouse.x || e.clientY != mouse.y) ) {
var n = ed.selection.getNode();

if ( 'IMG' == n.nodeName ) {
window.setTimeout(function(){
var DL = ed.dom.getParent(n, 'figure.wp-caption'), width;

if ( n.width != mouse.img_w || n.height != mouse.img_h )
n.className = n.className.replace(/size-[^ "']+/, '');

if ( DL ) {
width = ed.dom.getAttrib(n, 'width') || n.width;
width = parseInt(width, 10);
ed.dom.setStyle(DL, 'width', 10 + width);
ed.execCommand('mceRepaint');
}
}, 100);
}
}
mouse = {};
});

// show editimage buttons
ed.onMouseDown.add(function(ed, e){
t._showButtons(e);
});

ed.onBeforeSetContent.add(function(ed, o) {
o.content = ed.wpSetImgCaption(o.content);
});

ed.onPostProcess.add(function(ed, o) {
if (o.get)
o.content = ed.wpGetImgCaption(o.content);
});

ed.wpSetImgCaption = function(content) {
return t._do_shcode(content);
};

ed.wpGetImgCaption = function(content) {
return t._get_shcode(content);
};

// When inserting content, if the caret is inside a caption create new paragraph under
// and move the caret there
ed.onBeforeExecCommand.add(function(ed, cmd, ui, val) {
var node, p;

if ( cmd == 'mceInsertContent' ) {
node = ed.dom.getParent(ed.selection.getNode(), 'div.mceTemp');

if ( !node )
return;

p = ed.dom.create('p');
ed.dom.insertAfter( p, node );
ed.selection.setCursorLocation(p, 0);
}
});
},

_do_shcode : function(content) {
return content.replace(/(?:<p>)?\[(?:wp_)?caption([^\]]+)\]([\s\S]+?)\[\/(?:wp_)?caption\](?:<\/p>)?/g, function(a,b,c){
var id, cls, w, cap, div_cls, img, trim = tinymce.trim;

id = b.match(/id=['"]([^'"]*)['"] ?/);
if ( id )
b = b.replace(id[0], '');

cls = b.match(/align=['"]([^'"]*)['"] ?/);
if ( cls )
b = b.replace(cls[0], '');

w = b.match(/width=['"]([0-9]*)['"] ?/);
if ( w )
b = b.replace(w[0], '');

c = trim(c);
img = c.match(/((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)([\s\S]*)/i);

if ( img && img[2] ) {
cap = trim(img[2].toString().split('</figure> ')[1]);
img = trim( img[1] );
} else {
// old captions shortcode style
cap = trim(b).replace(/caption=['"]/, '').replace(/['"]$/, '');
img = c;
}

id = ( id && id[1] ) ? id[1] : '';
cls = ( cls && cls[1] ) ? cls[1] : 'alignnone';
w = ( w && w[1] ) ? w[1] : '';

if ( !w || !cap )
return c;

div_cls = 'mceTemp';
if ( cls == 'aligncenter' )
div_cls += ' mceIEcenter';

return '<figure id="'+id+'" class="wp-caption '+cls+'" style="width: '+( 10 + parseInt(w) )+
'px">'+img+'<figcaption class="wp-caption-dd">'+cap+'</figcaption></figure>';
});
},

_get_shcode : function(content) {
return content.replace(/<div (?:id="attachment_|class="mceTemp)[^>]*>([\s\S]+?)<\/div>/g, function(a, b){
var ret = b.replace(/<figure ([^>]+)>\s*([\s\S]+?)\s*<figcaption [^>]+>([\s\S]*?)<\/figcaption>\s*<\/figure>/gi, function(a,b,c,cap){
var id, cls, w;

w = c.match(/width="([0-9]*)"/);
w = ( w && w[1] ) ? w[1] : '';

if ( !w || !cap )
return c;

id = b.match(/id="([^"]*)"/);
id = ( id && id[1] ) ? id[1] : '';

cls = b.match(/class="([^"]*)"/);
cls = ( cls && cls[1] ) ? cls[1] : '';
cls = cls.match(/align[a-z]+/) || 'alignnone';

cap = cap.replace(/\r\n|\r/g, '').replace(/<[a-zA-Z0-9]+( [^<>]+)?>/g, function(a){
// no line breaks inside HTML tags
return a.replace(/[\r\n\t]+/, '');
});

// convert remaining line breaks to <br>
cap = cap.replace(/\s*\n\s*/g, '');

return '[caption id="'+id+'" align="'+cls+'" width="'+w+'"]'+c+' '+cap+'[/caption]';
});

if ( ret.indexOf('[caption') !== 0 ) {
// the caption html seems brocken, try to find the image that may be wrapped in a link
// and may be followed by <p> with the caption text.
ret = b.replace(/[\s\S]*?((?:<a [^>]+>)?<img [^>]+>(?:<\/a>)?)(<p>[\s\S]*<\/p>)?[\s\S]*/gi, '<p>$1</p>$2');
}

return ret;
});
},

_createButtons : function() {
var t = this, ed = tinymce.activeEditor, DOM = tinymce.DOM, editButton, dellButton, isRetina;

if ( DOM.get('wp_editbtns') )
return;

isRetina = ( window.devicePixelRatio && window.devicePixelRatio > 1 ) || // WebKit, Opera
( window.matchMedia && window.matchMedia('(min-resolution:130dpi)').matches ); // Firefox, IE10, Opera

DOM.add(document.body, 'div', {
id : 'wp_editbtns',
style : 'display:none;'
});

editButton = DOM.add('wp_editbtns', 'img', {
src : isRetina ? t.url+'/img/image-2x.png' : t.url+'/img/image.png',
id : 'wp_editimgbtn',
width : '24',
height : '24',
title : ed.getLang('wpeditimage2.edit_img')
});

tinymce.dom.Event.add(editButton, 'mousedown', function(e) {
t._editImage();
ed.plugins.wordpress._hideButtons();
});

dellButton = DOM.add('wp_editbtns', 'img', {
src : isRetina ? t.url+'/img/delete-2x.png' : t.url+'/img/delete.png',
id : 'wp_delimgbtn',
width : '24',
height : '24',
title : ed.getLang('wpeditimage2.del_img')
});

tinymce.dom.Event.add(dellButton, 'mousedown', function(e) {
var ed = tinymce.activeEditor, el = ed.selection.getNode(), parent;

if ( el.nodeName == 'IMG' && ed.dom.getAttrib(el, 'class').indexOf('mceItem') == -1 ) {
if ( (parent = ed.dom.getParent(el, 'div')) && ed.dom.hasClass(parent, 'mceTemp') ) {
ed.dom.remove(parent);
} else {
if ( el.parentNode.nodeName == 'A' && el.parentNode.childNodes.length == 1 )
el = el.parentNode;

if ( el.parentNode.nodeName == 'P' && el.parentNode.childNodes.length == 1 )
el = el.parentNode;

ed.dom.remove(el);
}

ed.execCommand('mceRepaint');
return false;
}
ed.plugins.wordpress._hideButtons();
});
},

_editImage : function() {
var ed = tinymce.activeEditor, url = this.url, el = ed.selection.getNode(), vp, H, W, cls = el.className;

if ( cls.indexOf('mceItem') != -1 || cls.indexOf('wpGallery') != -1 || el.nodeName != 'IMG' )
return;

vp = tinymce.DOM.getViewPort();
H = 680 < (vp.h - 70) ? 680 : vp.h - 70;
W = 650 < vp.w ? 650 : vp.w;

ed.windowManager.open({
file: url + '/editimage.html',
width: W+'px',
height: H+'px',
inline: true
});
},

_showButtons : function(e) {
var ed = this.editor, target = e.target;

if ( target.nodeName != 'IMG' ) {
if ( target.firstChild && target.firstChild.nodeName == 'IMG' && target.childNodes.length == 1 ) {
target = target.firstChild;
} else {
ed.plugins.wordpress._hideButtons();
return;
}
}

if ( ed.dom.getAttrib(target, 'class').indexOf('mceItem') == -1 ) {
mouse = {
x: e.clientX,
y: e.clientY,
img_w: target.clientWidth,
img_h: target.clientHeight
};

if ( e.type == 'touchstart' ) {
ed.selection.select(target);
ed.dom.events.cancel(e);
}

ed.plugins.wordpress._hideButtons();
ed.plugins.wordpress._showButtons(target, 'wp_editbtns');
}
},

getInfo : function() {
return {
longname : 'Edit Image',
author : 'WordPress',
authorurl : 'http://wordpress.org',
infourl : '',
version : "1.0"
};
}
});

tinymce.PluginManager.add('wpeditimage2', tinymce.plugins.wpEditImage2);
})();


andrewsan comments:

hallo webGP - just logged in: many thanks indeed: I'll plug, play and get back to you - best regards, Andrewsan


andrewsan comments:


OK here we go: what comes out - in both the editors (vis and text) and on the final web page is this format:


<figure id="attachment_1951" class="frame-alignleft-full">
<img class="size-full wp-image-1951" src="http://.../wp-content/uploads/2013/03/wright_2.png" alt="via text editor">
</img>
<figcaption class="caption-left-full">
with a caption
</figcaption>
</figure>
with a caption


i.e. a duplicate cope of the caption text outside and after the figure statement.

And I can't think for the life of me how to get rid of it. Some thoughts:
* deliver it to the editors and the web page wrapped in a p or div with an id or class so that it can be hidden via css with display: none;
* a preg replace (but at what point in the sequence?) that says 'kill not only the contents of the square brackets, but also the duplicate copy of the caption text'

Any thoughts?

cheers,
andrewsan





andrewsan comments:

hang on a sec. - forget my last feedback for a moment ... I just noticed something:

in your first code for functions.php, you began by namimg the function cutom_image_wrapper ('s' missing) ... and at the end it was referenced as custom_image_wrapper ... (now correctly matched in functions.php)

reality check: I use the additional php code together with the new js, yes?


andrewsan comments:

back again after exhaustive testing:

whenever an image is added into the vis or text editors, it is wrapped in unwanted and unnecessary code:


[caption id="attachment_1951" align="alignleft" width="384"]

<figure id="attachment_1951 " class="frame-left-medium">
<img src="http://.. .png" alt="x" width="384" height="231" class="alignsize-medium wp-image-1951" />
<figcaption class="caption-left-medium">with a caption</figcaption>
</figure>

with a caption[/caption]


this unwanted code is nowhere in the functions.php or the js ... I've no idea where it comes from.

however: is it possible to find the source
and then schedule a new filter afterwards that selectively deletes:

- for any html string in a post that begins with sq-bracket caption cls-sq-bracket
* the first 'caption' in square brackets
* everything after the last closing greater-than

?

cheers,
Andrewsan


webGP comments:

Hello!

I use your functions.php code and my newest js code and when image is added wordpress put this code into editor:

<figure class="wp-caption alignright" id="attachment_11" style="width: 1610px;"><img class="size-full wp-image-11" alt="test" src="http://....jpg" width="1600" height="2000" /><figcaption class="wp-caption-dd">test</figcaption></figure>


Please don't use my funtions.php and everything should work.


andrewsan comments:

wish I got the same!!!

right now, I'm getting that plus arepeat of the caption:


<body id="tinymce" class="mceContentBody content post-type-post wp-editor" contenteditable="true" onload="window.parent.tinyMCE.get('content').onLoad.dispatch();" dir="ltr">

<div class="mceTemp">
<figure id="attachment_675" class="wp-caption alignleft" data-mce-style="width: 310px;" style="width: 310px">

<img class="size-medium wp-image-675" width="300" height="198" data-mce-src="http://www.andrewsan.com/wp-content/uploads/2011/01/boat-300x198.jpg" src="http://www.andrewsan.com/wp-content/uploads/2011/01/boat-300x198.jpg" alt="boat"></img>

<figcaption class="wp-caption-dd"></figcaption>
</figure>
</div>

<p>
A picture is worth a thousand words
</p>

</body>


am I missing something terribly simple on controls/settings, that the caption gets repeated?


webGP comments:

Really strange, once again, I have this code: [[LINK href="http://pastebin.com/qNDLgJTB"]][[/LINK]] in functions.php file and this code: [[LINK href="http://pastebin.com/B1Kwdw7E"]][[/LINK]] in editor_plugin_src.js file and everything works great.


webGP comments:

Hmm, my links disappeared, first for functions.php goes here: http://pastebin.com/qNDLgJTB and seconf for editor_plugin_src.js goes here: http://pastebin.com/B1Kwdw7E


andrewsan comments:

I re-loaded both the php code and the js code from your files;
I get the same again: duplicated caption from the standard wp-shortcode.

it seems to be hard-wired into another part of wp.

Hum. it's head-scratching time.

also supper. I think about what I might be doing wrong overnight ...

meantime, thanks for your support and your patience, webGP

cheers,
Andrewsan


andrewsan comments:

Yes! I got it to work: no duplicated caption text :-)

happy camper.

what was the effort from your side?

best regards,
Andrewsan


webGP comments:

I worked on it for about an hour.


andrewsan comments:

hallo webGP,

apologies for the silence, I've been offline and out of town ...
what's an appropriate 'thank you' for your time?

best regards
Andrewsan