diff --git a/wp-admin/css/wp-admin.dev.css b/wp-admin/css/wp-admin.dev.css
index f2d055d47d..3b9dca7e3e 100644
--- a/wp-admin/css/wp-admin.dev.css
+++ b/wp-admin/css/wp-admin.dev.css
@@ -3873,6 +3873,43 @@ abbr.required {
padding-left: 15px;
}
+.media-item .edit-caption-controls {
+ margin: 5px 0;
+ width: 460px;
+}
+
+.media-item .edit-caption-controls label {
+ margin: 5px 0;
+ display: block;
+}
+
+.media-item .edit-caption-controls label span {
+ width: 100px;
+ float: left;
+ line-height: 22px;
+}
+
+.media-item .edit-caption-controls input[type="text"] {
+ width: 335px;
+}
+
+.media-item .caption-insert-link-buttons {
+ text-align: right;
+ margin: 5px 12px;
+}
+
+.media-item .caption-insert-link-wrap {
+ padding: 5px 0 5px 12px;
+ background-color: #f8f8f8;
+ border: 1px solid #eee;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+.media-item .post_excerpt textarea {
+ height: 60px;
+}
+
/*------------------------------------------------------------------------------
14.1 - Media Library
------------------------------------------------------------------------------*/
@@ -7940,4 +7977,4 @@ a.widget-control-edit {
}
.locale-ru-ru .pressthis a {
width: 143px; /* default 113px + 30px */
-}
\ No newline at end of file
+}
diff --git a/wp-admin/includes/media.php b/wp-admin/includes/media.php
index f77459a7e0..0ae2f100ed 100644
--- a/wp-admin/includes/media.php
+++ b/wp-admin/includes/media.php
@@ -149,22 +149,28 @@ function image_add_caption( $html, $id, $caption, $title, $align, $url, $size, $
$width = $matches[1];
- $caption = str_replace( array( '>', '<', '"', "'" ),
- array( '>', '<', '"', ''' ),
- $caption
- );
+ $caption = preg_replace_callback( '/<[a-zA-Z][^<>]+>/', '_cleanup_image_add_caption', $caption );
+ $caption = str_replace( '"', '"', $caption );
$html = preg_replace( '/(class=["\'][^\'"]*)align(none|left|right|center)\s?/', '$1', $html );
if ( empty($align) )
$align = 'none';
$shcode = '[caption id="' . $id . '" align="align' . $align
- . '" width="' . $width . '" caption="' . addslashes($caption) . '"]' . $html . '[/caption]';
+ . '" width="' . $width . '" caption="' . $caption . '"]' . $html . '[/caption]';
return apply_filters( 'image_add_caption_shortcode', $shcode, $html );
}
add_filter( 'image_send_to_editor', 'image_add_caption', 20, 8 );
+// Private, preg_replace callback used in image_add_caption()
+function _cleanup_image_add_caption($str) {
+ if ( isset($str[0]) )
+ return str_replace( '"', "'", $str[0] );
+
+ return '';
+}
+
/**
* {@internal Missing Short Description}}
*
@@ -776,12 +782,33 @@ function image_link_input_fields($post, $url_type = '') {
return "
-
-
-
+
+
+
";
}
+function wp_caption_input_textarea($edit_post) {
+ // post data is already escaped
+ $name = "attachments[{$edit_post->ID}][post_excerpt]";
+
+ return '
+
+
+ ';
+}
+
/**
* {@internal Missing Short Description}}
*
@@ -924,8 +951,9 @@ function get_attachment_fields_to_edit($post, $errors = null) {
),
'image_alt' => array(),
'post_excerpt' => array(
- 'label' => __('Caption'),
- 'value' => $edit_post->post_excerpt
+ 'label' => __('Default Caption'),
+ 'input' => 'html',
+ 'html' => wp_caption_input_textarea($edit_post)
),
'post_content' => array(
'label' => __('Description'),
@@ -1202,9 +1230,11 @@ function get_media_item( $attachment_id, $args = null ) {
if ( !empty( $field[ $field['input'] ] ) )
$item .= $field[ $field['input'] ];
elseif ( $field['input'] == 'textarea' ) {
- if ( user_can_richedit() ) { // textarea_escaped when user_can_richedit() = false
- $field['value'] = esc_textarea( $field['value'] );
+ if ( 'post_content' == $id && user_can_richedit() ) {
+ // sanitize_post() skips the post_content when user_can_richedit
+ $field['value'] = htmlspecialchars( $field['value'], ENT_QUOTES );
}
+ // post_excerpt is already escaped by sanitize_post() in get_attachment_fields_to_edit()
$item .= "';
} else {
$item .= "";
@@ -1513,8 +1543,13 @@ var addExtImage = {
alt = f.alt.value.replace(/'/g, ''').replace(/"/g, '"').replace(//g, '>');
- if ( f.caption.value )
- caption = f.caption.value.replace(/'/g, ''').replace(/"/g, '"').replace(//g, '>');
+ if ( f.caption.value ) {
+ caption = f.caption.value.replace(/<[a-z][^<>]+>/g, function(a){
+ return a.replace(/"/g, "'");
+ });
+
+ caption = caption.replace(/"/g, '"');
+ }
cls = caption ? '' : ' class="'+t.align+'"';
diff --git a/wp-admin/js/media-upload.dev.js b/wp-admin/js/media-upload.dev.js
index 488e3a01f2..9b998ff2a3 100644
--- a/wp-admin/js/media-upload.dev.js
+++ b/wp-admin/js/media-upload.dev.js
@@ -25,8 +25,8 @@ function send_to_editor(h) {
ed.selection.moveToBookmark(ed.windowManager.insertimagebookmark);
if ( h.indexOf('[caption') === 0 ) {
- if ( ed.plugins.wpeditimage )
- h = ed.plugins.wpeditimage._do_shcode(h);
+ if ( ed.wpSetImgCaption )
+ h = ed.wpSetImgCaption(h);
} else if ( h.indexOf('[gallery') === 0 ) {
if ( ed.plugins.wpgallery )
h = ed.plugins.wpgallery._do_gallery(h);
diff --git a/wp-includes/formatting.php b/wp-includes/formatting.php
index e7a0226867..b27ec2ad28 100644
--- a/wp-includes/formatting.php
+++ b/wp-includes/formatting.php
@@ -1188,14 +1188,14 @@ function force_balance_tags( $text ) {
/**
* Acts on text which is about to be edited.
*
- * Unless $richedit is set, it is simply a holder for the 'format_to_edit'
- * filter. If $richedit is set true htmlspecialchars(), through esc_textarea(),
- * will be run on the content, converting special characters to HTML entities.
+ * The $content is run through esc_textarea(), which uses htmlspecialchars()
+ * to convert special characters to HTML entities. If $richedit is set to true,
+ * it is simply a holder for the 'format_to_edit' filter.
*
* @since 0.71
*
* @param string $content The text about to be edited.
- * @param bool $richedit Whether the $content should pass through htmlspecialchars(). Default false.
+ * @param bool $richedit Whether the $content should not pass through htmlspecialchars(). Default false (meaning it will be passed).
* @return string The text after the filter (and possibly htmlspecialchars()) has been run.
*/
function format_to_edit( $content, $richedit = false ) {
diff --git a/wp-includes/js/plupload/handlers.dev.js b/wp-includes/js/plupload/handlers.dev.js
index d0f8708d7c..3ea0fcfec9 100644
--- a/wp-includes/js/plupload/handlers.dev.js
+++ b/wp-includes/js/plupload/handlers.dev.js
@@ -338,10 +338,43 @@ function uploadSizeError( up, file, over100mb ) {
}
jQuery(document).ready(function($){
- $('.media-upload-form').bind('click.uploader', function(e) {
- var target = $(e.target), tr, c;
+ var insert_link, bookmark;
- if ( target.is('input[type="radio"]') ) { // remember the last used image size and alignment
+ $('.media-upload-form').bind('click.uploader', function(e) {
+ var target = $(e.target), tr, c, el, textarea, sel, text, startPos, endPos;
+
+ if ( target.hasClass('caption-insert-link') ) {
+ el = target.siblings('div.caption-insert-link-wrap'), textarea = target.parent().siblings('textarea').get(0);
+
+ if ( document.selection ) {
+ textarea.focus();
+ sel = document.selection.createRange();
+ bookmark = sel.getBookmark();
+
+ if ( sel.text )
+ el.find('.caption-insert-link-text').val(sel.text);
+
+ } else if ( textarea.selectionStart || textarea.selectionStart == '0' ) {
+ text = textarea.value;
+ startPos = textarea.selectionStart;
+ endPos = textarea.selectionEnd;
+
+ if ( startPos != endPos )
+ el.find('.caption-insert-link-text').val( text.substring(startPos, endPos) );
+ }
+
+ target.hide();
+ el.show();
+ el.find('.caption-insert-link-url').focus();
+ } else if ( target.hasClass('caption-cancel') || target.hasClass('caption-save') ) {
+ el = target.closest('div.caption-insert-link-wrap');
+
+ if ( target.hasClass('caption-save') )
+ insert_link( el.closest('.edit-caption-controls').siblings('textarea'), el );
+
+ el.hide();
+ el.siblings('.caption-insert-link').show();
+ } else if ( target.is('input[type="radio"]') ) { // remember the last used image size and alignment
tr = target.closest('tr');
if ( $(tr).hasClass('align') )
@@ -355,7 +388,7 @@ jQuery(document).ready(function($){
if ( c && c[1] ) {
setUserSetting('urlbutton', c[1]);
- target.siblings('.urlfield').val( target.attr('title') );
+ target.siblings('.urlfield').val( target.data('link-url') );
}
} else if ( target.is('a.dismiss') ) {
target.parents('.media-item').fadeOut(200, function(){
@@ -364,11 +397,11 @@ jQuery(document).ready(function($){
} else if ( target.is('.upload-flash-bypass a') || target.is('a.uploader-html') ) { // switch uploader to html4
$('#media-items, p.submit, span.big-file-warning').css('display', 'none');
switchUploader(0);
- return false;
+ e.preventDefault();
} else if ( target.is('.upload-html-bypass a') ) { // switch uploader to multi-file
$('#media-items, p.submit, span.big-file-warning').css('display', '');
switchUploader(1);
- return false;
+ e.preventDefault();
} else if ( target.is('a.describe-toggle-on') ) { // Show
target.parent().addClass('open');
target.siblings('.slidetoggle').fadeIn(250, function(){
@@ -386,14 +419,53 @@ jQuery(document).ready(function($){
}
}
});
- return false;
+ e.preventDefault();
} else if ( target.is('a.describe-toggle-off') ) { // Hide
target.siblings('.slidetoggle').fadeOut(250, function(){
target.parent().removeClass('open');
});
- return false;
+ e.preventDefault();
}
});
+
+ insert_link = function(textarea, parent) {
+ var sel, content, startPos, endPos, scrollTop, text,
+ url = parent.find('.caption-insert-link-url'), link_text = parent.find('.caption-insert-link-text');
+
+ if ( !url.length || !link_text.length )
+ return;
+
+ textarea = textarea.get(0);
+ content = ""+link_text.val()+"";
+
+ if ( document.selection ) {
+ textarea.focus();
+ sel = document.selection.createRange();
+
+ if ( bookmark ) {
+ sel.moveToBookmark( bookmark );
+ bookmark = '';
+ }
+
+ sel.text = content;
+ textarea.focus();
+ } else if ( textarea.selectionStart || textarea.selectionStart == '0' ) {
+ text = textarea.value;
+ startPos = textarea.selectionStart;
+ endPos = textarea.selectionEnd;
+ scrollTop = textarea.scrollTop;
+
+ textarea.value = text.substring(0, startPos) + content + text.substring(endPos, text.length);
+
+ textarea.focus();
+ textarea.selectionStart = startPos + content.length;
+ textarea.selectionEnd = startPos + content.length;
+ textarea.scrollTop = scrollTop;
+ }
+
+ url.val('');
+ link_text.val('');
+ };
// init and set the uploader
uploader_init = function() {
diff --git a/wp-includes/js/tinymce/langs/wp-langs-en.js b/wp-includes/js/tinymce/langs/wp-langs-en.js
index 7909082a1d..f1674f21f7 100644
--- a/wp-includes/js/tinymce/langs/wp-langs-en.js
+++ b/wp-includes/js/tinymce/langs/wp-langs-en.js
@@ -12,7 +12,7 @@ not_set:"-- Not set --",
clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.",
clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",
popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",
-invalid_data:"Error: Invalid values entered, these are marked in red.",
+invalid_data:"ERROR: Invalid values entered, these are marked in red.",
invalid_data_number:"{#field} must be a number",
invalid_data_min:"{#field} must be a number greater than {#min}",
invalid_data_size:"{#field} must be a number or percentage",
@@ -240,8 +240,8 @@ code:"Code",
samp:"Code sample",
dt:"Definition term ",
dd:"Definition description",
-bold_desc:"Bold (Ctrl / Alt + Shift + B)",
-italic_desc:"Italic (Ctrl / Alt + Shift + I)",
+bold_desc:"Bold (Ctrl + B)",
+italic_desc:"Italic (Ctrl + I)",
underline_desc:"Underline",
striketrough_desc:"Strikethrough (Alt + Shift + D)",
justifyleft_desc:"Align Left (Alt + Shift + L)",
@@ -266,6 +266,7 @@ removeformat_desc:"Remove formatting",
forecolor_desc:"Select text color",
backcolor_desc:"Select background color",
charmap_desc:"Insert custom character",
+charmap_usage:"Use left and right arrows to navigate.",
visualaid_desc:"Toggle guidelines/invisible elements",
anchor_desc:"Insert/edit anchor",
cut_desc:"Cut",
@@ -498,5 +499,7 @@ s120:"120%",
s130:"130%",
img_title:"Title",
caption:"Caption",
+insert_link:"Insert link",
+linked_text:"Linked text",
alt:"Alternate Text"
});
diff --git a/wp-includes/js/tinymce/langs/wp-langs.php b/wp-includes/js/tinymce/langs/wp-langs.php
index f9299fb157..f9f959b84a 100644
--- a/wp-includes/js/tinymce/langs/wp-langs.php
+++ b/wp-includes/js/tinymce/langs/wp-langs.php
@@ -275,6 +275,7 @@ removeformat_desc:"' . mce_escape( __('Remove formatting') ) . '",
forecolor_desc:"' . mce_escape( __('Select text color') ) . '",
backcolor_desc:"' . mce_escape( __('Select background color') ) . '",
charmap_desc:"' . mce_escape( __('Insert custom character') ) . '",
+charmap_usage:"' . mce_escape( __('Use left and right arrows to navigate.') ) . '",
visualaid_desc:"' . mce_escape( __('Toggle guidelines/invisible elements') ) . '",
anchor_desc:"' . mce_escape( __('Insert/edit anchor') ) . '",
cut_desc:"' . mce_escape( __('Cut') ) . '",
@@ -507,6 +508,8 @@ s120:"' . mce_escape( __('120%') ) . '",
s130:"' . mce_escape( __('130%') ) . '",
img_title:"' . mce_escape( __('Title') ) . '",
caption:"' . mce_escape( __('Caption') ) . '",
+insert_link:"' . mce_escape( __('Insert link') ) . '",
+linked_text:"' . mce_escape( __('Linked text') ) . '",
alt:"' . mce_escape( __('Alternate Text') ) . '"
});
';
diff --git a/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage-rtl.css b/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage-rtl.css
deleted file mode 100644
index e78820ffef..0000000000
--- a/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage-rtl.css
+++ /dev/null
@@ -1,68 +0,0 @@
-
-body#media-upload ul#sidemenu {
- left: auto;
- right: 0;
-}
-
-#basic .align .field label {
- display: block;
- float: right;
- padding: 0 24px 0 0;
- margin: 5px 3px 5px 5px;
-}
-
-.align .field input {
- display: block;
- float: right;
- margin: 5px 15px 5px 0;
-}
-
-tr.image-size label {
- margin: 0;
-}
-
-tr.image-size input {
- margin: 3px 15px 0 5px;
-}
-
-.image-align-none-label,
-.image-align-left-label,
-.image-align-center-label,
-.image-align-right-label {
- background-position: center right;
-}
-
-#media-upload .describe th.label {
- text-align: right;
-}
-
-.show-align,
-.alignright,
-#img_size {
- float: left;
-}
-
-tr.image-size label,
-tr.image-size input,
-#img_dim label,
-#img_dim input,
-#img_prop label,
-#img_prop input,
-#img_size_div,
-.alignleft {
- float: right;
-}
-
-#img_dim label,
-#img_prop label {
- margin: 5px 0pt;
-}
-
-#img_dim input,
-#img_prop input {
- margin: 0 5px 0 10px;
-}
-
-#img_size_title {
- text-align: left;
-}
diff --git a/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage.css b/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage.css
index e2ff8dac5c..72f313d269 100644
--- a/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage.css
+++ b/wp-includes/js/tinymce/plugins/wpeditimage/css/editimage.css
@@ -356,3 +356,112 @@ div#media-upload-error {
background-color: #222222;
color: #CFCFCF;
}
+
+#img-edit .edit-caption-controls {
+ margin: 5px 0;
+}
+
+#img-edit .edit-caption-controls label {
+ margin: 5px 0;
+ display: block;
+}
+
+#img-edit .edit-caption-controls label span {
+ width: 100px;
+ float: left;
+ line-height: 22px;
+}
+
+#img-edit .edit-caption-controls input[type="text"] {
+ width: 335px;
+}
+
+#img-edit .caption-insert-link-buttons {
+ text-align: right;
+ margin: 5px 12px;
+}
+
+#img-edit .caption-insert-link-wrap {
+ padding: 5px 0 5px 12px;
+ background-color: #f8f8f8;
+ border: 1px solid #eee;
+ -webkit-border-radius: 3px;
+ border-radius: 3px;
+}
+
+#img-edit #img_cap_text {
+ font: normal 12px/18px monospace;
+}
+
+.hidden {
+ display: none;
+}
+
+/* RTL */
+body#media-upload.rtl ul#sidemenu {
+ left: auto;
+ right: 0;
+}
+
+.rtl #basic .align .field label {
+ display: block;
+ float: right;
+ padding: 0 24px 0 0;
+ margin: 5px 3px 5px 5px;
+}
+
+.rtl .align .field input {
+ display: block;
+ float: right;
+ margin: 5px 15px 5px 0;
+}
+
+.rtl tr.image-size label {
+ margin: 0;
+}
+
+.rtl tr.image-size input {
+ margin: 3px 15px 0 5px;
+}
+
+.rtl .image-align-none-label,
+.rtl .image-align-left-label,
+.rtl .image-align-center-label,
+.rtl .image-align-right-label {
+ background-position: center right;
+}
+
+#media-upload.rtl .describe th.label {
+ text-align: right;
+}
+
+.rtl .show-align,
+.rtl .alignright,
+.rtl #img_size {
+ float: left;
+}
+
+.rtl tr.image-size label,
+.rtl tr.image-size input,
+.rtl #img_dim label,
+.rtl #img_dim input,
+.rtl #img_prop label,
+.rtl #img_prop input,
+.rtl #img_size_div,
+.rtl .alignleft {
+ float: right;
+}
+
+.rtl #img_dim label,
+.rtl #img_prop label {
+ margin: 5px 0pt;
+}
+
+.rtl #img_dim input,
+.rtl #img_prop input {
+ margin: 0 5px 0 10px;
+}
+
+.rtl #img_size_title {
+ text-align: left;
+}
diff --git a/wp-includes/js/tinymce/plugins/wpeditimage/editimage.html b/wp-includes/js/tinymce/plugins/wpeditimage/editimage.html
index d7ad227168..643780104f 100644
--- a/wp-includes/js/tinymce/plugins/wpeditimage/editimage.html
+++ b/wp-includes/js/tinymce/plugins/wpeditimage/editimage.html
@@ -1,22 +1,20 @@
-
+
-
-
-
-
-
-
+
+
+
+