convert-rich-text
Advanced tools
Comparing version 1.0.4 to 1.1.0
@@ -7,5 +7,5 @@ var dom = require('./dom'); | ||
this.formats = formats; | ||
this.options = options; | ||
this.blockTag = options && options.blockTag || 'div'; | ||
this.inlineTag = options && options.inlineTag || 'span'; | ||
this.root = document.createElement('div'); | ||
this.line = null; | ||
this.newLine(); | ||
@@ -27,3 +27,3 @@ } | ||
if (lineText.length) { | ||
this.appendChild(lineText, attrs); | ||
this.appendToLine(lineText, attrs); | ||
} | ||
@@ -42,7 +42,7 @@ | ||
// HACK: fix this | ||
return this.root.innerHTML.replace(/<p><\/p>$/, ''); | ||
return this.root.innerHTML.replace(/<([a-z\-]+)><\/\1>$/, ''); | ||
}; | ||
Doc.prototype.newLine = function() { | ||
var node = document.createElement('p'); | ||
var node = document.createElement(this.blockTag); | ||
this.root.appendChild(node); | ||
@@ -52,3 +52,3 @@ this.line = node; | ||
Doc.prototype.appendChild = function(text, attrs) { | ||
Doc.prototype.appendToLine = function(text, attrs) { | ||
var node = document.createTextNode(text); | ||
@@ -68,20 +68,6 @@ | ||
// TODO: optimize line? | ||
this.line = this.root.lastChild; | ||
}; | ||
Doc.prototype.applyFormat = function(node, format, value) { | ||
if (typeof format === 'function') { | ||
return format(node, value); | ||
} | ||
if (format.parentTag) { | ||
var parentNode = document.createElement(format.parentTag); | ||
dom(node).wrap(parentNode); | ||
if (node.parentNode.previousSibling && node.parentNode.tagName === node.parentNode.previousSibling.tagName) { | ||
dom(node.parentNode.previousSibling).merge(node.parentNode); | ||
} | ||
if (node.parentNode.nextSibling && node.parentNode.tagName === node.parentNode.nextSibling.tagName) { | ||
dom(node.parentNode).merge(node.parentNode.nextSibling); | ||
} | ||
} | ||
if (format.tag) { | ||
@@ -91,18 +77,39 @@ if (format.type === 'line') { | ||
} else { | ||
var newNode = document.createElement(format.tag); | ||
if (dom.VOID_TAGS[format.tag]) { | ||
if (node.parentNode) { | ||
dom(node).replaceWith(newNode); | ||
} | ||
node = dom(node).replaceWith(document.createElement(format.tag)).get(); | ||
} else { | ||
dom(node).wrap(newNode); | ||
node = dom(node).wrap(format.tag).get(); | ||
} | ||
node = newNode; | ||
} | ||
} | ||
if (format.attribute) { | ||
node.setAttribute(format.attribute, value); | ||
if (format.parentTag) { | ||
node = dom(node).wrap(format.parentTag).get(); | ||
if (node.previousSibling && node.tagName === node.previousSibling.tagName) { | ||
dom(node.previousSibling).merge(node); | ||
} | ||
if (node.nextSibling && node.tagName === node.nextSibling.tagName) { | ||
dom(node).merge(node.nextSibling); | ||
} | ||
} | ||
if (format.attribute || format.class || format.style) { | ||
if (dom(node).isTextNode()) { | ||
node = dom(node).wrap(this.inlineTag).get(); | ||
} | ||
if (format.attribute) { | ||
node.setAttribute(format.attribute, value); | ||
} | ||
if (format.class) { | ||
node.classList.add(format.class + value); | ||
} | ||
if (format.style && value !== format.default) { | ||
node.style[format.style] = value; | ||
} | ||
} | ||
if (typeof format.add === 'function') { | ||
node = format.add(node, value); | ||
} | ||
return node; | ||
@@ -124,3 +131,2 @@ }; | ||
this.line = line; | ||
return line; | ||
}; |
@@ -163,12 +163,10 @@ var dom = module.exports = function(node) { | ||
dom.prototype.wrap = function(wrapper) { | ||
dom.prototype.wrap = function(tag) { | ||
var wrapper = document.createElement(tag); | ||
if (this.node.parentNode) { | ||
this.node.parentNode.insertBefore(wrapper, this.node); | ||
} | ||
var parent = wrapper; | ||
while (parent.firstChild) { | ||
parent = parent.firstChild; | ||
} | ||
parent.appendChild(this.node); | ||
wrapper.appendChild(this.node); | ||
this.node = wrapper; | ||
return this; | ||
}; |
{ | ||
"name": "convert-rich-text", | ||
"version": "1.0.4", | ||
"version": "1.1.0", | ||
"description": "Convert an insert-only rich-text delta into HTML", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "grunt" | ||
"info": "make info", | ||
"lint": "make lint", | ||
"start": "make start", | ||
"test": "make test" | ||
}, | ||
@@ -28,14 +31,9 @@ "repository": { | ||
"devDependencies": { | ||
"browserify": "^9.0.8", | ||
"chai": "^2.2.0", | ||
"grunt": "^0.4.5", | ||
"grunt-browserify": "^3.6.0", | ||
"grunt-contrib-clean": "^0.6.0", | ||
"grunt-contrib-connect": "^0.10.1", | ||
"grunt-contrib-jshint": "^0.11.1", | ||
"grunt-contrib-uglify": "^0.8.1", | ||
"grunt-contrib-watch": "^0.6.1", | ||
"grunt-mocha-phantomjs": "^0.6.1", | ||
"grunt-mocha-test": "^0.12.7", | ||
"mocha": "^2.0.1" | ||
"http-server": "^0.8.0", | ||
"jshint": "^2.7.0", | ||
"mocha-phantomjs": "^3.5.3", | ||
"watchify": "^3.2.0" | ||
} | ||
} |
@@ -64,20 +64,28 @@ # convert-rich-text | ||
`class: 'cursor-'` -- add a class with the given prefix, e.g. convert({ ops: [{ insert: 'hello', attributes: { cursor: 1234 } }] }, { cursor: { class: 'cursor-' })` => `<span class="cursor-1234">hello</span>` | ||
`style: 'fontSize'` -- set an inline style using the given name and the value from the delta | ||
A format may also be specified as a function of (node, value) for custom behavior. e.g. | ||
`add: function(node, value)` -- a hook for custom behavior, runs after logic for other options. e.g. | ||
``` | ||
```javascript | ||
convert(delta, { | ||
// reverse the text contents of the node | ||
reverse: function(node) { | ||
return document.createTextNode(node.textContent.split('').reverse().join('')); | ||
}, | ||
// repeat the contents N times | ||
repeat: function(node, value) { | ||
var wrapper = document.createDocumentFragment(); | ||
for (var i = 0, n = parseInt(value); i < n; i++) { | ||
wrapper.appendChild(node.cloneNode(true)); | ||
// wrap in a span, and set data attributes, | ||
// e.g. `{insert: 'hello', { data: { foo: 'bar' } } }` => `<span data-foo="bar">hello</span>` | ||
data: { tag: 'span', add: function(node, data) { | ||
Object.keys(data).forEach(function(key) { | ||
node.dataset[key] = data[key]; | ||
}); | ||
return node; | ||
} }, | ||
// repeat the line N times | ||
// e.g. `{insert: 'hello\n', { times: 3 } }` => `<p>hello</p><p>hello</p><p>hello</p>` | ||
repeat: { type: 'line', add: function(node, value) { | ||
var clone = node; | ||
for (var i = 1, n = parseInt(value); i < n; i++) { | ||
clone = node.cloneNode(true); | ||
node.parentNode.appendChild(clone); | ||
} | ||
return wrapper; | ||
} | ||
return clone; | ||
} } | ||
}); | ||
@@ -98,4 +106,9 @@ ``` | ||
## Development | ||
Run `npm start` to spin up a static web server and watchify. | ||
Open http://localhost:8080/test in a browser to run and debug tests. | ||
## Credit | ||
Thank you [@kbjr](https://github.com/kbjr) for https://github.com/UmbraEngineering/quilljs-renderer on which this project is forked. |
var assert = require('chai').assert; | ||
var convert = require('convert-rich-text'); | ||
var dom = require('../lib/dom'); | ||
var formats = { | ||
bold: { tag: 'B' }, | ||
color: { style: 'color' }, | ||
user: { class: 'user-' }, | ||
firstheader: { type: 'line', tag: 'H1' }, | ||
image: { type: 'embed', tag: 'IMG', attribute: 'src' }, | ||
link: { tag: 'A', attribute: 'href' }, | ||
className: { attribute: 'class' }, | ||
bullet: { type: 'line', tag: 'LI', parentTag: 'UL' }, | ||
list: { type: 'line', tag: 'LI', parentTag: 'OL' }, | ||
reverse: function(node) { | ||
reverse: { add: function(node) { | ||
var newNode = document.createTextNode(node.textContent.split('').reverse().join('')); | ||
node.parentNode.replaceChild(newNode, node); | ||
return newNode; | ||
}, | ||
repeat: function(node, value) { | ||
} }, | ||
repeat: { add: function(node, value) { | ||
var frag = document.createDocumentFragment(); | ||
@@ -22,3 +26,13 @@ for (var i = 0, n = parseInt(value); i < n; i++) { | ||
return frag; | ||
} | ||
} }, | ||
parent: { add: function(node, value) { | ||
dom(node.parentNode).switchTag(value); | ||
return node; | ||
} }, | ||
data: { type: 'line', add: function(node, value) { | ||
Object.keys(value).forEach(function(key) { | ||
node.dataset[key] = value[key]; | ||
}); | ||
return node; | ||
} } | ||
}; | ||
@@ -33,3 +47,3 @@ var tests = [ | ||
expected: | ||
'<p>Hello, <b>World!</b></p>' | ||
'<div>Hello, <b>World!</b></div>' | ||
}, | ||
@@ -49,9 +63,26 @@ { | ||
expected: | ||
'<p><b>Hello, World!</b></p>' + | ||
'<div><b>Hello, World!</b></div>' + | ||
'<h1><b>This is a second line.</b></h1>' + | ||
'<p>This is a demo of convert-rich-text ' + | ||
'<div>This is a demo of convert-rich-text ' + | ||
'<img src="http://i.imgur.com/2ockv.gif"> ' + | ||
'<a href="https://www.google.com">Google</a></p>' | ||
'<a href="https://www.google.com">Google</a></div>' | ||
}, | ||
{ | ||
desc: 'classes and styles', | ||
delta: { ops: [ | ||
{insert: 'Hello world', attributes: { color: 'red', user: 1234 }}, | ||
]}, | ||
expected: | ||
'<div><span style="color: red; " class="user-1234">Hello world</span></div>' | ||
}, | ||
{ | ||
desc: 'attribute with implicit span tag', | ||
delta: { ops: [ | ||
{insert: 'hello world', attributes: { className: 'greeting' }}, | ||
{insert: '\n'} | ||
]}, | ||
expected: | ||
'<div><span class="greeting">hello world</span></div>' | ||
}, | ||
{ | ||
desc: 'Lists', | ||
@@ -83,3 +114,3 @@ delta: { ops: [ | ||
expected: | ||
'<p><b>hello</b> <a href="http://vox.com">world</a> this works...?</p>' | ||
'<div><b>hello</b> <a href="http://vox.com">world</a> this works...?</div>' | ||
}, | ||
@@ -98,12 +129,27 @@ { | ||
{ | ||
desc: 'Custom', | ||
desc: 'Modify parent', | ||
delta: { ops: [ | ||
{insert: 'hello world', attributes: { parent: 'article' } }, | ||
{insert: '\n', attributes: { firstheader: true } } | ||
]}, | ||
expected: | ||
'<h1>hello world</h1>' | ||
}, | ||
{ | ||
desc: 'Custom formats', | ||
delta: { ops: [ | ||
{insert: 'Hello World!', attributes: {reverse: true}}, | ||
{insert: '\n'}, | ||
{insert: 'Foo Bar Baz', attributes: {bold: true, repeat: 3}}, | ||
{insert: '\n'} | ||
{insert: '\n', attributes: { data: {foo: 'bar'}}} | ||
]}, | ||
expected: | ||
'<p>!dlroW olleH</p>' + | ||
'<p><b>Foo Bar Baz</b><b>Foo Bar Baz</b><b>Foo Bar Baz</b></p>' | ||
'<div>!dlroW olleH</div>' + | ||
'<div data-foo="bar"><b>Foo Bar Baz</b><b>Foo Bar Baz</b><b>Foo Bar Baz</b></div>' | ||
}, | ||
{ | ||
desc: 'Change default blockTag', | ||
delta: { ops: [{insert: 'Hello world'}]}, | ||
opts: { blockTag: 'P' }, | ||
expected: '<p>Hello world</p>' | ||
} | ||
@@ -114,3 +160,3 @@ ]; | ||
it(test.desc, function() { | ||
var result = convert(test.delta, formats); | ||
var result = convert(test.delta, formats, test.opts); | ||
assert.equal(result, test.expected); | ||
@@ -117,0 +163,0 @@ }); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
6
12
113
25599
431