diff --git a/shared/index.css b/shared/index.css index b0134ca198d0f..2d93b543545d5 100644 --- a/shared/index.css +++ b/shared/index.css @@ -102,7 +102,8 @@ body { #editor figure { clear: both; float: none; - margin: 1em 0; + margin-left: auto; + margin-right: auto; width: 100%; /*transition: margin 0.5s, width 0.5s;*/ } @@ -152,7 +153,7 @@ body { #editor figure img, #editor figure iframe { display: block; - margin: 0; + margin: 0 auto; } #editor pre { diff --git a/tinymce-single/blocks/core/gallery/register.js b/tinymce-single/blocks/core/gallery/register.js index 8c39f71e6060d..2356d343dc3e1 100644 --- a/tinymce-single/blocks/core/gallery/register.js +++ b/tinymce-single/blocks/core/gallery/register.js @@ -1,31 +1,85 @@ -window.wp.blocks.registerBlock( { - name: 'gallery', - namespace: 'core', - displayName: 'Gallery', - type: 'media', - keywords: [], - icon: 'gridicons-image-multiple', - editable: [ 'figcaption' ], - controls: [ - 'block-align-left', - 'block-align-center', - 'block-align-right', - 'block-align-full', - // { - // type: 'select', - // label: 'Columns' - // }, - // { - // type: 'button', - // label: 'Columns', - // icon: 'gridicons-image', - // command: function( editor, node ) { - // // body... - // } - // }, - { - icon: 'gridicons-cog' +( function( wp ) { + + function insertEmpty() { + return ( + '
' + + '
' + + '
' + + '' + + '' + + '' + + '

Pick image

' + + '
' + + '
' + + '
' + + '
' + + '' + + '' + + '' + + '

Pick image

' + + '
' + + '
' + + '
' + ); + } + + function pickTarget( parents, child ) { + for ( var i = 0; i < parents.length; i++ ) { + if ( parents[ i ] === child || parents[ i ].contains( child ) ) { + return parents[ i ] + } } - ], - insert: function() {} -} ); + } + + function onClick( event, block, adjustUI ) { + var target = pickTarget( block.querySelectorAll( 'div' ), event.target ); + + if ( ! target ) { + return; + } + + if ( ( ' ' + target.className + ' ' ).indexOf( ' wp-blocks-placeholder ' ) === -1 ) { + return; + } + + wp.filePicker( false, 'image/*' ) + .then( function( files ) { + if ( ! files || ! files.length ) { + return; + } + + if ( files[0].type.indexOf( 'image/' ) !== 0 ) { + return; + } + + var img = document.createElement( 'img' ); + + img.src = URL.createObjectURL( files[0] ); + img.onload = adjustUI; + + target.parentNode.replaceChild( img, target ); + } ) + .catch( function() {} ); + } + + wp.blocks.registerBlock( { + name: 'gallery', + namespace: 'core', + displayName: 'Gallery', + type: 'media', + keywords: [], + icon: 'gridicons-image-multiple', + editable: [ 'figcaption' ], + controls: [ + 'block-align-left', + 'block-align-center', + 'block-align-right', + 'block-align-full', + { + icon: 'gridicons-cog' + } + ], + insert: insertEmpty, + onClick: onClick + } ); +} )( window.wp ); diff --git a/tinymce-single/blocks/core/gallery/structure.css b/tinymce-single/blocks/core/gallery/structure.css index 09c2ed9317a09..c05a0000b3a1e 100644 --- a/tinymce-single/blocks/core/gallery/structure.css +++ b/tinymce-single/blocks/core/gallery/structure.css @@ -33,7 +33,7 @@ } #editor figure[data-wp-block-type="core:gallery"][data-wp-block-setting-column="2"] figure { - width: 43%; + width: 49%; } #editor figure[data-wp-block-type="core:gallery"][data-wp-block-setting-column="3"] figure { diff --git a/tinymce-single/blocks/core/image/register.js b/tinymce-single/blocks/core/image/register.js index a9a4293a9cd7a..1492d96e5b0f6 100644 --- a/tinymce-single/blocks/core/image/register.js +++ b/tinymce-single/blocks/core/image/register.js @@ -1,40 +1,90 @@ -window.wp.blocks.registerBlock( { - name: 'image', - namespace: 'core', - displayName: 'Image', - type: 'media', - icon: 'gridicons-image', - editable: [ 'figcaption' ], - controls: [ - 'block-align-left', - 'block-align-center', - 'block-align-right', - 'block-align-full', - { - icon: 'gridicons-caption', - onClick: function( block ) { - var figcaption = block.querySelector( 'figcaption' ); - - if ( figcaption ) { - block.removeChild( figcaption ); - } else { - block.insertAdjacentHTML( 'beforeend', - '

' ); - } +( function( wp ) { - window.wp.blocks.selectBlock( block ); - }, - isActive: function( block ) { - return !! block.querySelector( 'figcaption' ); - } - } - ], - insert: function() { + function insertEmpty() { return ( - '
' + - '' + - '
I have no idea which mountain this is. It looks tall!
' + + '
' + + '
' + + '' + + '' + + '' + + '

Pick image

' + + '
' + '
' ); } -} ); + + function pickTarget( parents, child ) { + for ( var i = 0; i < parents.length; i++ ) { + if ( parents[ i ] === child || parents[ i ].contains( child ) ) { + return parents[ i ] + } + } + } + + function onClick( event, block, adjustUI ) { + var target = pickTarget( block.querySelectorAll( 'div' ), event.target ); + + if ( ! target ) { + return; + } + + if ( ( ' ' + target.className + ' ' ).indexOf( ' wp-blocks-placeholder ' ) === -1 ) { + return; + } + + wp.filePicker( false, 'image/*' ) + .then( function( files ) { + if ( ! files || ! files.length ) { + return; + } + + if ( files[0].type.indexOf( 'image/' ) !== 0 ) { + return; + } + + var img = document.createElement( 'img' ); + + img.src = URL.createObjectURL( files[0] ); + img.onload = adjustUI; + + target.parentNode.replaceChild( img, target ); + } ) + .catch( function() {} ); + } + + wp.blocks.registerBlock( { + name: 'image', + namespace: 'core', + displayName: 'Image', + type: 'media', + icon: 'gridicons-image', + editable: [ 'figcaption' ], + controls: [ + 'block-align-left', + 'block-align-center', + 'block-align-right', + 'block-align-full', + { + 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' ); + } + } + ], + insert: insertEmpty, + onClick: onClick + } ); + +} )( window.wp ); diff --git a/tinymce-single/blocks/elements/lists/register.js b/tinymce-single/blocks/elements/lists/register.js index d9420f13cf556..0ea5b8d8534d2 100644 --- a/tinymce-single/blocks/elements/lists/register.js +++ b/tinymce-single/blocks/elements/lists/register.js @@ -1,60 +1,90 @@ -window.wp.blocks.registerBlock( { - name: 'list', - displayName: 'List', - elements: [ 'ul', 'ol' ], - type: 'text', - icon: 'gridicons-list-unordered', - controls: [ - { - icon: 'gridicons-list-unordered', - stateSelector: 'ul', - onClick: function( block, editor ) { - // Use native command to toggle current selected list. - editor.execCommand( 'InsertUnorderedList' ); - } - }, - { - icon: 'gridicons-list-ordered', - stateSelector: 'ol', - onClick: function( block, editor ) { - // Use native command to toggle current selected list. - editor.execCommand( 'InsertOrderedList' ); +( function( wp ) { + + function insertEmpty() { + return ''; + } + + function fromBaseState( state ) { + var list = document.createElement( 'UL' ); + var item = document.createElement( 'LI' ); + + list.appendChild( item ); + + while ( state.firstChild ) { + if ( state.firstChild.nodeName === 'BR' ) { + item = document.createElement( 'LI' ); + list.appendChild( item ); + state.removeChild( state.firstChild ); + } else { + item.appendChild( state.firstChild ); } - }, - { - classes: 'remove-formatting', - icon: 'gridicons-list-unordered', - onClick: function( block, editor ) { - var p = document.createElement( 'P' ); - - function build( list, p ) { - var item; - - while ( item = list.firstChild ) { - if ( p.childNodes.length ) { - p.appendChild( document.createElement( 'BR' ) ); - } - - while ( item.firstChild ) { - if ( item.firstChild.nodeName === 'UL' || item.firstChild.nodeName === 'OL' ) { - build( item.firstChild, p ) - item.removeChild( item.firstChild ); - } else { - p.appendChild( item.firstChild ); - } - } - - list.removeChild( item ); - } + } + + state.parentNode.replaceChild( list, state ); + } + + function toBaseState( block ) { + var state = document.createElement( 'P' ); + + function build( list, state ) { + var item; + + while ( item = list.firstChild ) { + if ( state.childNodes.length ) { + state.appendChild( document.createElement( 'BR' ) ); } - build( block, p ); + while ( item.firstChild ) { + if ( item.firstChild.nodeName === 'UL' || item.firstChild.nodeName === 'OL' ) { + build( item.firstChild, state ) + item.removeChild( item.firstChild ); + } else { + state.appendChild( item.firstChild ); + } + } - block.parentNode.replaceChild( p, block ); + list.removeChild( item ); } } - ], - insert: function() { - return ''; + + build( block, state ); + + block.parentNode.replaceChild( state, block ); } -} ); + + wp.blocks.registerBlock( { + name: 'list', + displayName: 'List', + elements: [ 'ul', 'ol' ], + type: 'text', + icon: 'gridicons-list-unordered', + base: 'elements:paragraph', + insert: insertEmpty, + toBaseState: toBaseState, + fromBaseState: fromBaseState, + controls: [ + { + icon: 'gridicons-list-unordered', + stateSelector: 'ul', + onClick: function( block, editor ) { + // Use native command to toggle current selected list. + editor.execCommand( 'InsertUnorderedList' ); + } + }, + { + icon: 'gridicons-list-ordered', + stateSelector: 'ol', + onClick: function( block, editor ) { + // Use native command to toggle current selected list. + editor.execCommand( 'InsertOrderedList' ); + } + }, + { + classes: 'remove-formatting', + icon: 'gridicons-list-unordered', + onClick: toBaseState + } + ] + } ); + +} )( window.wp ); diff --git a/tinymce-single/blocks/elements/paragraph/register.js b/tinymce-single/blocks/elements/paragraph/register.js index 33f24f714bed1..46d96a1393529 100644 --- a/tinymce-single/blocks/elements/paragraph/register.js +++ b/tinymce-single/blocks/elements/paragraph/register.js @@ -19,23 +19,8 @@ window.wp.blocks.registerBlock( { }, { icon: 'gridicons-list-unordered', - onClick: function( block, editor ) { - var list = document.createElement( 'UL' ); - var item = document.createElement( 'LI' ); - - list.appendChild( item ); - - while ( block.firstChild ) { - if ( block.firstChild.nodeName === 'BR' ) { - item = document.createElement( 'LI' ); - list.appendChild( item ); - block.removeChild( block.firstChild ); - } else { - item.appendChild( block.firstChild ); - } - } - - block.parentNode.replaceChild( list, block ); + onClick: function( block ) { + wp.blocks.getBlockSettings( 'elements:list' ).fromBaseState( block ); } }, { diff --git a/tinymce-single/blocks/my-awesome-plugin/youtube/register.js b/tinymce-single/blocks/my-awesome-plugin/youtube/register.js index 35acf6f4c511b..5dc04a52b05fb 100644 --- a/tinymce-single/blocks/my-awesome-plugin/youtube/register.js +++ b/tinymce-single/blocks/my-awesome-plugin/youtube/register.js @@ -1,19 +1,52 @@ -window.wp.blocks.registerBlock( { - name: 'youtube', - namespace: 'my-awesome-plugin', - displayName: 'YouTube Video', - type: 'media', - keywords: [], - icon: 'gridicons-video', - editable: [ 'figcaption' ], - controls: [ - 'block-align-left', - 'block-align-center', - 'block-align-right', - 'block-align-full', - { - icon: 'gridicons-cog' +( function( wp ) { + + function insertEmpty() { + return ( + '
' + + '
' + + '' + + '' + + '' + + '

Paste YouTube link here

' + + '
' + + '
' + ); + } + + function onPaste( event, block ) { + var target = block.querySelector( 'div' ); + + if ( ! target ) { + return; } - ], - insert: function() {} -} ); + + var regEx = /https?:\/\/(?:www\.)?(?:youtube\.com\/watch\?v=|youtu\.be\/)([^?&]+).*/; + var matches = regEx.exec( event.content ); + + if ( matches && matches.length ) { + target.outerHTML = ''; + } + } + + wp.blocks.registerBlock( { + name: 'youtube', + namespace: 'my-awesome-plugin', + displayName: 'YouTube Video', + type: 'media', + keywords: [], + icon: 'gridicons-video', + editable: [ 'figcaption' ], + controls: [ + 'block-align-left', + 'block-align-center', + 'block-align-right', + 'block-align-full', + { + icon: 'gridicons-cog' + } + ], + insert: insertEmpty, + onPaste: onPaste + } ); + +} )( window.wp ); diff --git a/tinymce-single/controls/align.js b/tinymce-single/controls/align.js index 0556326761416..dd5158c23dac5 100644 --- a/tinymce-single/controls/align.js +++ b/tinymce-single/controls/align.js @@ -1,31 +1,20 @@ -( function( wp, $ ) { - var RX_ALIGN_CLASSNAME = /^(text-align-|align)([\w-]+)/; - +( function( wp ) { function createOnClick( classNamePrefix, position ) { return function( node ) { - return $( node ) - .removeClass( function( i, className ) { - return RX_ALIGN_CLASSNAME.test( className ) ? className : ''; - } ) - .addClass( classNamePrefix + position ); + node.className = node.className.replace( new RegExp( classNamePrefix + '[^ ]+ ?', 'g' ), '' ).trim(); + node.className += ( node.className ? ' ' : '' ) + classNamePrefix + position; }; } - function createIsActive( classNamePrefix, position ) { + function createIsActive( classNamePrefix, position, normal ) { return function( node ) { - var classNames = node.className.split( ' ' ), - i, className, match; - - for ( i = 0; i < classNames.length; i++ ) { - className = classNames[ i ]; - match = className.match( RX_ALIGN_CLASSNAME ); + var matches = node.className.match( new RegExp( classNamePrefix + '([^ ]+)' ) ); - if ( match && classNamePrefix === match[ 1 ] ) { - return position === match[ 2 ]; - } + if ( matches ) { + return position === matches[ 1 ]; + } else { + return position === normal; } - - return 'left' === position; }; } @@ -33,13 +22,13 @@ wp.blocks.registerControl( 'text-align-' + position, { icon: 'gridicons-align-' + position, onClick: createOnClick( 'text-align-', position ), - isActive: createIsActive( 'text-align-', position ) + isActive: createIsActive( 'text-align-', position, 'left' ) } ); wp.blocks.registerControl( 'block-align-' + position, { icon: 'gridicons-align-image-' + position, onClick: createOnClick( 'align', position ), - isActive: createIsActive( 'align', position ) + isActive: createIsActive( 'align', position, 'center' ) } ); } ); -} )( window.wp = window.wp || {}, window.jQuery ); +} )( window.wp ); diff --git a/tinymce-single/filePicker.js b/tinymce-single/filePicker.js new file mode 100644 index 0000000000000..2a7ca932b600d --- /dev/null +++ b/tinymce-single/filePicker.js @@ -0,0 +1,25 @@ +window.wp = window.wp || {}; +window.wp.filePicker = ( function() { + return function( multiple, accept ) { + return new Promise( function( resolve, reject ) { + var input = document.createElement( 'input' ); + + input.type = 'file'; + input.accept = accept; + input.multiple = multiple; + input.style.position = 'fixed'; + input.style.left = 0; + input.style.top = 0; + input.style.opacity = 0.001; + + input.onchange = function( event ) { + resolve( event.target.files ); + input.parentNode.removeChild( input ); + } + + document.body.appendChild( input ); + + input.click(); + } ); + } +} )(); diff --git a/tinymce-single/index.html b/tinymce-single/index.html index 1d11125304b54..40e39d9cfc1e7 100644 --- a/tinymce-single/index.html +++ b/tinymce-single/index.html @@ -66,9 +66,9 @@

NASA discovers system of seven Earth-sized planets

- + diff --git a/tinymce-single/tinymce/block.css b/tinymce-single/tinymce/block.css index ad651cccbcb3d..8d32598413c22 100644 --- a/tinymce-single/tinymce/block.css +++ b/tinymce-single/tinymce/block.css @@ -283,3 +283,14 @@ div.mce-inline-toolbar-grp.block-toolbar > div.mce-stack-layout { .insert-menu .mce-btn-has-text svg.gridicons-heading { margin: 0; } + +#editor .wp-blocks-placeholder { + padding: 50px 0; + background: #f0f2f4; + text-align: center; +} + +#editor .wp-blocks-placeholder svg { + display: block; + margin: 0 auto 20px; +} diff --git a/tinymce-single/tinymce/block.js b/tinymce-single/tinymce/block.js index 79339f8295958..a12ec933ea04f 100644 --- a/tinymce-single/tinymce/block.js +++ b/tinymce-single/tinymce/block.js @@ -46,6 +46,24 @@ editor.addButton( name, settings ); } ); + editor.on( 'pastePreProcess', function( event ) { + var block = getSelectedBlock(); + var settings = wp.blocks.getBlockSettingsByElement( block ); + + if ( settings.onPaste ) { + settings.onPaste( event, block ) + } + } ); + + editor.on( 'click', function( event ) { + var block = getSelectedBlock(); + var settings = wp.blocks.getBlockSettingsByElement( block ); + + if ( settings.onClick ) { + settings.onClick( event, block, function() { editor.nodeChanged() } ) + } + } ); + editor.on( 'setContent', function( event ) { $blocks = editor.$( editor.getBody() ).find( '*[data-wp-block-type]' ); $blocks.attr( 'contenteditable', 'false' ); @@ -60,6 +78,17 @@ } ); } ); + editor.on( 'nodeChange', function( event ) { + var block = wp.blocks.getSelectedBlock(); + var settings = wp.blocks.getBlockSettingsByElement( block ); + + if ( settings && settings.editable ) { + settings.editable.forEach( function( selector ) { + editor.$( block ).find( selector ).attr( 'contenteditable', 'true' ); + } ); + } + } ); + function toInlineContent( content ) { var settings = { valid_elements: 'strong,em,del,a[href]' @@ -318,7 +347,7 @@ var key; var types = [ 'text', 'media', 'separator' ]; - function onClick( callback ) { + function onClick( callback, settings ) { return function( block ) { var content = callback.apply( this, arguments ); var args = { @@ -340,6 +369,10 @@ block.parentNode.replaceChild( content, block ); + if ( ! settings.elements ) { + content.setAttribute( 'data-wp-block-type', settings._id ); + } + editor.fire( 'setContent', args ); } @@ -360,7 +393,7 @@ buttons.push( { text: allSettings[ key ].displayName, icon: allSettings[ key ].icon, - onClick: onClick( allSettings[ key ].insert ) + onClick: onClick( allSettings[ key ].insert, allSettings[ key ] ) } ); } }