From b6cde3cc6f34d82512adf614d216bf18cbfe0e34 Mon Sep 17 00:00:00 2001 From: Miguel Fonseca Date: Fri, 17 Feb 2017 11:09:02 +0000 Subject: [PATCH] Clone switcher controls into each block - Allows on-hover reveal of switcher to happen reliably with CSS - Requires refactoring of a few event-binding functions in order for them to operate on blocks rather than on a singleton node. - Reliance on the `selectedBlock` global is diminished. The drawback is a more hybrid code base, where some logic expects `selectedBlock` and some doesn't need it. The advantage is that less mutating state needs to be managed (setting `selectedBlock` can be delayed up until the point it is necessary for a given operation). - A couple of TypeErrors may pop up in the console. I suspect there are some interactions where the target block isn't defined. Needs to be addressed. --- blocks.js | 73 +++++++++++++++++++++++++++++++++++-------------------- style.css | 29 +++++++++++++++------- 2 files changed, 67 insertions(+), 35 deletions(-) diff --git a/blocks.js b/blocks.js index a2531c6358334..801c8603b8095 100644 --- a/blocks.js +++ b/blocks.js @@ -44,7 +44,6 @@ var config = { var editor = queryFirst( '.editor' ); var switcher = queryFirst( '.block-switcher' ); -var switcherButtons = query( '.block-switcher .type svg' ); var switcherMenu = queryFirst( '.switch-block__menu' ); var blockControls = queryFirst( '.block-controls' ); var inlineControls = queryFirst( '.inline-controls' ); @@ -73,13 +72,33 @@ insertBlockMenu.addEventListener( 'click', function( event ) { }, false ); window.addEventListener( 'mouseup', onSelectText, false ); +cloneSwitcher(); attachBlockHandlers(); -attachControlActions(); attachTypeSwitcherActions(); /** * Core logic */ +function cloneSwitcher() { + getBlocks().forEach( function( block ) { + var container = document.createElement( 'div' ); + var blockSwitcher = switcher.cloneNode( true ); + + var blockType = getTagType( block.nodeName ); + query( '.type svg', blockSwitcher ).forEach( function ( typeButton ) { + typeButton.style.display = 'none'; + } ); + var switcherQuery = '.type-icon-' + blockType; + queryFirst( switcherQuery, blockSwitcher ).style.display = 'block'; + + container.className = 'block-container'; + editor.insertBefore( container, block ); + container.appendChild( blockSwitcher ); + container.appendChild( block ); + attachControlActions( block ); + } ); +} + function attachBlockHandlers() { getBlocks().forEach( function( block ) { bind( 'click', block, selectBlock ); @@ -111,18 +130,8 @@ function clearBlocks() { } function showControls( node ) { - // toggle block-specific switcher - switcherButtons.forEach( function( element ) { - element.style.display = 'none'; - } ); var blockType = getTagType( node.nodeName ); - var switcherQuery = '.type-icon-' + blockType; - queryFirst( switcherQuery ).style.display = 'block'; - - // reposition switcher var position = node.getBoundingClientRect(); - switcher.style.opacity = 1; - switcher.style.top = ( position.top + 18 + window.scrollY ) + 'px'; // show/hide block-specific block controls var kinds = getTypeKinds( blockType ); @@ -138,7 +147,6 @@ function showControls( node ) { } function hideControls() { - switcher.style.opacity = 0; switcherMenu.style.display = 'none'; blockControls.style.display = 'none'; } @@ -170,8 +178,14 @@ function onSelectText( event ) { } } -function attachControlActions() { - Array.from( switcher.childNodes ).forEach( function( node ) { +function attachControlActions( block ) { + var buttons = query( '.block-switcher svg', block.parentNode ); + buttons.forEach( function( button ) { + bind( 'click', button, switchType ); + } ); + + var blockSwitcher = queryFirst( '.block-switcher', block.parentNode ); + Array.from( blockSwitcher.childNodes ).forEach( function( node ) { if ( 'svg' !== node.nodeName ) { return; } @@ -185,9 +199,15 @@ function attachControlActions() { if ( getter ) { node.addEventListener( 'click', function( event ) { event.stopPropagation(); - swapNodes( selectedBlock, getter( selectedBlock ) ); + clearBlocks(); + block.classList.add( 'is-selected' ); + selectedBlock = block; + swapNodes( + selectedBlock.parentNode, + getter( selectedBlock.parentNode ) + ); attachBlockHandlers(); - reselect(); + attachControlActions( queryFirst( '.is-selected' ) ); }, false ); } } ); @@ -199,10 +219,6 @@ function attachControlActions() { } function attachTypeSwitcherActions() { - switcherButtons.forEach( function( button ) { - button.addEventListener( 'click', showSwitcherMenu, false ); - } ); - Object.keys( config.typeToTag ).forEach( function( type ) { var selector = '.switch-block__block .type-icon-' + type; var button = queryFirst( selector ); @@ -228,10 +244,6 @@ function attachTypeSwitcherActions() { } ); } -function reselect() { - queryFirst( '.is-selected' ).click(); -} - function swapNodes( a, b ) { if ( ! ( a && b ) ) { return false; @@ -284,12 +296,21 @@ function hideMenu() { function showSwitcherMenu( event ) { event.stopPropagation(); - var position = switcher.getBoundingClientRect(); + var position = queryFirst( '.block-container:hover .block-switcher' ) + .getBoundingClientRect(); switcherMenu.style.top = ( position.top + 42 + window.scrollY ) + 'px'; switcherMenu.style.left = ( position.left - 32 + window.scrollX ) + 'px'; switcherMenu.style.display = 'block'; } +function switchType( event ) { + var block = event.target + .closest( '.block-container' ) + .childNodes[1]; + selectedBlock = block; + showSwitcherMenu( event ); +} + function setImageState( classes, event ) { event.stopPropagation(); selectedBlock.className = 'is-selected ' + classes; diff --git a/style.css b/style.css index a29b06ec9fa92..576e2758d5568 100644 --- a/style.css +++ b/style.css @@ -84,15 +84,20 @@ img { /* replaces some block margins */ } -h1:hover, -h2:hover, -h3:hover, -h4:hover, -h5:hover, -h6:hover, -p:hover, -blockquote:hover, -img:hover { +.block-container { + margin-left: -50px; + padding-left: 50px; +} + +.block-container:hover h1, +.block-container:hover h2, +.block-container:hover h3, +.block-container:hover h4, +.block-container:hover h5, +.block-container:hover h6, +.block-container:hover p, +.block-container:hover blockquote, +.block-container:hover img { box-shadow: inset 0px 0px 0px 2px #e0e5e9; } @@ -253,6 +258,12 @@ img.is-selected { transform: translateZ( 0 ); } +.block-container:hover .block-switcher, +.block-container:hover .switch-block__menu { + display: block; + opacity: 1; +} + .block-controls button { background: #191e23; color: #fff;