Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 64 additions & 10 deletions blocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,35 +17,44 @@ var setImageAlignRight = setImageState.bind( null, 'align-right' );
*/
var config = {
tagTypes: {
'IMG': 'image',
'BLOCKQUOTE': 'quote',
'H1': 'heading',
'H2': 'heading',
'H3': 'heading',
'H4': 'heading',
'H5': 'heading',
'H6': 'heading',
'IMG': 'image',
'P': 'paragraph',
'default': 'paragraph'
},
typeKinds: {
'paragraph': [ 'text' ],
'quote': [ 'text' ],
'heading': [ 'heading', 'text' ],
'image': [ 'image' ],
'paragraph': [ 'text' ],
'default': []
}
};

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' );
var insertBlockButton = queryFirst( '.insert-block__button' );
var insertBlockMenu = queryFirst( '.insert-block__menu' );
var imageFullBleed = queryFirst( '.block-image__full-width' );
var imageAlignNone = queryFirst( '.block-image__no-align' );
var imageAlignLeft = queryFirst( '.block-image__align-left' );
var imageAlignRight = queryFirst( '.block-image__align-right' );

var selectedBlock = null;

var supportedBlockTags = Object.keys( config.tagTypes )
.slice( 0, -1 ) // remove 'default' option
.map( function( tag ) { return tag.toLowerCase(); } );

/**
* Initialization
Expand All @@ -54,10 +63,14 @@ window.addEventListener( 'click', clearBlocks, false );
editor.addEventListener( 'input', attachBlockHandlers, false );
editor.addEventListener( 'input', clearBlocks, false );
insertBlockButton.addEventListener( 'click', openBlockMenu, false );
insertBlockMenu.addEventListener( 'click', function( event ) {
event.stopPropagation();
}, false );
window.addEventListener( 'mouseup', onSelectText, false );

attachBlockHandlers();
attachControlActions();
attachTypeSwitcherActions();

/**
* Core logic
Expand All @@ -71,7 +84,7 @@ function attachBlockHandlers() {

function getBlocks() {
return Array.prototype.concat.apply( [],
[ 'p', 'h2', 'img' ].map( query ) );
supportedBlockTags.map( query ) );
}

function selectBlock( event ) {
Expand Down Expand Up @@ -122,6 +135,7 @@ function showControls( node ) {

function hideControls() {
switcher.style.opacity = 0;
switcherMenu.style.display = 'none';
blockControls.style.display = 'none';
}

Expand Down Expand Up @@ -180,6 +194,42 @@ function attachControlActions() {
imageAlignRight.addEventListener( 'click', setImageAlignRight, false );
}

function attachTypeSwitcherActions() {
var typeToTag = {
paragraph: 'p',
quote: 'blockquote',
heading: 'h2'
};

switcherButtons.forEach( function( button ) {
button.addEventListener( 'click', showSwitcherMenu, false );
} );

Object.keys( typeToTag ).forEach( function( type ) {
var selector = '.switch-block__block .type-icon-' + type;
var button = queryFirst( selector );
var label = queryFirst( selector + ' + label' );

button.addEventListener( 'click', switchBlockType, false );
label.addEventListener( 'click', switchBlockType, false );

function switchBlockType( event ) {
if ( ! selectedBlock ) {
return;
}

var openingRe = /^<\w+/;
var closingRe = /\w+>$/;
var tag = typeToTag[ type ];
selectedBlock.outerHTML = selectedBlock.outerHTML
.replace( openingRe, '<' + tag )
.replace( closingRe, tag + '>' );
clearBlocks();
attachBlockHandlers();
}
} );
}

function reselect() {
queryFirst( '.is-selected' ).click();
}
Expand Down Expand Up @@ -226,16 +276,20 @@ function siblingGetter( direction ) {

function openBlockMenu( event ) {
event.stopPropagation();
var menu = queryFirst( '.insert-block__menu' );
menu.style.display = 'block';
menu.addEventListener( 'click', function( event ) {
event.stopPropagation();
}, false );
insertBlockMenu.style.display = 'block';
}

function hideMenu() {
var menu = queryFirst( '.insert-block__menu' );
menu.style.display = 'none';
insertBlockMenu.style.display = 'none';
}

function showSwitcherMenu( event ) {
event.stopPropagation();

var position = 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 setImageState( classes, event ) {
Expand Down
18 changes: 17 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<svg width="24" height="24" class="type-icon-paragraph" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path id="path-1_2_" class="st0" d="M13 5h2v16h2V5h2V3h-6.7.2-3C6.5 3 4 5.5 4 8.5S6.5 14 9.5 14H11v7h2v-7h-.5.5V5z"/><path class="st1" d="M9.5 3C6.5 3 4 5.5 4 8.5S6.5 14 9.5 14H11v7h2V5h2v16h2V5h2V3H9.5z"/></svg>
<svg width="24" height="24" class="type-icon-heading" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Heading</title><rect x="0" fill="none" width="24" height="24"/><g><path d="M18 20h-3v-6H9v6H6V5.01h3V11h6V5.01h3V20z"/></g></svg>
<svg width="24" height="24" class="type-icon-image" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Image</title><rect x="0" fill="none" width="24" height="24"/><g><path d="M13 9.5c0-.828.672-1.5 1.5-1.5s1.5.672 1.5 1.5-.672 1.5-1.5 1.5-1.5-.672-1.5-1.5zM22 6v12c0 1.105-.895 2-2 2H4c-1.105 0-2-.895-2-2V6c0-1.105.895-2 2-2h16c1.105 0 2 .895 2 2zm-2 0H4v7.444L8 9l5.895 6.55 1.587-1.85c.798-.932 2.24-.932 3.037 0L20 15.426V6z"/></g></svg>
<svg width="24" height="24" class="type-icon-quote" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Quote</title><rect x="0" fill="none" width="24" height="24"/><g><path d="M11.192 15.757c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L9.373 5c-.8.396-1.56.898-2.26 1.505-.71.607-1.34 1.305-1.9 2.094s-.98 1.68-1.25 2.69-.346 2.04-.217 3.1c.168 1.4.62 2.52 1.356 3.35.735.84 1.652 1.26 2.748 1.26.965 0 1.766-.29 2.4-.878.628-.576.94-1.365.94-2.368l.002.003zm9.124 0c0-.88-.23-1.618-.69-2.217-.326-.42-.77-.692-1.327-.817-.56-.124-1.074-.13-1.54-.022-.16-.94.09-1.95.75-3.02.66-1.06 1.514-1.86 2.557-2.4L18.49 5c-.8.396-1.555.898-2.26 1.505-.708.607-1.34 1.305-1.894 2.094-.556.79-.97 1.68-1.24 2.69-.273 1-.345 2.04-.217 3.1.165 1.4.615 2.52 1.35 3.35.732.833 1.646 1.25 2.742 1.25.967 0 1.768-.29 2.402-.876.627-.576.942-1.365.942-2.368v.01z"/></g></svg>
</span>
</div>
<div class="block-controls">
Expand Down Expand Up @@ -47,6 +48,20 @@
<button><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Strikethrough</title><rect x="0" fill="none" width="24" height="24"/><g><path d="M14.348 12H21v2h-4.613c.24.515.368 1.094.368 1.748 0 1.317-.474 2.355-1.423 3.114-.947.76-2.266 1.138-3.956 1.138-1.557 0-2.934-.293-4.132-.878v-2.874c.985.44 1.818.75 2.5.928.682.18 1.306.27 1.872.27.68 0 1.2-.13 1.562-.39.363-.26.545-.644.545-1.158 0-.285-.08-.54-.24-.763-.16-.222-.394-.437-.704-.643-.18-.12-.483-.287-.88-.49H3v-2H14.347zm-3.528-2c-.073-.077-.143-.155-.193-.235-.126-.202-.19-.44-.19-.713 0-.44.157-.795.47-1.068.313-.273.762-.41 1.348-.41.492 0 .993.064 1.502.19.51.127 1.153.35 1.93.67l1-2.405c-.753-.327-1.473-.58-2.16-.76-.69-.18-1.414-.27-2.173-.27-1.544 0-2.753.37-3.628 1.108-.874.738-1.312 1.753-1.312 3.044 0 .302.036.58.088.848h3.318z"/></g></svg></button>
<button><svg width="24" height="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Text Color</title><rect x="0" fill="none" width="24" height="24"/><g><path d="M3 19h18v3H3v-3zM15.82 17h3.424L14 3h-4L4.756 17H8.18l1.067-3.5h5.506L15.82 17zm-1.952-6h-3.73l1.868-5.725L13.868 11z"/></g></svg></button>
</div>
<div class="switch-block__menu popover is-bottom">
<div class="popover__arrow"></div>
<div class="switch-block__block-list">
<div class="switch-block__block">
<svg width="24" height="24" class="type-icon-paragraph" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path id="path-1_2_" class="st0" d="M13 5h2v16h2V5h2V3h-6.7.2-3C6.5 3 4 5.5 4 8.5S6.5 14 9.5 14H11v7h2v-7h-.5.5V5z"/><path class="st1" d="M9.5 3C6.5 3 4 5.5 4 8.5S6.5 14 9.5 14H11v7h2V5h2v16h2V5h2V3H9.5z"/></svg><label>Paragraph</label>
</div>
<div class="switch-block__block">
<svg width="24" height="24" class="type-icon-heading" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Heading</title><rect x="0" fill="none" width="24" height="24"/><g><path d="M18 20h-3v-6H9v6H6V5.01h3V11h6V5.01h3V20z"/></g></svg><label>Heading</label>
</div>
<div class="switch-block__block">
<svg class="type-icon-quote gridicon gridicons-quote" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M11.192 15.757c0-.88-.23-1.618-.69-2.217-.326-.412-.768-.683-1.327-.812-.55-.128-1.07-.137-1.54-.028-.16-.95.1-1.956.76-3.022.66-1.065 1.515-1.867 2.558-2.403L9.373 5c-.8.396-1.56.898-2.26 1.505-.71.607-1.34 1.305-1.9 2.094s-.98 1.68-1.25 2.69-.346 2.04-.217 3.1c.168 1.4.62 2.52 1.356 3.35.735.84 1.652 1.26 2.748 1.26.965 0 1.766-.29 2.4-.878.628-.576.94-1.365.94-2.368l.002.003zm9.124 0c0-.88-.23-1.618-.69-2.217-.326-.42-.77-.692-1.327-.817-.56-.124-1.074-.13-1.54-.022-.16-.94.09-1.95.75-3.02.66-1.06 1.514-1.86 2.557-2.4L18.49 5c-.8.396-1.555.898-2.26 1.505-.708.607-1.34 1.305-1.894 2.094-.556.79-.97 1.68-1.24 2.69-.273 1-.345 2.04-.217 3.1.165 1.4.615 2.52 1.35 3.35.732.833 1.646 1.25 2.742 1.25.967 0 1.768-.29 2.402-.876.627-.576.942-1.365.942-2.368v.01z"></path></g></svg><label>Quote</label>
</div>
</div>
</div>
<section class="editor" contenteditable="true">
<h2>1.0 Is The Loneliest Number</h2>
<p>Many entrepreneurs idolize Steve Jobs. He’s such a perfectionist, they say. Nothing leaves the doors of 1 Infinite Loop in Cupertino without a polish and finish that makes geeks everywhere drool. No compromise!</p>
Expand All @@ -57,7 +72,8 @@ <h2>1.0 Is The Loneliest Number</h2>
<button class="insert-block__button">
<svg class="gridicon gridicons-add-outline" height="24" width="24" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M12 4c4.41 0 8 3.59 8 8s-3.59 8-8 8-8-3.59-8-8 3.59-8 8-8m0-2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm5 9h-4V7h-2v4H7v2h4v4h2v-4h4v-2z"></path></g></svg>
</button>
<div class="insert-block__menu">
<div class="insert-block__menu popover is-top">
<div class="popover__arrow"></div>
<input class="insert-block__search" type="search" placeholder="Search..." />
<span class="insert-block__separator">Recent</span>
<div class="insert-block__block-list">
Expand Down
Loading