vendor/assets/javascripts/wysihtml5x.js in wysihtml5x-rails-0.4.5 vs vendor/assets/javascripts/wysihtml5x.js in wysihtml5x-rails-0.4.6
- 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.5
+ * @license wysihtml5x v0.4.6
* 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.5",
+ version: "0.4.6",
// namespaces
commands: {},
dom: {},
quirks: {},
@@ -5360,78 +5360,26 @@
return !!styles.length;
}
return styles[styles.length - 1] === cssStyle;
}
- function _getParentElementWithNodeName(node, nodeName, levels) {
- while (levels-- && node && node.nodeName !== "BODY") {
- if (_isSameNodeName(node.nodeName, nodeName)) {
- return node;
- }
- node = node.parentNode;
- }
- return null;
- }
+ return function(node, matchingSet, levels, container) {
+ var findByStyle = (matchingSet.cssStyle || matchingSet.styleRegExp),
+ findByClass = (matchingSet.className || matchingSet.classRegExp);
- function _getParentElementWithNodeNameAndClassName(node, nodeName, className, classRegExp, levels) {
- while (levels-- && node && node.nodeName !== "BODY") {
- if (_isElement(node) &&
- _isSameNodeName(node.nodeName, nodeName) &&
- _hasClassName(node, className, classRegExp)) {
- return node;
- }
- node = node.parentNode;
- }
- return null;
- }
+ levels = levels || 50; // Go max 50 nodes upwards from current node
- function _getParentElementWithNodeNameAndStyle(node, nodeName, cssStyle, styleRegExp, levels) {
- while (levels-- && node && node.nodeName !== "BODY") {
- if (_isElement(node) &&
- _isSameNodeName(node.nodeName, nodeName) &&
- _hasStyle(node, cssStyle, styleRegExp)
+ while (levels-- && node && node.nodeName !== "BODY" && (!container || node !== container)) {
+ if (_isElement(node) && _isSameNodeName(node.nodeName, matchingSet.nodeName) &&
+ (!findByStyle || _hasStyle(node, matchingSet.cssStyle, matchingSet.styleRegExp)) &&
+ (!findByClass || _hasClassName(node, matchingSet.className, matchingSet.classRegExp))
) {
return node;
}
node = node.parentNode;
}
return null;
- }
-
- function _getParentElementWithNodeNameAndClassNameAndStyle(node, nodeName, className, classRegExp, cssStyle, styleRegExp, levels) {
- while (levels-- && node && node.nodeName !== "BODY") {
- if (_isElement(node) &&
- _isSameNodeName(node.nodeName, nodeName) &&
- _hasStyle(node, cssStyle, styleRegExp) &&
- _hasClassName(node, className, classRegExp)
- ) {
- return node;
- }
- node = node.parentNode;
- }
- return null;
- }
-
- return function(node, matchingSet, levels) {
- levels = levels || 50; // Go max 50 nodes upwards from current node
- if ((matchingSet.className || matchingSet.classRegExp) && (matchingSet.cssStyle || matchingSet.styleRegExp)) {
- return _getParentElementWithNodeNameAndClassNameAndStyle(
- node, matchingSet.nodeName, matchingSet.className, matchingSet.classRegExp, matchingSet.cssStyle, matchingSet.styleRegExp, levels
- );
- } else if (matchingSet.className || matchingSet.classRegExp) {
- return _getParentElementWithNodeNameAndClassName(
- node, matchingSet.nodeName, matchingSet.className, matchingSet.classRegExp, levels
- );
- } else if (matchingSet.cssStyle || matchingSet.styleRegExp) {
- return _getParentElementWithNodeNameAndStyle(
- node, matchingSet.nodeName, matchingSet.cssStyle, matchingSet.styleRegExp, levels
- );
- } else {
- return _getParentElementWithNodeName(
- node, matchingSet.nodeName, levels
- );
- }
};
})();
;wysihtml5.dom.getNextElement = function(node){
var nextSibling = node.nextSibling;
while(nextSibling && nextSibling.nodeType != 1) {
@@ -5883,11 +5831,10 @@
newNode,
tagRules = currentRules.tags,
nodeName = oldNode.nodeName.toLowerCase(),
scopeName = oldNode.scopeName;
-
/**
* We already parsed that element
* ignore it! (yes, this sometimes happens in IE8 when the html is invalid)
*/
if (oldNode._wysihtml5) {
@@ -5938,11 +5885,11 @@
newNode = oldNode.ownerDocument.createElement(rule.rename_tag || nodeName);
_handleAttributes(oldNode, newNode, rule);
_handleStyles(oldNode, newNode, rule);
// tests if type condition is met or node should be removed/unwrapped
- if (rule.one_of_type && !_testTypes(newNode, currentRules, rule.one_of_type)) {
+ if (rule.one_of_type && !_testTypes(oldNode, currentRules, rule.one_of_type)) {
return (rule.remove_action && rule.remove_action == "unwrap") ? false : null;
}
oldNode = null;
@@ -5983,10 +5930,22 @@
var nodeClasses = oldNode.getAttribute("class"),
nodeStyles = oldNode.getAttribute("style"),
classesLength, s, s_corrected, a, attr, currentClass, styleProp;
+ // test for methods
+ if (definition.methods) {
+ for (var m in definition.methods) {
+ if (definition.methods.hasOwnProperty(m) && typeCeckMethods[m]) {
+
+ if (typeCeckMethods[m](oldNode)) {
+ return true;
+ }
+ }
+ }
+ }
+
// test for classes, if one found return true
if (nodeClasses && definition.classes) {
nodeClasses = nodeClasses.replace(/^\s+/g, '').replace(/\s+$/g, '').split(WHITE_SPACE_REG_EXP);
classesLength = nodeClasses.length;
for (var i = 0; i < classesLength; i++) {
@@ -6362,10 +6321,44 @@
return mapping[String(attributeValue).charAt(0)];
};
})()
};
+ // checks if element is possibly visible
+ var typeCeckMethods = {
+ has_visible_contet: (function() {
+ var txt,
+ isVisible = false,
+ visibleElements = ['img', 'video', 'picture', 'br', 'script', 'noscript',
+ 'style', 'table', 'iframe', 'object', 'embed', 'audio',
+ 'svg', 'input', 'button', 'select','textarea', 'canvas'];
+
+ return function(el) {
+
+ // has visible innertext. so is visible
+ txt = (el.innerText || el.textContent).replace(/\s/g, '');
+ if (txt && txt.length > 0) {
+ return true;
+ }
+
+ // matches list of visible dimensioned elements
+ for (var i = visibleElements.length; i--;) {
+ if (el.querySelector(visibleElements[i])) {
+ return true;
+ }
+ }
+
+ // try to measure dimesions in last resort. (can find only of elements in dom)
+ if (el.offsetWidth && el.offsetWidth > 0 && el.offsetHeight && el.offsetHeight > 0) {
+ return true;
+ }
+
+ return false;
+ };
+ })()
+ };
+
return parse;
})();
;/**
* Checks for empty text node childs and removes them
*
@@ -8553,10 +8546,23 @@
}
return (ret !== this.contain) ? ret : false;
},
+ getSelectionParentsByTag: function(tagName) {
+ var nodes = this.getSelectedOwnNodes(),
+ curEl, parents = [];
+
+ for (var i = 0, maxi = nodes.length; i < maxi; i++) {
+ curEl = (nodes[i].nodeName && nodes[i].nodeName === 'LI') ? nodes[i] : wysihtml5.dom.getParentElement(nodes[i], { nodeName: ['LI']}, false, this.contain);
+ if (curEl) {
+ parents.push(curEl);
+ }
+ }
+ return (parents.length) ? parents : null;
+ },
+
getRangeToNodeEnd: function() {
if (this.isCollapsed()) {
var range = this.getRange(),
sNode = range.startContainer,
pos = range.startOffset,
@@ -9604,10 +9610,11 @@
isAppliedToRange: function(range) {
var ancestors = [],
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);
@@ -9619,14 +9626,15 @@
selectedText = this.getTextSelectedByRange(textNodes[i], range[ri]);
ancestor = this.getAncestorWithClass(textNodes[i]);
if (!ancestor) {
ancestor = this.getAncestorWithStyle(textNodes[i]);
}
- if (!(selectedText != "" && !ancestor)) {
+ if (ancestor && selectedText != "") {
ancestors.push(ancestor);
}
}
+
}
return (ancestors.length) ? ancestors : false;
},
@@ -10459,17 +10467,23 @@
var alias = ALIAS_MAPPING[tagName];
return alias ? [tagName.toLowerCase(), alias.toLowerCase()] : [tagName.toLowerCase()];
}
function _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, container) {
- var identifier = tagName + ":" + className;
+ var identifier = tagName;
+
+ if (className) {
+ identifier += ":" + className;
+ }
if (cssStyle) {
identifier += ":" + cssStyle;
}
+
if (!htmlApplier[identifier]) {
htmlApplier[identifier] = new wysihtml5.selection.HTMLApplier(_getTagNames(tagName), className, classRegExp, true, cssStyle, styleRegExp, container);
}
+
return htmlApplier[identifier];
}
wysihtml5.commands.formatInline = {
exec: function(composer, command, tagName, className, classRegExp, cssStyle, styleRegExp, dontRestoreSelect, noCleanup) {
@@ -10544,11 +10558,11 @@
return false;
}
ownRanges = composer.selection.getOwnRanges();
- if (ownRanges.length == 0) {
+ if (!ownRanges || ownRanges.length === 0) {
return false;
}
return _getApplier(tagName, className, classRegExp, cssStyle, styleRegExp, composer.element).isAppliedToRange(ownRanges);
}
@@ -11080,11 +11094,129 @@
state: function(composer, command) {
return false;
}
};
-;/**
+;wysihtml5.commands.indentList = {
+ exec: function(composer, command, value) {
+ var listEls = composer.selection.getSelectionParentsByTag('LI');
+ if (listEls) {
+ return this.tryToPushLiLevel(listEls, composer.selection);
+ }
+ return false;
+ },
+
+ state: function(composer, command) {
+ return false;
+ },
+
+ tryToPushLiLevel: function(liNodes, selection) {
+ var listTag, list, prevLi, liNode, prevLiList,
+ found = false;
+
+ selection.executeAndRestoreRangy(function() {
+
+ for (var i = liNodes.length; i--;) {
+ liNode = liNodes[i];
+ listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
+ list = liNode.ownerDocument.createElement(listTag);
+ prevLi = wysihtml5.dom.getPreviousElement(liNode);
+ prevLiList = (prevLi) ? prevLi.querySelector('ul, ol') : null;
+
+ if (prevLi) {
+ if (prevLiList) {
+ prevLiList.appendChild(liNode);
+ } else {
+ list.appendChild(liNode);
+ prevLi.appendChild(list);
+ }
+ found = true;
+ }
+ }
+
+ });
+ return found;
+ }
+};
+;wysihtml5.commands.outdentList = {
+ exec: function(composer, command, value) {
+ var listEls = composer.selection.getSelectionParentsByTag('LI');
+ if (listEls) {
+ return this.tryToPullLiLevel(listEls, composer);
+ }
+ return false;
+ },
+
+ state: function(composer, command) {
+ return false;
+ },
+
+ tryToPullLiLevel: function(liNodes, composer) {
+ var listNode, outerListNode, outerLiNode, list, prevLi, liNode, afterList,
+ found = false,
+ that = this;
+
+ composer.selection.executeAndRestoreRangy(function() {
+
+ for (var i = liNodes.length; i--;) {
+ liNode = liNodes[i];
+ if (liNode.parentNode) {
+ listNode = liNode.parentNode;
+
+ if (listNode.tagName === 'OL' || listNode.tagName === 'UL') {
+ found = true;
+
+ outerListNode = wysihtml5.dom.getParentElement(listNode.parentNode, { nodeName: ['OL', 'UL']}, false, composer.element);
+ outerLiNode = wysihtml5.dom.getParentElement(listNode.parentNode, { nodeName: ['LI']}, false, composer.element);
+
+ if (outerListNode && outerLiNode) {
+
+ if (liNode.nextSibling) {
+ afterList = that.getAfterList(listNode, liNode);
+ liNode.appendChild(afterList);
+ }
+ outerListNode.insertBefore(liNode, outerLiNode.nextSibling);
+
+ } else {
+
+ if (liNode.nextSibling) {
+ afterList = that.getAfterList(listNode, liNode);
+ liNode.appendChild(afterList);
+ }
+
+ for (var j = liNode.childNodes.length; j--;) {
+ listNode.parentNode.insertBefore(liNode.childNodes[j], listNode.nextSibling);
+ }
+
+ listNode.parentNode.insertBefore(document.createElement('br'), listNode.nextSibling);
+ liNode.parentNode.removeChild(liNode);
+
+ }
+
+ // cleanup
+ if (listNode.childNodes.length === 0) {
+ listNode.parentNode.removeChild(listNode);
+ }
+ }
+ }
+ }
+
+ });
+ return found;
+ },
+
+ getAfterList: function(listNode, liNode) {
+ var nodeName = listNode.nodeName,
+ newList = document.createElement(nodeName);
+
+ while (liNode.nextSibling) {
+ newList.appendChild(liNode.nextSibling);
+ }
+ return newList;
+ }
+
+};;/**
* Undo Manager for wysihtml5
* slightly inspired by http://rniwa.com/editing/undomanager.html#the-undomanager-interface
*/
(function(wysihtml5) {
var Z_KEY = 90,
@@ -12057,14 +12189,17 @@
selection.setBefore(curNode);
}
}
};
- var handleDeleteKeyPress = function(event, selection, element) {
+ var handleDeleteKeyPress = function(event, selection, element, composer) {
if (selection.isCollapsed()) {
- if (selection.caretIsInTheBeginnig()) {
+ if (selection.caretIsInTheBeginnig('LI')) {
event.preventDefault();
+ composer.commands.exec('outdentList');
+ } else if (selection.caretIsInTheBeginnig()) {
+ event.preventDefault();
} else {
var beforeUneditable = selection.caretIsBeforeUneditable();
// Do a special delete if caret would delete uneditable
if (beforeUneditable) {
@@ -12076,42 +12211,15 @@
event.preventDefault();
selection.deleteContents();
}
};
- var tryToPushLiLevel = function(selection) {
- var prevLi;
- selection.executeAndRestoreRangy(function() {
- var selNode = selection.getSelectedNode(),
- liNode = (selNode.nodeName && selNode.nodeName === 'LI') ? selNode : selNode.parentNode,
- listTag, list;
-
- if (liNode.getAttribute('class') === "rangySelectionBoundary") {
- liNode = liNode.parentNode;
- }
-
- if (liNode.nodeName === 'LI') {
- listTag = (liNode.parentNode.nodeName === 'OL') ? 'OL' : 'UL';
- list = selNode.ownerDocument.createElement(listTag);
- prevLi = wysihtml5.dom.getPreviousElement(liNode);
-
- if (prevLi) {
- list.appendChild(liNode);
- prevLi.appendChild(list);
- }
- }
-
- });
- return (prevLi) ? true : false;
- };
-
-
var handleTabKeyDown = function(composer, element) {
if (!composer.selection.isCollapsed()) {
composer.selection.deleteContents();
} else if (composer.selection.caretIsInTheBeginnig('LI')) {
- if (tryToPushLiLevel(composer.selection)) return;
+ if (composer.commands.exec('indentList')) return;
}
// Is   close enough to tab. Could not find enough counter arguments for now.
composer.commands.exec("insertHTML", " ");
};
@@ -12258,12 +12366,12 @@
that.commands.exec(command);
event.preventDefault();
}
if (keyCode === 8) {
// delete key
- handleDeleteKeyPress(event, that.selection, element);
- } else if (keyCode === 9) {
+ handleDeleteKeyPress(event, that.selection, element, that);
+ } else if (that.config.handleTabKey && keyCode === 9) {
event.preventDefault();
handleTabKeyDown(that, element);
}
});
@@ -12538,10 +12646,12 @@
showToolbarAfterInit: true,
// Whether urls, entered by the user should automatically become clickable-links
autoLink: true,
// Includes table editing events and cell selection tracking
handleTables: true,
+ // Tab key inserts tab into text as default behaviour. It can be disabled to regain keyboard navigation
+ handleTabKey: true,
// Object which includes parser rules to apply when html gets inserted via copy & paste
// See parser_rules/*.js for examples
parserRules: { tags: { br: {}, span: {}, div: {}, p: {} }, classes: {} },
// Parser method to use when the user inserts content via copy & paste
parser: wysihtml5.dom.parse,
@@ -12559,11 +12669,10 @@
supportTouchDevices: true,
// Whether senseless <span> elements (empty or without attributes) should be removed/replaced with their content
cleanUp: true,
// Whether to use div instead of secure iframe
contentEditableMode: false,
- xingAlert: false,
// Classname of container that editor should not touch and pass through
// Pass false to disable
uneditableContainerClassname: "wysihtml5-uneditable-container"
};
@@ -12599,14 +12708,9 @@
if (typeof(this.config.parser) === "function") {
this._initParser();
}
this.on("beforeload", this.handleBeforeLoad);
-
-
- if (this.config.xingAlert) {
- try { console.log("Heya! This page is using wysihtml5 for rich text editing. Check out https://github.com/xing/wysihtml5");} catch(e) {}
- }
},
handleBeforeLoad: function() {
if (!this.config.noTextarea) {
this.synchronizer = new wysihtml5.views.Synchronizer(this, this.textarea, this.composer);