diff --git a/shared/index.css b/shared/index.css
index 2d93b543545d5..ec3992d37e81d 100644
--- a/shared/index.css
+++ b/shared/index.css
@@ -148,6 +148,8 @@ body {
#editor figcaption {
margin-top: 0.5em;
+ font-size: 0.9em;
+ font-style: italic;
}
#editor figure img,
@@ -180,6 +182,22 @@ body {
content: '— '
}
+#editor table {
+ border-collapse: collapse;
+ table-layout: fixed;
+ width: 100%;
+}
+
+#editor table {
+ width: 100%;
+}
+
+#editor td,
+#editor th {
+ padding: 0.5em;
+ border: 1px solid currentColor;
+}
+
#editor:after {
content: ".";
visibility: hidden;
diff --git a/shared/tinymce/toolbar.js b/shared/tinymce/toolbar.js
index 096fd64e26f0f..eeb1369a314d3 100644
--- a/shared/tinymce/toolbar.js
+++ b/shared/tinymce/toolbar.js
@@ -55,6 +55,47 @@
}
} ) );
+ tinymce.ui.Factory.add( 'svglistbox', tinymce.ui.ListBox.extend( {
+ renderHtml: function() {
+ var id = this._id;
+ var prefix = this.classPrefix;
+ var icon = this.state.get( 'icon' );
+ var text = this.state.get( 'text' );
+ var html = '';
+
+ if ( icon && icon.indexOf( 'gridicons-' ) === 0 ) {
+ html += (
+ ''
+ );
+ } else if ( icon ) {
+ html += '';
+ }
+
+ if ( text ) {
+ this.classes.add( 'btn-has-text' );
+ html += '' + this.encode( text ) + '';
+ }
+
+ html += (
+ ''
+ );
+
+ this.aria( 'role', 'button' );
+
+ return (
+ '
' +
+ '' +
+ '
'
+ );
+ }
+ } ) );
+
tinymce.PluginManager.add( 'toolbar', function( editor ) {
var each = tinymce.each;
var DOM = tinymce.DOM;
@@ -76,9 +117,9 @@
var itemName;
function onClick( callback ) {
- return function() {
+ return function( event ) {
editor.undoManager.transact( function() {
- callback( window.wp.blocks.getSelectedBlock(), editor );
+ callback( window.wp.blocks.getSelectedBlock(), editor, event );
} );
}
}
diff --git a/tinymce-single/blocks.js b/tinymce-single/blocks.js
index 49205351e56ab..7fe08c09006dc 100644
--- a/tinymce-single/blocks.js
+++ b/tinymce-single/blocks.js
@@ -23,6 +23,18 @@
} );
}
},
+ getType: function( name ) {
+ var settings = [];
+ var key;
+
+ for ( key in _blocks ) {
+ if ( _blocks[ key ].type === name ) {
+ settings.push( _blocks[ key ] );
+ }
+ }
+
+ return settings;
+ },
registerControl: function( name, settings ) {
_controls[ name ] = settings;
},
diff --git a/tinymce-single/blocks/core/table/register.js b/tinymce-single/blocks/core/table/register.js
new file mode 100644
index 0000000000000..933d8654707de
--- /dev/null
+++ b/tinymce-single/blocks/core/table/register.js
@@ -0,0 +1,84 @@
+( function( wp ) {
+
+ function insertEmpty() {
+ return (
+ '' +
+ '' +
+ '' +
+ '
| ' +
+ '
| ' +
+ '
' +
+ '' +
+ '
| ' +
+ '
| ' +
+ '
' +
+ '
' +
+ ' '
+ );
+ }
+
+ wp.blocks.registerBlock( {
+ name: 'table',
+ nameSpace: 'core',
+ displayName: 'Table',
+ type: 'media',
+ icon: 'gridicons-grid',
+ editable: [ 'table', 'figcaption' ],
+ insert: insertEmpty,
+ controls: [
+ 'block-align-left',
+ 'block-align-center',
+ 'block-align-right',
+ 'block-align-full',
+ {
+ classes: 'gridicons-rotate',
+ icon: 'gridicons-indent-right',
+ onClick: function( block, editor ) {
+ editor.execCommand( 'mceTableInsertRowBefore' );
+ }
+ },
+ {
+ classes: 'gridicons-rotate',
+ icon: 'gridicons-indent-left',
+ onClick: function( block, editor ) {
+ editor.execCommand( 'mceTableInsertRowAfter' );
+ }
+ },
+ {
+ icon: 'gridicons-indent-right',
+ onClick: function( block, editor ) {
+ editor.execCommand( 'mceTableInsertColBefore' );
+ }
+ },
+ {
+ icon: 'gridicons-indent-left',
+ onClick: function( block, editor ) {
+ editor.execCommand( 'mceTableInsertColAfter' );
+ }
+ },
+ {
+ icon: 'gridicons-caption',
+ onClick: function( block ) {
+ var figcaption = block.querySelector( 'figcaption' );
+
+ if ( figcaption ) {
+ block.removeChild( figcaption );
+ } else {
+ block.insertAdjacentHTML( 'beforeend',
+ '
' );
+ }
+
+ window.wp.blocks.selectBlock( block );
+ },
+ isActive: function( block ) {
+ return !! block.querySelector( 'figcaption' );
+ }
+ },
+ {
+ icon: 'gridicons-cog',
+ onClick: function() {}
+ }
+ ]
+ } );
+
+} )( window.wp );
diff --git a/tinymce-single/blocks/elements/blockquote/register.js b/tinymce-single/blocks/elements/blockquote/register.js
index 0e15d6d792f99..6c60101ea50f6 100644
--- a/tinymce-single/blocks/elements/blockquote/register.js
+++ b/tinymce-single/blocks/elements/blockquote/register.js
@@ -1,50 +1,61 @@
-window.wp.blocks.registerBlock( {
- name: 'blockquote',
- displayName: 'Quote',
- elements: [ 'blockquote' ],
- type: 'text',
- icon: 'gridicons-quote',
- restrictToInline: [ 'footer' ],
- controls: [
- {
- classes: 'remove-formatting',
- icon: 'gridicons-quote',
- onClick: function( block, editor ) {
- var footer = block.querySelector( 'footer' );
- var firstChild = block.firstChild;
-
- if ( footer ) {
- block.removeChild( footer );
- }
+( function( wp ) {
+ function insertEmpty() {
+ return '
';
+ }
- while ( block.firstChild ) {
- block.parentNode.insertBefore( block.firstChild, block );
- }
+ function fromBaseState( block, editor ) {
+ editor.formatter.apply( 'blockquote', block );
+ }
- block.parentNode.removeChild( block );
+ function toBaseState( block ) {
+ var footer = block.querySelector( 'footer' );
+ var firstChild = block.firstChild;
- window.wp.blocks.selectBlock( firstChild );
- }
- },
- {
- icon: 'gridicons-caption',
- onClick: function( block ) {
- var footer = block.querySelector( 'footer' );
-
- if ( footer ) {
- block.removeChild( footer );
- } else {
- block.insertAdjacentHTML( 'beforeend',
- '' );
- }
- },
- isActive: function( block ) {
- return !! block.querySelector( 'footer' );
- }
+ if ( footer ) {
+ block.removeChild( footer );
}
- ],
- insert: function() {
- return '
';
+
+ while ( block.firstChild ) {
+ block.parentNode.insertBefore( block.firstChild, block );
+ }
+
+ block.parentNode.removeChild( block );
+
+ window.wp.blocks.selectBlock( firstChild );
}
-} );
+ window.wp.blocks.registerBlock( {
+ name: 'blockquote',
+ displayName: 'Quote',
+ elements: [ 'blockquote' ],
+ type: 'text',
+ icon: 'gridicons-quote',
+ restrictToInline: [ 'footer' ],
+ controls: [
+ {
+ classes: 'remove-formatting',
+ icon: 'gridicons-quote',
+ onClick: toBaseState
+ },
+ {
+ icon: 'gridicons-caption',
+ onClick: function( block ) {
+ var footer = block.querySelector( 'footer' );
+
+ if ( footer ) {
+ block.removeChild( footer );
+ } else {
+ block.insertAdjacentHTML( 'beforeend',
+ '' );
+ }
+ },
+ isActive: function( block ) {
+ return !! block.querySelector( 'footer' );
+ }
+ }
+ ],
+ insert: insertEmpty,
+ fromBaseState: fromBaseState,
+ toBaseState: toBaseState
+ } );
+} )( window.wp );
diff --git a/tinymce-single/blocks/elements/headings/register.js b/tinymce-single/blocks/elements/headings/register.js
index eb626c09d3af1..0b30920a4bc8b 100644
--- a/tinymce-single/blocks/elements/headings/register.js
+++ b/tinymce-single/blocks/elements/headings/register.js
@@ -26,6 +26,14 @@
return controls;
}
+ function toBaseState( block, editor ) {
+ editor.formatter.apply( 'p', block );
+ }
+
+ function fromBaseState( block, editor ) {
+ editor.formatter.apply( 'h1', block );
+ }
+
wp.blocks.registerBlock( {
name: 'heading',
displayName: 'Heading',
@@ -33,6 +41,8 @@
type: 'text',
icon: 'gridicons-heading',
controls: getControls(),
+ toBaseState: toBaseState,
+ fromBaseState: fromBaseState,
insert: function() {
// Maybe detect best heading based on document outline.
return '
';
diff --git a/tinymce-single/blocks/elements/paragraph/register.js b/tinymce-single/blocks/elements/paragraph/register.js
index 46d96a1393529..498cb04648fee 100644
--- a/tinymce-single/blocks/elements/paragraph/register.js
+++ b/tinymce-single/blocks/elements/paragraph/register.js
@@ -3,36 +3,16 @@ window.wp.blocks.registerBlock( {
displayName: 'Paragraph',
elements: [ 'p' ],
type: 'text',
+ section: 'text',
icon: 'gridicons-posts',
controls: [
- {
- icon: 'gridicons-heading',
- onClick: function( block, editor ) {
- editor.formatter.apply( 'h1' );
- }
- },
- {
- icon: 'gridicons-quote',
- onClick: function( block, editor ) {
- editor.formatter.apply( 'blockquote' );
- }
- },
- {
- icon: 'gridicons-list-unordered',
- onClick: function( block ) {
- wp.blocks.getBlockSettings( 'elements:list' ).fromBaseState( block );
- }
- },
- {
- icon: 'gridicons-code',
- onClick: function( block, editor ) {
- editor.formatter.apply( 'pre' );
- }
- },
+ 'text-switcher',
'text-align-left',
'text-align-center',
'text-align-right'
],
+ toBaseState: function() {},
+ fromBaseState: function() {},
insert: function() {
return '
';
}
diff --git a/tinymce-single/blocks/elements/preformatted/register.js b/tinymce-single/blocks/elements/preformatted/register.js
index 449daf03fdb07..9623f227d92c1 100644
--- a/tinymce-single/blocks/elements/preformatted/register.js
+++ b/tinymce-single/blocks/elements/preformatted/register.js
@@ -1,22 +1,39 @@
-window.wp.blocks.registerBlock( {
- name: 'preformatted',
- displayName: 'Preformatted',
- elements: [ 'pre' ],
- type: 'text',
- icon: 'gridicons-code',
- controls: [
- {
- icon: 'gridicons-cog'
- },
- {
- classes: 'remove-formatting',
- icon: 'gridicons-code',
- onClick: function( block, editor ) {
- editor.formatter.remove( 'pre' );
- }
- }
- ],
- insert: function() {
+( function( wp ) {
+
+ function insertEmpty() {
return '
';
}
-} );
+
+ function fromBaseState( block, editor ) {
+ editor.formatter.apply( 'pre', block );
+ }
+
+ function toBaseState( block, editor ) {
+ editor.formatter.remove( 'pre', block );
+ }
+
+ window.wp.blocks.registerBlock( {
+ name: 'preformatted',
+ displayName: 'Preformatted',
+ elements: [ 'pre' ],
+ type: 'text',
+ icon: 'gridicons-code',
+ controls: [
+ {
+ icon: 'gridicons-cog',
+ onClick: function() {}
+ },
+ {
+ classes: 'remove-formatting',
+ icon: 'gridicons-code',
+ onClick: function( block, editor ) {
+ editor.formatter.remove( 'pre', block );
+ }
+ }
+ ],
+ insert: insertEmpty,
+ fromBaseState: fromBaseState,
+ toBaseState: toBaseState
+ } );
+
+} )( window.wp );
diff --git a/tinymce-single/blocks/my-awesome-plugin/youtube/register.js b/tinymce-single/blocks/my-awesome-plugin/youtube/register.js
index 5dc04a52b05fb..792647b0efab9 100644
--- a/tinymce-single/blocks/my-awesome-plugin/youtube/register.js
+++ b/tinymce-single/blocks/my-awesome-plugin/youtube/register.js
@@ -42,7 +42,26 @@
'block-align-right',
'block-align-full',
{
- icon: 'gridicons-cog'
+ icon: 'gridicons-caption',
+ onClick: function( block ) {
+ var figcaption = block.querySelector( 'figcaption' );
+
+ if ( figcaption ) {
+ block.removeChild( figcaption );
+ } else {
+ block.insertAdjacentHTML( 'beforeend',
+ '
' );
+ }
+
+ window.wp.blocks.selectBlock( block );
+ },
+ isActive: function( block ) {
+ return !! block.querySelector( 'figcaption' );
+ }
+ },
+ {
+ icon: 'gridicons-cog',
+ onClick: function() {}
}
],
insert: insertEmpty,
diff --git a/tinymce-single/index.html b/tinymce-single/index.html
index 40e39d9cfc1e7..ab9520d62b144 100644
--- a/tinymce-single/index.html
+++ b/tinymce-single/index.html
@@ -72,11 +72,12 @@ NASA discovers system of seven Earth-sized planets
-
+
+
+
-
diff --git a/tinymce-single/tinymce/block.css b/tinymce-single/tinymce/block.css
index 23e3d61ca09a6..96817f2eb1b98 100644
--- a/tinymce-single/tinymce/block.css
+++ b/tinymce-single/tinymce/block.css
@@ -146,6 +146,10 @@ svg.gridicon {
transform-origin: top left;
}
+.mce-gridicons-rotate svg {
+ transform: rotate( 90deg );
+}
+
div.mce-inline-toolbar-grp {
background-color: #fff;
border: 1px solid #e1e6ea;
@@ -337,3 +341,19 @@ div.mce-inline-toolbar-grp.block-toolbar > div.mce-stack-layout {
display: block;
margin: 0 auto 20px;
}
+
+.mce-floatpanel {
+ position: absolute;
+ background-color: #fff;
+ border: 1px solid #e1e6ea;
+ box-shadow: 0px 3px 20px rgba( 18, 24, 30, .1 ), 0px 1px 3px rgba( 18, 24, 30, .1 );
+ margin-top: 2px;
+}
+
+.mce-listbox .mce-txt {
+ display: none;
+}
+
+.mce-menu-item {
+ padding: 4px;
+}
diff --git a/tinymce-single/tinymce/block.js b/tinymce-single/tinymce/block.js
index c1837e4aab4b0..9bc36351f0932 100644
--- a/tinymce-single/tinymce/block.js
+++ b/tinymce-single/tinymce/block.js
@@ -46,6 +46,31 @@
editor.addButton( name, settings );
} );
+ var textBlocks = wp.blocks.getType( 'text' );
+
+ editor.addButton( 'text-switcher', {
+ type: 'svglistbox',
+ icon: 'gridicons-posts',
+ values: textBlocks.map( function( settings ) {
+ return {
+ text: settings.displayName,
+ value: settings._id
+ }
+ } ),
+ onClick: function( event ) {
+ if ( event.control && event.control.settings.value ) {
+ var block = wp.blocks.getSelectedBlock();
+ var currentSettings = wp.blocks.getBlockSettingsByElement( block );
+ var nextSettings = wp.blocks.getBlockSettings( event.control.settings.value );
+
+ editor.undoManager.transact( function() {
+ currentSettings.toBaseState( block, editor );
+ nextSettings.fromBaseState( block, editor );
+ } );
+ }
+ }
+ } );
+
editor.on( 'pastePreProcess', function( event ) {
var block = getSelectedBlock();
var settings = wp.blocks.getBlockSettingsByElement( block );
@@ -126,19 +151,22 @@
editor.on( 'keydown', function( event ) {
if ( event.keyCode === tinymce.util.VK.ENTER ) {
- var selectedBlock = wp.blocks.getSelectedBlock();
- var blockSettings = wp.blocks.getBlockSettingsByElement( selectedBlock );
+ var block = wp.blocks.getSelectedBlock();
+ var settings = wp.blocks.getBlockSettingsByElement( block );
- if ( editor.$( selectedBlock ).attr( 'contenteditable' ) === 'false' ) {
+ if ( editor.$( block ).attr( 'contenteditable' ) === 'false' ) {
event.preventDefault();
}
- if ( blockSettings && blockSettings.restrictToInline ) {
- blockSettings.restrictToInline.forEach( function( selector ) {
+ if ( settings ) {
+ var restrict = ( settings.restrictToInline || [] ).concat( settings.editable || [] );
+
+ restrict.forEach( function( selector ) {
var node = editor.selection.getNode();
if ( editor.$( node ).is( selector ) || editor.$( node ).parents( selector ).length ) {
event.preventDefault();
+ editor.execCommand( 'InsertLineBreak' );
}
} );
}
diff --git a/tinymce-single/tinymce/config.js b/tinymce-single/tinymce/config.js
index e265bda75342c..3f12f58bfc8c1 100644
--- a/tinymce-single/tinymce/config.js
+++ b/tinymce-single/tinymce/config.js
@@ -10,6 +10,7 @@ window.tinymce.init( {
'clean-paste',
'lists',
'paste',
+ 'table',
'toolbar',
'wplink',
'wptextpattern'