2014-07-16 04:19:15 +02:00
|
|
|
/* global tinymce */
|
2014-04-07 08:59:16 +02:00
|
|
|
/**
|
|
|
|
* Note: this API is "experimental" meaning that it will probably change
|
|
|
|
* in the next few releases based on feedback from 3.9.0.
|
|
|
|
* If you decide to use it, please follow the development closely.
|
2014-04-07 11:03:14 +02:00
|
|
|
*/
|
2014-03-05 08:01:14 +01:00
|
|
|
|
2012-09-26 03:00:08 +02:00
|
|
|
// Ensure the global `wp` object exists.
|
2012-10-06 02:43:36 +02:00
|
|
|
window.wp = window.wp || {};
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2014-06-12 04:49:16 +02:00
|
|
|
( function( $ ) {
|
|
|
|
'use strict';
|
|
|
|
|
2012-09-24 02:13:18 +02:00
|
|
|
var views = {},
|
2014-03-05 08:01:14 +01:00
|
|
|
instances = {},
|
|
|
|
media = wp.media,
|
|
|
|
viewOptions = ['encodedText'];
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2012-09-26 03:00:08 +02:00
|
|
|
// Create the `wp.mce` object if necessary.
|
|
|
|
wp.mce = wp.mce || {};
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
/**
|
|
|
|
* 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.
|
2014-06-05 19:27:13 +02:00
|
|
|
*
|
|
|
|
* @param {Object} [options={}]
|
2014-03-05 08:01:14 +01:00
|
|
|
*/
|
|
|
|
wp.mce.View = function( options ) {
|
2014-06-05 19:27:13 +02:00
|
|
|
options = options || {};
|
2014-06-12 04:49:16 +02:00
|
|
|
this.type = options.type;
|
2014-06-05 19:27:13 +02:00
|
|
|
_.extend( this, _.pick( options, viewOptions ) );
|
|
|
|
this.initialize.apply( this, arguments );
|
2014-03-05 08:01:14 +01:00
|
|
|
};
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
_.extend( wp.mce.View.prototype, {
|
|
|
|
initialize: function() {},
|
2014-07-08 00:41:15 +02:00
|
|
|
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>';
|
|
|
|
},
|
2014-03-05 08:01:14 +01:00
|
|
|
render: function() {
|
2014-07-08 00:41:15 +02:00
|
|
|
var html = this.getHtml() || this.loadingPlaceholder();
|
|
|
|
|
2014-06-12 04:49:16 +02:00
|
|
|
this.setContent(
|
2014-07-04 05:59:15 +02:00
|
|
|
'<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 + '">' +
|
2014-07-08 00:41:15 +02:00
|
|
|
html +
|
2014-07-04 05:59:15 +02:00
|
|
|
'</div>' +
|
|
|
|
( this.overlay ? '<div class="wpview-overlay"></div>' : '' ) +
|
2014-06-12 04:49:16 +02:00
|
|
|
'</div>' +
|
2014-07-04 05:59:15 +02:00
|
|
|
'<p class="wpview-selection-after">\u00a0</p>',
|
2014-06-12 04:49:16 +02:00
|
|
|
function( self, editor, node ) {
|
|
|
|
$( self ).trigger( 'ready', [ editor, node ] );
|
2014-07-04 05:59:15 +02:00
|
|
|
},
|
|
|
|
'wrap'
|
2014-06-12 04:49:16 +02:00
|
|
|
);
|
|
|
|
},
|
|
|
|
unbind: function() {},
|
2014-07-16 17:40:14 +02:00
|
|
|
getNodes: function( callback ) {
|
|
|
|
var nodes = [];
|
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
_.each( tinymce.editors, function( editor ) {
|
|
|
|
if ( editor.plugins.wpview ) {
|
2014-06-12 04:49:16 +02:00
|
|
|
$( editor.getBody() )
|
|
|
|
.find( '[data-wpview-text="' + this.encodedText + '"]' )
|
2014-07-16 17:40:14 +02:00
|
|
|
.each( function ( i, node ) {
|
|
|
|
if ( callback ) {
|
|
|
|
callback( editor, node );
|
2014-06-12 04:49:16 +02:00
|
|
|
}
|
|
|
|
|
2014-07-16 17:40:14 +02:00
|
|
|
nodes.push( node );
|
2014-06-12 04:49:16 +02:00
|
|
|
} );
|
2012-09-26 16:12:54 +02:00
|
|
|
}
|
2014-03-05 08:01:14 +01:00
|
|
|
}, this );
|
2014-07-16 17:40:14 +02:00
|
|
|
|
|
|
|
return nodes;
|
2014-04-12 02:46:14 +02:00
|
|
|
},
|
2014-07-16 17:40:14 +02:00
|
|
|
setContent: function( html, callback, option ) {
|
|
|
|
var self = this;
|
2014-07-16 00:18:14 +02:00
|
|
|
|
2014-07-16 17:40:14 +02:00
|
|
|
this.getNodes( function ( editor, element ) {
|
|
|
|
var contentWrap = $( element ).find( '.wpview-content' ),
|
|
|
|
wrap = element;
|
2014-07-16 00:18:14 +02:00
|
|
|
|
2014-07-16 17:40:14 +02:00
|
|
|
if ( contentWrap.length && option !== 'wrap' ) {
|
|
|
|
element = contentWrap = contentWrap[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( _.isString( html ) ) {
|
|
|
|
if ( option === 'replace' ) {
|
|
|
|
element = editor.dom.replace( editor.dom.createFragment( html ), wrap );
|
|
|
|
} else {
|
|
|
|
editor.dom.setHTML( element, html );
|
2014-07-16 00:18:14 +02:00
|
|
|
}
|
2014-07-16 17:40:14 +02:00
|
|
|
} else {
|
|
|
|
if ( option === 'replace' ) {
|
|
|
|
element = editor.dom.replace( html, wrap );
|
|
|
|
} else {
|
|
|
|
$( element ).empty().append( html );
|
|
|
|
}
|
|
|
|
}
|
2014-07-16 00:18:14 +02:00
|
|
|
|
2014-07-16 17:40:14 +02:00
|
|
|
if ( _.isFunction( callback ) ) {
|
|
|
|
callback( self, editor, $( element ).find( '.wpview-content' )[0] );
|
|
|
|
}
|
|
|
|
} );
|
|
|
|
},
|
|
|
|
|
|
|
|
/* jshint scripturl: true */
|
|
|
|
createIframe: function ( content ) {
|
|
|
|
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
|
2014-07-16 00:18:14 +02:00
|
|
|
|
2014-07-16 17:40:14 +02:00
|
|
|
if ( content.indexOf( '<script' ) !== -1 ) {
|
|
|
|
this.getNodes( function ( editor, node ) {
|
|
|
|
var dom = editor.dom,
|
|
|
|
iframe, iframeDoc, i, resize;
|
|
|
|
|
|
|
|
node = $( node ).find( '.wpview-content' )[0];
|
|
|
|
|
|
|
|
node.innerHTML = '';
|
|
|
|
|
|
|
|
iframe = dom.add( node, 'iframe', {
|
|
|
|
src: tinymce.Env.ie ? 'javascript:""' : '',
|
|
|
|
frameBorder: '0',
|
|
|
|
allowTransparency: 'true',
|
|
|
|
scrolling: 'no',
|
|
|
|
style: {
|
|
|
|
width: '100%',
|
|
|
|
display: 'block'
|
|
|
|
}
|
2014-07-16 00:18:14 +02:00
|
|
|
} );
|
2014-07-16 17:40:14 +02:00
|
|
|
|
|
|
|
iframeDoc = iframe.contentWindow.document;
|
|
|
|
|
|
|
|
iframeDoc.open();
|
|
|
|
iframeDoc.write(
|
|
|
|
'<!DOCTYPE html>' +
|
|
|
|
'<html>' +
|
|
|
|
'<head>' +
|
|
|
|
'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' +
|
|
|
|
'</head>' +
|
|
|
|
'<body style="padding: 0; margin: 0;" class="' + /* editor.getBody().className + */ '">' +
|
|
|
|
content +
|
|
|
|
'</body>' +
|
|
|
|
'</html>'
|
|
|
|
);
|
|
|
|
iframeDoc.close();
|
|
|
|
|
|
|
|
resize = function() {
|
|
|
|
$( 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 );
|
|
|
|
}
|
2014-07-16 00:18:14 +02:00
|
|
|
}
|
2014-07-16 17:40:14 +02:00
|
|
|
});
|
2014-07-16 00:18:14 +02:00
|
|
|
} else {
|
|
|
|
this.setContent( content );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2014-06-12 04:49:16 +02:00
|
|
|
setError: function( message, dashicon ) {
|
|
|
|
this.setContent(
|
|
|
|
'<div class="wpview-error">' +
|
|
|
|
'<div class="dashicons dashicons-' + ( dashicon ? dashicon : 'no' ) + '"></div>' +
|
|
|
|
'<p>' + message + '</p>' +
|
|
|
|
'</div>'
|
|
|
|
);
|
|
|
|
}
|
2014-03-05 08:01:14 +01:00
|
|
|
} );
|
|
|
|
|
|
|
|
// take advantage of the Backbone extend method
|
|
|
|
wp.mce.View.extend = Backbone.View.extend;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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 = {
|
|
|
|
|
|
|
|
/**
|
|
|
|
* wp.mce.views.register( type, view )
|
|
|
|
*
|
|
|
|
* Registers a new TinyMCE view.
|
|
|
|
*
|
|
|
|
* @param type
|
|
|
|
* @param constructor
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
register: function( type, constructor ) {
|
2014-06-05 19:27:13 +02:00
|
|
|
var defaultConstructor = {
|
2014-06-19 01:03:15 +02:00
|
|
|
type: type,
|
2014-06-05 19:27:13 +02:00
|
|
|
View: {},
|
|
|
|
toView: function( content ) {
|
2014-06-19 01:03:15 +02:00
|
|
|
var match = wp.shortcode.next( this.type, content );
|
2014-06-05 19:27:13 +02:00
|
|
|
|
|
|
|
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 );
|
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
views[ type ] = constructor;
|
2012-09-24 02:13:18 +02:00
|
|
|
},
|
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
/**
|
|
|
|
* wp.mce.views.get( id )
|
|
|
|
*
|
|
|
|
* Returns a TinyMCE view constructor.
|
2014-06-05 19:27:13 +02:00
|
|
|
*
|
|
|
|
* @param type
|
2014-03-05 08:01:14 +01:00
|
|
|
*/
|
|
|
|
get: function( type ) {
|
|
|
|
return views[ type ];
|
2012-09-24 02:13:18 +02:00
|
|
|
},
|
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
/**
|
|
|
|
* wp.mce.views.unregister( type )
|
|
|
|
*
|
|
|
|
* Unregisters a TinyMCE view.
|
2014-06-05 19:27:13 +02:00
|
|
|
*
|
|
|
|
* @param type
|
2014-03-05 08:01:14 +01:00
|
|
|
*/
|
|
|
|
unregister: function( type ) {
|
|
|
|
delete views[ type ];
|
2012-09-24 02:13:18 +02:00
|
|
|
},
|
|
|
|
|
2014-04-12 02:46:14 +02:00
|
|
|
/**
|
|
|
|
* wp.mce.views.unbind( editor )
|
|
|
|
*
|
|
|
|
* The editor DOM is being rebuilt, run cleanup.
|
|
|
|
*/
|
|
|
|
unbind: function() {
|
|
|
|
_.each( instances, function( instance ) {
|
|
|
|
instance.unbind();
|
|
|
|
} );
|
|
|
|
},
|
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2014-06-05 19:27:13 +02:00
|
|
|
* @param content
|
2014-03-05 08:01:14 +01:00
|
|
|
*/
|
2012-09-24 02:13:18 +02:00
|
|
|
toViews: function( content ) {
|
2012-09-26 03:00:08 +02:00
|
|
|
var pieces = [ { content: content } ],
|
|
|
|
current;
|
|
|
|
|
2012-09-24 02:13:18 +02:00
|
|
|
_.each( views, function( view, viewType ) {
|
2012-09-26 03:00:08 +02:00
|
|
|
current = pieces.slice();
|
|
|
|
pieces = [];
|
|
|
|
|
|
|
|
_.each( current, function( piece ) {
|
|
|
|
var remaining = piece.content,
|
|
|
|
result;
|
|
|
|
|
|
|
|
// Ignore processed pieces, but retain their location.
|
|
|
|
if ( piece.processed ) {
|
|
|
|
pieces.push( piece );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Iterate through the string progressively matching views
|
|
|
|
// and slicing the string as we go.
|
|
|
|
while ( remaining && (result = view.toView( remaining )) ) {
|
|
|
|
// Any text before the match becomes an unprocessed piece.
|
2014-03-05 08:01:14 +01:00
|
|
|
if ( result.index ) {
|
2012-09-26 03:00:08 +02:00
|
|
|
pieces.push({ content: remaining.substring( 0, result.index ) });
|
2014-03-05 08:01:14 +01:00
|
|
|
}
|
2012-09-26 03:00:08 +02:00
|
|
|
|
|
|
|
// Add the processed piece for the match.
|
|
|
|
pieces.push({
|
2014-03-05 08:01:14 +01:00
|
|
|
content: wp.mce.views.toView( viewType, result.content, result.options ),
|
2012-09-26 03:00:08 +02:00
|
|
|
processed: true
|
|
|
|
});
|
|
|
|
|
|
|
|
// Update the remaining content.
|
|
|
|
remaining = remaining.slice( result.index + result.content.length );
|
|
|
|
}
|
|
|
|
|
|
|
|
// There are no additional matches. If any content remains,
|
|
|
|
// add it as an unprocessed piece.
|
2014-03-05 08:01:14 +01:00
|
|
|
if ( remaining ) {
|
2012-09-26 03:00:08 +02:00
|
|
|
pieces.push({ content: remaining });
|
2014-03-05 08:01:14 +01:00
|
|
|
}
|
2012-09-26 03:00:08 +02:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
return _.pluck( pieces, 'content' ).join('');
|
|
|
|
},
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
/**
|
|
|
|
* 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 text;
|
|
|
|
}
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
if ( ! wp.mce.views.getInstance( encodedText ) ) {
|
|
|
|
viewOptions = options;
|
2014-06-12 04:49:16 +02:00
|
|
|
viewOptions.type = viewType;
|
2014-03-05 08:01:14 +01:00
|
|
|
viewOptions.encodedText = encodedText;
|
|
|
|
instance = new view.View( viewOptions );
|
|
|
|
instances[ encodedText ] = instance;
|
|
|
|
}
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2012-10-12 20:36:21 +02:00
|
|
|
return wp.html.string({
|
2014-03-05 08:01:14 +01:00
|
|
|
tag: 'div',
|
2012-10-12 20:36:21 +02:00
|
|
|
|
|
|
|
attrs: {
|
2014-07-04 05:59:15 +02:00
|
|
|
'class': 'wpview-wrap',
|
2014-03-05 08:01:14 +01:00
|
|
|
'data-wpview-text': encodedText,
|
2014-07-04 05:59:15 +02:00
|
|
|
'data-wpview-type': viewType
|
2014-03-05 08:01:14 +01:00
|
|
|
},
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
content: '\u00a0'
|
2012-09-24 02:13:18 +02:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
/**
|
|
|
|
* Refresh views after an update is made
|
2014-03-19 08:02:15 +01:00
|
|
|
*
|
2014-03-05 08:01:14 +01:00
|
|
|
* @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;
|
|
|
|
|
|
|
|
instance = wp.mce.views.getInstance( encodedText );
|
|
|
|
|
|
|
|
if ( ! instance ) {
|
|
|
|
result = view.toView( text );
|
|
|
|
viewOptions = result.options;
|
2014-06-12 04:49:16 +02:00
|
|
|
viewOptions.type = view.type;
|
2014-03-05 08:01:14 +01:00
|
|
|
viewOptions.encodedText = encodedText;
|
|
|
|
instance = new view.View( viewOptions );
|
|
|
|
instances[ encodedText ] = instance;
|
|
|
|
}
|
2012-09-24 02:13:18 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
wp.mce.views.render();
|
2012-09-26 16:12:54 +02:00
|
|
|
},
|
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
getInstance: function( encodedText ) {
|
|
|
|
return instances[ encodedText ];
|
2012-09-27 00:20:15 +02:00
|
|
|
},
|
|
|
|
|
2014-03-19 08:02:15 +01:00
|
|
|
/**
|
2014-03-05 08:01:14 +01:00
|
|
|
* render( scope )
|
2014-03-19 08:02:15 +01:00
|
|
|
*
|
2014-03-05 08:01:14 +01:00
|
|
|
* 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();
|
|
|
|
} );
|
2012-09-27 00:20:15 +02:00
|
|
|
},
|
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
edit: function( node ) {
|
|
|
|
var viewType = $( node ).data('wpview-type'),
|
|
|
|
view = wp.mce.views.get( viewType );
|
2012-10-12 05:28:22 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
if ( view ) {
|
|
|
|
view.edit( node );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2012-10-12 05:28:22 +02:00
|
|
|
|
2014-06-05 19:27:13 +02:00
|
|
|
wp.mce.views.register( 'gallery', {
|
|
|
|
View: {
|
|
|
|
template: media.template( 'editor-gallery' ),
|
2014-03-05 08:01:14 +01:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
},
|
2012-10-12 01:52:09 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
fetch: function() {
|
|
|
|
this.attachments = wp.media.gallery.attachments( this.shortcode, this.postID );
|
2014-04-02 04:18:15 +02:00
|
|
|
this.dfd = this.attachments.more().done( _.bind( this.render, this ) );
|
2014-03-05 08:01:14 +01:00
|
|
|
},
|
2012-10-12 01:52:09 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
getHtml: function() {
|
|
|
|
var attrs = this.shortcode.attrs.named,
|
2014-04-02 04:18:15 +02:00
|
|
|
attachments = false,
|
|
|
|
options;
|
2014-03-05 08:01:14 +01:00
|
|
|
|
2014-04-02 04:18:15 +02:00
|
|
|
// Don't render errors while still fetching attachments
|
|
|
|
if ( this.dfd && 'pending' === this.dfd.state() && ! this.attachments.length ) {
|
2014-07-08 00:41:15 +02:00
|
|
|
return '';
|
2014-03-05 08:01:14 +01:00
|
|
|
}
|
|
|
|
|
2014-04-02 04:18:15 +02:00
|
|
|
if ( this.attachments.length ) {
|
|
|
|
attachments = this.attachments.toJSON();
|
2014-03-18 04:25:14 +01:00
|
|
|
|
2014-04-02 04:18:15 +02:00
|
|
|
_.each( attachments, function( attachment ) {
|
2014-04-07 23:25:16 +02:00
|
|
|
if ( attachment.sizes ) {
|
|
|
|
if ( attachment.sizes.thumbnail ) {
|
|
|
|
attachment.thumbnail = attachment.sizes.thumbnail;
|
|
|
|
} else if ( attachment.sizes.full ) {
|
|
|
|
attachment.thumbnail = attachment.sizes.full;
|
|
|
|
}
|
2014-04-02 04:18:15 +02:00
|
|
|
}
|
|
|
|
} );
|
|
|
|
}
|
2014-03-18 04:25:14 +01:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
options = {
|
2014-03-18 04:25:14 +01:00
|
|
|
attachments: attachments,
|
2014-07-04 04:06:14 +02:00
|
|
|
columns: attrs.columns ? parseInt( attrs.columns, 10 ) : wp.media.galleryDefaults.columns
|
2014-03-05 08:01:14 +01:00
|
|
|
};
|
2012-10-12 01:52:09 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
return this.template( options );
|
|
|
|
}
|
2014-06-05 19:27:13 +02:00
|
|
|
},
|
2014-03-05 08:01:14 +01:00
|
|
|
|
|
|
|
edit: function( node ) {
|
|
|
|
var gallery = wp.media.gallery,
|
|
|
|
self = this,
|
|
|
|
frame, data;
|
|
|
|
|
2014-03-18 04:48:15 +01:00
|
|
|
data = window.decodeURIComponent( $( node ).attr('data-wpview-text') );
|
2014-03-05 08:01:14 +01:00
|
|
|
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();
|
|
|
|
});
|
2012-10-09 02:55:44 +02:00
|
|
|
}
|
2014-06-05 19:27:13 +02:00
|
|
|
} );
|
2014-03-26 13:11:14 +01:00
|
|
|
|
|
|
|
/**
|
2014-06-05 19:27:13 +02:00
|
|
|
* These are base methods that are shared by the audio and video shortcode's MCE controller.
|
2014-03-26 13:11:14 +01:00
|
|
|
*
|
|
|
|
* @mixin
|
|
|
|
*/
|
2014-06-05 19:27:13 +02:00
|
|
|
wp.mce.av = {
|
2014-07-16 00:18:14 +02:00
|
|
|
View: {
|
2014-06-12 04:49:16 +02:00
|
|
|
overlay: true,
|
|
|
|
|
2014-07-16 00:18:14 +02:00
|
|
|
action: 'parse-media-shortcode',
|
|
|
|
|
2014-06-05 19:27:13 +02:00
|
|
|
initialize: function( options ) {
|
|
|
|
this.shortcode = options.shortcode;
|
2014-07-16 00:18:14 +02:00
|
|
|
this.fetching = false;
|
|
|
|
|
|
|
|
_.bindAll( this, 'createIframe', 'setNode', 'fetch' );
|
|
|
|
$( this ).on( 'ready', this.setNode );
|
2014-06-05 19:27:13 +02:00
|
|
|
},
|
|
|
|
|
2014-07-16 00:18:14 +02:00
|
|
|
setNode: function () {
|
|
|
|
if ( this.parsed ) {
|
|
|
|
this.createIframe( this.parsed );
|
|
|
|
} else if ( ! this.fetching ) {
|
|
|
|
this.fetch();
|
|
|
|
}
|
|
|
|
},
|
2014-06-05 19:27:13 +02:00
|
|
|
|
2014-07-16 00:18:14 +02:00
|
|
|
fetch: function () {
|
|
|
|
var self = this;
|
|
|
|
this.fetching = true;
|
2014-06-05 19:27:13 +02:00
|
|
|
|
2014-07-16 00:18:14 +02:00
|
|
|
wp.ajax.send( this.action, {
|
|
|
|
data: {
|
|
|
|
post_ID: $( '#post_ID' ).val() || 0,
|
|
|
|
type: this.shortcode.tag,
|
|
|
|
shortcode: this.shortcode.string()
|
2014-06-05 19:27:13 +02:00
|
|
|
}
|
2014-07-16 00:18:14 +02:00
|
|
|
} )
|
|
|
|
.always( function() {
|
|
|
|
self.fetching = false;
|
|
|
|
} )
|
|
|
|
.done( function( response ) {
|
|
|
|
if ( response ) {
|
|
|
|
self.parsed = response;
|
|
|
|
self.createIframe( response );
|
|
|
|
}
|
|
|
|
} )
|
|
|
|
.fail( function( response ) {
|
|
|
|
if ( response && response.message ) {
|
|
|
|
if ( ( response.type === 'not-embeddable' && self.type === 'embed' ) ||
|
|
|
|
response.type === 'not-ssl' ) {
|
2014-06-05 19:27:13 +02:00
|
|
|
|
2014-07-16 00:18:14 +02:00
|
|
|
self.setError( response.message, 'admin-media' );
|
|
|
|
} else {
|
|
|
|
self.setContent( '<p>' + self.original + '</p>', null, 'replace' );
|
|
|
|
}
|
|
|
|
} else if ( response && response.statusText ) {
|
|
|
|
self.setError( response.statusText, 'admin-media' );
|
|
|
|
}
|
|
|
|
} );
|
2014-06-05 19:27:13 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2014-07-16 17:40:14 +02:00
|
|
|
* Return parsed response
|
2014-06-05 19:27:13 +02:00
|
|
|
*
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getHtml: function() {
|
2014-07-16 00:18:14 +02:00
|
|
|
if ( ! this.parsed ) {
|
2014-07-16 17:40:14 +02:00
|
|
|
return ' ';
|
2014-07-16 00:18:14 +02:00
|
|
|
}
|
|
|
|
return this.parsed;
|
2014-06-05 19:27:13 +02:00
|
|
|
}
|
2014-07-16 00:18:14 +02:00
|
|
|
},
|
2014-03-26 13:11:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when a TinyMCE view is clicked for editing.
|
|
|
|
* - Parses the shortcode out of the element's data attribute
|
|
|
|
* - Calls the `edit` method on the shortcode model
|
|
|
|
* - Launches the model window
|
|
|
|
* - Bind's an `update` callback which updates the element's data attribute
|
|
|
|
* re-renders the view
|
|
|
|
*
|
|
|
|
* @param {HTMLElement} node
|
|
|
|
*/
|
|
|
|
edit: function( node ) {
|
2014-06-19 01:03:15 +02:00
|
|
|
var media = wp.media[ this.type ],
|
2014-03-26 13:11:14 +01:00
|
|
|
self = this,
|
2014-03-27 18:58:15 +01:00
|
|
|
frame, data, callback;
|
2014-03-26 13:11:14 +01:00
|
|
|
|
2014-05-11 04:07:14 +02:00
|
|
|
$( document ).trigger( 'media:edit' );
|
2014-03-26 13:11:14 +01:00
|
|
|
|
|
|
|
data = window.decodeURIComponent( $( node ).attr('data-wpview-text') );
|
|
|
|
frame = media.edit( data );
|
|
|
|
frame.on( 'close', function() {
|
|
|
|
frame.detach();
|
|
|
|
} );
|
2014-03-27 18:58:15 +01:00
|
|
|
|
|
|
|
callback = function( selection ) {
|
2014-06-19 01:03:15 +02:00
|
|
|
var shortcode = wp.media[ self.type ].shortcode( selection ).string();
|
2014-03-26 13:11:14 +01:00
|
|
|
$( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) );
|
|
|
|
wp.mce.views.refreshView( self, shortcode );
|
|
|
|
frame.detach();
|
2014-03-27 18:58:15 +01:00
|
|
|
};
|
|
|
|
if ( _.isArray( self.state ) ) {
|
|
|
|
_.each( self.state, function (state) {
|
|
|
|
frame.state( state ).on( 'update', callback );
|
|
|
|
} );
|
|
|
|
} else {
|
|
|
|
frame.state( self.state ).on( 'update', callback );
|
|
|
|
}
|
2014-03-26 13:11:14 +01:00
|
|
|
frame.open();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* TinyMCE handler for the video shortcode
|
|
|
|
*
|
2014-06-05 19:27:13 +02:00
|
|
|
* @mixes wp.mce.av
|
2014-03-26 13:11:14 +01:00
|
|
|
*/
|
2014-06-05 19:27:13 +02:00
|
|
|
wp.mce.views.register( 'video', _.extend( {}, wp.mce.av, {
|
2014-07-16 00:18:14 +02:00
|
|
|
state: 'video-details'
|
2014-06-05 19:27:13 +02:00
|
|
|
} ) );
|
2014-03-26 13:11:14 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* TinyMCE handler for the audio shortcode
|
|
|
|
*
|
2014-06-05 19:27:13 +02:00
|
|
|
* @mixes wp.mce.av
|
2014-03-26 13:11:14 +01:00
|
|
|
*/
|
2014-06-05 19:27:13 +02:00
|
|
|
wp.mce.views.register( 'audio', _.extend( {}, wp.mce.av, {
|
2014-07-16 00:18:14 +02:00
|
|
|
state: 'audio-details'
|
2014-06-05 19:27:13 +02:00
|
|
|
} ) );
|
2014-03-26 13:11:14 +01:00
|
|
|
|
|
|
|
/**
|
2014-06-05 19:27:13 +02:00
|
|
|
* TinyMCE handler for the playlist shortcode
|
2014-03-26 13:11:14 +01:00
|
|
|
*
|
2014-06-05 19:27:13 +02:00
|
|
|
* @mixes wp.mce.av
|
2014-03-26 13:11:14 +01:00
|
|
|
*/
|
2014-06-05 19:27:13 +02:00
|
|
|
wp.mce.views.register( 'playlist', _.extend( {}, wp.mce.av, {
|
2014-07-16 00:18:14 +02:00
|
|
|
state: [ 'playlist-edit', 'video-playlist-edit' ]
|
2014-06-05 19:27:13 +02:00
|
|
|
} ) );
|
2014-05-11 01:36:18 +02:00
|
|
|
|
2014-05-27 22:00:15 +02:00
|
|
|
/**
|
|
|
|
* TinyMCE handler for the embed shortcode
|
|
|
|
*/
|
2014-07-16 00:18:14 +02:00
|
|
|
wp.mce.embedMixin = {
|
|
|
|
View: _.extend( {}, wp.mce.av.View, {
|
|
|
|
overlay: true,
|
|
|
|
action: 'parse-embed',
|
|
|
|
initialize: function( options ) {
|
|
|
|
this.content = options.content;
|
|
|
|
this.fetching = false;
|
|
|
|
this.parsed = false;
|
|
|
|
this.original = options.url || options.shortcode.string();
|
|
|
|
|
|
|
|
if ( options.url ) {
|
|
|
|
this.shortcode = media.embed.shortcode( {
|
|
|
|
url: options.url
|
2014-06-12 04:49:16 +02:00
|
|
|
} );
|
|
|
|
} else {
|
2014-07-16 00:18:14 +02:00
|
|
|
this.shortcode = options.shortcode;
|
2014-05-11 01:36:18 +02:00
|
|
|
}
|
2014-06-12 04:49:16 +02:00
|
|
|
|
2014-07-16 00:18:14 +02:00
|
|
|
_.bindAll( this, 'createIframe', 'setNode', 'fetch' );
|
|
|
|
$( this ).on( 'ready', this.setNode );
|
2014-07-16 17:40:14 +02:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return parsed response
|
|
|
|
*
|
|
|
|
* @returns {string}
|
|
|
|
*/
|
|
|
|
getHtml: function() {
|
|
|
|
if ( ! this.parsed ) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
return this.parsed;
|
2014-07-16 00:18:14 +02:00
|
|
|
}
|
|
|
|
} ),
|
2014-06-13 23:42:15 +02:00
|
|
|
edit: function( node ) {
|
|
|
|
var embed = media.embed,
|
|
|
|
self = this,
|
|
|
|
frame,
|
|
|
|
data,
|
2014-06-19 01:03:15 +02:00
|
|
|
isURL = 'embedURL' === this.type;
|
2014-06-13 23:42:15 +02:00
|
|
|
|
|
|
|
$( document ).trigger( 'media:edit' );
|
|
|
|
|
|
|
|
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 ( isURL ) {
|
|
|
|
shortcode = frame.state( 'embed' ).metadata.url;
|
|
|
|
} else {
|
|
|
|
shortcode = embed.shortcode( frame.state( 'embed' ).metadata ).string();
|
|
|
|
}
|
|
|
|
$( node ).attr( 'data-wpview-text', window.encodeURIComponent( shortcode ) );
|
|
|
|
wp.mce.views.refreshView( self, shortcode );
|
|
|
|
frame.detach();
|
|
|
|
} );
|
|
|
|
frame.open();
|
|
|
|
}
|
|
|
|
};
|
2014-06-12 04:49:16 +02:00
|
|
|
|
2014-06-13 23:42:15 +02:00
|
|
|
wp.mce.views.register( 'embed', _.extend( {}, wp.mce.embedMixin ) );
|
|
|
|
|
|
|
|
wp.mce.views.register( 'embedURL', _.extend( {}, wp.mce.embedMixin, {
|
2014-06-12 04:49:16 +02:00
|
|
|
toView: function( content ) {
|
|
|
|
var re = /(?:^|<p>)(https?:\/\/[^\s"]+?)(?:<\/p>\s*|$)/gi,
|
|
|
|
match = re.exec( tinymce.trim( content ) );
|
|
|
|
|
|
|
|
if ( ! match ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
index: match.index,
|
|
|
|
content: match[0],
|
|
|
|
options: {
|
|
|
|
url: match[1]
|
|
|
|
}
|
|
|
|
};
|
2014-06-13 23:42:15 +02:00
|
|
|
}
|
|
|
|
} ) );
|
2014-05-11 01:36:18 +02:00
|
|
|
|
2014-03-05 08:01:14 +01:00
|
|
|
}(jQuery));
|