/**
* ForceBlocks.js
*
* Released under LGPL License.
* Copyright (c) 1999-2017 Ephox Corp. All rights reserved
*
* License: http://www.tinymce.com/license
* Contributing: http://www.tinymce.com/contributing
*/
/**
* Makes sure that everything gets wrapped in paragraphs.
*
* @private
* @class tinymce.ForceBlocks
*/
define(
'tinymce.core.ForceBlocks',
[
'ephox.katamari.api.Arr',
'ephox.katamari.api.Fun',
'ephox.sugar.api.node.Element',
'tinymce.core.dom.Bookmarks',
'tinymce.core.dom.NodeType',
'tinymce.core.dom.Parents',
'tinymce.core.focus.EditorFocus'
],
function (Arr, Fun, Element, Bookmarks, NodeType, Parents, EditorFocus) {
var isBlockElement = function (blockElements, node) {
return blockElements.hasOwnProperty(node.nodeName);
};
var isValidTarget = function (blockElements, node) {
if (NodeType.isText(node)) {
return true;
} else if (NodeType.isElement(node)) {
return !isBlockElement(blockElements, node) && !Bookmarks.isBookmarkNode(node);
} else {
return false;
}
};
var hasBlockParent = function (blockElements, root, node) {
return Arr.exists(Parents.parents(Element.fromDom(node), Element.fromDom(root)), function (elm) {
return isBlockElement(blockElements, elm.dom());
});
};
var addRootBlocks = function (editor) {
var settings = editor.settings, dom = editor.dom, selection = editor.selection;
var schema = editor.schema, blockElements = schema.getBlockElements();
var node = selection.getStart(), rootNode = editor.getBody(), rng;
var startContainer, startOffset, endContainer, endOffset, rootBlockNode;
var tempNode, wrapped, restoreSelection;
var rootNodeName, forcedRootBlock;
forcedRootBlock = settings.forced_root_block;
if (!node || !NodeType.isElement(node) || !forcedRootBlock) {
return;
}
rootNodeName = rootNode.nodeName.toLowerCase();
if (!schema.isValidChild(rootNodeName, forcedRootBlock.toLowerCase()) || hasBlockParent(blockElements, rootNode, node)) {
return;
}
// Get current selection
rng = selection.getRng();
startContainer = rng.startContainer;
startOffset = rng.startOffset;
endContainer = rng.endContainer;
endOffset = rng.endOffset;
restoreSelection = EditorFocus.hasFocus(editor);
// Wrap non block elements and text nodes
node = rootNode.firstChild;
while (node) {
if (isValidTarget(blockElements, node)) {
// Remove empty text nodes
if (NodeType.isText(node) && node.nodeValue.length === 0) {
tempNode = node;
node = node.nextSibling;
dom.remove(tempNode);
continue;
}
if (!rootBlockNode) {
rootBlockNode = dom.create(forcedRootBlock, editor.settings.forced_root_block_attrs);
node.parentNode.insertBefore(rootBlockNode, node);
wrapped = true;
}
tempNode = node;
node = node.nextSibling;
rootBlockNode.appendChild(tempNode);
} else {
rootBlockNode = null;
node = node.nextSibling;
}
}
if (wrapped && restoreSelection) {
rng.setStart(startContainer, startOffset);
rng.setEnd(endContainer, endOffset);
selection.setRng(rng);
editor.nodeChanged();
}
};
var setup = function (editor) {
if (editor.settings.forced_root_block) {
editor.on('NodeChange', Fun.curry(addRootBlocks, editor));
}
};
return {
setup: setup
};
}
);
|