X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/8ab4a4532479e8db471032b51042ec8c4716d091..b22765f41bf0b2021b9beb9120ee0ac91fa89292:/wp-includes/js/mce-view.js diff --git a/wp-includes/js/mce-view.js b/wp-includes/js/mce-view.js index eab4560c..3d2616d7 100644 --- a/wp-includes/js/mce-view.js +++ b/wp-includes/js/mce-view.js @@ -1,7 +1,5 @@ /* global tinymce */ -window.wp = window.wp || {}; - /* * The TinyMCE view API. * @@ -24,7 +22,7 @@ window.wp = window.wp || {}; * |- registered view * | |- ... */ -( function( window, wp, $ ) { +( function( window, wp, shortcode, $ ) { 'use strict'; var views = {}, @@ -93,8 +91,7 @@ window.wp = window.wp || {}; setMarkers: function( content ) { var pieces = [ { content: content } ], self = this, - instance, - current; + instance, current; _.each( views, function( view, type ) { current = pieces.slice(); @@ -102,7 +99,7 @@ window.wp = window.wp || {}; _.each( current, function( piece ) { var remaining = piece.content, - result; + result, text; // Ignore processed pieces, but retain their location. if ( piece.processed ) { @@ -119,10 +116,11 @@ window.wp = window.wp || {}; } instance = self.createInstance( type, result.content, result.options ); + text = instance.loader ? '.' : instance.text; // Add the processed piece for the match. pieces.push( { - content: '

' + instance.text + '

', + content: instance.ignore ? text : '

' + text + '

', processed: true } ); @@ -138,31 +136,37 @@ window.wp = window.wp || {}; } ); } ); - return _.pluck( pieces, 'content' ).join( '' ); + content = _.pluck( pieces, 'content' ).join( '' ); + return content.replace( /

\s*

' ); }, /** * Create a view instance. * - * @param {String} type The view type. - * @param {String} text The textual representation of the view. - * @param {Object} options Options. + * @param {String} type The view type. + * @param {String} text The textual representation of the view. + * @param {Object} options Options. + * @param {Boolean} force Recreate the instance. Optional. * * @return {wp.mce.View} The view instance. */ - createInstance: function( type, text, options ) { + createInstance: function( type, text, options, force ) { var View = this.get( type ), encodedText, instance; - text = tinymce.DOM.decode( text ), - encodedText = encodeURIComponent( text ), - instance = this.getInstance( encodedText ); + text = tinymce.DOM.decode( text ); - if ( instance ) { - return instance; + if ( ! force ) { + instance = this.getInstance( text ); + + if ( instance ) { + return instance; + } } + encodedText = encodeURIComponent( text ); + options = _.extend( options || {}, { text: text, encodedText: encodedText @@ -214,12 +218,13 @@ window.wp = window.wp || {}; * @param {String} text The new text. * @param {tinymce.Editor} editor The TinyMCE editor instance the view node is in. * @param {HTMLElement} node The view node to update. + * @param {Boolean} force Recreate the instance. Optional. */ - update: function( text, editor, node ) { + update: function( text, editor, node, force ) { var instance = this.getInstance( node ); if ( instance ) { - instance.update( text, editor, node ); + instance.update( text, editor, node, force ); } }, @@ -233,8 +238,8 @@ window.wp = window.wp || {}; var instance = this.getInstance( node ); if ( instance && instance.edit ) { - instance.edit( instance.text, function( text ) { - instance.update( text, editor, node ); + instance.edit( instance.text, function( text, force ) { + instance.update( text, editor, node, force ); } ); } }, @@ -300,8 +305,8 @@ window.wp = window.wp || {}; /** * Renders all view nodes tied to this view instance that are not yet rendered. * - * @param {String} content The content to render. Optional. - * @param {Boolean} force Rerender all view nodes tied to this view instance. + * @param {String} content The content to render. Optional. + * @param {Boolean} force Rerender all view nodes tied to this view instance. Optional. */ render: function( content, force ) { if ( content != null ) { @@ -322,9 +327,9 @@ window.wp = window.wp || {}; this.replaceMarkers(); if ( content ) { - this.setContent( content, function( editor, node, contentNode ) { + this.setContent( content, function( editor, node ) { $( node ).data( 'rendered', true ); - this.bindNode.call( this, editor, node, contentNode ); + this.bindNode.call( this, editor, node ); }, force ? null : false ); } else { this.setLoader(); @@ -346,9 +351,8 @@ window.wp = window.wp || {}; * Runs before their content is removed from the DOM. */ unbind: function() { - this.getNodes( function( editor, node, contentNode ) { - this.unbindNode.call( this, editor, node, contentNode ); - $( node ).trigger( 'wp-mce-view-unbind' ); + this.getNodes( function( editor, node ) { + this.unbindNode.call( this, editor, node ); }, true ); }, @@ -389,7 +393,7 @@ window.wp = window.wp || {}; return rendered ? data : ! data; } ) .each( function() { - callback.call( self, editor, this, $( this ).find( '.wpview-content' ).get( 0 ) ); + callback.call( self, editor, this, this /* back compat */ ); } ); } ); }, @@ -416,23 +420,18 @@ window.wp = window.wp || {}; */ replaceMarkers: function() { this.getMarkers( function( editor, node ) { - if ( $( node ).text() !== this.text ) { + var $viewNode; + + if ( ! this.loader && $( node ).text() !== this.text ) { editor.dom.setAttrib( node, 'data-wpview-marker', null ); return; } - editor.dom.replace( - editor.dom.createFragment( - '

' + - '

\u00a0

' + - '
' + - '
' + - '
' + - '

\u00a0

' + - '
' - ), - node + $viewNode = editor.$( + '
' ); + + editor.$( node ).replaceWith( $viewNode ); } ); }, @@ -458,17 +457,20 @@ window.wp = window.wp || {}; } else if ( _.isString( content ) && content.indexOf( ' Visual. setTimeout( function() { - var iframe, iframeDoc, observer, i; - - contentNode.innerHTML = ''; + var iframe, iframeWin, iframeDoc, MutationObserver, observer, i, block; + + editor.undoManager.transact( function() { + node.innerHTML = ''; + + iframe = dom.add( node, 'iframe', { + /* jshint scripturl: true */ + src: tinymce.Env.ie ? 'javascript:""' : '', + frameBorder: '0', + allowTransparency: 'true', + scrolling: 'no', + 'class': 'wpview-sandbox', + style: { + width: '100%', + display: 'block' + }, + height: self.iframeHeight + } ); - iframe = dom.add( contentNode, 'iframe', { - /* jshint scripturl: true */ - src: tinymce.Env.ie ? 'javascript:""' : '', - frameBorder: '0', - allowTransparency: 'true', - scrolling: 'no', - 'class': 'wpview-sandbox', - style: { - width: '100%', - display: 'block' - } + dom.add( node, 'span', { 'class': 'mce-shim' } ); + dom.add( node, 'span', { 'class': 'wpview-end' } ); } ); - dom.add( contentNode, 'div', { 'class': 'wpview-overlay' } ); - - iframeDoc = iframe.contentWindow.document; + // Bail if the iframe node is not attached to the DOM. + // Happens when the view is dragged in the editor. + // There is a browser restriction when iframes are moved in the DOM. They get emptied. + // The iframe will be rerendered after dropping the view node at the new location. + if ( ! iframe.contentWindow ) { + return; + } + iframeWin = iframe.contentWindow; + iframeDoc = iframeWin.document; iframeDoc.open(); iframeDoc.write( @@ -559,21 +583,36 @@ window.wp = window.wp || {}; iframeDoc.close(); function resize() { - var $iframe, iframeDocHeight; + var $iframe; + + if ( block ) { + return; + } // Make sure the iframe still exists. if ( iframe.contentWindow ) { $iframe = $( iframe ); - iframeDocHeight = $( iframeDoc.body ).height(); + self.iframeHeight = $( iframeDoc.body ).height(); - if ( $iframe.height() !== iframeDocHeight ) { - $iframe.height( iframeDocHeight ); + if ( $iframe.height() !== self.iframeHeight ) { + $iframe.height( self.iframeHeight ); editor.nodeChanged(); } } } - $( iframe.contentWindow ).on( 'load', resize ); + if ( self.iframeHeight ) { + block = true; + + setTimeout( function() { + block = false; + resize(); + }, 3000 ); + } + + $( iframeWin ).on( 'load', resize ); + + MutationObserver = iframeWin.MutationObserver || iframeWin.WebKitMutationObserver || iframeWin.MozMutationObserver; if ( MutationObserver ) { observer = new MutationObserver( _.debounce( resize, 100 ) ); @@ -583,27 +622,13 @@ window.wp = window.wp || {}; childList: true, subtree: true } ); - - $( node ).one( 'wp-mce-view-unbind', function() { - observer.disconnect(); - } ); } else { for ( i = 1; i < 6; i++ ) { setTimeout( resize, i * 700 ); } } - function classChange() { - iframeDoc.body.className = editor.getBody().className; - } - - editor.on( 'wp-body-class-change', classChange ); - - $( node ).one( 'wp-mce-view-unbind', function() { - editor.off( 'wp-body-class-change', classChange ); - } ); - - callback && callback.call( self, editor, node, contentNode ); + callback && callback.call( self, editor, node ); }, 50 ); }, rendered ); }, @@ -624,7 +649,7 @@ window.wp = window.wp || {}; * Sets an error for all view nodes tied to this view instance. * * @param {String} message The error message to set. - * @param {String} dashicon A dashicon ID (optional). {@link https://developer.wordpress.org/resource/dashicons/} + * @param {String} dashicon A dashicon ID. Optional. {@link https://developer.wordpress.org/resource/dashicons/} */ setError: function( message, dashicon ) { this.setContent( @@ -643,7 +668,7 @@ window.wp = window.wp || {}; * @return {Object} */ match: function( content ) { - var match = wp.shortcode.next( this.type, content ); + var match = shortcode.next( this.type, content ); if ( match ) { return { @@ -662,15 +687,16 @@ window.wp = window.wp || {}; * @param {String} text The new text. * @param {tinymce.Editor} editor The TinyMCE editor instance the view node is in. * @param {HTMLElement} node The view node to update. + * @param {Boolean} force Recreate the instance. Optional. */ - update: function( text, editor, node ) { + update: function( text, editor, node, force ) { _.find( views, function( view, type ) { var match = view.prototype.match( text ); if ( match ) { $( node ).data( 'rendered', false ); editor.dom.setAttrib( node, 'data-wpview-text', encodeURIComponent( text ) ); - wp.mce.views.createInstance( type, text, match.options ).render(); + wp.mce.views.createInstance( type, text, match.options, force ).render(); editor.focus(); return true; @@ -685,35 +711,52 @@ window.wp = window.wp || {}; * @param {HTMLElement} node The view node to remove. */ remove: function( editor, node ) { - this.unbindNode.call( this, editor, node, $( node ).find( '.wpview-content' ).get( 0 ) ); - $( node ).trigger( 'wp-mce-view-unbind' ); + this.unbindNode.call( this, editor, node ); editor.dom.remove( node ); editor.focus(); } } ); -} )( window, window.wp, window.jQuery ); +} )( window, window.wp, window.wp.shortcode, window.jQuery ); /* * The WordPress core TinyMCE views. * Views for the gallery, audio, video, playlist and embed shortcodes, * and a view for embeddable URLs. */ -( function( window, views, $ ) { - var postID = $( '#post_ID' ).val() || 0, - media, gallery, av, embed; +( function( window, views, media, $ ) { + var base, gallery, av, embed, + schema, parser, serializer; + + function verifyHTML( string ) { + var settings = {}; + + if ( ! window.tinymce ) { + return string.replace( /<[^>]+>/g, '' ); + } + + if ( ! string || ( string.indexOf( '<' ) === -1 && string.indexOf( '>' ) === -1 ) ) { + return string; + } + + schema = schema || new window.tinymce.html.Schema( settings ); + parser = parser || new window.tinymce.html.DomParser( settings, schema ); + serializer = serializer || new window.tinymce.html.Serializer( settings, schema ); + + return serializer.serialize( parser.parse( string, { forced_root_block: false } ) ); + } - media = { + base = { state: [], edit: function( text, update ) { - var media = wp.media[ this.type ], - frame = media.edit( text ); + var type = this.type, + frame = media[ type ].edit( text ); this.pausePlayers && this.pausePlayers(); _.each( this.state, function( state ) { frame.state( state ).on( 'update', function( selection ) { - update( media.shortcode( selection ).string() ); + update( media[ type ].shortcode( selection ).string(), type === 'gallery' ); } ); } ); @@ -725,12 +768,12 @@ window.wp = window.wp || {}; } }; - gallery = _.extend( {}, media, { + gallery = _.extend( {}, base, { state: [ 'gallery-edit' ], - template: wp.media.template( 'editor-gallery' ), + template: media.template( 'editor-gallery' ), initialize: function() { - var attachments = wp.media.gallery.attachments( this.shortcode, postID ), + var attachments = media.gallery.attachments( this.shortcode, media.view.settings.post.id ), attrs = this.shortcode.attrs.named, self = this; @@ -751,8 +794,9 @@ window.wp = window.wp || {}; } ); self.render( self.template( { + verifyHTML: verifyHTML, attachments: attachments, - columns: attrs.columns ? parseInt( attrs.columns, 10 ) : wp.media.galleryDefaults.columns + columns: attrs.columns ? parseInt( attrs.columns, 10 ) : media.galleryDefaults.columns } ) ); } ) .fail( function( jqXHR, textStatus ) { @@ -761,7 +805,7 @@ window.wp = window.wp || {}; } } ); - av = _.extend( {}, media, { + av = _.extend( {}, base, { action: 'parse-media-shortcode', initialize: function() { @@ -769,13 +813,13 @@ window.wp = window.wp || {}; if ( this.url ) { this.loader = false; - this.shortcode = wp.media.embed.shortcode( { + this.shortcode = media.embed.shortcode( { url: this.text } ); } wp.ajax.post( this.action, { - post_ID: postID, + post_ID: media.view.settings.post.id, type: this.shortcode.tag, shortcode: this.shortcode.string() } ) @@ -784,6 +828,7 @@ window.wp = window.wp || {}; } ) .fail( function( response ) { if ( self.url ) { + self.ignore = true; self.removeMarkers(); } else { self.setError( response.message || response.statusText, 'admin-media' ); @@ -816,8 +861,7 @@ window.wp = window.wp || {}; action: 'parse-embed', edit: function( text, update ) { - var media = wp.media.embed, - frame = media.edit( text, this.url ), + var frame = media.embed.edit( text, this.url ), self = this; this.pausePlayers(); @@ -834,7 +878,7 @@ window.wp = window.wp || {}; if ( self.url ) { update( data.url ); } else { - update( media.shortcode( data ).string() ); + update( media.embed.shortcode( data ).string() ); } } ); @@ -878,4 +922,4 @@ window.wp = window.wp || {}; } } } ) ); -} )( window, window.wp.mce.views, window.jQuery ); +} )( window, window.wp.mce.views, window.wp.media, window.jQuery );