WIP: Note editing, markdown to html
[oweals/karmaworld.git] / karmaworld / apps / wysihtml5 / static / wysihtml5 / wysihtml-0.4.17 / src / dom / get_parent_element.js
1 /**
2  * Walks the dom tree from the given node up until it finds a match
3  * Designed for optimal performance.
4  *
5  * @param {Element} node The from which to check the parent nodes
6  * @param {Object} matchingSet Object to match against (possible properties: nodeName, className, classRegExp)
7  * @param {Number} [levels] How many parents should the function check up from the current node (defaults to 50)
8  * @return {null|Element} Returns the first element that matched the desiredNodeName(s)
9  * @example
10  *    var listElement = wysihtml5.dom.getParentElement(document.querySelector("li"), { nodeName: ["MENU", "UL", "OL"] });
11  *    // ... or ...
12  *    var unorderedListElement = wysihtml5.dom.getParentElement(document.querySelector("li"), { nodeName: "UL" });
13  *    // ... or ...
14  *    var coloredElement = wysihtml5.dom.getParentElement(myTextNode, { nodeName: "SPAN", className: "wysiwyg-color-red", classRegExp: /wysiwyg-color-[a-z]/g });
15  */
16 wysihtml5.dom.getParentElement = (function() {
17
18   function _isSameNodeName(nodeName, desiredNodeNames) {
19     if (!desiredNodeNames || !desiredNodeNames.length) {
20       return true;
21     }
22
23     if (typeof(desiredNodeNames) === "string") {
24       return nodeName === desiredNodeNames;
25     } else {
26       return wysihtml5.lang.array(desiredNodeNames).contains(nodeName);
27     }
28   }
29
30   function _isElement(node) {
31     return node.nodeType === wysihtml5.ELEMENT_NODE;
32   }
33
34   function _hasClassName(element, className, classRegExp) {
35     var classNames = (element.className || "").match(classRegExp) || [];
36     if (!className) {
37       return !!classNames.length;
38     }
39     return classNames[classNames.length - 1] === className;
40   }
41
42   function _hasStyle(element, cssStyle, styleRegExp) {
43     var styles = (element.getAttribute('style') || "").match(styleRegExp) || [];
44     if (!cssStyle) {
45       return !!styles.length;
46     }
47     return styles[styles.length - 1] === cssStyle;
48   }
49
50   return function(node, matchingSet, levels, container) {
51     var findByStyle = (matchingSet.cssStyle || matchingSet.styleRegExp),
52         findByClass = (matchingSet.className || matchingSet.classRegExp);
53
54     levels = levels || 50; // Go max 50 nodes upwards from current node
55
56     // make the matching class regex from class name if omitted
57     if (findByClass && !matchingSet.classRegExp) {
58       matchingSet.classRegExp = new RegExp(matchingSet.className);
59     }
60
61     while (levels-- && node && node.nodeName !== "BODY" && (!container || node !== container)) {
62       if (_isElement(node) && (!matchingSet.nodeName || _isSameNodeName(node.nodeName, matchingSet.nodeName)) &&
63           (!findByStyle || _hasStyle(node, matchingSet.cssStyle, matchingSet.styleRegExp)) &&
64           (!findByClass || _hasClassName(node, matchingSet.className, matchingSet.classRegExp))
65       ) {
66         return node;
67       }
68       node = node.parentNode;
69     }
70     return null;
71   };
72 })();