Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move blocks #4

Closed
wants to merge 7 commits into from
Closed
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
138 changes: 138 additions & 0 deletions blocks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
"use strict";

/**
* Derived functions
*/
var getNextSibling = siblingGetter( 'next' );
var getPreviousSibling = siblingGetter( 'previous' );

/**
* Globals
*/

var editor = document.getElementsByClassName( 'editor' )[0];
var controls = document.getElementsByClassName( 'block-controls' )[0];
var selectedBlock = null;

/**
* Initialization
*/

window.addEventListener( 'click', clearBlocks, false );
editor.addEventListener( 'input', attachBlockHandlers, false );
editor.addEventListener( 'input', clearBlocks, false );

attachBlockHandlers();
attachControlActions();

/**
* Core logic
*/

function attachBlockHandlers() {
var blocks = getBlocks();
Array.from( blocks ).forEach( function( block ) {
block.removeEventListener( 'click', selectBlock, false );
block.addEventListener( 'click', selectBlock, false );
} );
}

function getBlocks() {
var text = document.getElementsByTagName( 'p' );
var heading = document.getElementsByTagName( 'h2' );
var images = document.getElementsByTagName( 'img' );
return [ ...text, ...heading, ...images ];
}

function selectBlock( event ) {
clearBlocks();
event.stopPropagation();
event.target.className = 'is-selected';

var position = event.target.getBoundingClientRect();

// Show switcher
controls.style.opacity = 1;
controls.style.top = ( position.top + 18 ) + 'px';
selectedBlock = event.target;
}

function clearBlocks() {
Array.from( getBlocks() ).forEach( function( block ) {
block.className = '';
} );
var selectedBlock = null;

hideControls();
}

function hideControls() {
controls.style.opacity = 0;
}

function attachControlActions() {
Array.from( controls.childNodes ).forEach( function( node ) {
if ( 'svg' !== node.nodeName ) {
return;
}

var classes = node.className.baseVal;

if ( 'up' === classes ) {
node.addEventListener( 'click', function() {
swapNodes( selectedBlock, getPreviousSibling( selectedBlock ) );
attachBlockHandlers();
}, false );
} else if ( 'down' === classes ) {
node.addEventListener( 'click', function() {
swapNodes( selectedBlock, getNextSibling( selectedBlock ) );
attachBlockHandlers();
}, false );
}
} );
}

function swapNodes( a, b ) {
if ( ! ( a && b ) ) {
return false;
}

var parent = a.parentNode;
if ( ! parent ) {
return false;
}

// insert node copies before removal
parent.replaceChild( b.cloneNode( true ), a );
parent.replaceChild( a.cloneNode( true ), b );

return true;
}

/**
* Utility functions
*/
function siblingGetter( direction ) {
var sibling = direction + 'Sibling';

return function getAdjacentSibling( node ) {
if ( null === node ) {
return null;
}

if ( null === node[ sibling ] ) {
return null;
}

if ( '#text' === node[ sibling ].nodeName ) {
return getAdjacentSibling( node[ sibling ] );
}

return node[ sibling ];
}
}

function l( data ) {
console.log( data );
return data;
}
27 changes: 27 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<title>Editor Blocks</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel='stylesheet' id='h5-font-css' href='https://fonts.googleapis.com/css?family=Merriweather:700,300,700italic,300italic' />
<link href="style.css" rel="stylesheet" type="text/css" media="all">
</head>
<body>
<div class="block-controls">
<svg width="18" height="18" class="up" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><path d="M2 11l7-7 7 7-1.4 1.4L9 6.8l-5.6 5.6"/></svg>
<svg width="18" height="18" class="down" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><path d="M16 6.414l-7 7-7-7 1.4-1.4 5.6 5.6 5.6-5.6"/></svg>
<svg width="24" height="24" class="type" 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>
</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>
<p>I like Apple for the opposite reason: they’re not afraid of getting a rudimentary 1.0 out into the world.</p>
<img src="https://matiasventura.files.wordpress.com/2017/02/blue.png?w=720" />
<p> </p>
<svg class="gridicon gridicons-add-outline" height="48" width="48" 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>
</section>
<div class="insert-block">
</div>
<script src="blocks.js"></script>
</body>
</html>
152 changes: 152 additions & 0 deletions style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/**
* Basic
*/
html,
body {
margin: 0;
padding: 0;
height: 100%;
}

* {
box-sizing: border-box;
}

body {
font: 13px/1.8 -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen-Sans", "Ubuntu", "Cantarell", "Helvetica Neue", sans-serif;
max-width: 720px;
margin: 60px auto;
}

p,
h1,
h2,
h3,
h4,
h5,
h6,
img {
font-family: "Merriweather", serif;
margin: 15px 0;
/* Uses paddings instead */
}

h2 {
font-weight: 900;
font-size: 28px;
}

p {
font-size: 16px;
}

section:focus {
outline: none;
}

/**
* Hover controls
*/
h1,
h2,
h3,
h4,
h5,
h6,
p,
img {
position: relative;
box-shadow: inset 0px 0px 0px 0px #e0e5e9;
transition: all .2s ease;
padding: 15px;
/* replaces some block margins */
}
h1:hover,
h2:hover,
h3:hover,
h4:hover,
h5:hover,
h6:hover,
p:hover,
img:hover {
box-shadow: inset 0px 0px 0px 2px #e0e5e9;
}
h1.is-selected,
h2.is-selected,
h3.is-selected,
h4.is-selected,
h5.is-selected,
h6.is-selected,
p.is-selected,
img.is-selected {
box-shadow: inset 0px 0px 0px 2px #191e23;
}
h1:before,
h2:before,
h3:before,
h4:before,
h5:before,
h6:before,
p:before,
img:before {
content: "";
position: absolute;
display: block;
top: 0;
left: 0;
height: 0;
width: 108px;
background: #191e23;
transition: all .075s ease;
transform: translateZ(0);
}
h1.is-selected:before,
h2.is-selected:before,
h3.is-selected:before,
h4.is-selected:before,
h5.is-selected:before,
h6.is-selected:before,
p.is-selected:before,
img.is-selected:before {
height: 36px;
top: -36px;
}

p {
min-height: 3.4em;
}

.block-controls {
opacity: 0;
margin-left: -54px;
height: 36px;
width: 54px;
position: absolute;
transition: opacity .075s ease;
transform: translateZ(0);
}
.block-controls svg {
fill: #86909c;
position: absolute;
cursor: pointer;
}
.block-controls svg:hover {
fill: #191e23;
}
.block-controls svg.up {
left: 0;
top: 0;
}
.block-controls svg.down {
left: 0;
bottom: 0;
}
.block-controls svg.type {
right: 6px;
top: 6px;
}

img {
max-width: 100%;
height: auto;
}