Skip to content

Commit

Permalink
Implement Mobiledoc 0.3.2 (text alignment attribute) (continued) (#688)
Browse files Browse the repository at this point in the history
* Implement Mobiledoc 0.3.2

* Replace text for buttons in demo editor with icons

* Document the new setAttribute API
  • Loading branch information
YoranBrondsema authored and mixonic committed Jul 16, 2019
1 parent 0449e15 commit 9d842fb
Show file tree
Hide file tree
Showing 28 changed files with 1,459 additions and 31 deletions.
20 changes: 20 additions & 0 deletions assets/demo/demo.css
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,26 @@ table tr {

.toolbar {
text-align: center;
display: flex;
}

.toolbar-section {
display: flex;
margin: 0 12px;
}
.toolbar-section:first-child { margin-left: 0; }
.toolbar-section:last-child { margin-right: 0; }

.toolbar-section button {
display: flex;
align-items: center;
margin: 0 4px;
}
.toolbar-section button:first-child { margin-left: 0; }
.toolbar-section button:last-child { margin-right: 0; }

.toolbar-section button svg {
height: 24px;
}

#editor-wrapper {
Expand Down
4 changes: 2 additions & 2 deletions assets/demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,9 @@ let activateButtons = (parentSelector, editor) => {
$(`${parentSelector} button`).click(function() {
let button = $(this);
let action = button.data('action');
let arg = button.data('arg');
let args = button.data('args').split(',');

editor[action](arg);
editor[action](...args);
});
};

Expand Down
47 changes: 39 additions & 8 deletions assets/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,41 @@
</div>
<div id="editor-wrapper">
<div class="toolbar">
<button data-action='toggleSection' data-arg='h1'>Headline</button>
<button data-action='toggleSection' data-arg='h2'>Subheadline</button>
<button data-action='toggleMarkup' data-arg='strong'>Bold</button>
<button data-action='toggleMarkup' data-arg='em'>Italic</button>
<button data-action='toggleSection' data-arg='ul'>Bullet List</button>
<button data-action='toggleSection' data-arg='ol'>Number List</button>
<!-- Icons are from https://material.io/tools/icons/ -->
<div class="toolbar-section">
<button data-action='toggleSection' data-args='h1'>Headline</button>
<button data-action='toggleSection' data-args='h2'>Subheadline</button>
</div>
<div class="toolbar-section">
<button data-action='toggleMarkup' data-args='strong'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15.6 10.79c.97-.67 1.65-1.77 1.65-2.79 0-2.26-1.75-4-4-4H7v14h7.04c2.09 0 3.71-1.7 3.71-3.79 0-1.52-.86-2.82-2.15-3.42zM10 6.5h3c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5h-3v-3zm3.5 9H10v-3h3.5c.83 0 1.5.67 1.5 1.5s-.67 1.5-1.5 1.5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
</button>
<button data-action='toggleMarkup' data-args='em'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M10 4v3h2.21l-3.42 8H6v3h8v-3h-2.21l3.42-8H18V4z"/></svg>
</button>
</div>
<div class="toolbar-section">
<button data-action='toggleSection' data-args='ul'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 10.5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0-6c-.83 0-1.5.67-1.5 1.5S3.17 7.5 4 7.5 5.5 6.83 5.5 6 4.83 4.5 4 4.5zm0 12c-.83 0-1.5.68-1.5 1.5s.68 1.5 1.5 1.5 1.5-.68 1.5-1.5-.67-1.5-1.5-1.5zM7 19h14v-2H7v2zm0-6h14v-2H7v2zm0-8v2h14V5H7z"/><path fill="none" d="M0 0h24v24H0V0z"/></svg>
</button>
<button data-action='toggleSection' data-args='ol'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M2 17h2v.5H3v1h1v.5H2v1h3v-4H2v1zm1-9h1V4H2v1h1v3zm-1 3h1.8L2 13.1v.9h3v-1H3.2L5 10.9V10H2v1zm5-6v2h14V5H7zm0 14h14v-2H7v2zm0-6h14v-2H7v2z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
</button>
</div>
<div class="toolbar-section">
<button data-action='setAttribute' data-args='text-align,left'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M15 15H3v2h12v-2zm0-8H3v2h12V7zM3 13h18v-2H3v2zm0 8h18v-2H3v2zM3 3v2h18V3H3z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
</button>
<button data-action='setAttribute' data-args='text-align,center'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M7 15v2h10v-2H7zm-4 6h18v-2H3v2zm0-8h18v-2H3v2zm4-6v2h10V7H7zM3 3v2h18V3H3z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
</button>
<button data-action='setAttribute' data-args='text-align,right'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 21h18v-2H3v2zm6-4h12v-2H9v2zm-6-4h18v-2H3v2zm6-4h12V7H9v2zM3 3v2h18V3H3z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
</button>
<button data-action='setAttribute' data-args='text-align,justify'>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 21h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18v-2H3v2zm0-4h18V7H3v2zm0-6v2h18V3H3z"/><path d="M0 0h24v24H0z" fill="none"/></svg>
</button>
</div>
</div>
<div id='editor'></div>
</div>
Expand Down Expand Up @@ -173,8 +202,7 @@ <h3>Basic Editor</h3>
<h3>Toolbar Buttons</h3>

<p>
Use the <a href='http://bustle.github.io/mobiledoc-kit/demo/docs/Editor.html#toggleMarkup'><code>editor.toggleMarkup</code></a> and <a href='http://bustle.github.io/mobiledoc-kit/demo/docs/Editor.html#toggleSection'><code>editor.toggleSelection</code></a> methods to modify
the text.
Use the <a href='http://bustle.github.io/mobiledoc-kit/demo/docs/Editor.html#toggleMarkup'><code>editor.toggleMarkup</code></a>, <a href='http://bustle.github.io/mobiledoc-kit/demo/docs/Editor.html#toggleSection'><code>editor.toggleSection</code></a> and <a href='http://bustle.github.io/mobiledoc-kit/demo/docs/Editor.html#setAttribute'><code>editor.setAttribute</code></a> methods to modify the text.
</p>

<div class="two-column">
Expand All @@ -186,6 +214,9 @@ <h3>Toolbar Buttons</h3>
$('button.strong').click(() =&gt; {
editor.toggleMarkup('strong');
});
$('button.center').click(() =&gt; {
editor.setAttribute('text-align', 'center');
});
</code></pre>
</div>
<div class="column right">
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@
],
"license": "MIT",
"dependencies": {
"mobiledoc-dom-renderer": "0.6.5",
"mobiledoc-text-renderer": "0.3.2"
"mobiledoc-dom-renderer": "0.7.0",
"mobiledoc-text-renderer": "0.4.0"
},
"devDependencies": {
"broccoli": "^1.1.3",
Expand Down
21 changes: 21 additions & 0 deletions src/css/mobiledoc-kit.css
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,27 @@
max-width: 100%;
}

.__mobiledoc-editor [data-md-text-align='left'] {
text-align: left;
}

.__mobiledoc-editor [data-md-text-align='center'] {
text-align: center;
}

.__mobiledoc-editor [data-md-text-align='right'] {
text-align: right;
}

.__mobiledoc-editor [data-md-text-align='justify'] {
text-align: justify;
}

.__mobiledoc-editor ol,
.__mobiledoc-editor ul {
list-style-position: inside;
}

/**
* Cards
*/
Expand Down
12 changes: 12 additions & 0 deletions src/js/editor/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -953,6 +953,18 @@ class Editor {
this.run(postEditor => postEditor.toggleSection(tagName, this.range));
}

/**
* Sets an attribute for the current active section(s).
*
* @param {String} key The attribute. The only valid attribute is 'text-align'.
* @param {String} value The value of the attribute.
* @public
* @see PostEditor#setAttribute
*/
setAttribute(key, value) {
this.run(postEditor => postEditor.setAttribute(key, value, this.range));
}

/**
* Finds and runs the first matching key command for the event
*
Expand Down
19 changes: 19 additions & 0 deletions src/js/editor/post.js
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,25 @@ class PostEditor {
this.setRange(nextRange);
}

setAttribute(key, value, range) {
range = toRange(range);
let { post } = this.editor;
let attribute = `data-md-${key}`;

post.walkMarkerableSections(range, section => {
if (section.isListItem) {
section = section.parent;
}

if (section.getAttribute(attribute) !== value) {
section.setAttribute(attribute, value);
this._markDirty(section);
}
});

this.setRange(range);
}

_isSameSectionType(section, sectionTagName) {
return section.isListItem ?
section.parent.tagName === sectionTagName :
Expand Down
25 changes: 25 additions & 0 deletions src/js/models/_attributable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const VALID_ATTRIBUTES = [
'data-md-text-align'
];

/*
* A "mixin" to add section attribute support
* to markup and list sections.
*/
export function attributable(ctx) {
ctx.attributes = {};

ctx.setAttribute = (key, value) => {
if (!VALID_ATTRIBUTES.includes(key)) {
throw new Error(`Invalid attribute "${key}" was passed. Constrain attributes to the spec-compliant whitelist.`);
}
ctx.attributes[key] = value;
};
ctx.removeAttribute = key => {
delete ctx.attributes[key];
};
ctx.getAttribute = key => ctx.attributes[key];
ctx.eachAttribute = cb => {
Object.entries(ctx.attributes).forEach(([k,v]) => cb(k,v));
};
}
6 changes: 5 additions & 1 deletion src/js/models/list-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { LIST_SECTION_TYPE } from './types';
import Section from './_section';
import { normalizeTagName } from '../utils/dom-utils';
import assert from '../utils/assert';
import { attributable } from './_attributable';

export const VALID_LIST_SECTION_TAGNAMES = [
'ul', 'ol'
Expand All @@ -12,12 +13,15 @@ export const VALID_LIST_SECTION_TAGNAMES = [
export const DEFAULT_TAG_NAME = VALID_LIST_SECTION_TAGNAMES[0];

export default class ListSection extends Section {
constructor(tagName=DEFAULT_TAG_NAME, items=[]) {
constructor(tagName=DEFAULT_TAG_NAME, items=[], attributes={}) {
super(LIST_SECTION_TYPE);
this.tagName = tagName;
this.isListSection = true;
this.isLeafSection = false;

attributable(this);
Object.entries(attributes).forEach(([k,v]) => this.setAttribute(k, v));

this.items = new LinkedList({
adoptItem: i => {
assert(`Cannot insert non-list-item to list (is: ${i.type})`,
Expand Down
7 changes: 6 additions & 1 deletion src/js/models/markup-section.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Markerable from './_markerable';
import { normalizeTagName } from '../utils/dom-utils';
import { contains } from '../utils/array-utils';
import { MARKUP_SECTION_TYPE } from './types';
import { attributable } from './_attributable';

// valid values of `tagName` for a MarkupSection
export const VALID_MARKUP_SECTION_TAGNAMES = [
Expand Down Expand Up @@ -33,8 +34,12 @@ export const MARKUP_SECTION_ELEMENT_NAMES = [
export const DEFAULT_TAG_NAME = VALID_MARKUP_SECTION_TAGNAMES[8];

const MarkupSection = class MarkupSection extends Markerable {
constructor(tagName=DEFAULT_TAG_NAME, markers=[]) {
constructor(tagName=DEFAULT_TAG_NAME, markers=[], attributes={}) {
super(MARKUP_SECTION_TYPE, tagName, markers);

attributable(this);
Object.entries(attributes).forEach(([k,v]) => this.setAttribute(k, v));

this.isMarkupSection = true;
}

Expand Down
8 changes: 4 additions & 4 deletions src/js/models/post-node-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,19 @@ class PostNodeBuilder {
* @param {Marker[]} [markers=[]]
* @return {MarkupSection}
*/
createMarkupSection(tagName=DEFAULT_MARKUP_SECTION_TAG_NAME, markers=[], isGenerated=false) {
createMarkupSection(tagName=DEFAULT_MARKUP_SECTION_TAG_NAME, markers=[], isGenerated=false, attributes={}) {
tagName = normalizeTagName(tagName);
const section = new MarkupSection(tagName, markers);
const section = new MarkupSection(tagName, markers, attributes);
if (isGenerated) {
section.isGenerated = true;
}
section.builder = this;
return section;
}

createListSection(tagName=DEFAULT_LIST_SECTION_TAG_NAME, items=[]) {
createListSection(tagName=DEFAULT_LIST_SECTION_TAG_NAME, items=[], attributes={}) {
tagName = normalizeTagName(tagName);
const section = new ListSection(tagName, items);
const section = new ListSection(tagName, items, attributes);
section.builder = this;
return section;
}
Expand Down
Loading

0 comments on commit 9d842fb

Please sign in to comment.