-/* global tinymce, MediaElementPlayer, WPPlaylistView */
+/* global tinymce */
/**
* Note: this API is "experimental" meaning that it will probably change
* in the next few releases based on feedback from 3.9.0.
// Ensure the global `wp` object exists.
window.wp = window.wp || {};
-(function($){
+( function( $ ) {
+ 'use strict';
+
var views = {},
instances = {},
media = wp.media,
*
* 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.
+ *
+ * @param {Object} [options={}]
*/
wp.mce.View = function( options ) {
- options || (options = {});
- _.extend(this, _.pick(options, viewOptions));
- this.initialize.apply(this, arguments);
+ options = options || {};
+ this.type = options.type;
+ _.extend( this, _.pick( options, viewOptions ) );
+ this.initialize.apply( this, arguments );
};
_.extend( wp.mce.View.prototype, {
initialize: function() {},
- getHtml: function() {},
- render: function() {
- var html = this.getHtml();
- // Search all tinymce editor instances and update the placeholders
+ getHtml: function() {
+ return '';
+ },
+ loadingPlaceholder: function() {
+ return '' +
+ '<div class="loading-placeholder">' +
+ '<div class="dashicons dashicons-admin-media"></div>' +
+ '<div class="wpview-loading"><ins></ins></div>' +
+ '</div>';
+ },
+ render: function( force ) {
+ if ( force || ! this.rendered() ) {
+ this.unbind();
+
+ this.setContent(
+ '<p class="wpview-selection-before">\u00a0</p>' +
+ '<div class="wpview-body" contenteditable="false">' +
+ '<div class="toolbar">' +
+ ( _.isFunction( views[ this.type ].edit ) ? '<div class="dashicons dashicons-edit edit"></div>' : '' ) +
+ '<div class="dashicons dashicons-no-alt remove"></div>' +
+ '</div>' +
+ '<div class="wpview-content wpview-type-' + this.type + '">' +
+ ( this.getHtml() || this.loadingPlaceholder() ) +
+ '</div>' +
+ ( this.overlay ? '<div class="wpview-overlay"></div>' : '' ) +
+ '</div>' +
+ '<p class="wpview-selection-after">\u00a0</p>',
+ 'wrap'
+ );
+
+ $( this ).trigger( 'ready' );
+
+ this.rendered( true );
+ }
+ },
+ unbind: function() {},
+ getEditors: function( callback ) {
+ var editors = [];
+
_.each( tinymce.editors, function( editor ) {
- var doc, self = this;
if ( editor.plugins.wpview ) {
- doc = editor.getDoc();
- $( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each(function (i, elem) {
- var node = $( elem );
- // The <ins> is used to mark the end of the wrapper div. Needed when comparing
- // the content as string for preventing extra undo levels.
- node.html( html ).append( '<ins data-wpview-end="1"></ins>' );
- $( self ).trigger( 'ready', elem );
- });
+ if ( callback ) {
+ callback( editor );
+ }
+
+ editors.push( editor );
}
}, this );
+
+ return editors;
},
- unbind: function() {}
+ getNodes: function( callback ) {
+ var nodes = [],
+ self = this;
+
+ this.getEditors( function( editor ) {
+ $( editor.getBody() )
+ .find( '[data-wpview-text="' + self.encodedText + '"]' )
+ .each( function ( i, node ) {
+ if ( callback ) {
+ callback( editor, node, $( node ).find( '.wpview-content' ).get( 0 ) );
+ }
+
+ nodes.push( node );
+ } );
+ } );
+
+ return nodes;
+ },
+ setContent: function( html, option ) {
+ this.getNodes( function ( editor, node, content ) {
+ var el = ( option === 'wrap' || option === 'replace' ) ? node : content,
+ insert = html;
+
+ if ( _.isString( insert ) ) {
+ insert = editor.dom.createFragment( insert );
+ }
+
+ if ( option === 'replace' ) {
+ editor.dom.replace( insert, el );
+ } else {
+ el.innerHTML = '';
+ el.appendChild( insert );
+ }
+ } );
+ },
+ /* jshint scripturl: true */
+ setIframes: function ( head, body ) {
+ var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
+ importStyles = this.type === 'video' || this.type === 'audio' || this.type === 'playlist';
+
+ if ( head || body.indexOf( '<script' ) !== -1 ) {
+ this.getNodes( function ( editor, node, content ) {
+ var dom = editor.dom,
+ styles = '',
+ bodyClasses = editor.getBody().className || '',
+ iframe, iframeDoc, i, resize;
+
+ content.innerHTML = '';
+ head = head || '';
+
+ if ( importStyles ) {
+ if ( ! wp.mce.views.sandboxStyles ) {
+ tinymce.each( dom.$( 'link[rel="stylesheet"]', editor.getDoc().head ), function( link ) {
+ if ( link.href && link.href.indexOf( 'skins/lightgray/content.min.css' ) === -1 &&
+ link.href.indexOf( 'skins/wordpress/wp-content.css' ) === -1 ) {
+
+ styles += dom.getOuterHTML( link ) + '\n';
+ }
+ });
+
+ wp.mce.views.sandboxStyles = styles;
+ } else {
+ styles = wp.mce.views.sandboxStyles;
+ }
+ }
+
+ // Seems Firefox needs a bit of time to insert/set the view nodes, or the iframe will fail
+ // especially when switching Text => Visual.
+ setTimeout( function() {
+ iframe = dom.add( content, 'iframe', {
+ src: tinymce.Env.ie ? 'javascript:""' : '',
+ frameBorder: '0',
+ allowTransparency: 'true',
+ scrolling: 'no',
+ 'class': 'wpview-sandbox',
+ style: {
+ width: '100%',
+ display: 'block'
+ }
+ } );
+
+ iframeDoc = iframe.contentWindow.document;
+
+ iframeDoc.open();
+ iframeDoc.write(
+ '<!DOCTYPE html>' +
+ '<html>' +
+ '<head>' +
+ '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' +
+ head +
+ styles +
+ '<style>' +
+ 'html {' +
+ 'background: transparent;' +
+ 'padding: 0;' +
+ 'margin: 0;' +
+ '}' +
+ 'body#wpview-iframe-sandbox {' +
+ 'background: transparent;' +
+ 'padding: 1px 0 !important;' +
+ 'margin: -1px 0 0 !important;' +
+ '}' +
+ 'body#wpview-iframe-sandbox:before,' +
+ 'body#wpview-iframe-sandbox:after {' +
+ 'display: none;' +
+ 'content: "";' +
+ '}' +
+ '</style>' +
+ '</head>' +
+ '<body id="wpview-iframe-sandbox" class="' + bodyClasses + '">' +
+ body +
+ '</body>' +
+ '</html>'
+ );
+ iframeDoc.close();
+
+ resize = function() {
+ // Make sure the iframe still exists.
+ iframe.contentWindow && $( iframe ).height( $( iframeDoc.body ).height() );
+ };
+
+ if ( MutationObserver ) {
+ new MutationObserver( _.debounce( function() {
+ resize();
+ }, 100 ) )
+ .observe( iframeDoc.body, {
+ attributes: true,
+ childList: true,
+ subtree: true
+ } );
+ } else {
+ for ( i = 1; i < 6; i++ ) {
+ setTimeout( resize, i * 700 );
+ }
+ }
+
+ if ( importStyles ) {
+ editor.on( 'wp-body-class-change', function() {
+ iframeDoc.body.className = editor.getBody().className;
+ });
+ }
+ }, 50 );
+ });
+ } else {
+ this.setContent( body );
+ }
+ },
+ setError: function( message, dashicon ) {
+ this.setContent(
+ '<div class="wpview-error">' +
+ '<div class="dashicons dashicons-' + ( dashicon ? dashicon : 'no' ) + '"></div>' +
+ '<p>' + message + '</p>' +
+ '</div>'
+ );
+ },
+ rendered: function( value ) {
+ var notRendered;
+
+ this.getNodes( function( editor, node ) {
+ if ( value != null ) {
+ $( node ).data( 'rendered', value === true );
+ } else {
+ notRendered = notRendered || ! $( node ).data( 'rendered' );
+ }
+ } );
+
+ return ! notRendered;
+ }
} );
// take advantage of the Backbone extend method
*
*/
register: function( type, constructor ) {
+ var defaultConstructor = {
+ type: type,
+ View: {},
+ toView: function( content ) {
+ var match = wp.shortcode.next( this.type, content );
+
+ if ( ! match ) {
+ return;
+ }
+
+ return {
+ index: match.index,
+ content: match.content,
+ options: {
+ shortcode: match.shortcode
+ }
+ };
+ }
+ };
+
+ constructor = _.defaults( constructor, defaultConstructor );
+ constructor.View = wp.mce.View.extend( constructor.View );
+
views[ type ] = constructor;
},
* wp.mce.views.get( id )
*
* Returns a TinyMCE view constructor.
+ *
+ * @param type
*/
get: function( type ) {
return views[ type ];
* wp.mce.views.unregister( type )
*
* Unregisters a TinyMCE view.
+ *
+ * @param type
*/
unregister: function( type ) {
delete views[ type ];
* matches with wrapper elements, and creates a new instance for
* every match, which triggers the related data to be fetched.
*
+ * @param content
*/
toViews: function( content ) {
var pieces = [ { content: content } ],
if ( ! wp.mce.views.getInstance( encodedText ) ) {
viewOptions = options;
+ viewOptions.type = viewType;
viewOptions.encodedText = encodedText;
instance = new view.View( viewOptions );
instances[ encodedText ] = instance;
tag: 'div',
attrs: {
- 'class': 'wpview-wrap wpview-type-' + viewType,
+ 'class': 'wpview-wrap',
'data-wpview-text': encodedText,
- 'data-wpview-type': viewType,
- 'contenteditable': 'false'
+ 'data-wpview-type': viewType
},
content: '\u00a0'
if ( ! instance ) {
result = view.toView( text );
viewOptions = result.options;
+ viewOptions.type = view.type;
viewOptions.encodedText = encodedText;
instance = new view.View( viewOptions );
instances[ encodedText ] = instance;
}
- wp.mce.views.render();
+ instance.render();
},
getInstance: function( encodedText ) {
* To generate wrapper elements, pass your content through
* `wp.mce.view.toViews( content )`.
*/
- render: function() {
+ render: function( force ) {
_.each( instances, function( instance ) {
- instance.render();
+ instance.render( force );
} );
},
}
};
- 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'),
+ wp.mce.views.register( 'gallery', {
+ View: {
+ 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.
},
fetch: function() {
+ var self = this;
+
this.attachments = wp.media.gallery.attachments( this.shortcode, this.postID );
- this.dfd = this.attachments.more().done( _.bind( this.render, this ) );
+ this.dfd = this.attachments.more().done( function() {
+ self.render( true );
+ } );
},
getHtml: function() {
// Don't render errors while still fetching attachments
if ( this.dfd && 'pending' === this.dfd.state() && ! this.attachments.length ) {
- return;
+ return '';
}
if ( this.attachments.length ) {
options = {
attachments: attachments,
- columns: attrs.columns ? parseInt( attrs.columns, 10 ) : 3
+ columns: attrs.columns ? parseInt( attrs.columns, 10 ) : wp.media.galleryDefaults.columns
};
return this.template( options );
-
}
- }),
+ },
edit: function( node ) {
var gallery = wp.media.gallery,
var shortcode = gallery.shortcode( selection ).string();
$( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) );
wp.mce.views.refreshView( self, shortcode );
+ });
+
+ frame.on( 'close', function() {
frame.detach();
});
}
-
- };
- wp.mce.views.register( 'gallery', wp.mce.gallery );
-
- /**
- * Tiny MCE Views for Audio / Video
- *
- */
+ } );
/**
- * These are base methods that are shared by each shortcode's MCE controller
+ * These are base methods that are shared by the audio and video shortcode's MCE controller.
*
* @mixin
*/
- wp.mce.media = {
- loaded: false,
- /**
- * @global wp.shortcode
- *
- * @param {string} content
- * @returns {Object}
- */
- toView: function( content ) {
- var match = wp.shortcode.next( this.shortcode, content );
+ wp.mce.av = {
+ View: {
+ overlay: true,
- if ( ! match ) {
- return;
- }
+ action: 'parse-media-shortcode',
- return {
- index: match.index,
- content: match.content,
- options: {
- shortcode: match.shortcode
+ initialize: function( options ) {
+ var self = this;
+
+ this.shortcode = options.shortcode;
+
+ _.bindAll( this, 'setIframes', 'setNodes', 'fetch', 'stopPlayers' );
+ $( this ).on( 'ready', this.setNodes );
+
+ $( document ).on( 'media:edit', this.stopPlayers );
+
+ this.fetch();
+
+ this.getEditors( function( editor ) {
+ editor.on( 'hide', self.stopPlayers );
+ });
+ },
+
+ setNodes: function () {
+ if ( this.parsed ) {
+ this.setIframes( this.parsed.head, this.parsed.body );
+ } else {
+ this.fail();
}
- };
+ },
+
+ fetch: function () {
+ var self = this;
+
+ wp.ajax.send( this.action, {
+ data: {
+ post_ID: $( '#post_ID' ).val() || 0,
+ type: this.shortcode.tag,
+ shortcode: this.shortcode.string()
+ }
+ } )
+ .done( function( response ) {
+ if ( response ) {
+ self.parsed = response;
+ self.setIframes( response.head, response.body );
+ } else {
+ self.fail( true );
+ }
+ } )
+ .fail( function( response ) {
+ self.fail( response || true );
+ } );
+ },
+
+ fail: function( error ) {
+ if ( ! this.error ) {
+ if ( error ) {
+ this.error = error;
+ } else {
+ return;
+ }
+ }
+
+ if ( this.error.message ) {
+ if ( ( this.error.type === 'not-embeddable' && this.type === 'embed' ) || this.error.type === 'not-ssl' ||
+ this.error.type === 'no-items' ) {
+
+ this.setError( this.error.message, 'admin-media' );
+ } else {
+ this.setContent( '<p>' + this.original + '</p>', 'replace' );
+ }
+ } else if ( this.error.statusText ) {
+ this.setError( this.error.statusText, 'admin-media' );
+ } else if ( this.original ) {
+ this.setContent( '<p>' + this.original + '</p>', 'replace' );
+ }
+ },
+
+ stopPlayers: function( remove ) {
+ var rem = remove === 'remove';
+
+ this.getNodes( function( editor, node, content ) {
+ var p, win,
+ iframe = $( 'iframe.wpview-sandbox', content ).get(0);
+
+ if ( iframe && ( win = iframe.contentWindow ) && win.mejs ) {
+ // Sometimes ME.js may show a "Download File" placeholder and player.remove() doesn't exist there.
+ try {
+ for ( p in win.mejs.players ) {
+ win.mejs.players[p].pause();
+
+ if ( rem ) {
+ win.mejs.players[p].remove();
+ }
+ }
+ } catch( er ) {}
+ }
+ });
+ },
+
+ unbind: function() {
+ this.stopPlayers( 'remove' );
+ }
},
/**
* @param {HTMLElement} node
*/
edit: function( node ) {
- var media = wp.media[ this.shortcode ],
+ var media = wp.media[ this.type ],
self = this,
frame, data, callback;
- wp.media.mixin.pauseAllPlayers();
+ $( document ).trigger( 'media:edit' );
data = window.decodeURIComponent( $( node ).attr('data-wpview-text') );
frame = media.edit( data );
} );
callback = function( selection ) {
- var shortcode = wp.media[ self.shortcode ].shortcode( selection ).string();
+ var shortcode = wp.media[ self.type ].shortcode( selection ).string();
$( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) );
wp.mce.views.refreshView( self, shortcode );
frame.detach();
}
};
- /**
- * Base View class for audio and video shortcodes
- *
- * @constructor
- * @augments wp.mce.View
- * @mixes wp.media.mixin
- */
- wp.mce.media.View = wp.mce.View.extend({
- initialize: function( options ) {
- this.players = [];
- this.shortcode = options.shortcode;
- _.bindAll( this, 'setPlayer' );
- $(this).on( 'ready', this.setPlayer );
- },
-
- /**
- * Creates the player instance for the current node
- *
- * @global MediaElementPlayer
- * @global _wpmejsSettings
- *
- * @param {Event} e
- * @param {HTMLElement} node
- */
- setPlayer: function(e, node) {
- // if the ready event fires on an empty node
- if ( ! node ) {
- return;
- }
-
- var self = this,
- media,
- firefox = this.ua.is( 'ff' ),
- className = '.wp-' + this.shortcode.tag + '-shortcode';
-
- media = $( node ).find( className );
-
- if ( ! this.isCompatible( media ) ) {
- media.closest( '.wpview-wrap' ).addClass( 'wont-play' );
- if ( ! media.parent().hasClass( 'wpview-wrap' ) ) {
- media.parent().replaceWith( media );
- }
- media.replaceWith( '<p>' + media.find( 'source' ).eq(0).prop( 'src' ) + '</p>' );
- return;
- } else {
- media.closest( '.wpview-wrap' ).removeClass( 'wont-play' );
- if ( firefox ) {
- media.prop( 'preload', 'metadata' );
- } else {
- media.prop( 'preload', 'none' );
- }
- }
-
- media = wp.media.view.MediaDetails.prepareSrc( media.get(0) );
-
- setTimeout( function() {
- wp.mce.media.loaded = true;
- self.players.push( new MediaElementPlayer( media, self.mejsSettings ) );
- }, wp.mce.media.loaded ? 10 : 500 );
- },
-
- /**
- * Pass data to the View's Underscore template and return the compiled output
- *
- * @returns {string}
- */
- getHtml: function() {
- var attrs = this.shortcode.attrs.named;
- attrs.content = this.shortcode.content;
-
- return this.template({ model: _.defaults(
- attrs,
- wp.media[ this.shortcode.tag ].defaults )
- });
- },
-
- unbind: function() {
- this.unsetPlayers();
- }
- });
- _.extend( wp.mce.media.View.prototype, wp.media.mixin );
-
/**
* TinyMCE handler for the video shortcode
*
- * @mixes wp.mce.media
+ * @mixes wp.mce.av
*/
- wp.mce.video = _.extend( {}, wp.mce.media, {
- shortcode: 'video',
- state: 'video-details',
- View: wp.mce.media.View.extend({
- className: 'editor-video',
- template: media.template('editor-video')
- })
- } );
- wp.mce.views.register( 'video', wp.mce.video );
+ wp.mce.views.register( 'video', _.extend( {}, wp.mce.av, {
+ state: 'video-details'
+ } ) );
/**
* TinyMCE handler for the audio shortcode
*
- * @mixes wp.mce.media
+ * @mixes wp.mce.av
*/
- wp.mce.audio = _.extend( {}, wp.mce.media, {
- shortcode: 'audio',
- state: 'audio-details',
- View: wp.mce.media.View.extend({
- className: 'editor-audio',
- template: media.template('editor-audio')
- })
- } );
- wp.mce.views.register( 'audio', wp.mce.audio );
+ wp.mce.views.register( 'audio', _.extend( {}, wp.mce.av, {
+ state: 'audio-details'
+ } ) );
/**
- * Base View class for playlist shortcodes
+ * TinyMCE handler for the playlist shortcode
*
- * @constructor
- * @augments wp.mce.View
- * @mixes wp.media.mixin
+ * @mixes wp.mce.av
*/
- wp.mce.media.PlaylistView = wp.mce.View.extend({
- className: 'editor-playlist',
- template: media.template('editor-playlist'),
-
- initialize: function( options ) {
- this.players = [];
- this.data = {};
- this.attachments = [];
- this.shortcode = options.shortcode;
- this.fetch();
- },
-
- /**
- * Asynchronously fetch the shortcode's attachments
- */
- fetch: function() {
- this.attachments = wp.media.playlist.attachments( this.shortcode );
- this.dfd = this.attachments.more().done( _.bind( this.render, this ) );
- },
-
- /**
- * Get the HTML for the view (which also set's the data), replace the
- * current HTML, and then invoke the WPPlaylistView instance to render
- * the playlist in the editor
- *
- * @global WPPlaylistView
- * @global tinymce.editors
- */
- render: function() {
- var html = this.getHtml(), self = this;
-
- _.each( tinymce.editors, function( editor ) {
- var doc;
- if ( editor.plugins.wpview ) {
- doc = editor.getDoc();
- $( doc ).find( '[data-wpview-text="' + this.encodedText + '"]' ).each(function (i, elem) {
- var node = $( elem );
-
- // The <ins> is used to mark the end of the wrapper div. Needed when comparing
- // the content as string for preventing extra undo levels.
- node.html( html ).append( '<ins data-wpview-end="1"></ins>' );
+ wp.mce.views.register( 'playlist', _.extend( {}, wp.mce.av, {
+ state: [ 'playlist-edit', 'video-playlist-edit' ]
+ } ) );
- if ( ! self.data.tracks ) {
- return;
- }
+ /**
+ * TinyMCE handler for the embed shortcode
+ */
+ wp.mce.embedMixin = {
+ View: _.extend( {}, wp.mce.av.View, {
+ overlay: true,
+ action: 'parse-embed',
+ initialize: function( options ) {
+ this.content = options.content;
+ this.original = options.url || options.shortcode.string();
- self.players.push( new WPPlaylistView({
- el: $( elem ).find( '.wp-playlist' ).get(0),
- metadata: self.data
- }).player );
- });
+ if ( options.url ) {
+ this.shortcode = media.embed.shortcode( {
+ url: options.url
+ } );
+ } else {
+ this.shortcode = options.shortcode;
}
- }, this );
- },
-
- /**
- * Set the data that will be used to compile the Underscore template,
- * compile the template, and then return it.
- *
- * @returns {string}
- */
- getHtml: function() {
- var data = this.shortcode.attrs.named,
- model = wp.media.playlist,
- options,
- attachments,
- tracks = [];
-
- // Don't render errors while still fetching attachments
- if ( this.dfd && 'pending' === this.dfd.state() && ! this.attachments.length ) {
- return;
- }
-
- _.each( model.defaults, function( value, key ) {
- data[ key ] = model.coerce( data, key );
- });
- options = {
- type: data.type,
- style: data.style,
- tracklist: data.tracklist,
- tracknumbers: data.tracknumbers,
- images: data.images,
- artists: data.artists
- };
+ _.bindAll( this, 'setIframes', 'setNodes', 'fetch' );
+ $( this ).on( 'ready', this.setNodes );
- if ( ! this.attachments.length ) {
- return this.template( options );
+ this.fetch();
}
+ } ),
+ edit: function( node ) {
+ var embed = media.embed,
+ self = this,
+ frame,
+ data,
+ isURL = 'embedURL' === this.type;
- attachments = this.attachments.toJSON();
+ $( document ).trigger( 'media:edit' );
- _.each( attachments, function( attachment ) {
- var size = {}, resize = {}, track = {
- src : attachment.url,
- type : attachment.mime,
- title : attachment.title,
- caption : attachment.caption,
- description : attachment.description,
- meta : attachment.meta
- };
+ data = window.decodeURIComponent( $( node ).attr('data-wpview-text') );
+ frame = embed.edit( data, isURL );
+ frame.on( 'close', function() {
+ frame.detach();
+ } );
+ frame.state( 'embed' ).props.on( 'change:url', function (model, url) {
+ if ( ! url ) {
+ return;
+ }
+ frame.state( 'embed' ).metadata = model.toJSON();
+ } );
+ frame.state( 'embed' ).on( 'select', function() {
+ var shortcode;
- if ( 'video' === data.type ) {
- size.width = attachment.width;
- size.height = attachment.height;
- if ( media.view.settings.contentWidth ) {
- resize.width = media.view.settings.contentWidth - 22;
- resize.height = Math.ceil( ( size.height * resize.width ) / size.width );
- if ( ! options.width ) {
- options.width = resize.width;
- options.height = resize.height;
- }
- } else {
- if ( ! options.width ) {
- options.width = attachment.width;
- options.height = attachment.height;
- }
- }
- track.dimensions = {
- original : size,
- resized : _.isEmpty( resize ) ? size : resize
- };
+ if ( isURL ) {
+ shortcode = frame.state( 'embed' ).metadata.url;
} else {
- options.width = 400;
+ shortcode = embed.shortcode( frame.state( 'embed' ).metadata ).string();
}
-
- track.image = attachment.image;
- track.thumb = attachment.thumb;
-
- tracks.push( track );
+ $( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) );
+ wp.mce.views.refreshView( self, shortcode );
+ frame.detach();
} );
+ frame.open();
+ }
+ };
- options.tracks = tracks;
- this.data = options;
+ wp.mce.views.register( 'embed', _.extend( {}, wp.mce.embedMixin ) );
- return this.template( options );
- },
+ wp.mce.views.register( 'embedURL', _.extend( {}, wp.mce.embedMixin, {
+ toView: function( content ) {
+ var re = /(?:^|<p>)(https?:\/\/[^\s"]+?)(?:<\/p>\s*|$)/gi,
+ match = re.exec( tinymce.trim( content ) );
- unbind: function() {
- this.unsetPlayers();
+ if ( ! match ) {
+ return;
+ }
+
+ return {
+ index: match.index,
+ content: match[0],
+ options: {
+ url: match[1]
+ }
+ };
}
- });
- _.extend( wp.mce.media.PlaylistView.prototype, wp.media.mixin );
+ } ) );
- /**
- * TinyMCE handler for the playlist shortcode
- *
- * @mixes wp.mce.media
- */
- wp.mce.playlist = _.extend( {}, wp.mce.media, {
- shortcode: 'playlist',
- state: ['playlist-edit', 'video-playlist-edit'],
- View: wp.mce.media.PlaylistView
- } );
- wp.mce.views.register( 'playlist', wp.mce.playlist );
}(jQuery));