Commit | Line | Data |
---|---|---|
e3747bbc | 1 | # JavaScript Helper Functions |
f4e1aa26 | 2 | |
ec839e38 MS |
3 | !!! danger "These helper functions are deprecated since version 5.4. Refer to our [migration guide](../migration/wsc53/javascript.md#replacements-for-deprecated-components) on how to replace them." |
4 | ||
f4e1aa26 AE |
5 | ## Introduction |
6 | ||
c1056ace | 7 | Since version 3.0, WoltLab Suite ships with a set of global helper functions that are |
f4e1aa26 AE |
8 | exposed on the `window`-object and thus are available regardless of the context. |
9 | They are meant to reduce code repetition and to increase readability by moving | |
10 | potentially relevant parts to the front of an instruction. | |
11 | ||
f4968e0b | 12 | ## Elements |
f4e1aa26 | 13 | |
15db9986 | 14 | ### `elCreate(tagName: string): Element` |
f4e1aa26 AE |
15 | |
16 | Creates a new element with the provided tag name. | |
17 | ||
18 | ```js | |
19 | var element = elCreate("div"); | |
20 | // equals | |
21 | var element = document.createElement("div"); | |
22 | ``` | |
23 | ||
15db9986 | 24 | ### `elRemove(element: Element)` |
f4e1aa26 AE |
25 | |
26 | Removes an element from its parent without returning it. This function will throw | |
27 | an error if the `element` doesn't have a parent node. | |
28 | ||
29 | ```js | |
30 | elRemove(element); | |
31 | // equals | |
32 | element.parentNode.removeChild(element); | |
33 | ``` | |
34 | ||
15db9986 | 35 | ### `elShow(element: Element)` |
f4e1aa26 AE |
36 | |
37 | Attempts to show an element by removing the `display` CSS-property, usually used | |
38 | in conjunction with the `elHide()` function. | |
39 | ||
40 | ```js | |
41 | elShow(element); | |
42 | // equals | |
43 | element.style.removeProperty("display"); | |
44 | ``` | |
45 | ||
15db9986 | 46 | ### `elHide(element: Element)` |
f4e1aa26 AE |
47 | |
48 | Attempts to hide an element by setting the `display` CSS-property to `none`, this | |
49 | is intended to be used with `elShow()` that relies on this behavior. | |
50 | ||
51 | ```js | |
52 | elHide(element); | |
53 | // equals | |
54 | element.style.setProperty("display", "none", ""); | |
55 | ``` | |
56 | ||
15db9986 | 57 | ### `elToggle(element: Element)` |
f4e1aa26 AE |
58 | |
59 | Attempts to toggle the visibility of an element by examining the value of the | |
60 | `display` CSS-property and calls either `elShow()` or `elHide()`. | |
61 | ||
f4968e0b | 62 | ## Attributes |
f4e1aa26 | 63 | |
15db9986 | 64 | ### `elAttr(element: Element, attribute: string, value?: string): string` |
f4e1aa26 AE |
65 | |
66 | Sets or reads an attribute value, value are implicitly casted into strings and | |
67 | reading non-existing attributes will always yield an empty string. If you want | |
68 | to test for attribute existence, you'll have to fall-back to the native | |
69 | [`Element.hasAttribute()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/hasAttribute) | |
70 | method. | |
71 | ||
72 | You should read and set native attributes directly, such as `img.src` rather | |
73 | than `img.getAttribute("src");`. | |
74 | ||
75 | ```js | |
76 | var value = elAttr(element, "some-attribute"); | |
77 | // equals | |
78 | var value = element.getAttribute("some-attribute"); | |
79 | ||
80 | elAttr(element, "some-attribute", "some value"); | |
81 | // equals | |
82 | element.setAttribute("some-attribute", "some value"); | |
83 | ``` | |
84 | ||
15db9986 | 85 | ### `elAttrBool(element: Element, attribute: string): boolean` |
f4e1aa26 AE |
86 | |
87 | Reads an attribute and converts it value into a boolean value, the strings `"1"` | |
88 | and `"true"` will evaluate to `true`. All other values, including a missing attribute, | |
89 | will return `false`. | |
90 | ||
91 | ```js | |
92 | if (elAttrBool(element, "some-attribute")) { | |
93 | // attribute is true-ish | |
94 | } | |
95 | ``` | |
96 | ||
15db9986 | 97 | ### `elData(element: Element, attribute: string, value?: string): string` |
f4e1aa26 AE |
98 | |
99 | Short-hand function to read or set HTML5 `data-*`-attributes, it essentially | |
100 | prepends the `data-` prefix before forwarding the call to `elAttr()`. | |
101 | ||
102 | ```js | |
103 | var value = elData(element, "some-attribute"); | |
104 | // equals | |
105 | var value = elAttr(element, "data-some-attribute"); | |
106 | ||
107 | elData(element, "some-attribute", "some value"); | |
108 | // equals | |
109 | elAttr(element, "data-some-attribute", "some value"); | |
110 | ``` | |
111 | ||
15db9986 | 112 | ### `elDataBool(element: Element, attribute: string): boolean` |
f4e1aa26 AE |
113 | |
114 | Short-hand function to convert a HTML5 `data-*`-attribute into a boolean value. It | |
115 | prepends the `data-` prefix before forwarding the call to `elAttrBool()`. | |
116 | ||
117 | ```js | |
118 | if (elDataBool(element, "some-attribute")) { | |
119 | // attribute is true-ish | |
120 | } | |
121 | // equals | |
122 | if (elAttrBool(element, "data-some-attribute")) { | |
123 | // attribute is true-ish | |
124 | } | |
125 | ``` | |
126 | ||
f4968e0b | 127 | ## Selecting Elements |
f4e1aa26 | 128 | |
9003992d | 129 | !!! warning "Unlike libraries like jQuery, these functions will return `null` if an element is not found. You are responsible to validate if the element exist and to branch accordingly, invoking methods on the return value without checking for `null` will yield an error." |
f4e1aa26 | 130 | |
15db9986 | 131 | ### `elById(id: string): Element | null` |
f4e1aa26 AE |
132 | |
133 | Selects an element by its `id`-attribute value. | |
134 | ||
135 | ```js | |
136 | var element = elById("my-awesome-element"); | |
137 | // equals | |
138 | var element = document.getElementById("my-awesome-element"); | |
139 | ``` | |
140 | ||
15db9986 | 141 | ### `elBySel(selector: string, context?: Element): Element | null` |
f4e1aa26 | 142 | |
9003992d | 143 | !!! danger "The underlying `querySelector()`-method works on the entire DOM hierarchy and can yield results outside of your context element! Please read and understand the MDN article on [`Element.querySelector()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector#The_entire_hierarchy_counts) to learn more about this." |
f4e1aa26 AE |
144 | |
145 | Select a single element based on a CSS selector, optionally limiting the results | |
146 | to be a direct or indirect children of the context element. | |
147 | ||
148 | ```js | |
149 | var element = elBySel(".some-element"); | |
150 | // equals | |
151 | var element = document.querySelector(".some-element"); | |
152 | ||
153 | // limiting the scope to a context element: | |
154 | var element = elBySel(".some-element", context); | |
155 | // equals | |
156 | var element = context.querySelector(".some-element"); | |
157 | ``` | |
158 | ||
15db9986 | 159 | ### `elBySelAll(selector: string, context?: Element, callback: (element: Element) => void): NodeList` |
f4e1aa26 | 160 | |
9003992d | 161 | !!! danger "The underlying `querySelector()`-method works on the entire DOM hierarchy and can yield results outside of your context element! Please read and understand the MDN article on [`Element.querySelector()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/querySelector#The_entire_hierarchy_counts) to learn more about this." |
f4e1aa26 AE |
162 | |
163 | Finds and returns a `NodeList` containing all elements that match the provided | |
164 | CSS selector. Although `NodeList` is an array-like structure, it is not possible | |
165 | to iterate over it using array functions, including `.forEach()` which is not | |
166 | available in Internet Explorer 11. | |
167 | ||
168 | ```js | |
169 | var elements = elBySelAll(".some-element"); | |
170 | // equals | |
171 | var elements = document.querySelectorAll(".some-element"); | |
172 | ||
173 | // limiting the scope to a context element: | |
174 | var elements = elBySelAll(".some-element", context); | |
175 | // equals | |
176 | var elements = context.querySelectorAll(".some-element"); | |
177 | ``` | |
178 | ||
f4968e0b | 179 | #### Callback to Iterate Over Elements |
f4e1aa26 AE |
180 | |
181 | `elBySelAll()` supports an optional third parameter that expects a callback function | |
182 | that is invoked for every element in the list. | |
183 | ||
184 | ```js | |
185 | // set the 2nd parameter to `undefined` or `null` to query the whole document | |
186 | elBySelAll(".some-element", undefined, function(element) { | |
187 | // is called for each element | |
188 | }); | |
189 | ||
190 | // limiting the scope to a context element: | |
191 | elBySelAll(".some-element", context, function(element) { | |
192 | // is called for each element | |
193 | }); | |
194 | ``` | |
195 | ||
15db9986 | 196 | ### `elClosest(element: Element, selector: string): Element | null` |
f4e1aa26 AE |
197 | |
198 | Returns the first `Element` that matches the provided CSS selector, this will | |
199 | return the provided element itself if it matches the selector. | |
200 | ||
201 | ```js | |
202 | var element = elClosest(context, ".some-element"); | |
203 | // equals | |
204 | var element = context.closest(".some-element"); | |
205 | ``` | |
206 | ||
f4968e0b | 207 | #### Text Nodes |
f4e1aa26 AE |
208 | |
209 | If the provided context is a `Text`-node, the function will move the context to | |
210 | the parent element before applying the CSS selector. If the `Text` has no parent, | |
211 | `null` is returned without evaluating the selector. | |
212 | ||
15db9986 | 213 | ### `elByClass(className: string, context?: Element): NodeList` |
f4e1aa26 AE |
214 | |
215 | Returns a live `NodeList` containing all elements that match the provided CSS | |
216 | class now _and_ in the future! The collection is automatically updated whenever | |
217 | an element with that class is added or removed from the DOM, it will also include | |
218 | elements that get dynamically assigned or removed this CSS class. | |
219 | ||
220 | You absolutely need to understand that this collection is dynamic, that means that | |
221 | elements can and will be added and removed from the collection _even while_ you | |
222 | iterate over it. There are only very few cases where you would need such a collection, | |
223 | almost always `elBySelAll()` is what you're looking for. | |
224 | ||
225 | ```js | |
226 | // no leading dot! | |
227 | var elements = elByClass("some-element"); | |
228 | // equals | |
229 | var elements = document.getElementsByClassName("some-element"); | |
230 | ||
231 | // limiting the scope to a context element: | |
232 | var elements = elByClass("some-element", context); | |
233 | // equals | |
234 | var elements = context.getElementsByClassName(".some-element"); | |
235 | ``` | |
236 | ||
15db9986 | 237 | ### `elByTag(tagName: string, context?: Element): NodeList` |
f4e1aa26 AE |
238 | |
239 | Returns a live `NodeList` containing all elements with the provided tag name now | |
240 | _and_ in the future! Please read the remarks on `elByClass()` above to understand | |
241 | the implications of this. | |
242 | ||
243 | ```js | |
244 | var elements = elByTag("div"); | |
245 | // equals | |
246 | var elements = document.getElementsByTagName("div"); | |
247 | ||
248 | // limiting the scope to a context element: | |
249 | var elements = elByTag("div", context); | |
250 | // equals | |
251 | var elements = context.getElementsByTagName("div"); | |
252 | ``` | |
253 | ||
f4968e0b | 254 | ## Utility Functions |
f4e1aa26 | 255 | |
15db9986 | 256 | ### `elInnerError(element: Element, errorMessage?: string, isHtml?: boolean): Element | null`` |
f4e1aa26 AE |
257 | |
258 | Unified function to display and remove inline error messages for input elements, | |
21609ed2 | 259 | please read the [section in the migration docs](../migration/wsc30/javascript.md#helper-function-for-inline-error-messages) |
f4e1aa26 AE |
260 | to learn more about this function. |
261 | ||
f4968e0b | 262 | ## String Extensions |
f4e1aa26 | 263 | |
15db9986 | 264 | ### `hashCode(): string` |
f4e1aa26 AE |
265 | |
266 | Computes a numeric hash value of a string similar to Java's `String.hashCode()` method. | |
267 | ||
268 | ```js | |
269 | console.log("Hello World".hashCode()); | |
270 | // outputs: -862545276 | |
271 | ``` |