vendor/assets/javascripts/wysihtml5x.js in wysihtml5x-rails-0.4.9 vs vendor/assets/javascripts/wysihtml5x.js in wysihtml5x-rails-0.4.10
- old
+ new
@@ -23,22 +23,22 @@
if(!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
};/**
- * @license wysihtml5x v0.4.9
+ * @license wysihtml5x v0.4.10
* https://github.com/Edicy/wysihtml5
*
* Author: Christopher Blum (https://github.com/tiff)
* Secondary author of extended features: Oliver Pulges (https://github.com/pulges)
*
* Copyright (C) 2012 XING AG
* Licensed under the MIT license (MIT)
*
*/
var wysihtml5 = {
- version: "0.4.9",
+ version: "0.4.10",
// namespaces
commands: {},
dom: {},
quirks: {},
@@ -5503,17 +5503,19 @@
}
}
};
};
})();
-;wysihtml5.dom.getTextNodes = function(node){
+;wysihtml5.dom.getTextNodes = function(node, ingoreEmpty){
var all = [];
for (node=node.firstChild;node;node=node.nextSibling){
- if (node.nodeType==3) {
+ if (node.nodeType == 3) {
+ if (!ingoreEmpty || !(/^\s*$/).test(node.innerText || node.textContent)) {
all.push(node);
+ }
} else {
- all = all.concat(wysihtml5.dom.getTextNodes(node));
+ all = all.concat(wysihtml5.dom.getTextNodes(node, ingoreEmpty));
}
}
return all;
};;/**
* High performant way to check whether an element with a specific tag name is in the given document
@@ -8606,10 +8608,16 @@
range = this.getRange(this.doc);
return range ? range.commonAncestorContainer : this.doc.body;
}
},
+ fixSelBorders: function() {
+ var range = this.getRange();
+ expandRangeToSurround(range);
+ this.setSelection(range);
+ },
+
getSelectedOwnNodes: function(controlRange) {
var selection,
ranges = this.getOwnRanges(),
ownNodes = [];
@@ -8724,16 +8732,21 @@
return (/^\s*$/).test(endtxt);
},
caretIsFirstInSelection: function() {
var r = rangy.createRange(this.doc),
- s = this.getSelection();
-
- r.selectNodeContents(this.getRange().commonAncestorContainer);
- r.collapse(true);
-
- return (this.isCollapsed() && (r.startContainer === s.anchorNode || r.endContainer === s.anchorNode) && r.startOffset === s.anchorOffset);
+ s = this.getSelection(),
+ range = this.getRange(),
+ startNode = range.startContainer;
+
+ if (startNode.nodeType === wysihtml5.TEXT_NODE) {
+ return this.isCollapsed() && (startNode.nodeType === wysihtml5.TEXT_NODE && (/^\s*$/).test(startNode.data.substr(0,range.startOffset)));
+ } else {
+ r.selectNodeContents(this.getRange().commonAncestorContainer);
+ r.collapse(true);
+ return (this.isCollapsed() && (r.startContainer === s.anchorNode || r.endContainer === s.anchorNode) && r.startOffset === s.anchorOffset);
+ }
},
caretIsInTheBeginnig: function(ofNode) {
var selection = this.getSelection(),
node = selection.anchorNode,
@@ -9104,12 +9117,12 @@
}
}
},
_endOffsetForNode: function(node) {
- var range = document.createRange()
- range.selectNodeContents(node)
+ var range = document.createRange();
+ range.selectNodeContents(node);
return range.endOffset;
},
_detectInlineRangeProblems: function(range) {
position = dom.compareDocumentPosition(range.startContainer, range.endContainer);
@@ -9347,10 +9360,29 @@
}
return false;
}
+ function isMatchingAllready(node, tags, style, className) {
+ if (style) {
+ return getMatchingStyleRegexp(node, style);
+ } else if (className) {
+ return wysihtml5.dom.hasClass(node, className);
+ } else {
+ return rangy.dom.arrayContains(tags, node.tagName.toLowerCase());
+ }
+ }
+
+ function areMatchingAllready(nodes, tags, style, className) {
+ for (var i = nodes.length; i--;) {
+ if (!isMatchingAllready(nodes[i], tags, style, className)) {
+ return false;
+ }
+ }
+ return nodes.length ? true : false;
+ }
+
function removeOrChangeStyle(el, style, regExp) {
var exactRegex = getMatchingStyleRegexp(el, style);
if (exactRegex) {
// adding same style value on property again removes style
@@ -9370,13 +9402,10 @@
function replaceWithOwnChildren(el) {
var parent = el.parentNode;
while (el.firstChild) {
parent.insertBefore(el.firstChild, el);
}
- if (parent.normalize) {
- parent.normalize();
- }
parent.removeChild(el);
}
function elementsHaveSameNonClassAttributes(el1, el2) {
if (el1.attributes.length != el2.attributes.length) {
@@ -9520,10 +9549,31 @@
node = node.parentNode;
}
return false;
},
+ getMatchingAncestor: function(node) {
+ var ancestor = this.getAncestorWithClass(node),
+ matchType = false;
+
+ if (!ancestor) {
+ ancestor = this.getAncestorWithStyle(node);
+ if (ancestor) {
+ matchType = "style";
+ }
+ } else {
+ if (this.cssStyle) {
+ matchType = "class";
+ }
+ }
+
+ return {
+ "element": ancestor,
+ "type": matchType
+ };
+ },
+
// Normalizes nodes after applying a CSS class to a Range.
postApply: function(textNodes, range) {
var firstNode = textNodes[0], lastNode = textNodes[textNodes.length - 1];
var merges = [], currentMerge;
@@ -9693,16 +9743,13 @@
if (textNodes.length) {
var textNode;
for (var i = 0, len = textNodes.length; i < len; ++i) {
textNode = textNodes[i];
- if (!this.getAncestorWithClass(textNode)) {
+ if (!this.getMatchingAncestor(textNode).element) {
this.applyToTextNode(textNode);
}
- if (!this.getAncestorWithStyle(textNode)) {
- this.applyToTextNode(textNode);
- }
}
range[ri].setStart(textNodes[0], 0);
textNode = textNodes[textNodes.length - 1];
range[ri].setEnd(textNode, textNode.length);
@@ -9715,12 +9762,12 @@
}
},
undoToRange: function(range) {
var textNodes, textNode, ancestorWithClass, ancestorWithStyle;
-
for (var ri = range.length; ri--;) {
+
textNodes = range[ri].getNodes([wysihtml5.TEXT_NODE]);
if (textNodes.length) {
range[ri].splitBoundaries();
textNodes = range[ri].getNodes([wysihtml5.TEXT_NODE]);
} else {
@@ -9729,20 +9776,19 @@
range[ri].insertNode(node);
range[ri].selectNode(node);
textNodes = [node];
}
-
for (var i = 0, len = textNodes.length; i < len; ++i) {
if (range[ri].isValid()) {
textNode = textNodes[i];
- ancestorWithClass = this.getAncestorWithClass(textNode);
- ancestorWithStyle = this.getAncestorWithStyle(textNode);
- if (ancestorWithClass) {
- this.undoToTextNode(textNode, range[ri], ancestorWithClass);
- } else if (ancestorWithStyle) {
- this.undoToTextNode(textNode, range[ri], false, ancestorWithStyle);
+
+ ancestor = this.getMatchingAncestor(textNode);
+ if (ancestor.type === "style") {
+ this.undoToTextNode(textNode, range[ri], false, ancestor.element);
+ } else if (ancestor.element) {
+ this.undoToTextNode(textNode, range[ri], ancestor.element);
}
}
}
if (len == 1) {
@@ -9790,42 +9836,69 @@
return text;
},
isAppliedToRange: function(range) {
var ancestors = [],
+ appliedType = "full",
ancestor, styleAncestor, textNodes;
for (var ri = range.length; ri--;) {
textNodes = range[ri].getNodes([wysihtml5.TEXT_NODE]);
if (!textNodes.length) {
- ancestor = this.getAncestorWithClass(range[ri].startContainer);
- if (!ancestor) {
- ancestor = this.getAncestorWithStyle(range[ri].startContainer);
- }
- return ancestor ? [ancestor] : false;
+ ancestor = this.getMatchingAncestor(range[ri].startContainer).element;
+
+ return (ancestor) ? {
+ "elements": [ancestor],
+ "coverage": appliedType
+ } : false;
}
for (var i = 0, len = textNodes.length, selectedText; i < len; ++i) {
selectedText = this.getTextSelectedByRange(textNodes[i], range[ri]);
- ancestor = this.getAncestorWithClass(textNodes[i]);
- if (!ancestor) {
- ancestor = this.getAncestorWithStyle(textNodes[i]);
- }
+ ancestor = this.getMatchingAncestor(textNodes[i]).element;
if (ancestor && selectedText != "") {
ancestors.push(ancestor);
+
+ if (wysihtml5.dom.getTextNodes(ancestor, true).length === 1) {
+ appliedType = "full";
+ } else if (appliedType === "full") {
+ appliedType = "inline";
+ }
+ } else if (!ancestor) {
+ appliedType = "partial";
}
}
}
- return (ancestors.length) ? ancestors : false;
+ return (ancestors.length) ? {
+ "elements": ancestors,
+ "coverage": appliedType
+ } : false;
},
toggleRange: function(range) {
- if (this.isAppliedToRange(range)) {
- this.undoToRange(range);
+ var isApplied = this.isAppliedToRange(range),
+ parentsExactMatch;
+
+ if (isApplied) {
+ if (isApplied.coverage === "full") {
+ this.undoToRange(range);
+ } else if (isApplied.coverage === "inline") {
+ parentsExactMatch = areMatchingAllready(isApplied.elements, this.tagNames, this.cssStyle, this.cssClass);
+ this.undoToRange(range);
+ if (!parentsExactMatch) {
+ this.applyToRange(range);
+ }
+ } else {
+ // partial
+ if (!areMatchingAllready(isApplied.elements, this.tagNames, this.cssStyle, this.cssClass)) {
+ this.undoToRange(range);
+ }
+ this.applyToRange(range);
+ }
} else {
this.applyToRange(range);
}
}
};
@@ -10649,11 +10722,11 @@
},
state: function(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp) {
var doc = composer.doc,
aliasTagName = ALIAS_MAPPING[tagName] || tagName,
- ownRanges;
+ ownRanges, isApplied;
// Check whether the document contains a node with the desired tagName
if (!wysihtml5.dom.hasElementWithTagName(doc, tagName) &&
!wysihtml5.dom.hasElementWithTagName(doc, aliasTagName)) {
return false;
@@ -10668,11 +10741,13 @@
if (!ownRanges || ownRanges.length === 0) {
return false;
}
- return _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, composer.element).isAppliedToRange(ownRanges);
+ isApplied = _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, composer.element).isAppliedToRange(ownRanges);
+
+ return (isApplied && isApplied.elements) ? isApplied.elements : false;
}
};
})(wysihtml5);
;(function(wysihtml5) {
@@ -12377,20 +12452,40 @@
event.preventDefault();
composer.commands.exec('outdentList');
} else if (selection.caretIsInTheBeginnig()) {
event.preventDefault();
} else {
- var beforeUneditable = selection.caretIsBeforeUneditable();
+ if (selection.caretIsFirstInSelection() &&
+ selection.getPreviousNode() &&
+ selection.getPreviousNode().nodeName &&
+ (/^H\d$/gi).test(selection.getPreviousNode().nodeName)
+ ) {
+ var prevNode = selection.getPreviousNode();
+ event.preventDefault();
+ if ((/^\s*$/).test(prevNode.textContent || prevNode.innerText)) {
+ // heading is empty
+ prevNode.parentNode.removeChild(prevNode);
+ } else {
+ var range = prevNode.ownerDocument.createRange();
+ range.selectNodeContents(prevNode);
+ range.collapse(false);
+ selection.setSelection(range);
+ }
+ }
+
+ var beforeUneditable = selection.caretIsBeforeUneditable();
// Do a special delete if caret would delete uneditable
if (beforeUneditable) {
event.preventDefault();
deleteAroundEditable(selection, beforeUneditable, element);
}
}
- } else if (selection.containsUneditable()) {
- event.preventDefault();
- selection.deleteContents();
+ } else {
+ if (selection.containsUneditable()) {
+ event.preventDefault();
+ selection.deleteContents();
+ }
}
};
var handleTabKeyDown = function(composer, element) {
if (!composer.selection.isCollapsed()) {