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()) {