Convert `Dom/Traverse` to TypeScript
authorAlexander Ebert <ebert@woltlab.com>
Fri, 16 Oct 2020 13:59:05 +0000 (15:59 +0200)
committerTim Düsterhus <duesterhus@woltlab.com>
Wed, 28 Oct 2020 11:26:30 +0000 (12:26 +0100)
wcfsetup/install/files/js/WoltLabSuite/Core/Dom/Traverse.js
wcfsetup/install/files/ts/WoltLabSuite/Core/Dom/Traverse.ts [new file with mode: 0644]

index 0635b60ca0708b0758107b0559260125a1773853..1da77f0476b3b6fa0e10879ec77c6aeae8f462de 100644 (file)
 /**
  * Provides helper functions to traverse the DOM.
- * 
- * @author     Alexander Ebert
- * @copyright  2001-2019 WoltLab GmbH
- * @license    GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
- * @module     Dom/Traverse (alias)
- * @module     WoltLabSuite/Core/Dom/Traverse
+ *
+ * @author  Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  Dom/Traverse (alias)
+ * @module  WoltLabSuite/Core/Dom/Traverse
  */
-define([], function() {
-       "use strict";
-       
-       /** @const */ var NONE = 0;
-       /** @const */ var SELECTOR = 1;
-       /** @const */ var CLASS_NAME = 2;
-       /** @const */ var TAG_NAME = 3;
-       
-       var _probe = [
-               function(el, none) { return true; },
-               function(el, selector) { return el.matches(selector); },
-               function(el, className) { return el.classList.contains(className); },
-               function(el, tagName) { return el.nodeName === tagName; }
-       ];
-       
-       var _children = function(el, type, value) {
-               if (!(el instanceof Element)) {
-                       throw new TypeError("Expected a valid element as first argument.");
-               }
-               
-               var children = [];
-               
-               for (var i = 0; i < el.childElementCount; i++) {
-                       if (_probe[type](el.children[i], value)) {
-                               children.push(el.children[i]);
-                       }
-               }
-               
-               return children;
-       };
-       
-       var _parent = function(el, type, value, untilElement) {
-               if (!(el instanceof Element)) {
-                       throw new TypeError("Expected a valid element as first argument.");
-               }
-               
-               el = el.parentNode;
-               
-               while (el instanceof Element) {
-                       if (el === untilElement) {
-                               return null;
-                       }
-                       
-                       if (_probe[type](el, value)) {
-                               return el;
-                       }
-                       
-                       el = el.parentNode;
-               }
-               
-               return null;
-       };
-       
-       var _sibling = function(el, siblingType, type, value) {
-               if (!(el instanceof Element)) {
-                       throw new TypeError("Expected a valid element as first argument.");
-               }
-               
-               if (el instanceof Element) {
-                       if (el[siblingType] !== null && _probe[type](el[siblingType], value)) {
-                               return el[siblingType];
-                       }
-               }
-               
-               return null;
-       };
-       
-       /**
-        * @exports     WoltLabSuite/Core/Dom/Traverse
-        */
-       return {
-               /**
-                * Examines child elements and returns the first child matching the given selector.
-                * 
-                * @param       {Element}               el              element
-                * @param       {string}                selector        CSS selector to match child elements against
-                * @return      {(Element|null)}        null if there is no child node matching the selector
-                */
-               childBySel: function(el, selector) {
-                       return _children(el, SELECTOR, selector)[0] || null;
-               },
-               
-               /**
-                * Examines child elements and returns the first child that has the given CSS class set.
-                * 
-                * @param       {Element}               el              element
-                * @param       {string}                className       CSS class name
-                * @return      {(Element|null)}        null if there is no child node with given CSS class
-                */
-               childByClass: function(el, className) {
-                       return _children(el, CLASS_NAME, className)[0] || null;
-               },
-               
-               /**
-                * Examines child elements and returns the first child which equals the given tag.
-                * 
-                * @param       {Element}               el              element
-                * @param       {string}                tagName         element tag name
-                * @return      {(Element|null)}        null if there is no child node which equals given tag
-                */
-               childByTag: function(el, tagName) {
-                       return _children(el, TAG_NAME, tagName)[0] || null;
-               },
-               
-               /**
-                * Examines child elements and returns all children matching the given selector.
-                * 
-                * @param       {Element}               el              element
-                * @param       {string}                selector        CSS selector to match child elements against
-                * @return      {array<Element>}        list of children matching the selector
-                */
-               childrenBySel: function(el, selector) {
-                       return _children(el, SELECTOR, selector);
-               },
-               
-               /**
-                * Examines child elements and returns all children that have the given CSS class set.
-                * 
-                * @param       {Element}               el              element
-                * @param       {string}                className       CSS class name
-                * @return      {array<Element>}        list of children with the given class
-                */
-               childrenByClass: function(el, className) {
-                       return _children(el, CLASS_NAME, className);
-               },
-               
-               /**
-                * Examines child elements and returns all children which equal the given tag.
-                * 
-                * @param       {Element}               el              element
-                * @param       {string}                tagName         element tag name
-                * @return      {array<Element>}        list of children equaling the tag name
-                */
-               childrenByTag: function(el, tagName) {
-                       return _children(el, TAG_NAME, tagName);
-               },
-               
-               /**
-                * Examines parent nodes and returns the first parent that matches the given selector.
-                * 
-                * @param       {Element}       el              child element
-                * @param       {string}        selector        CSS selector to match parent nodes against
-                * @param       {Element=}      untilElement    stop when reaching this element
-                * @return      {(Element|null)}        null if no parent node matched the selector
-                */
-               parentBySel: function(el, selector, untilElement) {
-                       return _parent(el, SELECTOR, selector, untilElement);
-               },
-               
-               /**
-                * Examines parent nodes and returns the first parent that has the given CSS class set.
-                * 
-                * @param       {Element}       el              child element
-                * @param       {string}        className       CSS class name
-                * @param       {Element=}      untilElement    stop when reaching this element
-                * @return      {(Element|null)}        null if there is no parent node with given class
-                */
-               parentByClass: function(el, className, untilElement) {
-                       return _parent(el, CLASS_NAME, className, untilElement);
-               },
-               
-               /**
-                * Examines parent nodes and returns the first parent which equals the given tag.
-                * 
-                * @param       {Element}       el              child element
-                * @param       {string}        tagName         element tag name
-                * @param       {Element=}      untilElement    stop when reaching this element
-                * @return      {(Element|null)}        null if there is no parent node of given tag type
-                */
-               parentByTag: function(el, tagName, untilElement) {
-                       return _parent(el, TAG_NAME, tagName, untilElement);
-               },
-               
-               /**
-                * Returns the next element sibling.
-                * 
-                * @param       {Element}       el              element
-                * @return      {(Element|null)}        null if there is no next sibling element
-                */
-               next: function(el) {
-                       return _sibling(el, 'nextElementSibling', NONE, null);
-               },
-               
-               /**
-                * Returns the next element sibling that matches the given selector.
-                * 
-                * @param       {Element}       el              element
-                * @param       {string}        selector        CSS selector to match parent nodes against
-                * @return      {(Element|null)}        null if there is no next sibling element or it does not match the selector
-                */
-               nextBySel: function(el, selector) {
-                       return _sibling(el, 'nextElementSibling', SELECTOR, selector);
-               },
-               
-               /**
-                * Returns the next element sibling with given CSS class.
-                * 
-                * @param       {Element}       el              element
-                * @param       {string}        className       CSS class name
-                * @return      {(Element|null)}        null if there is no next sibling element or it does not have the class set
-                */
-               nextByClass: function(el, className) {
-                       return _sibling(el, 'nextElementSibling', CLASS_NAME, className);
-               },
-               
-               /**
-                * Returns the next element sibling with given CSS class.
-                * 
-                * @param       {Element}       el              element
-                * @param       {string}        tagName         element tag name
-                * @return      {(Element|null)}        null if there is no next sibling element or it does not have the class set
-                */
-               nextByTag: function(el, tagName) {
-                       return _sibling(el, 'nextElementSibling', TAG_NAME, tagName);
-               },
-               
-               /**
-                * Returns the previous element sibling.
-                * 
-                * @param       {Element}       el              element
-                * @return      {(Element|null)}        null if there is no previous sibling element
-                */
-               prev: function(el) {
-                       return _sibling(el, 'previousElementSibling', NONE, null);
-               },
-               
-               /**
-                * Returns the previous element sibling that matches the given selector.
-                * 
-                * @param       {Element}       el              element
-                * @param       {string}        selector        CSS selector to match parent nodes against
-                * @return      {(Element|null)}        null if there is no previous sibling element or it does not match the selector
-                */
-               prevBySel: function(el, selector) {
-                       return _sibling(el, 'previousElementSibling', SELECTOR, selector);
-               },
-               
-               /**
-                * Returns the previous element sibling with given CSS class.
-                * 
-                * @param       {Element}       el              element
-                * @param       {string}        className       CSS class name
-                * @return      {(Element|null)}        null if there is no previous sibling element or it does not have the class set
-                */
-               prevByClass: function(el, className) {
-                       return _sibling(el, 'previousElementSibling', CLASS_NAME, className);
-               },
-               
-               /**
-                * Returns the previous element sibling with given CSS class.
-                * 
-                * @param       {Element}       el              element
-                * @param       {string}        tagName         element tag name
-                * @return      {(Element|null)}        null if there is no previous sibling element or it does not have the class set
-                */
-               prevByTag: function(el, tagName) {
-                       return _sibling(el, 'previousElementSibling', TAG_NAME, tagName);
-               }
-       };
+define(["require", "exports"], function (require, exports) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", { value: true });
+    exports.prevByTag = exports.prevByClass = exports.prevBySel = exports.prev = exports.nextByTag = exports.nextByClass = exports.nextBySel = exports.next = exports.parentByTag = exports.parentByClass = exports.parentBySel = exports.childrenByTag = exports.childrenByClass = exports.childrenBySel = exports.childByTag = exports.childByClass = exports.childBySel = void 0;
+    const _test = new Map([
+        [0 /* None */, () => true],
+        [1 /* Selector */, (element, selector) => element.matches(selector)],
+        [2 /* ClassName */, (element, className) => element.classList.contains(className)],
+        [3 /* TagName */, (element, tagName) => element.nodeName === tagName],
+    ]);
+    function _getChildren(element, type, value) {
+        if (!(element instanceof Element)) {
+            throw new TypeError('Expected a valid element as first argument.');
+        }
+        const children = [];
+        for (let i = 0; i < element.childElementCount; i++) {
+            if (_test[type](element.children[i], value)) {
+                children.push(element.children[i]);
+            }
+        }
+        return children;
+    }
+    function _getParent(element, type, value, untilElement) {
+        if (!(element instanceof Element)) {
+            throw new TypeError('Expected a valid element as first argument.');
+        }
+        let target = element.parentNode;
+        while (target instanceof Element) {
+            if (target === untilElement) {
+                return null;
+            }
+            if (_test[type](target, value)) {
+                return target;
+            }
+            target = target.parentNode;
+        }
+        return null;
+    }
+    function _getSibling(element, siblingType, type, value) {
+        if (!(element instanceof Element)) {
+            throw new TypeError('Expected a valid element as first argument.');
+        }
+        if (element instanceof Element) {
+            if (element[siblingType] !== null && _test[type](element[siblingType], value)) {
+                return element[siblingType];
+            }
+        }
+        return null;
+    }
+    /**
+     * Examines child elements and returns the first child matching the given selector.
+     */
+    function childBySel(element, selector) {
+        return _getChildren(element, 1 /* Selector */, selector)[0] || null;
+    }
+    exports.childBySel = childBySel;
+    /**
+     * Examines child elements and returns the first child that has the given CSS class set.
+     */
+    function childByClass(element, className) {
+        return _getChildren(element, 2 /* ClassName */, className)[0] || null;
+    }
+    exports.childByClass = childByClass;
+    /**
+     * Examines child elements and returns the first child which equals the given tag.
+     */
+    function childByTag(element, tagName) {
+        return _getChildren(element, 3 /* TagName */, tagName)[0] || null;
+    }
+    exports.childByTag = childByTag;
+    /**
+     * Examines child elements and returns all children matching the given selector.
+     */
+    function childrenBySel(element, selector) {
+        return _getChildren(element, 1 /* Selector */, selector);
+    }
+    exports.childrenBySel = childrenBySel;
+    /**
+     * Examines child elements and returns all children that have the given CSS class set.
+     */
+    function childrenByClass(element, className) {
+        return _getChildren(element, 2 /* ClassName */, className);
+    }
+    exports.childrenByClass = childrenByClass;
+    /**
+     * Examines child elements and returns all children which equal the given tag.
+     */
+    function childrenByTag(element, tagName) {
+        return _getChildren(element, 3 /* TagName */, tagName);
+    }
+    exports.childrenByTag = childrenByTag;
+    /**
+     * Examines parent nodes and returns the first parent that matches the given selector.
+     */
+    function parentBySel(element, selector, untilElement) {
+        return _getParent(element, 1 /* Selector */, selector, untilElement);
+    }
+    exports.parentBySel = parentBySel;
+    /**
+     * Examines parent nodes and returns the first parent that has the given CSS class set.
+     */
+    function parentByClass(element, className, untilElement) {
+        return _getParent(element, 2 /* ClassName */, className, untilElement);
+    }
+    exports.parentByClass = parentByClass;
+    /**
+     * Examines parent nodes and returns the first parent which equals the given tag.
+     */
+    function parentByTag(element, tagName, untilElement) {
+        return _getParent(element, 3 /* TagName */, tagName, untilElement);
+    }
+    exports.parentByTag = parentByTag;
+    /**
+     * Returns the next element sibling.
+     *
+     * @deprecated 5.4 Use `element.nextElementSibling` instead.
+     */
+    function next(element) {
+        return _getSibling(element, 'nextElementSibling', 0 /* None */, '');
+    }
+    exports.next = next;
+    /**
+     * Returns the next element sibling that matches the given selector.
+     */
+    function nextBySel(element, selector) {
+        return _getSibling(element, 'nextElementSibling', 1 /* Selector */, selector);
+    }
+    exports.nextBySel = nextBySel;
+    /**
+     * Returns the next element sibling with given CSS class.
+     */
+    function nextByClass(element, className) {
+        return _getSibling(element, 'nextElementSibling', 2 /* ClassName */, className);
+    }
+    exports.nextByClass = nextByClass;
+    /**
+     * Returns the next element sibling with given CSS class.
+     */
+    function nextByTag(element, tagName) {
+        return _getSibling(element, 'nextElementSibling', 3 /* TagName */, tagName);
+    }
+    exports.nextByTag = nextByTag;
+    /**
+     * Returns the previous element sibling.
+     *
+     * @deprecated 5.4 Use `element.previousElementSibling` instead.
+     */
+    function prev(element) {
+        return _getSibling(element, 'previousElementSibling', 0 /* None */, '');
+    }
+    exports.prev = prev;
+    /**
+     * Returns the previous element sibling that matches the given selector.
+     */
+    function prevBySel(element, selector) {
+        return _getSibling(element, 'previousElementSibling', 1 /* Selector */, selector);
+    }
+    exports.prevBySel = prevBySel;
+    /**
+     * Returns the previous element sibling with given CSS class.
+     */
+    function prevByClass(element, className) {
+        return _getSibling(element, 'previousElementSibling', 2 /* ClassName */, className);
+    }
+    exports.prevByClass = prevByClass;
+    /**
+     * Returns the previous element sibling with given CSS class.
+     */
+    function prevByTag(element, tagName) {
+        return _getSibling(element, 'previousElementSibling', 3 /* TagName */, tagName);
+    }
+    exports.prevByTag = prevByTag;
 });
diff --git a/wcfsetup/install/files/ts/WoltLabSuite/Core/Dom/Traverse.ts b/wcfsetup/install/files/ts/WoltLabSuite/Core/Dom/Traverse.ts
new file mode 100644 (file)
index 0000000..d57cc85
--- /dev/null
@@ -0,0 +1,196 @@
+/**
+ * Provides helper functions to traverse the DOM.
+ *
+ * @author  Alexander Ebert
+ * @copyright  2001-2019 WoltLab GmbH
+ * @license  GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
+ * @module  Dom/Traverse (alias)
+ * @module  WoltLabSuite/Core/Dom/Traverse
+ */
+
+const enum Type {
+  None,
+  Selector,
+  ClassName,
+  TagName,
+}
+
+const _test = new Map<Type, (...args: any[]) => boolean>([
+  [Type.None, () => true],
+  [Type.Selector, (element: Element, selector: string) => element.matches(selector)],
+  [Type.ClassName, (element: Element, className: string) => element.classList.contains(className)],
+  [Type.TagName, (element: Element, tagName: string) => element.nodeName === tagName],
+]);
+
+function _getChildren(element: Element, type: Type, value: string): Element[] {
+  if (!(element instanceof Element)) {
+    throw new TypeError('Expected a valid element as first argument.');
+  }
+
+  const children: Element[] = [];
+  for (let i = 0; i < element.childElementCount; i++) {
+    if (_test[type](element.children[i], value)) {
+      children.push(element.children[i]);
+    }
+  }
+
+  return children;
+}
+
+function _getParent(element: Element, type: Type, value: string, untilElement?: Element): Element | null {
+  if (!(element instanceof Element)) {
+    throw new TypeError('Expected a valid element as first argument.');
+  }
+
+  let target = element.parentNode;
+  while (target instanceof Element) {
+    if (target === untilElement) {
+      return null;
+    }
+
+    if (_test[type](target, value)) {
+      return target;
+    }
+
+    target = target.parentNode;
+  }
+
+  return null;
+}
+
+function _getSibling(element: Element, siblingType: string, type: Type, value: string): Element | null {
+  if (!(element instanceof Element)) {
+    throw new TypeError('Expected a valid element as first argument.');
+  }
+
+  if (element instanceof Element) {
+    if (element[siblingType] !== null && _test[type](element[siblingType], value)) {
+      return element[siblingType];
+    }
+  }
+
+  return null;
+}
+
+/**
+ * Examines child elements and returns the first child matching the given selector.
+ */
+export function childBySel(element: Element, selector: string): Element | null {
+  return _getChildren(element, Type.Selector, selector)[0] || null;
+}
+
+/**
+ * Examines child elements and returns the first child that has the given CSS class set.
+ */
+export function childByClass(element: Element, className: string): Element | null {
+  return _getChildren(element, Type.ClassName, className)[0] || null;
+}
+
+/**
+ * Examines child elements and returns the first child which equals the given tag.
+ */
+export function childByTag(element: Element, tagName: string): Element | null {
+  return _getChildren(element, Type.TagName, tagName)[0] || null;
+}
+
+/**
+ * Examines child elements and returns all children matching the given selector.
+ */
+export function childrenBySel(element, selector: string): Element[] {
+  return _getChildren(element, Type.Selector, selector);
+}
+
+/**
+ * Examines child elements and returns all children that have the given CSS class set.
+ */
+export function childrenByClass(element: Element, className: string): Element[] {
+  return _getChildren(element, Type.ClassName, className);
+}
+
+/**
+ * Examines child elements and returns all children which equal the given tag.
+ */
+export function childrenByTag(element: Element, tagName: string): Element[] {
+  return _getChildren(element, Type.TagName, tagName);
+}
+
+/**
+ * Examines parent nodes and returns the first parent that matches the given selector.
+ */
+export function parentBySel(element: Element, selector: string, untilElement?: Element): Element | null {
+  return _getParent(element, Type.Selector, selector, untilElement);
+}
+
+/**
+ * Examines parent nodes and returns the first parent that has the given CSS class set.
+ */
+export function parentByClass(element: Element, className: string, untilElement?: Element): Element | null {
+  return _getParent(element, Type.ClassName, className, untilElement);
+}
+
+/**
+ * Examines parent nodes and returns the first parent which equals the given tag.
+ */
+export function parentByTag(element: Element, tagName: string, untilElement?: Element): Element | null {
+  return _getParent(element, Type.TagName, tagName, untilElement);
+}
+
+/**
+ * Returns the next element sibling.
+ *
+ * @deprecated 5.4 Use `element.nextElementSibling` instead.
+ */
+export function next(element: Element): Element | null {
+  return _getSibling(element, 'nextElementSibling', Type.None, '');
+}
+
+/**
+ * Returns the next element sibling that matches the given selector.
+ */
+export function nextBySel(element: Element, selector: string): Element | null {
+  return _getSibling(element, 'nextElementSibling', Type.Selector, selector);
+}
+
+/**
+ * Returns the next element sibling with given CSS class.
+ */
+export function nextByClass(element: Element, className: string): Element | null {
+  return _getSibling(element, 'nextElementSibling', Type.ClassName, className);
+}
+
+/**
+ * Returns the next element sibling with given CSS class.
+ */
+export function nextByTag(element: Element, tagName: string): Element | null {
+  return _getSibling(element, 'nextElementSibling', Type.TagName, tagName);
+}
+
+/**
+ * Returns the previous element sibling.
+ *
+ * @deprecated 5.4 Use `element.previousElementSibling` instead.
+ */
+export function prev(element: Element): Element | null {
+  return _getSibling(element, 'previousElementSibling', Type.None, '');
+}
+
+/**
+ * Returns the previous element sibling that matches the given selector.
+ */
+export function prevBySel(element: Element, selector: string): Element | null {
+  return _getSibling(element, 'previousElementSibling', Type.Selector, selector);
+}
+
+/**
+ * Returns the previous element sibling with given CSS class.
+ */
+export function prevByClass(element: Element, className: string): Element | null {
+  return _getSibling(element, 'previousElementSibling', Type.ClassName, className);
+}
+
+/**
+ * Returns the previous element sibling with given CSS class.
+ */
+export function prevByTag(element: Element, tagName: string): Element | null {
+  return _getSibling(element, 'previousElementSibling', Type.TagName, tagName);
+}