Skip to content

Commit

Permalink
implements pasteHTML
Browse files Browse the repository at this point in the history
  • Loading branch information
hackerwins committed Apr 21, 2015
1 parent d12c9e5 commit faf8f2d
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 31 deletions.
68 changes: 39 additions & 29 deletions src/js/core/dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -746,33 +746,39 @@ define([
* split element or #text
*
* @param {BoundaryPoint} point
* @param {Boolean} [isSkipPaddingBlankHTML]
* @param {Object} [options]
* @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
* @param {Boolean} [options.isNotSplitEdgePoint] - default: false
* @return {Node} right node of boundaryPoint
*/
var splitNode = function (point, isSkipPaddingBlankHTML) {
// split #text
if (isText(point.node)) {
// edge case
var splitNode = function (point, options) {
var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;
var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;

// edge case
if (isEdgePoint(point) && (isText(point.node) || isNotSplitEdgePoint)) {
if (isLeftEdgePoint(point)) {
return point.node;
} else if (isRightEdgePoint(point)) {
return point.node.nextSibling;
}
}

// split #text
if (isText(point.node)) {
return point.node.splitText(point.offset);
}
} else {
var childNode = point.node.childNodes[point.offset];
var clone = insertAfter(point.node.cloneNode(false), point.node);
appendChildNodes(clone, listNext(childNode));

// split element
var childNode = point.node.childNodes[point.offset];
var clone = insertAfter(point.node.cloneNode(false), point.node);
appendChildNodes(clone, listNext(childNode));
if (!isSkipPaddingBlankHTML) {
paddingBlankHTML(point.node);
paddingBlankHTML(clone);
}

if (!isSkipPaddingBlankHTML) {
paddingBlankHTML(point.node);
paddingBlankHTML(clone);
return clone;
}

return clone;
};

/**
Expand All @@ -782,33 +788,33 @@ define([
*
* @param {Node} root - split root
* @param {BoundaryPoint} point
* @param {Boolean} [isSkipPaddingBlankHTML]
* @param {Object} [options]
* @param {Boolean} [options.isSkipPaddingBlankHTML] - default: false
* @param {Boolean} [options.isNotSplitEdgePoint] - default: false
* @return {Node} right node of boundaryPoint
*/
var splitTree = function (root, point, isSkipPaddingBlankHTML) {
var splitTree = function (root, point, options) {
// ex) [#text, <span>, <p>]
var ancestors = listAncestor(point.node, func.eq(root));

var isSkipPaddingBlankHTML = options && options.isSkipPaddingBlankHTML;
var isNotSplitEdgePoint = options && options.isNotSplitEdgePoint;

if (!ancestors.length) {
return null;
} else if (ancestors.length === 1) {
return splitNode(point, isSkipPaddingBlankHTML);
return splitNode(point, options);
}

return ancestors.reduce(function (node, parent) {
var clone = insertAfter(parent.cloneNode(false), parent);

if (node === point.node) {
node = splitNode(point, isSkipPaddingBlankHTML);
node = splitNode(point, options);
}

appendChildNodes(clone, listNext(node));

if (!isSkipPaddingBlankHTML) {
paddingBlankHTML(parent);
paddingBlankHTML(clone);
}
return clone;
return splitNode({
node: parent,
offset: node ? dom.position(node) : nodeLength(parent)
}, options);
});
};

Expand Down Expand Up @@ -837,7 +843,10 @@ define([
}

// if splitRoot is exists, split with splitTree
var pivot = splitRoot && splitTree(splitRoot, point, isInline);
var pivot = splitRoot && splitTree(splitRoot, point, {
isSkipPaddingBlankHTML: isInline,
isNotSplitEdgePoint: isInline
});

// if container is point.node, find pivot with point.offset
if (!pivot && container === point.node) {
Expand Down Expand Up @@ -987,6 +996,7 @@ define([
isPara: isPara,
isPurePara: isPurePara,
isInline: isInline,
isBlock: func.not(isInline),
isBodyInline: isBodyInline,
isBody: isBody,
isParaInline: isParaInline,
Expand Down
14 changes: 14 additions & 0 deletions src/js/core/range.js
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,20 @@ define([

return node;
};

/**
* insert html at current cursor
*/
this.pasteHTML = function (markup) {
var self = this;
var rng = this.wrapBodyInlineWithPara().deleteContents();
var contentsContainer = $('<div></div>').html(markup)[0];
var childNodes = list.from(contentsContainer.childNodes);

return $.map(childNodes.reverse(), function (childNode) {
return self.insertNode(childNode);
}).reverse();
};

/**
* returns text in range
Expand Down
8 changes: 6 additions & 2 deletions src/js/editing/Bullet.js
Original file line number Diff line number Diff line change
Expand Up @@ -187,12 +187,16 @@ define([
var lastList = headList.childNodes.length > 1 ? dom.splitTree(headList, {
node: last.parentNode,
offset: dom.position(last) + 1
}, true) : null;
}, {
isSkipPaddingBlankHTML: true
}) : null;

var middleList = dom.splitTree(headList, {
node: head.parentNode,
offset: dom.position(head)
}, true);
}, {
isSkipPaddingBlankHTML: true
});

paras = isEscapseToBody ? dom.listDescendant(middleList, dom.isLi) :
list.from(middleList.childNodes).filter(dom.isLi);
Expand Down
13 changes: 13 additions & 0 deletions src/js/module/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,19 @@ define([
afterCommand($editable);
};

/**
* paste HTML
* @param {Node} $editable
* @param {String} markup
*/
this.pasteHTML = function ($editable, markup) {
beforeCommand($editable);
var rng = this.createRange($editable);
var contents = rng.pasteHTML(markup);
range.createFromNode(list.last(contents)).collapse().select();
afterCommand($editable);
};

/**
* formatBlock
*
Expand Down
22 changes: 22 additions & 0 deletions test/unit/range.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,28 @@ define([
equalsToUpperCase($cont.html(), '<p><b>bo</b><u>u</u><b>ld</b></p>', 'rng.insertNode with inline should not split paragraph.');
});

test('rng.pasteHTML', function () {
var $cont, $p, $b, markup;

// $cont = $('<div class="note-editable"><p>text</p></div>');
// $p = $cont.find('p');
// markup = '<span>span</span><i>italic</i>';

// // split text with inline nodes
// range.create($p[0].firstChild, 2).pasteHTML(markup);
// equalsToUpperCase($cont.html(), '<p>te<span>span</span><i>italic</i>xt</p>', 'rng.pasteHTML with inlines should not split text.');

$cont = $('<div class="note-editable"><p><b>bold</b></p></div>');
$p = $cont.find('p');
$b = $cont.find('b');
markup = '<span>span</span><i>italic</i>';

// split inline node with inline nodes
range.create($b[0].firstChild, 2).pasteHTML(markup);
equalsToUpperCase($cont.html(), '<p><b>bo</b><span>span</span><i>italic</i><b>ld</b></p>', 'rng.pasteHTML with inlines should not split text.');

});

test('rng.deleteContents', function () {
var $cont, $p, $b, $u;

Expand Down

0 comments on commit faf8f2d

Please sign in to comment.