From 6074dfa27223d955ee65cb2cac0ae68c700d53ba Mon Sep 17 00:00:00 2001 From: Andrew Ozz Date: Wed, 5 Mar 2014 07:01:14 +0000 Subject: [PATCH] Update mce-view.js and the `wpview` TinyMCE plugin, and use them to show gallery previews in the Visual editor, props gcorne, see #26959 Built from https://develop.svn.wordpress.org/trunk@27408 git-svn-id: http://core.svn.wordpress.org/trunk@27255 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/class-wp-editor.php | 4 + wp-includes/js/mce-view.js | 484 ++++++++--------- wp-includes/js/mce-view.min.js | 2 +- .../js/tinymce/plugins/wpgallery/plugin.js | 8 +- .../tinymce/plugins/wpgallery/plugin.min.js | 2 +- .../js/tinymce/plugins/wpview/plugin.js | 492 ++++++++++++------ .../js/tinymce/plugins/wpview/plugin.min.js | 2 +- .../js/tinymce/skins/wordpress/wp-content.css | 135 +++++ wp-includes/js/tinymce/wp-tinymce.js.gz | Bin 121301 -> 121874 bytes wp-includes/media-template.php | 30 ++ wp-includes/version.php | 2 +- 11 files changed, 733 insertions(+), 428 deletions(-) diff --git a/wp-includes/class-wp-editor.php b/wp-includes/class-wp-editor.php index af2a071c6c..d209c588b7 100644 --- a/wp-includes/class-wp-editor.php +++ b/wp-includes/class-wp-editor.php @@ -242,6 +242,7 @@ final class _WP_Editors { 'wpgallery', 'wplink', 'wpdialogs', + 'wpview', ) ) ); if ( ( $key = array_search( 'spellchecker', $plugins ) ) !== false ) { @@ -501,6 +502,9 @@ final class _WP_Editors { if ( self::$has_medialib ) { add_thickbox(); wp_enqueue_script('media-upload'); + + if ( self::$has_tinymce ) + wp_enqueue_script('mce-view'); } } diff --git a/wp-includes/js/mce-view.js b/wp-includes/js/mce-view.js index 912c4c7ce4..0881680b77 100644 --- a/wp-includes/js/mce-view.js +++ b/wp-includes/js/mce-view.js @@ -1,173 +1,95 @@ +/* global tinymce */ + // Ensure the global `wp` object exists. window.wp = window.wp || {}; (function($){ var views = {}, - instances = {}; + instances = {}, + media = wp.media, + viewOptions = ['encodedText']; // Create the `wp.mce` object if necessary. wp.mce = wp.mce || {}; - // wp.mce.view - // ----------- - // A set of utilities that simplifies adding custom UI within a TinyMCE editor. - // At its core, it serves as a series of converters, transforming text to a - // custom UI, and back again. - wp.mce.view = { - // ### defaults - defaults: { - // The default properties used for objects with the `pattern` key in - // `wp.mce.view.add()`. - pattern: { - view: Backbone.View, - text: function( instance ) { - return instance.options.original; - }, + /** + * wp.mce.View + * + * A Backbone-like View constructor intended for use when rendering a TinyMCE View. The main difference is + * that the TinyMCE View is not tied to a particular DOM node. + */ + wp.mce.View = function( options ) { + options || (options = {}); + _.extend(this, _.pick(options, viewOptions)); + this.initialize.apply(this, arguments); + }; - toView: function( content ) { - if ( ! this.pattern ) - return; - - this.pattern.lastIndex = 0; - var match = this.pattern.exec( content ); - - if ( ! match ) - return; - - return { - index: match.index, - content: match[0], - options: { - original: match[0], - results: match - } - }; + _.extend( wp.mce.View.prototype, { + initialize: function() {}, + html: function() {}, + render: function() { + var html = this.getHtml(); + // Search all tinymce editor instances and update the placeholders + _.each( tinymce.editors, function( editor ) { + var doc; + if ( editor.plugins.wpview ) { + doc = editor.getDoc(); + $( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).html( html ); } - }, + }, this ); + } + } ); - // The default properties used for objects with the `shortcode` key in - // `wp.mce.view.add()`. - shortcode: { - view: Backbone.View, - text: function( instance ) { - return instance.options.shortcode.string(); - }, + // take advantage of the Backbone extend method + wp.mce.View.extend = Backbone.View.extend; - toView: function( content ) { - var match = wp.shortcode.next( this.shortcode, content ); + /** + * wp.mce.views + * + * A set of utilities that simplifies adding custom UI within a TinyMCE editor. + * At its core, it serves as a series of converters, transforming text to a + * custom UI, and back again. + */ + wp.mce.views = { - if ( ! match ) - return; - - return { - index: match.index, - content: match.content, - options: { - shortcode: match.shortcode - } - }; - } - } + /** + * wp.mce.views.register( type, view ) + * + * Registers a new TinyMCE view. + * + * @param type + * @param constructor + * + */ + register: function( type, constructor ) { + views[ type ] = constructor; }, - // ### add( id, options ) - // Registers a new TinyMCE view. - // - // Accepts a unique `id` and an `options` object. - // - // `options` accepts the following properties: - // - // * `pattern` is the regular expression used to scan the content and - // detect matching views. - // - // * `view` is a `Backbone.View` constructor. If a plain object is - // provided, it will automatically extend the parent constructor - // (usually `Backbone.View`). Views are instantiated when the `pattern` - // is successfully matched. The instance's `options` object is provided - // with the `original` matched value, the match `results` including - // capture groups, and the `viewType`, which is the constructor's `id`. - // - // * `extend` an existing view by passing in its `id`. The current - // view will inherit all properties from the parent view, and if - // `view` is set to a plain object, it will extend the parent `view` - // constructor. - // - // * `text` is a method that accepts an instance of the `view` - // constructor and transforms it into a text representation. - add: function( id, options ) { - var parent, remove, base, properties; - - // Fetch the parent view or the default options. - if ( options.extend ) - parent = wp.mce.view.get( options.extend ); - else if ( options.shortcode ) - parent = wp.mce.view.defaults.shortcode; - else - parent = wp.mce.view.defaults.pattern; - - // Extend the `options` object with the parent's properties. - _.defaults( options, parent ); - options.id = id; - - // Create properties used to enhance the view for use in TinyMCE. - properties = { - // Ensure the wrapper element and references to the view are - // removed. Otherwise, removed views could randomly restore. - remove: function() { - delete instances[ this.el.id ]; - this.$el.parent().remove(); - - // Trigger the inherited `remove` method. - if ( remove ) - remove.apply( this, arguments ); - - return this; - } - }; - - // If the `view` provided was an object, use the parent's - // `view` constructor as a base. If a `view` constructor - // was provided, treat that as the base. - if ( _.isFunction( options.view ) ) { - base = options.view; - } else { - base = parent.view; - remove = options.view.remove; - _.defaults( properties, options.view ); - } - - // If there's a `remove` method on the `base` view that wasn't - // created by this method, inherit it. - if ( ! remove && ! base._mceview ) - remove = base.prototype.remove; - - // Automatically create the new `Backbone.View` constructor. - options.view = base.extend( properties, { - // Flag that the new view has been created by `wp.mce.view`. - _mceview: true - }); - - views[ id ] = options; + /** + * wp.mce.views.get( id ) + * + * Returns a TinyMCE view constructor. + */ + get: function( type ) { + return views[ type ]; }, - // ### get( id ) - // Returns a TinyMCE view options object. - get: function( id ) { - return views[ id ]; + /** + * wp.mce.views.unregister( type ) + * + * Unregisters a TinyMCE view. + */ + unregister: function( type ) { + delete views[ type ]; }, - // ### remove( id ) - // Unregisters a TinyMCE view. - remove: function( id ) { - delete views[ id ]; - }, - - // ### toViews( content ) - // Scans a `content` string for each view's pattern, replacing any - // matches with wrapper elements, and creates a new view instance for - // every match. - // - // To render the views, call `wp.mce.view.render( scope )`. + /** + * toViews( content ) + * Scans a `content` string for each view's pattern, replacing any + * matches with wrapper elements, and creates a new instance for + * every match, which triggers the related data to be fetched. + * + */ toViews: function( content ) { var pieces = [ { content: content } ], current; @@ -190,12 +112,13 @@ window.wp = window.wp || {}; // and slicing the string as we go. while ( remaining && (result = view.toView( remaining )) ) { // Any text before the match becomes an unprocessed piece. - if ( result.index ) + if ( result.index ) { pieces.push({ content: remaining.substring( 0, result.index ) }); + } // Add the processed piece for the match. pieces.push({ - content: wp.mce.view.toView( viewType, result.options ), + content: wp.mce.views.toView( viewType, result.content, result.options ), processed: true }); @@ -205,145 +128,178 @@ window.wp = window.wp || {}; // There are no additional matches. If any content remains, // add it as an unprocessed piece. - if ( remaining ) + if ( remaining ) { pieces.push({ content: remaining }); + } }); }); return _.pluck( pieces, 'content' ).join(''); }, - toView: function( viewType, options ) { - var view = wp.mce.view.get( viewType ), - instance, id; + /** + * Create a placeholder for a particular view type + * + * @param viewType + * @param text + * @param options + * + */ + toView: function( viewType, text, options ) { + var view = wp.mce.views.get( viewType ), + encodedText = window.encodeURIComponent( text ), + instance, viewOptions; - if ( ! view ) - return ''; - // Create a new view instance. - instance = new view.view( _.extend( options || {}, { - viewType: viewType - }) ); + if ( ! view ) { + return text; + } - // Use the view's `id` if it already exists. Otherwise, - // create a new `id`. - id = instance.el.id = instance.el.id || _.uniqueId('__wpmce-'); - instances[ id ] = instance; - - // Create a dummy `$wrapper` property to allow `$wrapper` to be - // called in the view's `render` method without a conditional. - instance.$wrapper = $(); + if ( ! wp.mce.views.getInstance( encodedText ) ) { + viewOptions = options; + viewOptions.encodedText = encodedText; + instance = new view.View( viewOptions ); + instances[ encodedText ] = instance; + } return wp.html.string({ - // If the view is a span, wrap it in a span. - tag: 'span' === instance.tagName ? 'span' : 'div', + tag: 'div', attrs: { - 'class': 'wp-view-wrap wp-view-type-' + viewType, - 'data-wp-view': id, - 'contenteditable': false - } + 'class': 'wpview-wrap wpview-type-' + viewType, + 'data-wpview-text': encodedText, + 'data-wpview-type': viewType, + 'contenteditable': 'false' + }, + + content: '\u00a0' }); }, - // ### render( scope ) - // Renders any view instances inside a DOM node `scope`. - // - // View instances are detected by the presence of wrapper elements. - // To generate wrapper elements, pass your content through - // `wp.mce.view.toViews( content )`. - render: function( scope ) { - $( '.wp-view-wrap', scope ).each( function() { - var wrapper = $(this), - view = wp.mce.view.instance( this ); + /** + * Refresh views after an update is made + * + * @param view {object} being refreshed + * @param text {string} textual representation of the view + */ + refreshView: function( view, text ) { + var encodedText = window.encodeURIComponent( text ), + viewOptions, + result, instance; - if ( ! view ) - return; + instance = wp.mce.views.getInstance( encodedText ); - // Link the real wrapper to the view. - view.$wrapper = wrapper; - // Render the view. - view.render(); - // Detach the view element to ensure events are not unbound. - view.$el.detach(); + if ( ! instance ) { + result = view.toView( text ); + viewOptions = result.options; + viewOptions.encodedText = encodedText; + instance = new view.View( viewOptions ); + instances[ encodedText ] = instance; + } - // Empty the wrapper, attach the view element to the wrapper, - // and add an ending marker to the wrapper to help regexes - // scan the HTML string. - wrapper.empty().append( view.el ).append(''); - }); + wp.mce.views.render(); }, - // ### toText( content ) - // Scans an HTML `content` string and replaces any view instances with - // their respective text representations. - toText: function( content ) { - return content.replace( /<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?]+data-wp-view-end[^>]*><\/span><\/(?:div|span)>/g, function( match, id ) { - var instance = instances[ id ], - view; - - if ( instance ) - view = wp.mce.view.get( instance.options.viewType ); - - return instance && view ? view.text( instance ) : ''; - }); + getInstance: function( encodedText ) { + return instances[ encodedText ]; }, - // ### Remove internal TinyMCE attributes. - removeInternalAttrs: function( attrs ) { - var result = {}; - _.each( attrs, function( value, attr ) { - if ( -1 === attr.indexOf('data-mce') ) - result[ attr ] = value; - }); - return result; + /** + * render( scope ) + * + * Renders any view instances inside a DOM node `scope`. + * + * View instances are detected by the presence of wrapper elements. + * To generate wrapper elements, pass your content through + * `wp.mce.view.toViews( content )`. + */ + render: function() { + _.each( instances, function( instance ) { + instance.render(); + } ); }, - // ### Parse an attribute string and removes internal TinyMCE attributes. - attrs: function( content ) { - return wp.mce.view.removeInternalAttrs( wp.html.attrs( content ) ); - }, + edit: function( node ) { + var viewType = $( node ).data('wpview-type'), + view = wp.mce.views.get( viewType ); - // ### instance( scope ) - // - // Accepts a MCE view wrapper `node` (i.e. a node with the - // `wp-view-wrap` class). - instance: function( node ) { - var id = $( node ).data('wp-view'); - - if ( id ) - return instances[ id ]; - }, - - // ### Select a view. - // - // Accepts a MCE view wrapper `node` (i.e. a node with the - // `wp-view-wrap` class). - select: function( node ) { - var $node = $(node); - - // Bail if node is already selected. - if ( $node.hasClass('selected') ) - return; - - $node.addClass('selected'); - $( node.firstChild ).trigger('select'); - }, - - // ### Deselect a view. - // - // Accepts a MCE view wrapper `node` (i.e. a node with the - // `wp-view-wrap` class). - deselect: function( node ) { - var $node = $(node); - - // Bail if node is already selected. - if ( ! $node.hasClass('selected') ) - return; - - $node.removeClass('selected'); - $( node.firstChild ).trigger('deselect'); + if ( view ) { + view.edit( node ); + } } }; -}(jQuery)); \ No newline at end of file + wp.mce.gallery = { + shortcode: 'gallery', + toView: function( content ) { + var match = wp.shortcode.next( this.shortcode, content ); + + if ( ! match ) { + return; + } + + return { + index: match.index, + content: match.content, + options: { + shortcode: match.shortcode + } + }; + }, + View: wp.mce.View.extend({ + className: 'editor-gallery', + template: media.template('editor-gallery'), + + // The fallback post ID to use as a parent for galleries that don't + // specify the `ids` or `include` parameters. + // + // Uses the hidden input on the edit posts page by default. + postID: $('#post_ID').val(), + + initialize: function( options ) { + this.shortcode = options.shortcode; + this.fetch(); + }, + + fetch: function() { + this.attachments = wp.media.gallery.attachments( this.shortcode, this.postID ); + this.attachments.more().done( _.bind( this.render, this ) ); + }, + + getHtml: function() { + var attrs = this.shortcode.attrs.named, + options; + + if ( ! this.attachments.length ) { + return; + } + + options = { + attachments: this.attachments.toJSON(), + columns: attrs.columns ? parseInt( attrs.columns, 10 ) : 3 + }; + + return this.template( options ); + + } + }), + + edit: function( node ) { + var gallery = wp.media.gallery, + self = this, + frame, data; + + data = window.decodeURIComponent( $( node ).data('wpview-text') ); + frame = gallery.edit( data ); + + frame.state('gallery-edit').on( 'update', function( selection ) { + var shortcode = gallery.shortcode( selection ).string(); + $( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) ); + wp.mce.views.refreshView( self, shortcode ); + frame.detach(); + }); + } + + }; + wp.mce.views.register( 'gallery', wp.mce.gallery ); +}(jQuery)); diff --git a/wp-includes/js/mce-view.min.js b/wp-includes/js/mce-view.min.js index 20bd2d6b88..12d09cc560 100644 --- a/wp-includes/js/mce-view.min.js +++ b/wp-includes/js/mce-view.min.js @@ -1 +1 @@ -window.wp=window.wp||{},function(a){var b={},c={};wp.mce=wp.mce||{},wp.mce.view={defaults:{pattern:{view:Backbone.View,text:function(a){return a.options.original},toView:function(a){if(this.pattern){this.pattern.lastIndex=0;var b=this.pattern.exec(a);if(b)return{index:b.index,content:b[0],options:{original:b[0],results:b}}}}},shortcode:{view:Backbone.View,text:function(a){return a.options.shortcode.string()},toView:function(a){var b=wp.shortcode.next(this.shortcode,a);if(b)return{index:b.index,content:b.content,options:{shortcode:b.shortcode}}}}},add:function(a,d){var e,f,g,h;e=d.extend?wp.mce.view.get(d.extend):d.shortcode?wp.mce.view.defaults.shortcode:wp.mce.view.defaults.pattern,_.defaults(d,e),d.id=a,h={remove:function(){return delete c[this.el.id],this.$el.parent().remove(),f&&f.apply(this,arguments),this}},_.isFunction(d.view)?g=d.view:(g=e.view,f=d.view.remove,_.defaults(h,d.view)),f||g._mceview||(f=g.prototype.remove),d.view=g.extend(h,{_mceview:!0}),b[a]=d},get:function(a){return b[a]},remove:function(a){delete b[a]},toViews:function(a){var c,d=[{content:a}];return _.each(b,function(a,b){c=d.slice(),d=[],_.each(c,function(c){var e,f=c.content;if(c.processed)return void d.push(c);for(;f&&(e=a.toView(f));)e.index&&d.push({content:f.substring(0,e.index)}),d.push({content:wp.mce.view.toView(b,e.options),processed:!0}),f=f.slice(e.index+e.content.length);f&&d.push({content:f})})}),_.pluck(d,"content").join("")},toView:function(b,d){var e,f,g=wp.mce.view.get(b);return g?(e=new g.view(_.extend(d||{},{viewType:b})),f=e.el.id=e.el.id||_.uniqueId("__wpmce-"),c[f]=e,e.$wrapper=a(),wp.html.string({tag:"span"===e.tagName?"span":"div",attrs:{"class":"wp-view-wrap wp-view-type-"+b,"data-wp-view":f,contenteditable:!1}})):""},render:function(b){a(".wp-view-wrap",b).each(function(){var b=a(this),c=wp.mce.view.instance(this);c&&(c.$wrapper=b,c.render(),c.$el.detach(),b.empty().append(c.el).append(''))})},toText:function(a){return a.replace(/<(?:div|span)[^>]+data-wp-view="([^"]+)"[^>]*>.*?]+data-wp-view-end[^>]*><\/span><\/(?:div|span)>/g,function(a,b){var d,e=c[b];return e&&(d=wp.mce.view.get(e.options.viewType)),e&&d?d.text(e):""})},removeInternalAttrs:function(a){var b={};return _.each(a,function(a,c){-1===c.indexOf("data-mce")&&(b[c]=a)}),b},attrs:function(a){return wp.mce.view.removeInternalAttrs(wp.html.attrs(a))},instance:function(b){var d=a(b).data("wp-view");return d?c[d]:void 0},select:function(b){var c=a(b);c.hasClass("selected")||(c.addClass("selected"),a(b.firstChild).trigger("select"))},deselect:function(b){var c=a(b);c.hasClass("selected")&&(c.removeClass("selected"),a(b.firstChild).trigger("deselect"))}}}(jQuery); \ No newline at end of file +window.wp=window.wp||{},function(a){var b={},c={},d=wp.media,e=["encodedText"];wp.mce=wp.mce||{},wp.mce.View=function(a){a||(a={}),_.extend(this,_.pick(a,e)),this.initialize.apply(this,arguments)},_.extend(wp.mce.View.prototype,{initialize:function(){},html:function(){},render:function(){var b=this.getHtml();_.each(tinymce.editors,function(c){var d;c.plugins.wpview&&(d=c.getDoc(),a(d).find('[data-wpview-text="'+this.encodedText+'"]').html(b))},this)}}),wp.mce.View.extend=Backbone.View.extend,wp.mce.views={register:function(a,c){b[a]=c},get:function(a){return b[a]},unregister:function(a){delete b[a]},toViews:function(a){var c,d=[{content:a}];return _.each(b,function(a,b){c=d.slice(),d=[],_.each(c,function(c){var e,f=c.content;if(c.processed)return void d.push(c);for(;f&&(e=a.toView(f));)e.index&&d.push({content:f.substring(0,e.index)}),d.push({content:wp.mce.views.toView(b,e.content,e.options),processed:!0}),f=f.slice(e.index+e.content.length);f&&d.push({content:f})})}),_.pluck(d,"content").join("")},toView:function(a,b,d){var e,f,g=wp.mce.views.get(a),h=window.encodeURIComponent(b);return g?(wp.mce.views.getInstance(h)||(f=d,f.encodedText=h,e=new g.View(f),c[h]=e),wp.html.string({tag:"div",attrs:{"class":"wpview-wrap wpview-type-"+a,"data-wpview-text":h,"data-wpview-type":a,contenteditable:"false"},content:" "})):b},refreshView:function(a,b){var d,e,f,g=window.encodeURIComponent(b);f=wp.mce.views.getInstance(g),f||(e=a.toView(b),d=e.options,d.encodedText=g,f=new a.View(d),c[g]=f),wp.mce.views.render()},getInstance:function(a){return c[a]},render:function(){_.each(c,function(a){a.render()})},edit:function(b){var c=a(b).data("wpview-type"),d=wp.mce.views.get(c);d&&d.edit(b)}},wp.mce.gallery={shortcode:"gallery",toView:function(a){var b=wp.shortcode.next(this.shortcode,a);if(b)return{index:b.index,content:b.content,options:{shortcode:b.shortcode}}},View:wp.mce.View.extend({className:"editor-gallery",template:d.template("editor-gallery"),postID:a("#post_ID").val(),initialize:function(a){this.shortcode=a.shortcode,this.fetch()},fetch:function(){this.attachments=wp.media.gallery.attachments(this.shortcode,this.postID),this.attachments.more().done(_.bind(this.render,this))},getHtml:function(){var a,b=this.shortcode.attrs.named;if(this.attachments.length)return a={attachments:this.attachments.toJSON(),columns:b.columns?parseInt(b.columns,10):3},this.template(a)}}),edit:function(b){var c,d,e=wp.media.gallery,f=this;d=window.decodeURIComponent(a(b).data("wpview-text")),c=e.edit(d),c.state("gallery-edit").on("update",function(d){var g=e.shortcode(d).string();a(b).attr("data-wpview-text",window.encodeURIComponent(g)),wp.mce.views.refreshView(f,g),c.detach()})}},wp.mce.views.register("gallery",wp.mce.gallery)}(jQuery); \ No newline at end of file diff --git a/wp-includes/js/tinymce/plugins/wpgallery/plugin.js b/wp-includes/js/tinymce/plugins/wpgallery/plugin.js index def97d6faf..6e645709f3 100644 --- a/wp-includes/js/tinymce/plugins/wpgallery/plugin.js +++ b/wp-includes/js/tinymce/plugins/wpgallery/plugin.js @@ -59,7 +59,7 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { return; } - // Check if the `wp.media.gallery` API exists. + // Check if the `wp.media` API exists. if ( typeof wp === 'undefined' || ! wp.media ) { return; } @@ -166,7 +166,11 @@ tinymce.PluginManager.add('wpgallery', function( editor ) { }); editor.on( 'BeforeSetContent', function( event ) { - event.content = replaceGalleryShortcodes( event.content ); + // 'wpview' handles the gallery shortcode when present + if ( ! editor.plugins.wpview ) { + event.content = replaceGalleryShortcodes( event.content ); + } + event.content = replaceAVShortcodes( event.content ); }); diff --git a/wp-includes/js/tinymce/plugins/wpgallery/plugin.min.js b/wp-includes/js/tinymce/plugins/wpgallery/plugin.min.js index af1c41f51a..087f938ebc 100644 --- a/wp-includes/js/tinymce/plugins/wpgallery/plugin.min.js +++ b/wp-includes/js/tinymce/plugins/wpgallery/plugin.min.js @@ -1 +1 @@ -tinymce.PluginManager.add("wpgallery",function(a){function b(a){return a.replace(/\[gallery([^\]]*)\]/g,function(a){return c("wp-gallery",a)})}function c(a,b){return b=window.encodeURIComponent(b),''}function d(a,b,d){var e;return d&&d.indexOf("["+b)>-1?(e=a.length-d.length,c("wp-"+b,a.substring(0,e))+a.substring(e)):c("wp-"+b,a)}function e(a){for(var b=/\[(video-playlist|audio|video|playlist)[^\]]*\]/,c=/\[(video-playlist|audio|video|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/;b.test(a);)a=a.replace(c,d);return a}function f(a){function b(a,b){return b=new RegExp(b+'="([^"]+)"').exec(a),b?window.decodeURIComponent(b[1]):""}return a.replace(/(?:]+)?>)*(]+>)(?:<\/p>)*/g,function(a,c){var d=b(c,"data-wp-media");return d?"

"+d+"

":a})}function g(b){var c,d,e;"IMG"===b.nodeName&&"undefined"!=typeof wp&&wp.media&&(a.dom.hasClass(b,"wp-gallery")&&wp.media.gallery?(c=wp.media.gallery,e=window.decodeURIComponent(a.dom.getAttrib(b,"data-wp-media")),d=c.edit(e),d.state("gallery-edit").on("update",function(e){var f=c.shortcode(e).string();a.dom.setAttrib(b,"data-wp-media",window.encodeURIComponent(f)),d.detach()})):a.dom.hasClass(b,"wp-playlist")&&wp.media.playlist?(e=window.decodeURIComponent(a.dom.getAttrib(b,"data-wp-media")),d=wp.media.playlist.edit(e),d.state("playlist-edit").on("update",function(c){var e=wp.media.playlist.shortcode(c).string();a.dom.setAttrib(b,"data-wp-media",window.encodeURIComponent(e)),d.detach()})):a.dom.hasClass(b,"wp-video-playlist")&&wp.media["video-playlist"]?(e=window.decodeURIComponent(a.dom.getAttrib(b,"data-wp-media")),d=wp.media["video-playlist"].edit(e),d.state("video-playlist-edit").on("update",function(c){var e=wp.media["video-playlist"].shortcode(c).string();a.dom.setAttrib(b,"data-wp-media",window.encodeURIComponent(e)),d.detach()})):window.console&&window.console.log("Edit AV shortcode "+window.decodeURIComponent(a.dom.getAttrib(b,"data-wp-media"))))}a.addCommand("WP_Gallery",function(){g(a.selection.getNode())}),a.on("mouseup",function(b){function c(){d.removeClass(d.select("img.wp-media-selected"),"wp-media-selected")}var d=a.dom,e=b.target;"IMG"===e.nodeName&&d.getAttrib(e,"data-wp-media")?2!==b.button&&(d.hasClass(e,"wp-media-selected")?g(e):(c(),d.addClass(e,"wp-media-selected"))):c()}),a.on("ResolveName",function(b){var c=a.dom,d=b.target;"IMG"===d.nodeName&&c.getAttrib(d,"data-wp-media")&&(c.hasClass(d,"wp-gallery")?b.name="gallery":c.hasClass(d,"wp-video")?b.name="video":c.hasClass(d,"wp-audio")?b.name="audio":c.hasClass(d,"wp-playlist")?b.name="playlist":c.hasClass(d,"wp-video-playlist")&&(b.name="video-playlist"))}),a.on("BeforeSetContent",function(a){a.content=b(a.content),a.content=e(a.content)}),a.on("PostProcess",function(a){a.get&&(a.content=f(a.content))})}); \ No newline at end of file +tinymce.PluginManager.add("wpgallery",function(a){function b(a){return a.replace(/\[gallery([^\]]*)\]/g,function(a){return c("wp-gallery",a)})}function c(a,b){return b=window.encodeURIComponent(b),''}function d(a,b,d){var e;return d&&d.indexOf("["+b)>-1?(e=a.length-d.length,c("wp-"+b,a.substring(0,e))+a.substring(e)):c("wp-"+b,a)}function e(a){for(var b=/\[(video-playlist|audio|video|playlist)[^\]]*\]/,c=/\[(video-playlist|audio|video|playlist)[^\]]*\]([\s\S]*?\[\/\1\])?/;b.test(a);)a=a.replace(c,d);return a}function f(a){function b(a,b){return b=new RegExp(b+'="([^"]+)"').exec(a),b?window.decodeURIComponent(b[1]):""}return a.replace(/(?:]+)?>)*(]+>)(?:<\/p>)*/g,function(a,c){var d=b(c,"data-wp-media");return d?"

"+d+"

":a})}function g(b){var c,d,e;"IMG"===b.nodeName&&"undefined"!=typeof wp&&wp.media&&(a.dom.hasClass(b,"wp-gallery")&&wp.media.gallery?(c=wp.media.gallery,e=window.decodeURIComponent(a.dom.getAttrib(b,"data-wp-media")),d=c.edit(e),d.state("gallery-edit").on("update",function(e){var f=c.shortcode(e).string();a.dom.setAttrib(b,"data-wp-media",window.encodeURIComponent(f)),d.detach()})):a.dom.hasClass(b,"wp-playlist")&&wp.media.playlist?(e=window.decodeURIComponent(a.dom.getAttrib(b,"data-wp-media")),d=wp.media.playlist.edit(e),d.state("playlist-edit").on("update",function(c){var e=wp.media.playlist.shortcode(c).string();a.dom.setAttrib(b,"data-wp-media",window.encodeURIComponent(e)),d.detach()})):a.dom.hasClass(b,"wp-video-playlist")&&wp.media["video-playlist"]?(e=window.decodeURIComponent(a.dom.getAttrib(b,"data-wp-media")),d=wp.media["video-playlist"].edit(e),d.state("video-playlist-edit").on("update",function(c){var e=wp.media["video-playlist"].shortcode(c).string();a.dom.setAttrib(b,"data-wp-media",window.encodeURIComponent(e)),d.detach()})):window.console&&window.console.log("Edit AV shortcode "+window.decodeURIComponent(a.dom.getAttrib(b,"data-wp-media"))))}a.addCommand("WP_Gallery",function(){g(a.selection.getNode())}),a.on("mouseup",function(b){function c(){d.removeClass(d.select("img.wp-media-selected"),"wp-media-selected")}var d=a.dom,e=b.target;"IMG"===e.nodeName&&d.getAttrib(e,"data-wp-media")?2!==b.button&&(d.hasClass(e,"wp-media-selected")?g(e):(c(),d.addClass(e,"wp-media-selected"))):c()}),a.on("ResolveName",function(b){var c=a.dom,d=b.target;"IMG"===d.nodeName&&c.getAttrib(d,"data-wp-media")&&(c.hasClass(d,"wp-gallery")?b.name="gallery":c.hasClass(d,"wp-video")?b.name="video":c.hasClass(d,"wp-audio")?b.name="audio":c.hasClass(d,"wp-playlist")?b.name="playlist":c.hasClass(d,"wp-video-playlist")&&(b.name="video-playlist"))}),a.on("BeforeSetContent",function(c){a.plugins.wpview||(c.content=b(c.content)),c.content=e(c.content)}),a.on("PostProcess",function(a){a.get&&(a.content=f(a.content))})}); \ No newline at end of file diff --git a/wp-includes/js/tinymce/plugins/wpview/plugin.js b/wp-includes/js/tinymce/plugins/wpview/plugin.js index 0c56ecba1f..e56e3da334 100644 --- a/wp-includes/js/tinymce/plugins/wpview/plugin.js +++ b/wp-includes/js/tinymce/plugins/wpview/plugin.js @@ -2,190 +2,366 @@ /** * WordPress View plugin. */ - -(function() { - var VK = tinymce.VK, +tinymce.PluginManager.add( 'wpview', function( editor ) { + var selected, + VK = tinymce.util.VK, TreeWalker = tinymce.dom.TreeWalker, - selected; + toRemove = false; - tinymce.create('tinymce.plugins.wpView', { - init : function( editor ) { - var wpView = this; - - // Check if the `wp.mce` API exists. - if ( typeof wp === 'undefined' || ! wp.mce ) { - return; + function getParentView( node ) { + while ( node && node.nodeName !== 'BODY' ) { + if ( isView( node ) ) { + return node; } - editor.on( 'PreInit', function() { - // Add elements so we can set `contenteditable` to false. - editor.schema.addValidElements('div[*],span[*]'); - }); + node = node.parentNode; + } + } - // When the editor's content changes, scan the new content for - // matching view patterns, and transform the matches into - // view wrappers. Since the editor's DOM is outdated at this point, - // we'll wait to render the views. - editor.on( 'BeforeSetContent', function( e ) { - if ( ! e.content ) { - return; - } + function isView( node ) { + return node && /\bwpview-wrap\b/.test( node.className ); + } - e.content = wp.mce.view.toViews( e.content ); - }); + function createPadNode() { + return editor.dom.create( 'p', { 'data-wpview-pad': 1 }, + ( tinymce.Env.ie && tinymce.Env.ie < 11 ) ? '' : '
' ); + } - // When the editor's content has been updated and the DOM has been - // processed, render the views in the document. - editor.on( 'SetContent', function() { - wp.mce.view.render( editor.getDoc() ); - }); + /** + * Get the text/shortcode string for a view. + * + * @param view The view wrapper's HTML id or node + * @returns string The text/shoercode string of the view + */ + function getViewText( view ) { + view = getParentView( typeof view === 'string' ? editor.dom.get( view ) : view ); - editor.on( 'init', function() { - var selection = editor.selection; - // When a view is selected, ensure content that is being pasted - // or inserted is added to a text node (instead of the view). - editor.on( 'BeforeSetContent', function() { - var walker, target, - view = wpView.getParentView( selection.getNode() ); + if ( view ) { + return window.decodeURIComponent( editor.dom.getAttrib( view, 'data-wpview-text' ) || '' ); + } + return ''; + } - // If the selection is not within a view, bail. - if ( ! view ) { - return; - } + /** + * Set the view's original text/shortcode string + * + * @param view The view wrapper's HTML id or node + * @param text The text string to be set + */ + function setViewText( view, text ) { + view = getParentView( typeof view === 'string' ? editor.dom.get( view ) : view ); - // If there are no additional nodes or the next node is a - // view, create a text node after the current view. - if ( ! view.nextSibling || wpView.isView( view.nextSibling ) ) { - target = editor.getDoc().createTextNode(''); - editor.dom.insertAfter( target, view ); + if ( view ) { + editor.dom.setAttrib( view, 'data-wpview-text', window.encodeURIComponent( text || '' ) ); + return true; + } + return false; + } - // Otherwise, find the next text node. - } else { - walker = new TreeWalker( view.nextSibling, view.nextSibling ); - target = walker.next(); - } + function _stop( event ) { + event.stopPropagation(); + } - // Select the `target` text node. - selection.select( target ); - selection.collapse( true ); - }); + function select( viewNode ) { + var clipboard, + dom = editor.dom; - // When the selection's content changes, scan any new content - // for matching views and immediately render them. - // - // Runs on paste and on inserting nodes/html. - editor.on( 'SetContent', function( e ) { - if ( ! e.context ) { - return; - } + // Bail if node is already selected. + if ( viewNode === selected ) { + return; + } - var node = selection.getNode(); + deselect(); + selected = viewNode; + dom.addClass( viewNode, 'selected' ); - if ( ! node.innerHTML ) { - return; - } + clipboard = dom.create( 'div', { + 'class': 'wpview-clipboard', + 'contenteditable': 'true' + }, getViewText( viewNode ) ); - node.innerHTML = wp.mce.view.toViews( node.innerHTML ); - wp.mce.view.render( node ); - }); - }); + viewNode.appendChild( clipboard ); - // When the editor's contents are being accessed as a string, - // transform any views back to their text representations. - editor.on( 'PostProcess', function( e ) { - if ( ( ! e.get && ! e.save ) || ! e.content ) { - return; - } + // Both of the following are necessary to prevent manipulating the selection/focus + editor.dom.bind( clipboard, 'beforedeactivate focusin focusout', _stop ); + editor.dom.bind( selected, 'beforedeactivate focusin focusout', _stop ); - e.content = wp.mce.view.toText( e.content ); - }); + // select the hidden div + editor.selection.select( clipboard, true ); + } - // Triggers when the selection is changed. - // Add the event handler to the top of the stack. - editor.on( 'NodeChange', function( e ) { - var view = wpView.getParentView( e.element ); + /** + * Deselect a selected view and remove clipboard + */ + function deselect() { + var clipboard, + dom = editor.dom; - // Update the selected view. - if ( view ) { - wpView.select( view ); + if ( selected ) { + clipboard = editor.dom.select( '.wpview-clipboard', selected )[0]; + dom.unbind( clipboard ); + dom.remove( clipboard ); - // Prevent the selection from propagating to other plugins. - return false; + dom.unbind( selected, 'beforedeactivate focusin focusout click mouseup', _stop ); + dom.removeClass( selected, 'selected' ); - // If we've clicked off of the selected view, deselect it. - } else { - wpView.deselect(); - } - }); + editor.selection.select( selected.nextSibling ); + editor.selection.collapse(); - editor.on( 'keydown', function( event ) { - var keyCode = event.keyCode, - view, instance; + } - // If a view isn't selected, let the event go on its merry way. - if ( ! selected ) { - return; - } + selected = null; + } - // If the caret is not within the selected view, deselect the - // view and bail. - view = wpView.getParentView( editor.selection.getNode() ); - if ( view !== selected ) { - wpView.deselect(); - return; - } + // Check if the `wp.mce` API exists. + if ( typeof wp === 'undefined' || ! wp.mce ) { + return; + } - // If delete or backspace is pressed, delete the view. - if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) { - if ( (instance = wp.mce.view.instance( selected )) ) { - instance.remove(); - wpView.deselect(); - } - } - - // Let keypresses that involve the command or control keys through. - // Also, let any of the F# keys through. - if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) { - return; - } - - event.preventDefault(); - }); - }, - - getParentView : function( node ) { - while ( node ) { - if ( this.isView( node ) ) { - return node; - } - - node = node.parentNode; - } - }, - - isView : function( node ) { - return (/(?:^|\s)wp-view-wrap(?:\s|$)/).test( node.className ); - }, - - select : function( view ) { - if ( view === selected ) { - return; - } - - this.deselect(); - selected = view; - wp.mce.view.select( selected ); - }, - - deselect : function() { - if ( selected ) { - wp.mce.view.deselect( selected ); - } - - selected = null; + editor.on( 'BeforeAddUndo', function( event ) { + if ( selected && ! toRemove ) { + event.preventDefault(); } }); - // Register plugin - tinymce.PluginManager.add( 'wpview', tinymce.plugins.wpView ); -})(); + // When the editor's content changes, scan the new content for + // matching view patterns, and transform the matches into + // view wrappers. + editor.on( 'BeforeSetContent', function( e ) { + if ( ! e.content ) { + return; + } + + e.content = wp.mce.views.toViews( e.content ); + }); + + // When the editor's content has been updated and the DOM has been + // processed, render the views in the document. + editor.on( 'SetContent', function( event ) { + var body, padNode; + + wp.mce.views.render(); + + // Add padding

if the noneditable node is last + if ( event.load || ! event.set ) { + body = editor.getBody(); + + if ( isView( body.lastChild ) ) { + padNode = createPadNode(); + body.appendChild( padNode ); + editor.selection.setCursorLocation( padNode, 0 ); + } + } + + // refreshEmptyContentNode(); + }); + + // Detect mouse down events that are adjacent to a view when a view is the first view or the last view + editor.on( 'click', function( event ) { + var body = editor.getBody(), + doc = editor.getDoc(), + scrollTop = doc.documentElement.scrollTop || body.scrollTop || 0, + x, y, firstNode, lastNode, padNode; + + if ( event.target.nodeName === 'HTML' && ! event.metaKey && ! event.ctrlKey ) { + firstNode = body.firstChild; + lastNode = body.lastChild; + x = event.clientX; + y = event.clientY; + + if ( isView( firstNode ) && ( ( x < firstNode.offsetLeft && y < ( firstNode.offsetHeight - scrollTop ) ) || + y < firstNode.offsetTop ) ) { + // detect events above or to the left of the first view + + padNode = createPadNode(); + body.insertBefore( padNode, firstNode ); + } else if ( isView( lastNode ) && ( x > ( lastNode.offsetLeft + lastNode.offsetWidth ) || + ( ( scrollTop + y ) - ( lastNode.offsetTop + lastNode.offsetHeight ) ) > 0 ) ) { + // detect events to the right and below the last view + + padNode = createPadNode(); + body.appendChild( padNode ); + } + + if ( padNode ) { + editor.selection.setCursorLocation( padNode, 0 ); + } + } + }); + + editor.on( 'init', function() { + var selection = editor.selection; + // When a view is selected, ensure content that is being pasted + // or inserted is added to a text node (instead of the view). + editor.on( 'BeforeSetContent', function() { + var walker, target, + view = getParentView( selection.getNode() ); + + // If the selection is not within a view, bail. + if ( ! view ) { + return; + } + + if ( ! view.nextSibling || isView( view.nextSibling ) ) { + // If there are no additional nodes or the next node is a + // view, create a text node after the current view. + target = editor.getDoc().createTextNode(''); + editor.dom.insertAfter( target, view ); + } else { + // Otherwise, find the next text node. + walker = new TreeWalker( view.nextSibling, view.nextSibling ); + target = walker.next(); + } + + // Select the `target` text node. + selection.select( target ); + selection.collapse( true ); + }); + + // When the selection's content changes, scan any new content + // for matching views. + // + // Runs on paste and on inserting nodes/html. + editor.on( 'SetContent', function( e ) { + if ( ! e.context ) { + return; + } + + var node = selection.getNode(); + + if ( ! node.innerHTML ) { + return; + } + + node.innerHTML = wp.mce.views.toViews( node.innerHTML ); + }); + + editor.dom.bind( editor.getBody(), 'mousedown mouseup click', function( event ) { + var view = getParentView( event.target ); + + // Contain clicks inside the view wrapper + if ( view ) { + event.stopPropagation(); + + if ( event.type === 'click' ) { + if ( ! event.metaKey && ! event.ctrlKey ) { + if ( editor.dom.hasClass( event.target, 'edit' ) ) { + wp.mce.views.edit( view ); + } else if ( editor.dom.hasClass( event.target, 'remove' ) ) { + editor.dom.remove( view ); + } + } + } + select( view ); + // returning false stops the ugly bars from appearing in IE11 and stops the view being selected as a range in FF + // unfortunately, it also inhibits the dragging fo views to a new location + return false; + } else { + if ( event.type === 'click' ) { + deselect(); + } + } + }); + + }); + + editor.on( 'PreProcess', function( event ) { + var dom = editor.dom; + + // Remove empty padding nodes + tinymce.each( dom.select( 'p[data-wpview-pad]', event.node ), function( node ) { + if ( dom.isEmpty( node ) ) { + dom.remove( node ); + } else { + dom.setAttrib( node, 'data-wpview-pad', null ); + } + }); + + // Replace the wpview node with the wpview string/shortcode? + tinymce.each( dom.select( 'div[data-wpview-text]', event.node ), function( node ) { + // Empty the wrap node + if ( 'textContent' in node ) { + node.textContent = ''; + } else { + node.innerText = ''; + } + + // TODO: that makes all views into block tags (as we use

). + // Can use 'PostProcess' and a regex instead. + dom.replace( dom.create( 'p', null, window.decodeURIComponent( dom.getAttrib( node, 'data-wpview-text' ) ) ), node ); + }); + }); + + editor.on( 'keydown', function( event ) { + var keyCode = event.keyCode, + view; + + // If a view isn't selected, let the event go on its merry way. + if ( ! selected ) { + return; + } + + // Let keypresses that involve the command or control keys through. + // Also, let any of the F# keys through. + if ( event.metaKey || event.ctrlKey || ( keyCode >= 112 && keyCode <= 123 ) ) { + if ( ( event.metaKey || event.ctrlKey ) && keyCode === 88 ) { + toRemove = selected; + } + return; + } + + // If the caret is not within the selected view, deselect the + // view and bail. + view = getParentView( editor.selection.getNode() ); + + if ( view !== selected ) { + deselect(); + return; + } + + // If delete or backspace is pressed, delete the view. + if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) { + editor.dom.remove( selected ); + } + + event.preventDefault(); + }); + + editor.on( 'keyup', function( event ) { + var padNode, + keyCode = event.keyCode, + body = editor.getBody(), + range; + + if ( toRemove ) { + editor.dom.remove( toRemove ); + toRemove = false; + } + + if ( keyCode === VK.DELETE || keyCode === VK.BACKSPACE ) { + // Make sure there is padding if the last element is a view + if ( isView( body.lastChild ) ) { + padNode = createPadNode(); + body.appendChild( padNode ); + + if ( body.childNodes.length === 2 ) { + editor.selection.setCursorLocation( padNode, 0 ); + } + } + + range = editor.selection.getRng(); + + // Allow an initial element in the document to be removed when it is before a view + if ( body.firstChild === range.startContainer && range.collapsed === true && + isView( range.startContainer.nextSibling ) && range.startOffset === 0 ) { + + editor.dom.remove( range.startContainer ); + } + } + }); + + return { + getViewText: getViewText, + setViewText: setViewText + }; +}); diff --git a/wp-includes/js/tinymce/plugins/wpview/plugin.min.js b/wp-includes/js/tinymce/plugins/wpview/plugin.min.js index 61eb4d7a65..bfe7870b46 100644 --- a/wp-includes/js/tinymce/plugins/wpview/plugin.min.js +++ b/wp-includes/js/tinymce/plugins/wpview/plugin.min.js @@ -1 +1 @@ -!function(){var a,b=tinymce.VK,c=tinymce.dom.TreeWalker;tinymce.create("tinymce.plugins.wpView",{init:function(d){var e=this;"undefined"!=typeof wp&&wp.mce&&(d.on("PreInit",function(){d.schema.addValidElements("div[*],span[*]")}),d.on("BeforeSetContent",function(a){a.content&&(a.content=wp.mce.view.toViews(a.content))}),d.on("SetContent",function(){wp.mce.view.render(d.getDoc())}),d.on("init",function(){var a=d.selection;d.on("BeforeSetContent",function(){var b,f,g=e.getParentView(a.getNode());g&&(!g.nextSibling||e.isView(g.nextSibling)?(f=d.getDoc().createTextNode(""),d.dom.insertAfter(f,g)):(b=new c(g.nextSibling,g.nextSibling),f=b.next()),a.select(f),a.collapse(!0))}),d.on("SetContent",function(b){if(b.context){var c=a.getNode();c.innerHTML&&(c.innerHTML=wp.mce.view.toViews(c.innerHTML),wp.mce.view.render(c))}})}),d.on("PostProcess",function(a){(a.get||a.save)&&a.content&&(a.content=wp.mce.view.toText(a.content))}),d.on("NodeChange",function(a){var b=e.getParentView(a.element);return b?(e.select(b),!1):void e.deselect()}),d.on("keydown",function(c){var f,g,h=c.keyCode;if(a){if(f=e.getParentView(d.selection.getNode()),f!==a)return void e.deselect();(h===b.DELETE||h===b.BACKSPACE)&&(g=wp.mce.view.instance(a))&&(g.remove(),e.deselect()),c.metaKey||c.ctrlKey||h>=112&&123>=h||c.preventDefault()}}))},getParentView:function(a){for(;a;){if(this.isView(a))return a;a=a.parentNode}},isView:function(a){return/(?:^|\s)wp-view-wrap(?:\s|$)/.test(a.className)},select:function(b){b!==a&&(this.deselect(),a=b,wp.mce.view.select(a))},deselect:function(){a&&wp.mce.view.deselect(a),a=null}}),tinymce.PluginManager.add("wpview",tinymce.plugins.wpView)}(); \ No newline at end of file +tinymce.PluginManager.add("wpview",function(a){function b(a){for(;a&&"BODY"!==a.nodeName;){if(c(a))return a;a=a.parentNode}}function c(a){return a&&/\bwpview-wrap\b/.test(a.className)}function d(){return a.dom.create("p",{"data-wpview-pad":1},tinymce.Env.ie&&tinymce.Env.ie<11?"":'
')}function e(c){return c=b("string"==typeof c?a.dom.get(c):c),c?window.decodeURIComponent(a.dom.getAttrib(c,"data-wpview-text")||""):""}function f(c,d){return c=b("string"==typeof c?a.dom.get(c):c),c?(a.dom.setAttrib(c,"data-wpview-text",window.encodeURIComponent(d||"")),!0):!1}function g(a){a.stopPropagation()}function h(b){var c,d=a.dom;b!==j&&(i(),j=b,d.addClass(b,"selected"),c=d.create("div",{"class":"wpview-clipboard",contenteditable:"true"},e(b)),b.appendChild(c),a.dom.bind(c,"beforedeactivate focusin focusout",g),a.dom.bind(j,"beforedeactivate focusin focusout",g),a.selection.select(c,!0))}function i(){var b,c=a.dom;j&&(b=a.dom.select(".wpview-clipboard",j)[0],c.unbind(b),c.remove(b),c.unbind(j,"beforedeactivate focusin focusout click mouseup",g),c.removeClass(j,"selected"),a.selection.select(j.nextSibling),a.selection.collapse()),j=null}var j,k=tinymce.util.VK,l=tinymce.dom.TreeWalker,m=!1;if("undefined"!=typeof wp&&wp.mce)return a.on("BeforeAddUndo",function(a){j&&!m&&a.preventDefault()}),a.on("BeforeSetContent",function(a){a.content&&(a.content=wp.mce.views.toViews(a.content))}),a.on("SetContent",function(b){var e,f;wp.mce.views.render(),(b.load||!b.set)&&(e=a.getBody(),c(e.lastChild)&&(f=d(),e.appendChild(f),a.selection.setCursorLocation(f,0)))}),a.on("click",function(b){var e,f,g,h,i,j=a.getBody(),k=a.getDoc(),l=k.documentElement.scrollTop||j.scrollTop||0;"HTML"!==b.target.nodeName||b.metaKey||b.ctrlKey||(g=j.firstChild,h=j.lastChild,e=b.clientX,f=b.clientY,c(g)&&(eh.offsetLeft+h.offsetWidth||l+f-(h.offsetTop+h.offsetHeight)>0)&&(i=d(),j.appendChild(i)),i&&a.selection.setCursorLocation(i,0))}),a.on("init",function(){var d=a.selection;a.on("BeforeSetContent",function(){var e,f,g=b(d.getNode());g&&(!g.nextSibling||c(g.nextSibling)?(f=a.getDoc().createTextNode(""),a.dom.insertAfter(f,g)):(e=new l(g.nextSibling,g.nextSibling),f=e.next()),d.select(f),d.collapse(!0))}),a.on("SetContent",function(a){if(a.context){var b=d.getNode();b.innerHTML&&(b.innerHTML=wp.mce.views.toViews(b.innerHTML))}}),a.dom.bind(a.getBody(),"mousedown mouseup click",function(c){var d=b(c.target);return d?(c.stopPropagation(),"click"===c.type&&(c.metaKey||c.ctrlKey||(a.dom.hasClass(c.target,"edit")?wp.mce.views.edit(d):a.dom.hasClass(c.target,"remove")&&a.dom.remove(d))),h(d),!1):void("click"===c.type&&i())})}),a.on("PreProcess",function(b){var c=a.dom;tinymce.each(c.select("p[data-wpview-pad]",b.node),function(a){c.isEmpty(a)?c.remove(a):c.setAttrib(a,"data-wpview-pad",null)}),tinymce.each(c.select("div[data-wpview-text]",b.node),function(a){"textContent"in a?a.textContent="":a.innerText="",c.replace(c.create("p",null,window.decodeURIComponent(c.getAttrib(a,"data-wpview-text"))),a)})}),a.on("keydown",function(c){var d,e=c.keyCode;if(j){if(c.metaKey||c.ctrlKey||e>=112&&123>=e)return void((c.metaKey||c.ctrlKey)&&88===e&&(m=j));if(d=b(a.selection.getNode()),d!==j)return void i();(e===k.DELETE||e===k.BACKSPACE)&&a.dom.remove(j),c.preventDefault()}}),a.on("keyup",function(b){var e,f,g=b.keyCode,h=a.getBody();m&&(a.dom.remove(m),m=!1),(g===k.DELETE||g===k.BACKSPACE)&&(c(h.lastChild)&&(e=d(),h.appendChild(e),2===h.childNodes.length&&a.selection.setCursorLocation(e,0)),f=a.selection.getRng(),h.firstChild===f.startContainer&&f.collapsed===!0&&c(f.startContainer.nextSibling)&&0===f.startOffset&&a.dom.remove(f.startContainer))}),{getViewText:e,setViewText:f}}); \ No newline at end of file diff --git a/wp-includes/js/tinymce/skins/wordpress/wp-content.css b/wp-includes/js/tinymce/skins/wordpress/wp-content.css index 95f1f6c831..afff0c8599 100644 --- a/wp-includes/js/tinymce/skins/wordpress/wp-content.css +++ b/wp-includes/js/tinymce/skins/wordpress/wp-content.css @@ -198,6 +198,141 @@ img::selection { outline: 0; } + +/** + * WP Views + */ + +/* IE hasLayout. Needed for all IE incl. 11 (ugh, not again!!) */ +.wpview-wrap { + width: 99.99%; + position: relative; +} + +/* delegate the handling of the selection to the wpview tinymce plugin */ +.wpview-wrap, +.wpview-wrap * { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; +} + +/* hide the shortcode content, but allow the content to still be selected */ +.wpview-wrap .wpview-clipboard { + position: absolute; + top: 0; + left: 0; + z-index: -1; + clip: rect(1px, 1px, 1px, 1px); + overflow: hidden; + outline: 0; +} + +/** + * Gallery preview + */ +.wpview-type-gallery { + position: relative; + padding: 0 0 12px; + margin-bottom: 16px; + cursor: pointer; +} + + .wpview-type-gallery:after { + content: ''; + display: block; + height: 0; + clear: both; + visibility: hidden; +} + + .wpview-type-gallery.selected { + background-color: #efefef; +} + +.wpview-type-gallery .toolbar { + position: absolute; + top: 0; + left: 0; + background-color: #333; + color: white; + padding: 4px; + display: none; +} + +.wpview-type-gallery.selected .toolbar { + display: block; +} + +.wpview-type-gallery .toolbar span { + cursor: pointer; +} + +.gallery img[data-mce-selected]:focus { + outline: none; +} + +.gallery a { + cursor: default; +} + +.gallery { + margin: auto; + line-height: 1; +} + +.gallery .gallery-item { + float: left; + margin: 10px 0 0 0; + text-align: center; +} + +.gallery .gallery-caption, +.gallery .gallery-icon { + margin: 0; +} + +.gallery-columns-1 .gallery-item { + width: 99%; +} + +.gallery-columns-2 .gallery-item { + width: 49.5%; +} + +.gallery-columns-3 .gallery-item { + width: 33%; +} + +.gallery-columns-4 .gallery-item { + width: 24.75%; +} + +.gallery-columns-5 .gallery-item { + width: 19.825%; +} + +.gallery-columns-6 .gallery-item { + width: 16%; +} + +.gallery-columns-7 .gallery-item { + width: 14%; +} + +.gallery-columns-8 .gallery-item { + width: 12%; +} + +.gallery-columns-9 .gallery-item { + width: 11%; +} + +.gallery img { + border: 1px solid #cfcfcf; +} + img.wp-oembed { border: 1px dashed #888; background: #f7f5f2 url(images/embedded.png) no-repeat scroll center center; diff --git a/wp-includes/js/tinymce/wp-tinymce.js.gz b/wp-includes/js/tinymce/wp-tinymce.js.gz index 8e0c8388f84f4b84db680e16dc20af1e3a24666f..248d6e7160b5e9512941470340c083d67e8f2d5b 100644 GIT binary patch delta 15145 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 Vo9_nyhE@yv{{!9>#Q7hM1po+nzwH13 diff --git a/wp-includes/media-template.php b/wp-includes/media-template.php index 5304899f3c..97430d0f18 100644 --- a/wp-includes/media-template.php +++ b/wp-includes/media-template.php @@ -648,6 +648,36 @@ function wp_print_media_templates() {
+ + +