Файл: library/wysihtml5/src/commands/formatBlock.js
Строк: 381
<?php
(function(wysihtml5) {
var dom = wysihtml5.dom,
// Following elements are grouped
// when the caret is within a H1 and the H4 is invoked, the H1 should turn into H4
// instead of creating a H4 within a H1 which would result in semantically invalid html
BLOCK_ELEMENTS_GROUP = ["H1", "H2", "H3", "H4", "H5", "H6", "P", "BLOCKQUOTE", "DIV"];
/**
* Remove similiar classes (based on classRegExp)
* and add the desired class name
*/
function _addClass(element, className, classRegExp) {
if (element.className) {
_removeClass(element, classRegExp);
element.className += " " + className;
} else {
element.className = className;
}
}
function _removeClass(element, classRegExp) {
element.className = element.className.replace(classRegExp, "");
}
/**
* Check whether given node is a text node and whether it's empty
*/
function _isBlankTextNode(node) {
return node.nodeType === wysihtml5.TEXT_NODE && !wysihtml5.lang.string(node.data).trim();
}
/**
* Returns previous sibling node that is not a blank text node
*/
function _getPreviousSiblingThatIsNotBlank(node) {
var previousSibling = node.previousSibling;
while (previousSibling && _isBlankTextNode(previousSibling)) {
previousSibling = previousSibling.previousSibling;
}
return previousSibling;
}
/**
* Returns next sibling node that is not a blank text node
*/
function _getNextSiblingThatIsNotBlank(node) {
var nextSibling = node.nextSibling;
while (nextSibling && _isBlankTextNode(nextSibling)) {
nextSibling = nextSibling.nextSibling;
}
return nextSibling;
}
/**
* Adds line breaks before and after the given node if the previous and next siblings
* aren't already causing a visual line break (block element or <br>)
*/
function _addLineBreakBeforeAndAfter(node) {
var doc = node.ownerDocument,
nextSibling = _getNextSiblingThatIsNotBlank(node),
previousSibling = _getPreviousSiblingThatIsNotBlank(node);
if (nextSibling && !_isLineBreakOrBlockElement(nextSibling)) {
node.parentNode.insertBefore(doc.createElement("br"), nextSibling);
}
if (previousSibling && !_isLineBreakOrBlockElement(previousSibling)) {
node.parentNode.insertBefore(doc.createElement("br"), node);
}
}
/**
* Removes line breaks before and after the given node
*/
function _removeLineBreakBeforeAndAfter(node) {
var nextSibling = _getNextSiblingThatIsNotBlank(node),
previousSibling = _getPreviousSiblingThatIsNotBlank(node);
if (nextSibling && _isLineBreak(nextSibling)) {
nextSibling.parentNode.removeChild(nextSibling);
}
if (previousSibling && _isLineBreak(previousSibling)) {
previousSibling.parentNode.removeChild(previousSibling);
}
}
function _removeLastChildIfLineBreak(node) {
var lastChild = node.lastChild;
if (lastChild && _isLineBreak(lastChild)) {
lastChild.parentNode.removeChild(lastChild);
}
}
function _isLineBreak(node) {
return node.nodeName === "BR";
}
/**
* Checks whether the elment causes a visual line break
* (<br> or block elements)
*/
function _isLineBreakOrBlockElement(element) {
if (_isLineBreak(element)) {
return true;
}
if (dom.getStyle("display").from(element) === "block") {
return true;
}
return false;
}
/**
* Execute native query command
* and if necessary modify the inserted node's className
*/
function _execCommand(doc, command, nodeName, className) {
if (className) {
var eventListener = dom.observe(doc, "DOMNodeInserted", function(event) {
var target = event.target,
displayStyle;
if (target.nodeType !== wysihtml5.ELEMENT_NODE) {
return;
}
displayStyle = dom.getStyle("display").from(target);
if (displayStyle.substr(0, 6) !== "inline") {
// Make sure that only block elements receive the given class
target.className += " " + className;
}
});
}
doc.execCommand(command, false, nodeName);
if (eventListener) {
eventListener.stop();
}
}
function _selectLineAndWrap(composer, element) {
composer.selection.selectLine();
composer.selection.surround(element);
_removeLineBreakBeforeAndAfter(element);
_removeLastChildIfLineBreak(element);
composer.selection.selectNode(element, wysihtml5.browser.displaysCaretInEmptyContentEditableCorrectly());
}
function _hasClasses(element) {
return !!wysihtml5.lang.string(element.className).trim();
}
wysihtml5.commands.formatBlock = {
exec: function(composer, command, nodeName, className, classRegExp) {
var doc = composer.doc,
blockElement = this.state(composer, command, nodeName, className, classRegExp),
useLineBreaks = composer.config.useLineBreaks,
defaultNodeName = useLineBreaks ? "DIV" : "P",
selectedNode;
nodeName = typeof(nodeName) === "string" ? nodeName.toUpperCase() : nodeName;
if (blockElement) {
composer.selection.executeAndRestoreSimple(function() {
if (classRegExp) {
_removeClass(blockElement, classRegExp);
}
var hasClasses = _hasClasses(blockElement);
if (!hasClasses && (useLineBreaks || nodeName === "P")) {
// Insert a line break afterwards and beforewards when there are siblings
// that are not of type line break or block element
_addLineBreakBeforeAndAfter(blockElement);
dom.replaceWithChildNodes(blockElement);
} else {
// Make sure that styling is kept by renaming the element to a <div> or <p> and copying over the class name
dom.renameElement(blockElement, nodeName === "P" ? "DIV" : defaultNodeName);
}
});
return;
}
// Find similiar block element and rename it (<h2 class="foo"></h2> => <h1 class="foo"></h1>)
if (nodeName === null || wysihtml5.lang.array(BLOCK_ELEMENTS_GROUP).contains(nodeName)) {
selectedNode = composer.selection.getSelectedNode();
blockElement = dom.getParentElement(selectedNode, {
nodeName: BLOCK_ELEMENTS_GROUP
});
if (blockElement) {
composer.selection.executeAndRestore(function() {
// Rename current block element to new block element and add class
if (nodeName) {
blockElement = dom.renameElement(blockElement, nodeName);
}
if (className) {
_addClass(blockElement, className, classRegExp);
}
});
return;
}
}
if (composer.commands.support(command)) {
_execCommand(doc, command, nodeName || defaultNodeName, className);
return;
}
blockElement = doc.createElement(nodeName || defaultNodeName);
if (className) {
blockElement.className = className;
}
_selectLineAndWrap(composer, blockElement);
},
state: function(composer, command, nodeName, className, classRegExp) {
nodeName = typeof(nodeName) === "string" ? nodeName.toUpperCase() : nodeName;
var selectedNode = composer.selection.getSelectedNode();
return dom.getParentElement(selectedNode, {
nodeName: nodeName,
className: className,
classRegExp: classRegExp
});
}
};
})(wysihtml5);
?>