GSoC: Editor Experiments #2

I meant to do a post last week, so this one is a bit late, but here it is anyway. I’ve mostly been working on the extendibility of views in TinyMCE and little improvements to the views themselves.

Registration

I’m trying to find a way to make it as easy as possible for plugins to create a view for their shortcode (though it doesn’t necesarily have to be a shortcode). At the moment the biggest challenge is the handling of scripts for those views. Views with scripts are sandboxed in an iframe, but while this is great for a view that just displays external content (like a map or tweet), it’s not so great for normal content because the iframe doesn’t inherit the styles of its parent. Sure, we could “detect” some styles, but that’s not good enough. We could also put editor-style.css in each iframe, but that will break once you switch formats or categories, unless we change every iframe’s body class simultaneously. I wish all major browsers supported “seamless” frames. :(

On the front-end, however, we wouldn’t have this problem. The content is not wrapped in an iframe, so scripts can be added where they normally would.

The current registation of a shortcode and view looks like this. It will change a lot though.

register_shortcode( 'my_shortcode', array(
	'__FILE__' => __FILE__,
	'content' => '',
	'block' => true,
	'attributes' => array(
		'my_attribute' => array(
			'title' => __( 'My Title' ),
			'defaults' => ''
		),
		...
	),
	'scripts' => array( 'script-handle', ... ),
) );

Notice that all the attributes must be defined here, unlike add_shortcode(). Now you’ll need to create a directory my_shortcode in the directory of __FILE__.

__FILE__
/myshortcode
	/template.php
	/register.js
	/preview.js
	/edit.php

template.php

This is what the shortcode will output on the front-end. This file receives the variables $attributes, $content and $tag.

register.js

This file registers the view for the TinyMCE editor.

( function( $, views ) {
	'use strict';

	views.register( 'my_shortcode', {
		getHTML: function( attributes, content, tag ) {
			// Content goes here.
		},
		edit: function( shortcode, attributes, content, tag, node ) {
			// This function is run when the user clicks on the edit icon.
			// E.g. you could create a default modal (or create your own).

			// This modal will display the `edit.php` template. You can provide a callback to do some crazy stuff.
			// If edit.php is set up correctly, all the attributes will be filled in for you.
			this.modal( node, callback );
			
			// OR
			
			// While the modal above will handle the update automatically when the user clicks on <input type="sumbit">,
			// you can also do it manually.
			this.refresh( attributes_or_shortcode, node );
		}
	} );

} )( jQuery, wp.mce.views );

preview.js

A script to run with the view’s content. This could also go in a <script> tag inside the content. Both will trigger an iframe.

edit.php

An html template to display the input fields. This will be optional, by default it would just display input fields for all the attributes you registered. You can hide certain attributes and set up your own controls by providing a custom edit.php template and add JavaScript using the modal callback.

The name attributes that match the registered shortcode attributes will be filled in automatically with the old shortcode attributes and the defaults when using this.modal().

<input type="text" name="my_attribute" value"">
<input type="submit" class="button button-primary">

An example

Eventually I’ll create several examples to illustrate all this. So far I’ve made an example for a map (a Google map). The code can be found in a child plugin: https://github.com/avryl/editor-experiments/tree/master/google-maps-block. You can see all the files I described when you enter the map directory.

In the editor, it just looks like this.

Screen Shot 2014-06-20 at 09.55.34

The edit view looks like this. You can search, add a marker, drag and drop it, move the map, change it to satellite and save it all.

Screen Shot 2014-06-20 at 09.59.06

View for embed

I’ve also been working a bit on the embed view for core. You can now paste an embeddable URL and it will automatically create a view for it. See #28195.

View improvements

I experimented a bit with the views themselves to make navigation and editing around them easier. Right now you can’t put your cursor right before or after a view. But with the Editor Experiments plugin you can! This is done by creating a fake cursor next to the view and detecting when the cursor enters and leaves the view. The cursor behaves exactly like a normal cursor (though the height is equal to the view), you can’t see the difference.

Screen Shot 2014-06-19 at 14.54.34