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 @@ - + - - - - - - + + + +