@lexriver/dome 1.3.0 → 1.4.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.
- package/README.md +1 -0
- package/jest.config.js +0 -0
- package/out/AnimatedArray.d.ts +29 -27
- package/out/AnimatedArray.js +51 -44
- package/out/AnimatedTable.d.ts +38 -38
- package/out/AnimatedTable.js +91 -91
- package/out/AnimatedText.d.ts +13 -13
- package/out/AnimatedText.js +24 -24
- package/out/Animation.d.ts +4 -4
- package/out/Animation.js +0 -0
- package/out/Dome.d.ts +9 -9
- package/out/Dome.js +295 -295
- package/out/DomeComponent.d.ts +19 -19
- package/out/DomeComponent.js +44 -44
- package/out/DomeManipulator.d.ts +48 -48
- package/out/DomeManipulator.js +329 -329
- package/out/DomeRouter.console-test.d.ts +0 -0
- package/out/DomeRouter.console-test.js +44 -44
- package/out/DomeRouter.d.ts +36 -36
- package/out/DomeRouter.js +227 -227
- package/out/LongestCommonSubsequence.d.ts +15 -15
- package/out/LongestCommonSubsequence.js +164 -164
- package/out/index.d.ts +12 -12
- package/out/index.js +14 -14
- package/out/temp-test.d.ts +1 -1
- package/out/temp-test.js +20 -20
- package/package.json +1 -1
- package/src/AnimatedArray.ts +11 -0
- package/src/AnimatedTable.ts +0 -0
- package/src/AnimatedText.ts +0 -0
- package/src/Animation.ts +0 -0
- package/src/Dome.ts +0 -0
- package/src/DomeComponent.ts +0 -0
- package/src/DomeManipulator.ts +0 -0
- package/src/DomeRouter.console-test.ts +0 -0
- package/src/DomeRouter.ts +0 -0
- package/src/LongestCommonSubsequence.ts +0 -0
- package/src/index.ts +0 -0
- package/src/temp-test.ts +0 -0
- package/tsconfig.json +0 -0
package/out/DomeManipulator.js
CHANGED
|
@@ -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 { 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 = {}));
|