Ticket #26959: 26959-02.patch
File 26959-02.patch, 27.3 KB (added by , 11 years ago) |
---|
-
src/wp-includes/class-wp-editor.php
diff --git src/wp-includes/class-wp-editor.php src/wp-includes/class-wp-editor.php index 5a169bb..ef4ffb0 100644
final class _WP_Editors { 231 231 'fullscreen', 232 232 'wordpress', 233 233 'wpeditimage', 234 'wpgallery',235 234 'wplink', 236 235 'wpdialogs', 236 'wpview' 237 237 ) ) ); 238 238 239 239 if ( ( $key = array_search( 'spellchecker', $plugins ) ) !== false ) { … … final class _WP_Editors { 489 489 if ( self::$has_medialib ) { 490 490 add_thickbox(); 491 491 wp_enqueue_script('media-upload'); 492 493 if ( self::$has_tinymce ) 494 wp_enqueue_script('mce-view'); 492 495 } 496 493 497 } 494 498 495 499 public static function wp_mce_translation() { -
src/wp-includes/css/editor.css
diff --git src/wp-includes/css/editor.css src/wp-includes/css/editor.css index b240346..819cdfb 100644
i.mce-i-wp_page:before { 1079 1079 padding-left: 12px; 1080 1080 } 1081 1081 */ 1082 1083 1084 1082 1085 /* Distraction Free Writing mode 1083 1086 * =Overlay Styles 1084 1087 -------------------------------------------------------------- */ -
src/wp-includes/js/mce-view.js
diff --git src/wp-includes/js/mce-view.js src/wp-includes/js/mce-view.js index 912c4c7..753ae66 100644
window.wp = window.wp || {}; 3 3 4 4 (function($){ 5 5 var views = {}, 6 instances = {}; 6 instances = {}, 7 media = wp.media; 7 8 8 9 // Create the `wp.mce` object if necessary. 9 10 wp.mce = wp.mce || {}; … … window.wp = window.wp || {}; 25 26 }, 26 27 27 28 toView: function( content ) { 28 if ( ! this.pattern ) 29 if ( ! this.pattern ) { 29 30 return; 31 } 30 32 31 33 this.pattern.lastIndex = 0; 32 34 var match = this.pattern.exec( content ); 33 35 34 if ( ! match ) 36 if ( ! match ) { 35 37 return; 38 } 36 39 37 40 return { 38 41 index: match.index, … … window.wp = window.wp || {}; 56 59 toView: function( content ) { 57 60 var match = wp.shortcode.next( this.shortcode, content ); 58 61 59 if ( ! match ) 62 if ( ! match ) { 60 63 return; 64 } 61 65 62 66 return { 63 67 index: match.index, … … window.wp = window.wp || {}; 98 102 var parent, remove, base, properties; 99 103 100 104 // Fetch the parent view or the default options. 101 if ( options.extend ) 105 if ( options.extend ) { 102 106 parent = wp.mce.view.get( options.extend ); 103 else if ( options.shortcode )107 } else if ( options.shortcode ) { 104 108 parent = wp.mce.view.defaults.shortcode; 105 else109 } else { 106 110 parent = wp.mce.view.defaults.pattern; 111 } 107 112 108 113 // Extend the `options` object with the parent's properties. 109 114 _.defaults( options, parent ); … … window.wp = window.wp || {}; 118 123 this.$el.parent().remove(); 119 124 120 125 // Trigger the inherited `remove` method. 121 if ( remove ) 126 if ( remove ) { 122 127 remove.apply( this, arguments ); 128 } 123 129 124 130 return this; 125 131 } … … window.wp = window.wp || {}; 138 144 139 145 // If there's a `remove` method on the `base` view that wasn't 140 146 // created by this method, inherit it. 141 if ( ! remove && ! base._mceview ) 147 if ( ! remove && ! base._mceview ) { 142 148 remove = base.prototype.remove; 149 } 143 150 144 151 // Automatically create the new `Backbone.View` constructor. 145 152 options.view = base.extend( properties, { … … window.wp = window.wp || {}; 168 175 // every match. 169 176 // 170 177 // To render the views, call `wp.mce.view.render( scope )`. 178 // TODO: needs unit tests! 171 179 toViews: function( content ) { 172 180 var pieces = [ { content: content } ], 173 181 current; … … window.wp = window.wp || {}; 190 198 // and slicing the string as we go. 191 199 while ( remaining && (result = view.toView( remaining )) ) { 192 200 // Any text before the match becomes an unprocessed piece. 193 if ( result.index ) 201 if ( result.index ) { 194 202 pieces.push({ content: remaining.substring( 0, result.index ) }); 203 } 195 204 196 205 // Add the processed piece for the match. 197 206 pieces.push({ … … window.wp = window.wp || {}; 205 214 206 215 // There are no additional matches. If any content remains, 207 216 // add it as an unprocessed piece. 208 if ( remaining ) 217 if ( remaining ) { 209 218 pieces.push({ content: remaining }); 219 } 210 220 }); 211 221 }); 212 222 … … window.wp = window.wp || {}; 217 227 var view = wp.mce.view.get( viewType ), 218 228 instance, id; 219 229 220 if ( ! view ) 230 if ( ! view ) { 221 231 return ''; 222 232 } 223 233 // Create a new view instance. 224 234 instance = new view.view( _.extend( options || {}, { 225 235 viewType: viewType … … window.wp = window.wp || {}; 239 249 tag: 'span' === instance.tagName ? 'span' : 'div', 240 250 241 251 attrs: { 242 'class': 252 'class': 'wp-view-wrap wp-view-type-' + viewType, 243 253 'data-wp-view': id, 244 254 'contenteditable': false 245 } 255 }, 256 257 content: '\u00a0' 246 258 }); 247 259 }, 248 260 … … window.wp = window.wp || {}; 255 267 render: function( scope ) { 256 268 $( '.wp-view-wrap', scope ).each( function() { 257 269 var wrapper = $(this), 258 view = wp.mce.view.instance( this ); 270 view = wp.mce.view.instance( this ), 271 $shortcode; 259 272 260 if ( ! view ) 273 if ( ! view ) { 261 274 return; 275 } 262 276 263 277 // Link the real wrapper to the view. 264 278 view.$wrapper = wrapper; … … window.wp = window.wp || {}; 267 281 // Detach the view element to ensure events are not unbound. 268 282 view.$el.detach(); 269 283 284 $shortcode = $( '<div />' ) 285 .addClass( 'wp-view-shortcode' ) 286 .prop( 'contenteditable', 'true' ) 287 .data( 'mce-bogus', '1' ) 288 .text( view.options.shortcode.string() ); 289 270 290 // Empty the wrapper, attach the view element to the wrapper, 291 // add a hidden element with the shortcode, 271 292 // and add an ending marker to the wrapper to help regexes 272 293 // scan the HTML string. 273 wrapper.empty().append( view.el ).append('<span data-wp-view-end class="wp-view-end"></span>'); 294 wrapper.empty().append( view.el ) 295 .prepend( $shortcode ) 296 .append('<span data-wp-view-end class="wp-view-end"></span>'); 274 297 }); 275 298 }, 276 299 … … window.wp = window.wp || {}; 278 301 // Scans an HTML `content` string and replaces any view instances with 279 302 // their respective text representations. 280 303 toText: function( content ) { 281 return content.replace( /<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?<span[^>]+data-wp-view-end[^>]*><\/span><\/(?:div|span)>/g, function( match, id ) { 304 305 return content.replace( /<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?<span[^>]+data-wp-view-end[^>]*><\/span><\/(?:div|span)>/mg, function( match, id ) { 282 306 var instance = instances[ id ], 283 307 view; 284 308 285 if ( instance ) 309 if ( instance ) { 286 310 view = wp.mce.view.get( instance.options.viewType ); 287 311 } 288 312 return instance && view ? view.text( instance ) : ''; 289 313 }); 290 314 }, … … window.wp = window.wp || {}; 293 317 removeInternalAttrs: function( attrs ) { 294 318 var result = {}; 295 319 _.each( attrs, function( value, attr ) { 296 if ( -1 === attr.indexOf('data-mce') ) 320 if ( -1 === attr.indexOf('data-mce') ) { 297 321 result[ attr ] = value; 322 } 298 323 }); 299 324 return result; 300 325 }, … … window.wp = window.wp || {}; 311 336 instance: function( node ) { 312 337 var id = $( node ).data('wp-view'); 313 338 314 if ( id ) 339 if ( id ) { 315 340 return instances[ id ]; 341 } 316 342 }, 317 343 318 344 // ### Select a view. … … window.wp = window.wp || {}; 323 349 var $node = $(node); 324 350 325 351 // Bail if node is already selected. 326 if ( $node.hasClass('selected') ) 352 if ( $node.hasClass('selected') ) { 327 353 return; 354 } 328 355 329 356 $node.addClass('selected'); 330 357 $( node.firstChild ).trigger('select'); … … window.wp = window.wp || {}; 338 365 var $node = $(node); 339 366 340 367 // Bail if node is already selected. 341 if ( ! $node.hasClass('selected') ) 368 if ( ! $node.hasClass('selected') ) { 342 369 return; 370 } 343 371 344 372 $node.removeClass('selected'); 345 373 $( node.firstChild ).trigger('deselect'); 346 374 } 347 375 }; 348 376 349 }(jQuery)); 350 No newline at end of file 377 wp.mce.view.add( 'gallery', { 378 shortcode: 'gallery', 379 380 gallery: (function() { 381 var galleries = {}; 382 383 return { 384 attachments: function( shortcode, parent ) { 385 var shortcodeString = shortcode.string(), 386 result = galleries[ shortcodeString ], 387 attrs, args, query, others; 388 389 delete galleries[ shortcodeString ]; 390 391 if ( result ) { 392 return result; 393 } 394 395 attrs = shortcode.attrs.named; 396 args = _.pick( attrs, 'orderby', 'order' ); 397 398 args.type = 'image'; 399 args.perPage = -1; 400 401 // Map the `ids` param to the correct query args. 402 if ( attrs.ids ) { 403 args.post__in = attrs.ids.split(','); 404 args.orderby = 'post__in'; 405 } else if ( attrs.include ) { 406 args.post__in = attrs.include.split(','); 407 } 408 409 if ( attrs.exclude ) { 410 args.post__not_in = attrs.exclude.split(','); 411 } 412 413 if ( ! args.post__in ) { 414 args.parent = attrs.id || parent; 415 } 416 417 // Collect the attributes that were not included in `args`. 418 others = {}; 419 _.filter( attrs, function( value, key ) { 420 if ( _.isUndefined( args[ key ] ) ) { 421 others[ key ] = value; 422 } 423 }); 424 425 query = media.query( args ); 426 query.gallery = new Backbone.Model( others ); 427 return query; 428 }, 429 430 shortcode: function( attachments ) { 431 var props = attachments.props.toJSON(), 432 attrs = _.pick( props, 'include', 'exclude', 'orderby', 'order' ), 433 shortcode, clone; 434 435 if ( attachments.gallery ) { 436 _.extend( attrs, attachments.gallery.toJSON() ); 437 } 438 439 attrs.ids = attachments.pluck('id'); 440 441 // If the `ids` attribute is set and `orderby` attribute 442 // is the default value, clear it for cleaner output. 443 if ( attrs.ids && 'post__in' === attrs.orderby ) { 444 delete attrs.orderby; 445 } 446 447 shortcode = new wp.shortcode({ 448 tag: 'gallery', 449 attrs: attrs, 450 type: 'single' 451 }); 452 453 // Use a cloned version of the gallery. 454 clone = new wp.media.model.Attachments( attachments.models, { 455 props: props 456 }); 457 clone.gallery = attachments.gallery; 458 galleries[ shortcode.string() ] = clone; 459 460 return shortcode; 461 } 462 }; 463 }()), 464 465 view: { 466 className: 'editor-gallery', 467 template: media.template('editor-gallery'), 468 469 // The fallback post ID to use as a parent for galleries that don't 470 // specify the `ids` or `include` parameters. 471 // 472 // Uses the hidden input on the edit posts page by default. 473 parent: $('#post_ID').val(), 474 475 events: { 476 'click .remove': 'remove', 477 'click .edit': 'edit' 478 }, 479 480 initialize: function() { 481 this.update(); 482 }, 483 484 update: function() { 485 var view = wp.mce.view.get('gallery'); 486 487 this.attachments = view.gallery.attachments( this.options.shortcode, this.parent ); 488 this.attachments.more().done( _.bind( this.render, this ) ); 489 }, 490 491 492 render: function() { 493 var attrs = this.options.shortcode.attrs.named, 494 options; 495 496 if ( ! this.attachments.length ) { 497 return; 498 } 499 500 options = { 501 attachments: this.attachments.toJSON(), 502 columns: attrs.columns ? parseInt( attrs.columns, 10 ) : 3 503 }; 504 505 this.$el.html( this.template( options ) ); 506 }, 507 508 edit: function() { 509 var selection; 510 511 if ( ! wp.media.view || this.frame ) { 512 return; 513 } 514 515 selection = new wp.media.model.Selection( this.attachments.models, { 516 props: this.attachments.props.toJSON(), 517 multiple: true 518 }); 519 selection.gallery = this.attachments.gallery; 520 521 this.frame = wp.media({ 522 frame: 'post', 523 state: 'gallery-edit', 524 editing: true, 525 multiple: true, 526 selection: selection 527 }); 528 529 // Create a single-use frame. If the frame is closed, 530 // then detach it from the DOM and remove the reference. 531 this.frame.on( 'close', function() { 532 if ( this.frame ) { 533 this.frame.detach(); 534 } 535 delete this.frame; 536 }, this ); 537 538 // Update the `shortcode` and `attachments`. 539 this.frame.state('gallery-edit').on( 'update', function( selection ) { 540 var view = wp.mce.view.get('gallery'); 541 542 this.options.shortcode = view.gallery.shortcode( selection ); 543 this.update(); 544 }, this ); 545 546 this.frame.open(); 547 } 548 } 549 }); 550 }(jQuery)); -
src/wp-includes/js/tinymce/plugins/wpview/plugin.js
diff --git src/wp-includes/js/tinymce/plugins/wpview/plugin.js src/wp-includes/js/tinymce/plugins/wpview/plugin.js index 0c56ecb..a466abe 100644
2 2 /** 3 3 * WordPress View plugin. 4 4 */ 5 6 (function() { 7 var VK = tinymce.VK, 5 tinymce.PluginManager.add( 'wpview', function( editor ) { 6 var VK = tinymce.util.VK, 8 7 TreeWalker = tinymce.dom.TreeWalker, 8 removeSelected = false, 9 9 selected; 10 10 11 tinymce.create('tinymce.plugins.wpView', { 12 init : function( editor ) { 13 var wpView = this; 11 function getParentView( node ) { 12 while ( node ) { 13 if ( isView( node ) ) { 14 return node; 15 } 16 17 node = node.parentNode; 18 } 19 } 20 21 function isView( node ) { 22 return (/(?:^|\s)wp-view-wrap(?:\s|$)/).test( node.className ); 23 } 24 25 function select( view ) { 26 var elem; 27 if ( view === selected ) { 28 return; 29 } 30 31 deselect(); 32 selected = view; 33 34 elem = editor.dom.select( '.wp-view-shortcode', view )[0]; 35 36 // the following are both necessary to avoid tinymce from manipulating the selection/focus 37 editor.dom.bind(elem, 'beforedeactivate focusin focusout', function(e) { 38 e.stopPropagation(); 39 }); 40 editor.dom.bind(selected, 'beforedeactivate focusin focusout click ouseup', function(e) { 41 e.stopPropagation(); 42 }); 43 44 // select a the hidden div 45 editor.selection.select( elem, true ); 46 elem.focus(); 47 wp.mce.view.select( selected ); 48 } 49 50 function deselect() { 51 var elem; 52 53 if ( selected ) { 54 elem = editor.dom.select( '.wp-view-shortcode', selected )[0]; 55 editor.dom.unbind(elem, 'beforedeactivate focusin focusout'); 56 editor.dom.unbind(selected, 'beforedeactivate focusin focusout click mouseup'); 57 58 editor.selection.select( selected.nextSibling ); 59 editor.selection.collapse(); 60 wp.mce.view.deselect( selected ); 61 } 62 63 selected = null; 64 } 65 66 // Check if the `wp.mce` API exists. 67 if ( typeof wp === 'undefined' || ! wp.mce ) { 68 return; 69 } 70 71 editor.on( 'PreInit', function() { 72 // Add elements so we can set `contenteditable` to false. 73 // TODO: since we are serializing, is this needed? 74 editor.schema.addValidElements('div[*],span[*]'); 75 }); 76 77 // When the editor's content changes, scan the new content for 78 // matching view patterns, and transform the matches into 79 // view wrappers. Since the editor's DOM is outdated at this point, 80 // we'll wait to render the views. 81 editor.on( 'BeforeSetContent', function( e ) { 82 if ( ! e.content ) { 83 return; 84 } 85 86 e.content = wp.mce.view.toViews( e.content ); 87 }); 88 89 // When the editor's content has been updated and the DOM has been 90 // processed, render the views in the document. 91 editor.on( 'SetContent', function() { 92 wp.mce.view.render( editor.getDoc() ); 93 }); 94 95 // Provide our own handler for selecting a view that is picked up before TinyMCE 96 // Ideally, TinyMCE would provide a way to relinquish control over a block that is marked contenteditable=false perhaps through some sort of data attribute 97 editor.on( 'mousedown', function( event ) { 98 var view = getParentView( event.target ); 14 99 15 // Check if the `wp.mce` API exists. 16 if ( typeof wp === 'undefined' || ! wp.mce ) { 100 if ( event.metaKey || event.ctrlKey ) { 101 return; 102 } 103 104 // Update the selected view. 105 if ( view ) { 106 select( view ); 107 108 // maybe we can trigger the mousedown so that a view can listen to it. 109 // Prevent the selection from propagating to other plugins. 110 return false; 111 112 } else { 113 deselect(); 114 } 115 } ); 116 117 editor.on( 'init', function() { 118 var selection = editor.selection; 119 // When a view is selected, ensure content that is being pasted 120 // or inserted is added to a text node (instead of the view). 121 editor.on( 'BeforeSetContent', function() { 122 var walker, target, 123 view = getParentView( selection.getNode() ); 124 125 // If the selection is not within a view, bail. 126 if ( ! view ) { 17 127 return; 18 128 } 19 129 20 editor.on( 'PreInit', function() { 21 // Add elements so we can set `contenteditable` to false. 22 editor.schema.addValidElements('div[*],span[*]'); 23 }); 24 25 // When the editor's content changes, scan the new content for 26 // matching view patterns, and transform the matches into 27 // view wrappers. Since the editor's DOM is outdated at this point, 28 // we'll wait to render the views. 29 editor.on( 'BeforeSetContent', function( e ) { 30 if ( ! e.content ) { 31 return; 32 } 33 34 e.content = wp.mce.view.toViews( e.content ); 35 }); 36 37 // When the editor's content has been updated and the DOM has been 38 // processed, render the views in the document. 39 editor.on( 'SetContent', function() { 40 wp.mce.view.render( editor.getDoc() ); 41 }); 42 43 editor.on( 'init', function() { 44 var selection = editor.selection; 45 // When a view is selected, ensure content that is being pasted 46 // or inserted is added to a text node (instead of the view). 47 editor.on( 'BeforeSetContent', function() { 48 var walker, target, 49 view = wpView.getParentView( selection.getNode() ); 50 51 // If the selection is not within a view, bail. 52 if ( ! view ) { 53 return; 54 } 55 56 // If there are no additional nodes or the next node is a 57 // view, create a text node after the current view. 58 if ( ! view.nextSibling || wpView.isView( view.nextSibling ) ) { 59 target = editor.getDoc().createTextNode(''); 60 editor.dom.insertAfter( target, view ); 61 62 // Otherwise, find the next text node. 63 } else { 64 walker = new TreeWalker( view.nextSibling, view.nextSibling ); 65 target = walker.next(); 66 } 67 68 // Select the `target` text node. 69 selection.select( target ); 70 selection.collapse( true ); 71 }); 72 73 // When the selection's content changes, scan any new content 74 // for matching views and immediately render them. 75 // 76 // Runs on paste and on inserting nodes/html. 77 editor.on( 'SetContent', function( e ) { 78 if ( ! e.context ) { 79 return; 80 } 81 82 var node = selection.getNode(); 83 84 if ( ! node.innerHTML ) { 85 return; 86 } 87 88 node.innerHTML = wp.mce.view.toViews( node.innerHTML ); 89 wp.mce.view.render( node ); 90 }); 91 }); 92 93 // When the editor's contents are being accessed as a string, 94 // transform any views back to their text representations. 95 editor.on( 'PostProcess', function( e ) { 96 if ( ( ! e.get && ! e.save ) || ! e.content ) { 97 return; 98 } 99 100 e.content = wp.mce.view.toText( e.content ); 101 }); 102 103 // Triggers when the selection is changed. 104 // Add the event handler to the top of the stack. 105 editor.on( 'NodeChange', function( e ) { 106 var view = wpView.getParentView( e.element ); 107 108 // Update the selected view. 109 if ( view ) { 110 wpView.select( view ); 111 112 // Prevent the selection from propagating to other plugins. 113 return false; 114 115 // If we've clicked off of the selected view, deselect it. 116 } else { 117 wpView.deselect(); 118 } 119 }); 120 121 editor.on( 'keydown', function( event ) { 122 var keyCode = event.keyCode, 123 view, instance; 124 125 // If a view isn't selected, let the event go on its merry way. 126 if ( ! selected ) { 127 return; 128 } 129 130 // If the caret is not within the selected view, deselect the 131 // view and bail. 132 view = wpView.getParentView( editor.selection.getNode() ); 133 if ( view !== selected ) { 134 wpView.deselect(); 135 return; 136 } 137 138 // If delete or backspace is pressed, delete the view. 139 if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) { 140 if ( (instance = wp.mce.view.instance( selected )) ) { 141 instance.remove(); 142 wpView.deselect(); 143 } 144 } 145 146 // Let keypresses that involve the command or control keys through. 147 // Also, let any of the F# keys through. 148 if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) { 149 return; 150 } 151 152 event.preventDefault(); 153 }); 154 }, 155 156 getParentView : function( node ) { 157 while ( node ) { 158 if ( this.isView( node ) ) { 159 return node; 160 } 161 162 node = node.parentNode; 130 // If there are no additional nodes or the next node is a 131 // view, create a text node after the current view. 132 if ( ! view.nextSibling || isView( view.nextSibling ) ) { 133 target = editor.getDoc().createTextNode(''); 134 editor.dom.insertAfter( target, view ); 135 136 // Otherwise, find the next text node. 137 } else { 138 walker = new TreeWalker( view.nextSibling, view.nextSibling ); 139 target = walker.next(); 163 140 } 164 },165 141 166 isView : function( node ) { 167 return (/(?:^|\s)wp-view-wrap(?:\s|$)/).test( node.className ); 168 }, 142 // Select the `target` text node. 143 selection.select( target ); 144 selection.collapse( true ); 145 }); 146 147 // When the selection's content changes, scan any new content 148 // for matching views and immediately render them. 149 // 150 // Runs on paste and on inserting nodes/html. 151 editor.on( 'SetContent', function( e ) { 152 if ( ! e.context ) { 153 return; 154 } 155 156 var node = selection.getNode(); 169 157 170 select : function( view ) { 171 if ( view === selected ) { 158 if ( ! node.innerHTML ) { 172 159 return; 173 160 } 174 161 175 this.deselect(); 176 selected = view; 177 wp.mce.view.select( selected ); 178 }, 162 node.innerHTML = wp.mce.view.toViews( node.innerHTML ); 163 wp.mce.view.render( node ); 164 }); 165 }); 166 167 // When the editor's contents are being accessed as a string, 168 // transform any views back to their text representations. 169 editor.on( 'PostProcess', function( e ) { 170 if ( ( ! e.get && ! e.save ) || ! e.content ) { 171 return; 172 } 173 174 e.content = wp.mce.view.toText( e.content ); 175 }); 176 177 editor.on( 'keydown', function( event ) { 178 var keyCode = event.keyCode, 179 view, instance; 180 181 // If a view isn't selected, let the event go on its merry way. 182 if ( ! selected ) { 183 return; 184 } 179 185 180 deselect : function() { 181 if ( selected ) { 182 wp.mce.view.deselect( selected ); 186 // Let keypresses that involve the command or control keys through. 187 // Also, let any of the F# keys through. 188 if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) { 189 if ( ( event.metaKey || event.ctrlKey ) && keyCode === 88 ) { 190 removeSelected = true; 183 191 } 192 return; 193 } 184 194 185 selected = null; 195 // If the caret is not within the selected view, deselect the 196 // view and bail. 197 view = getParentView( editor.selection.getNode() ); 198 if ( view !== selected ) { 199 deselect(); 200 return; 186 201 } 202 203 // If delete or backspace is pressed, delete the view. 204 if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) { 205 if ( (instance = wp.mce.view.instance( selected )) ) { 206 instance.remove(); 207 deselect(); 208 } 209 } 210 211 event.preventDefault(); 187 212 }); 188 213 189 // Register plugin 190 tinymce.PluginManager.add( 'wpview', tinymce.plugins.wpView ); 191 })(); 214 editor.on( 'keyup', function() { 215 var instance; 216 217 if ( selected && removeSelected ) { 218 instance = wp.mce.view.instance( selected ); 219 removeSelected = false; 220 instance.remove(); 221 deselect(); 222 } 223 224 }); 225 }); -
src/wp-includes/js/tinymce/skins/wordpress/wp-content.css
diff --git src/wp-includes/js/tinymce/skins/wordpress/wp-content.css src/wp-includes/js/tinymce/skins/wordpress/wp-content.css index 92e1f35..f1e44d4 100644
img::selection { 127 127 border-style: solid; 128 128 } 129 129 130 131 /** 132 * WP Views 133 */ 134 135 /* delegate the handling of the selection to the wpview tinymce plugin */ 136 137 .wp-view-wrap, 138 .wp-view-wrap * { 139 -moz-user-select: none; 140 -webkit-user-select: none; 141 -ms-user-select: none; 142 user-select: none; 143 } 144 145 /* hide the shortcode content, but allow the content to still be selected */ 146 .wp-view-wrap .wp-view-shortcode { 147 position: absolute; 148 top: 20px; 149 width: 10px; 150 z-index: 100; 151 overflow: hidden; 152 opacity: 1; 153 left: -9999px; 154 display: block; 155 -moz-user-select: element; 156 -webkit-user-select: element; 157 -ms-user-select: element; 158 user-select: element; 159 160 } 161 162 /** 163 * Gallery preview 164 */ 165 .wp-view-type-gallery { 166 position: relative; 167 padding: 16px 0; 168 margin-bottom: 16px; 169 cursor: pointer; 170 } 171 172 .wp-view-type-gallery:after { 173 content: ''; 174 display: block; 175 height: 0; 176 clear: both; 177 visibility: hidden; 178 } 179 180 .wp-view-type-gallery.selected { 181 background-color: #efefef; 182 } 183 184 .wp-view-type-gallery .toolbar { 185 position: absolute; 186 top: 0; 187 left: 0; 188 background-color: #333; 189 color: white; 190 padding: 4px; 191 display: none; 192 } 193 194 .wp-view-type-gallery.selected .toolbar { 195 display: block; 196 } 197 198 .wp-view-type-gallery .toolbar span { 199 cursor: pointer; 200 } 201 202 .gallery img[data-mce-selected]:focus { 203 outline: none; 204 } 205 206 .gallery a { 207 cursor: default; 208 } 209 210 .gallery { 211 margin: auto; 212 line-height: 1; 213 } 214 215 .gallery .gallery-item { 216 float: left; 217 margin: 10px 0 0 0; 218 text-align: center; 219 } 220 221 .gallery .gallery-caption, 222 .gallery .gallery-icon { 223 margin: 0; 224 } 225 226 .gallery-columns-1 .gallery-item { 227 width: 100%; 228 } 229 230 .gallery-columns-2 .gallery-item { 231 width: 50%; 232 } 233 234 .gallery-columns-3 .gallery-item { 235 width: 33.333%; 236 } 237 238 .gallery-columns-4 .gallery-item { 239 width: 25%; 240 } 241 242 .gallery-columns-5 .gallery-item { 243 width: 20%; 244 } 245 246 .gallery-columns-6 .gallery-item { 247 width: 16%; 248 } 249 250 .gallery-columns-7 .gallery-item { 251 width: 14%; 252 } 253 254 .gallery-columns-8 .gallery-item { 255 width: 12%; 256 } 257 258 .gallery-columns-9 .gallery-item { 259 width: 11%; 260 } 261 262 .gallery img { 263 border: 2px solid #cfcfcf; 264 } 265 130 266 img.wp-oembed { 131 267 border: 1px dashed #888; 132 268 background: #f7f5f2 url("images/embedded.png") no-repeat scroll center center; -
src/wp-includes/media-template.php
diff --git src/wp-includes/media-template.php src/wp-includes/media-template.php index 93bf672..68e305d 100644
function wp_print_media_templates() { 600 600 </script> 601 601 <?php 602 602 603 //TODO: do we want to deal with the fact that the elements used for gallery items are filterable and can be overriden via shortcode attributes 604 // do we want to deal with the difference between display and edit context at all? (e.g. wptexturize() being applied to the caption. 605 ?> 606 607 <script type="text/html" id="tmpl-editor-gallery"> 608 <div class="toolbar"><span class="edit"><?php _e( 'edit' ); ?></span> <span class="remove"><?php _e( 'remove' ); ?></span></div> 609 <div class="gallery gallery-columns-{{{ data.columns }}}"> 610 <# _.each( data.attachments, function( attachment, index ) { #> 611 <dl class="gallery-item"> 612 <dt class="gallery-icon"> 613 <?php // TODO: need to figure out the best way to make sure that we have thumbnails ?> 614 <img src="{{{ attachment.sizes.thumbnail.url }}}" /> 615 </dt> 616 <dd class="wp-caption-text gallery-caption"> 617 {{ attachment.caption }} 618 </dd> 619 </dl> 620 <?php // this is kind silly, but copied from the gallery shortcode. Maybe it should be removed ?> 621 <# if ( index % data.columns === data.columns - 1 ) { #> 622 <br style="clear: both;"> 623 <# } #> 624 625 <# } ); #> 626 </div> 627 </script> 628 <?php 629 603 630 /** 604 631 * Prints the media manager custom media templates. 605 632 *