@lexriver/dome 1.5.10 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/out/{AnimatedArray.d.ts → src/AnimatedArray.d.mts} +29 -29
  2. package/out/{AnimatedArray.js → src/AnimatedArray.mjs} +52 -51
  3. package/out/{AnimatedTable.d.ts → src/AnimatedTable.d.mts} +38 -38
  4. package/out/{AnimatedTable.js → src/AnimatedTable.mjs} +88 -91
  5. package/out/{AnimatedText.d.ts → src/AnimatedText.d.mts} +13 -13
  6. package/out/{AnimatedText.js → src/AnimatedText.mjs} +24 -24
  7. package/out/{Animation.d.ts → src/Animation.d.mts} +4 -4
  8. package/out/{temp-test.d.ts → src/Animation.mjs} +1 -1
  9. package/out/{Dome.d.ts → src/Dome.d.mts} +9 -9
  10. package/out/{Dome.js → src/Dome.mjs} +291 -295
  11. package/out/{DomeComponent.d.ts → src/DomeComponent.d.mts} +22 -19
  12. package/out/{DomeComponent.js → src/DomeComponent.mjs} +47 -44
  13. package/out/{DomeManipulator.d.ts → src/DomeManipulator.d.mts} +48 -48
  14. package/out/{DomeManipulator.js → src/DomeManipulator.mjs} +329 -329
  15. package/out/src/DomeRouter.console-test.d.mts +1 -0
  16. package/out/{DomeRouter.console-test.js → src/DomeRouter.console-test.mjs} +44 -44
  17. package/out/{DomeRouter.d.ts → src/DomeRouter.d.mts} +30 -30
  18. package/out/{DomeRouter.js → src/DomeRouter.mjs} +236 -237
  19. package/out/{LongestCommonSubsequence.d.ts → src/LongestCommonSubsequence.d.mts} +15 -15
  20. package/out/{LongestCommonSubsequence.js → src/LongestCommonSubsequence.mjs} +164 -164
  21. package/out/src/index.d.mts +11 -0
  22. package/out/src/index.mjs +11 -0
  23. package/out/src/temp-test.d.mts +1 -0
  24. package/out/{temp-test.js → src/temp-test.mjs} +20 -20
  25. package/out/vitest.config.d.ts +2 -0
  26. package/out/vitest.config.js +9 -0
  27. package/package.json +16 -14
  28. package/src/{AnimatedArray.ts → AnimatedArray.mts} +3 -3
  29. package/src/{AnimatedTable.ts → AnimatedTable.mts} +6 -6
  30. package/src/{AnimatedText.ts → AnimatedText.mts} +4 -4
  31. package/src/{Dome.ts → Dome.mts} +7 -11
  32. package/src/{DomeComponent.ts → DomeComponent.mts} +3 -3
  33. package/src/{DomeManipulator.ts → DomeManipulator.mts} +5 -5
  34. package/src/{DomeRouter.ts → DomeRouter.mts} +3 -3
  35. package/src/index.mts +12 -0
  36. package/src/{temp-test.ts → temp-test.mts} +1 -1
  37. package/tsconfig.json +57 -60
  38. package/vitest.config.ts +10 -0
  39. package/jest.config.js +0 -22
  40. package/out/Animation.js +0 -0
  41. package/out/DomeRouter.console-test.d.ts +0 -0
  42. package/out/index.d.ts +0 -12
  43. package/out/index.js +0 -14
  44. package/src/index.ts +0 -14
  45. /package/src/{Animation.ts → Animation.mts} +0 -0
  46. /package/src/{DomeRouter.console-test.ts → DomeRouter.console-test.mts} +0 -0
  47. /package/src/{LongestCommonSubsequence.ts → LongestCommonSubsequence.mts} +0 -0
@@ -1,329 +1,329 @@
1
- import { checkIfObservable } from "@lexriver/observable";
2
- import { Async } from "@lexriver/async";
3
- import { DataTypes } from "@lexriver/data-types";
4
- export var DomeManipulator;
5
- (function (DomeManipulator) {
6
- async function hideElementAsync(element, animation) {
7
- if (!element)
8
- throw new Error('hideElementAsync failed, no element');
9
- if (element.hidden)
10
- return;
11
- if (animation) {
12
- await addCssClassAsync(element, animation.cssClassName, animation.timeMs);
13
- }
14
- element.style.display = 'none'; //TODO: remove this?
15
- element.hidden = true;
16
- }
17
- DomeManipulator.hideElementAsync = hideElementAsync;
18
- async function unhideElementAsync(element, animation) {
19
- if (!element)
20
- throw new Error('unhideElementAsync failed, no element');
21
- if (!element.hidden)
22
- return;
23
- element.style.display = ''; //TODO: remove this?
24
- element.hidden = false;
25
- if (animation) {
26
- await addCssClassAsync(element, animation.cssClassName, animation.timeMs);
27
- }
28
- }
29
- DomeManipulator.unhideElementAsync = unhideElementAsync;
30
- async function insertAsFirstChildAsync(elementToInsert, parentElement, animation) {
31
- parentElement.insertBefore(elementToInsert, parentElement.firstChild);
32
- if (animation) {
33
- await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs);
34
- }
35
- }
36
- DomeManipulator.insertAsFirstChildAsync = insertAsFirstChildAsync;
37
- async function insertBeforeAsync(elementToInsert, refElement, parentElement, animation) {
38
- parentElement.insertBefore(elementToInsert, refElement);
39
- if (animation) {
40
- await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs);
41
- }
42
- }
43
- DomeManipulator.insertBeforeAsync = insertBeforeAsync;
44
- async function insertAfterAsync(elementToInsert, refElement, parentElement, animation) {
45
- if (refElement) {
46
- parentElement.insertBefore(elementToInsert, refElement.nextSibling);
47
- }
48
- else {
49
- parentElement.appendChild(elementToInsert);
50
- }
51
- if (animation) {
52
- await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs);
53
- }
54
- }
55
- DomeManipulator.insertAfterAsync = insertAfterAsync;
56
- async function insertByIndexAsync(elementToInsert, index, parentElement, animation) {
57
- if (index == 0) {
58
- parentElement.appendChild(elementToInsert);
59
- if (animation) {
60
- await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs);
61
- }
62
- return;
63
- }
64
- await insertAfterAsync(elementToInsert, parentElement.children[index], parentElement, animation);
65
- }
66
- DomeManipulator.insertByIndexAsync = insertByIndexAsync;
67
- async function replaceAsync(oldElement, newElement, animationHide, animationShow) {
68
- if (!oldElement.parentNode) {
69
- // almost impossible if in DOM
70
- console.error('replaceAsync() failed, no parentNode.', 'oldElement=', oldElement);
71
- throw new Error('no parent node for replaceAsync');
72
- }
73
- // hide
74
- if (animationHide) {
75
- await addCssClassAsync(oldElement, animationHide.cssClassName, animationHide.timeMs);
76
- }
77
- // replace
78
- const parent = oldElement.parentNode;
79
- if (!parent) {
80
- //TODO: do not throw error here?
81
- console.error('replaceAsync() failed, no parent. Probably node was deleted while hide animation.', 'oldElement=', oldElement, 'type=', typeof oldElement, 'parent=', oldElement.parentElement, oldElement.parentNode);
82
- throw new Error('no parent for replaceAsync()');
83
- }
84
- parent.replaceChild(newElement, oldElement);
85
- // show
86
- if (animationShow) {
87
- await addCssClassAsync(newElement, animationShow.cssClassName, animationShow.timeMs);
88
- }
89
- return newElement;
90
- }
91
- DomeManipulator.replaceAsync = replaceAsync;
92
- async function removeElementAsync(element, animation) {
93
- //console.log('#dome', 'removeELementAsync', element)
94
- if (animation) {
95
- //console.log('#dome', 'add animation', animation.cssClassName, animation.timeMs, element)
96
- await addCssClassAsync(element, animation.cssClassName, animation.timeMs);
97
- }
98
- //console.log('#dome', 'removing from dom', element)
99
- element.remove();
100
- }
101
- DomeManipulator.removeElementAsync = removeElementAsync;
102
- function forEachChildrenOf(element, action) {
103
- for (let i = 0; i < element.childNodes.length; i++) {
104
- action(element.childNodes[i]);
105
- }
106
- }
107
- DomeManipulator.forEachChildrenOf = forEachChildrenOf;
108
- async function removeAllChildrenAsync(element, animation) {
109
- // await Promise.all( //TODO: this doesn't remove text nodes
110
- // Array.from(element.children).map(child => removeElementAsync(child, animation))
111
- // )
112
- if (!animation) {
113
- while (element.firstChild) {
114
- //element.removeChild(element.firstChild);
115
- element.firstChild.remove();
116
- }
117
- //return
118
- }
119
- else {
120
- //console.log('##', 'assign remove animation for each children', element.childNodes)
121
- forEachChildrenOf(element, (child) => child.nodeType == Node.ELEMENT_NODE && child.classList.add(animation.cssClassName));
122
- //console.log('##', 'wait ms', animation.timeMs)
123
- await Async.waitMsAsync(animation.timeMs);
124
- //console.log('##', 'removing children', element.childNodes)
125
- forEachChildrenOf(element, (child) => child.remove());
126
- //console.log('##', 'done')
127
- }
128
- // if(element.children.length>0) {
129
- // console.error('DomeManipulator: removeAllChildrenAsync() failed', 'length=', element.children.length, 'children=', element.children, 'animation=', animation, 'element=', element)
130
- // throw new Error()
131
- // }
132
- }
133
- DomeManipulator.removeAllChildrenAsync = removeAllChildrenAsync;
134
- async function appendChildAsync(containerElement, child, animation) {
135
- containerElement.appendChild(child);
136
- if (animation) {
137
- await addCssClassAsync(child, animation.cssClassName, animation.timeMs);
138
- }
139
- }
140
- DomeManipulator.appendChildAsync = appendChildAsync;
141
- async function appendChildrenAsync(containerElement, children, animation) {
142
- //console.log('DomeManipulator: appendChildrenAsync', 'containerELement=', containerElement, 'children=', children, 'animation=', animation)
143
- if (DataTypes.isString(children)) {
144
- // no animation for text?
145
- containerElement.appendChild(document.createTextNode(children));
146
- }
147
- else if (DataTypes.isArray(children)) {
148
- await Promise.all(children.map(child => appendChildAsync(containerElement, child, animation)));
149
- }
150
- else if (children) {
151
- await appendChildAsync(containerElement, children, animation);
152
- }
153
- }
154
- DomeManipulator.appendChildrenAsync = appendChildrenAsync;
155
- async function replaceAllChildrenAsync(containerElement, childrenToInsert, animationForHide, animationForShow) {
156
- //await removeAllChildrenAsync(containerElement, animationForHide)
157
- if (containerElement.childNodes.length > 0) {
158
- await removeAllChildrenAsync(containerElement, animationForHide);
159
- }
160
- // while(containerElement.childNodes.length>0){
161
- // await removeAllChildrenAsync(containerElement, animationForHide) // can be executed more than once! TODO: why?
162
- // }
163
- // if(containerElement.children.length>0) {
164
- // console.error('DomeManipulator: replaceAllChildenrAsync() failed:', 'containerElement.children.length=', containerElement.children.length, 'children=', containerElement.children, 'containerElement=', containerElement, 'animationForHide=', animationForHide)
165
- // throw new Error()
166
- // }
167
- await appendChildrenAsync(containerElement, childrenToInsert, animationForShow);
168
- }
169
- DomeManipulator.replaceAllChildrenAsync = replaceAllChildrenAsync;
170
- function isInDom(el) {
171
- if (!el)
172
- return false;
173
- return document.body.contains(el);
174
- }
175
- DomeManipulator.isInDom = isInDom;
176
- function isOnScreen(el) {
177
- if (!el)
178
- return false;
179
- var rect = el.getBoundingClientRect();
180
- var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
181
- return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
182
- }
183
- DomeManipulator.isOnScreen = isOnScreen;
184
- async function addCssClassAsync(element, cssClassName, removeAfterMs) {
185
- if (element.nodeType !== Node.ELEMENT_NODE)
186
- return;
187
- element.classList.add(cssClassName);
188
- if (removeAfterMs && removeAfterMs > 0) {
189
- await Async.waitMsAsync(removeAfterMs);
190
- element.classList.remove(cssClassName);
191
- }
192
- }
193
- DomeManipulator.addCssClassAsync = addCssClassAsync;
194
- async function addCssClassesAsync(element, cssClassNames, removeAfterMs) {
195
- await Promise.all(cssClassNames.map(cssClassName => addCssClassAsync(element, cssClassName, removeAfterMs)));
196
- }
197
- DomeManipulator.addCssClassesAsync = addCssClassesAsync;
198
- function removeCssClass(element, cssClassName) {
199
- element.classList.remove(cssClassName);
200
- }
201
- DomeManipulator.removeCssClass = removeCssClass;
202
- function removeCssClasses(element, cssClassNames) {
203
- for (let cssClassName of cssClassNames) {
204
- element.classList.remove(cssClassName);
205
- }
206
- }
207
- DomeManipulator.removeCssClasses = removeCssClasses;
208
- /**
209
- * set css classes by array ['class1', 'class2'] or
210
- * by object {class1:true, class2:false} or
211
- * by Observable<boolean> {class1:true, class2:myVarO} or
212
- * by string
213
- * this function will replace class attribute so all classes that are not in params will be removed
214
- * @param value
215
- * @param element
216
- */
217
- function setCssClasses(element, value) {
218
- if (!value)
219
- return; // skip empty
220
- if (DataTypes.isArray(value)) {
221
- //console.log('setCssClasses', 'data is array', value)
222
- setAttribute(element, 'class', value.join(' '));
223
- }
224
- else if (DataTypes.isObjectWithKeys(value)) {
225
- //console.log('setCssClasses', 'data is object with keys', value)
226
- let classNameArray = [];
227
- for (let [k, v] of Object.entries(value)) {
228
- if (checkIfObservable(v)) {
229
- if (v.get()) {
230
- classNameArray.push(k);
231
- }
232
- }
233
- else if (v) {
234
- classNameArray.push(k);
235
- }
236
- }
237
- setAttribute(element, 'class', classNameArray.join(' '));
238
- }
239
- else {
240
- //console.log('setCssClasses', 'data is unknown', value)
241
- setAttribute(element, 'class', value);
242
- }
243
- }
244
- DomeManipulator.setCssClasses = setCssClasses;
245
- function setAttribute(element, name, value) {
246
- if (value === undefined || value === null) {
247
- return;
248
- }
249
- // Naive support for xlink namespace
250
- // Full list: https://github.com/facebook/react/blob/1843f87/src/renderers/dom/shared/SVGDOMPropertyConfig.js#L258-L264
251
- if (/^xlink[AHRST]/.test(name)) {
252
- element.setAttributeNS('http://www.w3.org/1999/xlink', name.replace('xlink', 'xlink:').toLowerCase(), value);
253
- }
254
- else {
255
- element.setAttribute(name, value);
256
- }
257
- }
258
- DomeManipulator.setAttribute = setAttribute;
259
- function hasFocus(el) {
260
- return document.activeElement == el;
261
- }
262
- DomeManipulator.hasFocus = hasFocus;
263
- function scrollIntoView(element, paddingFromTop = 100) {
264
- if (isOnScreen(element)) {
265
- return; // no need to scroll
266
- }
267
- //const positionBefore = getCurrentScrollPosition()
268
- //element.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
269
- //const positionAfter = getCurrentScrollPosition()
270
- //console.log('before=', positionBefore, 'after=', positionAfter)
271
- let expectedPosition = element.getBoundingClientRect().top + window.pageYOffset;
272
- expectedPosition -= paddingFromTop;
273
- window.scrollTo({ top: expectedPosition, behavior: 'smooth' });
274
- }
275
- DomeManipulator.scrollIntoView = scrollIntoView;
276
- // https://stackoverflow.com/questions/15935318/smooth-scroll-to-top/55926067
277
- DomeManipulator.scrollToTop = () => {
278
- //console.log('scrollToTop')
279
- let position = getCurrentScrollPosition();
280
- if (position > 0) {
281
- window.requestAnimationFrame(DomeManipulator.scrollToTop);
282
- if (position < 20) {
283
- window.scrollTo(0, 0);
284
- }
285
- else {
286
- window.scrollTo(0, position - position / 9);
287
- }
288
- }
289
- };
290
- function getCurrentScrollPosition() {
291
- return document.documentElement.scrollTop || document.body.scrollTop;
292
- }
293
- DomeManipulator.getCurrentScrollPosition = getCurrentScrollPosition;
294
- async function scrollToAsync(p) {
295
- //console.log('scrollToAsync', p)
296
- const msStep = p.msStep ?? 50;
297
- const maxMsToWait = p.maxMsToWait ?? 5000;
298
- let scrollOptions = {};
299
- if (p.pxFromTop) {
300
- scrollOptions.top = p.pxFromTop;
301
- }
302
- if (p.pxFromLeft) {
303
- scrollOptions.left = p.pxFromLeft;
304
- }
305
- if (p.smooth) {
306
- scrollOptions.behavior = 'smooth';
307
- }
308
- try {
309
- if (p.pxFromLeft || p.pxFromTop) {
310
- await Async.waitForFunctionToReturnTrueAsync(() => {
311
- if (p.pxFromTop) {
312
- return document.body.scrollHeight >= p.pxFromTop;
313
- }
314
- if (p.pxFromLeft) {
315
- return document.body.scrollWidth >= p.pxFromLeft;
316
- }
317
- return false;
318
- }, msStep, maxMsToWait);
319
- }
320
- }
321
- catch (error) {
322
- // ignore error
323
- }
324
- //console.log('scrollToY', pxFromTop, 'height=', document.body.clientHeight)
325
- //console.log('scrollToAsync now', scrollOptions)
326
- window.scrollTo(scrollOptions);
327
- }
328
- DomeManipulator.scrollToAsync = scrollToAsync;
329
- })(DomeManipulator || (DomeManipulator = {}));
1
+ import { Async } from "@lexriver/async";
2
+ import { DataTypes } from "@lexriver/data-types";
3
+ import { checkIfObservable } from "@lexriver/observable";
4
+ export var DomeManipulator;
5
+ (function (DomeManipulator) {
6
+ async function hideElementAsync(element, animation) {
7
+ if (!element)
8
+ throw new Error('hideElementAsync failed, no element');
9
+ if (element.hidden)
10
+ return;
11
+ if (animation) {
12
+ await addCssClassAsync(element, animation.cssClassName, animation.timeMs);
13
+ }
14
+ element.style.display = 'none'; //TODO: remove this?
15
+ element.hidden = true;
16
+ }
17
+ DomeManipulator.hideElementAsync = hideElementAsync;
18
+ async function unhideElementAsync(element, animation) {
19
+ if (!element)
20
+ throw new Error('unhideElementAsync failed, no element');
21
+ if (!element.hidden)
22
+ return;
23
+ element.style.display = ''; //TODO: remove this?
24
+ element.hidden = false;
25
+ if (animation) {
26
+ await addCssClassAsync(element, animation.cssClassName, animation.timeMs);
27
+ }
28
+ }
29
+ DomeManipulator.unhideElementAsync = unhideElementAsync;
30
+ async function insertAsFirstChildAsync(elementToInsert, parentElement, animation) {
31
+ parentElement.insertBefore(elementToInsert, parentElement.firstChild);
32
+ if (animation) {
33
+ await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs);
34
+ }
35
+ }
36
+ DomeManipulator.insertAsFirstChildAsync = insertAsFirstChildAsync;
37
+ async function insertBeforeAsync(elementToInsert, refElement, parentElement, animation) {
38
+ parentElement.insertBefore(elementToInsert, refElement);
39
+ if (animation) {
40
+ await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs);
41
+ }
42
+ }
43
+ DomeManipulator.insertBeforeAsync = insertBeforeAsync;
44
+ async function insertAfterAsync(elementToInsert, refElement, parentElement, animation) {
45
+ if (refElement) {
46
+ parentElement.insertBefore(elementToInsert, refElement.nextSibling);
47
+ }
48
+ else {
49
+ parentElement.appendChild(elementToInsert);
50
+ }
51
+ if (animation) {
52
+ await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs);
53
+ }
54
+ }
55
+ DomeManipulator.insertAfterAsync = insertAfterAsync;
56
+ async function insertByIndexAsync(elementToInsert, index, parentElement, animation) {
57
+ if (index == 0) {
58
+ parentElement.appendChild(elementToInsert);
59
+ if (animation) {
60
+ await addCssClassAsync(elementToInsert, animation.cssClassName, animation.timeMs);
61
+ }
62
+ return;
63
+ }
64
+ await insertAfterAsync(elementToInsert, parentElement.children[index], parentElement, animation);
65
+ }
66
+ DomeManipulator.insertByIndexAsync = insertByIndexAsync;
67
+ async function replaceAsync(oldElement, newElement, animationHide, animationShow) {
68
+ if (!oldElement.parentNode) {
69
+ // almost impossible if in DOM
70
+ console.error('replaceAsync() failed, no parentNode.', 'oldElement=', oldElement);
71
+ throw new Error('no parent node for replaceAsync');
72
+ }
73
+ // hide
74
+ if (animationHide) {
75
+ await addCssClassAsync(oldElement, animationHide.cssClassName, animationHide.timeMs);
76
+ }
77
+ // replace
78
+ const parent = oldElement.parentNode;
79
+ if (!parent) {
80
+ //TODO: do not throw error here?
81
+ console.error('replaceAsync() failed, no parent. Probably node was deleted while hide animation.', 'oldElement=', oldElement, 'type=', typeof oldElement, 'parent=', oldElement.parentElement, oldElement.parentNode);
82
+ throw new Error('no parent for replaceAsync()');
83
+ }
84
+ parent.replaceChild(newElement, oldElement);
85
+ // show
86
+ if (animationShow) {
87
+ await addCssClassAsync(newElement, animationShow.cssClassName, animationShow.timeMs);
88
+ }
89
+ return newElement;
90
+ }
91
+ DomeManipulator.replaceAsync = replaceAsync;
92
+ async function removeElementAsync(element, animation) {
93
+ //console.log('#dome', 'removeELementAsync', element)
94
+ if (animation) {
95
+ //console.log('#dome', 'add animation', animation.cssClassName, animation.timeMs, element)
96
+ await addCssClassAsync(element, animation.cssClassName, animation.timeMs);
97
+ }
98
+ //console.log('#dome', 'removing from dom', element)
99
+ element.remove();
100
+ }
101
+ DomeManipulator.removeElementAsync = removeElementAsync;
102
+ function forEachChildrenOf(element, action) {
103
+ for (let i = 0; i < element.childNodes.length; i++) {
104
+ action(element.childNodes[i]);
105
+ }
106
+ }
107
+ DomeManipulator.forEachChildrenOf = forEachChildrenOf;
108
+ async function removeAllChildrenAsync(element, animation) {
109
+ // await Promise.all( //TODO: this doesn't remove text nodes
110
+ // Array.from(element.children).map(child => removeElementAsync(child, animation))
111
+ // )
112
+ if (!animation) {
113
+ while (element.firstChild) {
114
+ //element.removeChild(element.firstChild);
115
+ element.firstChild.remove();
116
+ }
117
+ //return
118
+ }
119
+ else {
120
+ //console.log('##', 'assign remove animation for each children', element.childNodes)
121
+ forEachChildrenOf(element, (child) => child.nodeType == Node.ELEMENT_NODE && child.classList.add(animation.cssClassName));
122
+ //console.log('##', 'wait ms', animation.timeMs)
123
+ await Async.waitMsAsync(animation.timeMs);
124
+ //console.log('##', 'removing children', element.childNodes)
125
+ forEachChildrenOf(element, (child) => child.remove());
126
+ //console.log('##', 'done')
127
+ }
128
+ // if(element.children.length>0) {
129
+ // console.error('DomeManipulator: removeAllChildrenAsync() failed', 'length=', element.children.length, 'children=', element.children, 'animation=', animation, 'element=', element)
130
+ // throw new Error()
131
+ // }
132
+ }
133
+ DomeManipulator.removeAllChildrenAsync = removeAllChildrenAsync;
134
+ async function appendChildAsync(containerElement, child, animation) {
135
+ containerElement.appendChild(child);
136
+ if (animation) {
137
+ await addCssClassAsync(child, animation.cssClassName, animation.timeMs);
138
+ }
139
+ }
140
+ DomeManipulator.appendChildAsync = appendChildAsync;
141
+ async function appendChildrenAsync(containerElement, children, animation) {
142
+ //console.log('DomeManipulator: appendChildrenAsync', 'containerELement=', containerElement, 'children=', children, 'animation=', animation)
143
+ if (DataTypes.isString(children)) {
144
+ // no animation for text?
145
+ containerElement.appendChild(document.createTextNode(children));
146
+ }
147
+ else if (DataTypes.isArray(children)) {
148
+ await Promise.all(children.map(child => appendChildAsync(containerElement, child, animation)));
149
+ }
150
+ else if (children) {
151
+ await appendChildAsync(containerElement, children, animation);
152
+ }
153
+ }
154
+ DomeManipulator.appendChildrenAsync = appendChildrenAsync;
155
+ async function replaceAllChildrenAsync(containerElement, childrenToInsert, animationForHide, animationForShow) {
156
+ //await removeAllChildrenAsync(containerElement, animationForHide)
157
+ if (containerElement.childNodes.length > 0) {
158
+ await removeAllChildrenAsync(containerElement, animationForHide);
159
+ }
160
+ // while(containerElement.childNodes.length>0){
161
+ // await removeAllChildrenAsync(containerElement, animationForHide) // can be executed more than once! TODO: why?
162
+ // }
163
+ // if(containerElement.children.length>0) {
164
+ // console.error('DomeManipulator: replaceAllChildenrAsync() failed:', 'containerElement.children.length=', containerElement.children.length, 'children=', containerElement.children, 'containerElement=', containerElement, 'animationForHide=', animationForHide)
165
+ // throw new Error()
166
+ // }
167
+ await appendChildrenAsync(containerElement, childrenToInsert, animationForShow);
168
+ }
169
+ DomeManipulator.replaceAllChildrenAsync = replaceAllChildrenAsync;
170
+ function isInDom(el) {
171
+ if (!el)
172
+ return false;
173
+ return document.body.contains(el);
174
+ }
175
+ DomeManipulator.isInDom = isInDom;
176
+ function isOnScreen(el) {
177
+ if (!el)
178
+ return false;
179
+ var rect = el.getBoundingClientRect();
180
+ var viewHeight = Math.max(document.documentElement.clientHeight, window.innerHeight);
181
+ return !(rect.bottom < 0 || rect.top - viewHeight >= 0);
182
+ }
183
+ DomeManipulator.isOnScreen = isOnScreen;
184
+ async function addCssClassAsync(element, cssClassName, removeAfterMs) {
185
+ if (element.nodeType !== Node.ELEMENT_NODE)
186
+ return;
187
+ element.classList.add(cssClassName);
188
+ if (removeAfterMs && removeAfterMs > 0) {
189
+ await Async.waitMsAsync(removeAfterMs);
190
+ element.classList.remove(cssClassName);
191
+ }
192
+ }
193
+ DomeManipulator.addCssClassAsync = addCssClassAsync;
194
+ async function addCssClassesAsync(element, cssClassNames, removeAfterMs) {
195
+ await Promise.all(cssClassNames.map(cssClassName => addCssClassAsync(element, cssClassName, removeAfterMs)));
196
+ }
197
+ DomeManipulator.addCssClassesAsync = addCssClassesAsync;
198
+ function removeCssClass(element, cssClassName) {
199
+ element.classList.remove(cssClassName);
200
+ }
201
+ DomeManipulator.removeCssClass = removeCssClass;
202
+ function removeCssClasses(element, cssClassNames) {
203
+ for (let cssClassName of cssClassNames) {
204
+ element.classList.remove(cssClassName);
205
+ }
206
+ }
207
+ DomeManipulator.removeCssClasses = removeCssClasses;
208
+ /**
209
+ * set css classes by array ['class1', 'class2'] or
210
+ * by object {class1:true, class2:false} or
211
+ * by Observable<boolean> {class1:true, class2:myVarO} or
212
+ * by string
213
+ * this function will replace class attribute so all classes that are not in params will be removed
214
+ * @param value
215
+ * @param element
216
+ */
217
+ function setCssClasses(element, value) {
218
+ if (!value)
219
+ return; // skip empty
220
+ if (DataTypes.isArray(value)) {
221
+ //console.log('setCssClasses', 'data is array', value)
222
+ setAttribute(element, 'class', value.join(' '));
223
+ }
224
+ else if (DataTypes.isObjectWithKeys(value)) {
225
+ //console.log('setCssClasses', 'data is object with keys', value)
226
+ let classNameArray = [];
227
+ for (let [k, v] of Object.entries(value)) {
228
+ if (checkIfObservable(v)) {
229
+ if (v.get()) {
230
+ classNameArray.push(k);
231
+ }
232
+ }
233
+ else if (v) {
234
+ classNameArray.push(k);
235
+ }
236
+ }
237
+ setAttribute(element, 'class', classNameArray.join(' '));
238
+ }
239
+ else {
240
+ //console.log('setCssClasses', 'data is unknown', value)
241
+ setAttribute(element, 'class', value);
242
+ }
243
+ }
244
+ DomeManipulator.setCssClasses = setCssClasses;
245
+ function setAttribute(element, name, value) {
246
+ if (value === undefined || value === null) {
247
+ return;
248
+ }
249
+ // Naive support for xlink namespace
250
+ // Full list: https://github.com/facebook/react/blob/1843f87/src/renderers/dom/shared/SVGDOMPropertyConfig.js#L258-L264
251
+ if (/^xlink[AHRST]/.test(name)) {
252
+ element.setAttributeNS('http://www.w3.org/1999/xlink', name.replace('xlink', 'xlink:').toLowerCase(), value);
253
+ }
254
+ else {
255
+ element.setAttribute(name, value);
256
+ }
257
+ }
258
+ DomeManipulator.setAttribute = setAttribute;
259
+ function hasFocus(el) {
260
+ return document.activeElement == el;
261
+ }
262
+ DomeManipulator.hasFocus = hasFocus;
263
+ function scrollIntoView(element, paddingFromTop = 100) {
264
+ if (isOnScreen(element)) {
265
+ return; // no need to scroll
266
+ }
267
+ //const positionBefore = getCurrentScrollPosition()
268
+ //element.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
269
+ //const positionAfter = getCurrentScrollPosition()
270
+ //console.log('before=', positionBefore, 'after=', positionAfter)
271
+ let expectedPosition = element.getBoundingClientRect().top + window.pageYOffset;
272
+ expectedPosition -= paddingFromTop;
273
+ window.scrollTo({ top: expectedPosition, behavior: 'smooth' });
274
+ }
275
+ DomeManipulator.scrollIntoView = scrollIntoView;
276
+ // https://stackoverflow.com/questions/15935318/smooth-scroll-to-top/55926067
277
+ DomeManipulator.scrollToTop = () => {
278
+ //console.log('scrollToTop')
279
+ let position = getCurrentScrollPosition();
280
+ if (position > 0) {
281
+ window.requestAnimationFrame(DomeManipulator.scrollToTop);
282
+ if (position < 20) {
283
+ window.scrollTo(0, 0);
284
+ }
285
+ else {
286
+ window.scrollTo(0, position - position / 9);
287
+ }
288
+ }
289
+ };
290
+ function getCurrentScrollPosition() {
291
+ return document.documentElement.scrollTop || document.body.scrollTop;
292
+ }
293
+ DomeManipulator.getCurrentScrollPosition = getCurrentScrollPosition;
294
+ async function scrollToAsync(p) {
295
+ //console.log('scrollToAsync', p)
296
+ const msStep = p.msStep ?? 50;
297
+ const maxMsToWait = p.maxMsToWait ?? 5000;
298
+ let scrollOptions = {};
299
+ if (p.pxFromTop) {
300
+ scrollOptions.top = p.pxFromTop;
301
+ }
302
+ if (p.pxFromLeft) {
303
+ scrollOptions.left = p.pxFromLeft;
304
+ }
305
+ if (p.smooth) {
306
+ scrollOptions.behavior = 'smooth';
307
+ }
308
+ try {
309
+ if (p.pxFromLeft || p.pxFromTop) {
310
+ await Async.waitForFunctionToReturnTrueAsync(() => {
311
+ if (p.pxFromTop) {
312
+ return document.body.scrollHeight >= p.pxFromTop;
313
+ }
314
+ if (p.pxFromLeft) {
315
+ return document.body.scrollWidth >= p.pxFromLeft;
316
+ }
317
+ return false;
318
+ }, msStep, maxMsToWait);
319
+ }
320
+ }
321
+ catch (error) {
322
+ // ignore error
323
+ }
324
+ //console.log('scrollToY', pxFromTop, 'height=', document.body.clientHeight)
325
+ //console.log('scrollToAsync now', scrollOptions)
326
+ window.scrollTo(scrollOptions);
327
+ }
328
+ DomeManipulator.scrollToAsync = scrollToAsync;
329
+ })(DomeManipulator || (DomeManipulator = {}));