jj 0.1.1 → 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 (89) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +35 -7
  3. package/lib/ComponentFiles.d.ts +35 -0
  4. package/lib/ComponentFiles.js +116 -0
  5. package/lib/ComponentFiles.js.map +1 -0
  6. package/lib/WC.d.ts +33 -0
  7. package/lib/WC.js +160 -0
  8. package/lib/WC.js.map +1 -0
  9. package/lib/WDF.d.ts +11 -0
  10. package/lib/WDF.js +31 -0
  11. package/lib/WDF.js.map +1 -0
  12. package/lib/WE.d.ts +42 -0
  13. package/lib/WE.js +132 -0
  14. package/lib/WE.js.map +1 -0
  15. package/lib/WF.d.ts +14 -0
  16. package/lib/WF.js +44 -0
  17. package/lib/WF.js.map +1 -0
  18. package/lib/WHE.d.ts +21 -0
  19. package/lib/WHE.js +75 -0
  20. package/lib/WHE.js.map +1 -0
  21. package/lib/WN-mixin.d.ts +9 -0
  22. package/lib/WN-mixin.js +59 -0
  23. package/lib/WN-mixin.js.map +1 -0
  24. package/lib/WN.d.ts +34 -0
  25. package/lib/WN.js +145 -0
  26. package/lib/WN.js.map +1 -0
  27. package/lib/WS.d.ts +11 -0
  28. package/lib/WS.js +32 -0
  29. package/lib/WS.js.map +1 -0
  30. package/lib/WSH.d.ts +11 -0
  31. package/lib/WSH.js +29 -0
  32. package/lib/WSH.js.map +1 -0
  33. package/lib/WT.d.ts +12 -0
  34. package/lib/WT.js +39 -0
  35. package/lib/WT.js.map +1 -0
  36. package/lib/Welem.d.ts +49 -0
  37. package/lib/Welem.js +173 -0
  38. package/lib/Welem.js.map +1 -0
  39. package/lib/Wfrag.d.ts +15 -0
  40. package/lib/Wfrag.js +56 -0
  41. package/lib/Wfrag.js.map +1 -0
  42. package/lib/Whelem.d.ts +17 -0
  43. package/lib/Whelem.js +69 -0
  44. package/lib/Whelem.js.map +1 -0
  45. package/lib/Wnode.d.ts +6 -0
  46. package/lib/Wnode.js +33 -0
  47. package/lib/Wnode.js.map +1 -0
  48. package/lib/Wshad.d.ts +9 -0
  49. package/lib/Wshad.js +31 -0
  50. package/lib/Wshad.js.map +1 -0
  51. package/lib/bundle.js +737 -0
  52. package/lib/bundle.js.map +7 -0
  53. package/lib/bundle.min.js +3 -0
  54. package/lib/case.d.ts +3 -0
  55. package/lib/case.js +34 -0
  56. package/lib/case.js.map +1 -0
  57. package/lib/case.test.d.ts +1 -0
  58. package/lib/case.test.js +79 -0
  59. package/lib/case.test.js.map +1 -0
  60. package/lib/h.d.ts +3 -0
  61. package/lib/h.js +9 -0
  62. package/lib/h.js.map +1 -0
  63. package/lib/index.d.ts +11 -0
  64. package/lib/index.js +12 -0
  65. package/lib/index.js.map +1 -0
  66. package/lib/util.d.ts +5 -0
  67. package/lib/util.js +19 -0
  68. package/lib/util.js.map +1 -0
  69. package/lib/wrap-unwrap.d.ts +22 -0
  70. package/lib/wrap-unwrap.js +68 -0
  71. package/lib/wrap-unwrap.js.map +1 -0
  72. package/package.json +56 -26
  73. package/CSS.js +0 -145
  74. package/Router.js +0 -89
  75. package/Selector.js +0 -175
  76. package/Tag.js +0 -827
  77. package/control.js +0 -74
  78. package/dist/jj.js +0 -1580
  79. package/dist/jj.js.gz +0 -0
  80. package/dist/jj.min.js +0 -1
  81. package/dist/jj.min.js.gz +0 -0
  82. package/dist/jj.min.js.map +0 -1
  83. package/events.js +0 -16
  84. package/index.js +0 -26
  85. package/observer.js +0 -27
  86. package/rollup.config.js +0 -25
  87. package/unit.js +0 -78
  88. package/util.js +0 -153
  89. package/win.js +0 -11
package/dist/jj.js DELETED
@@ -1,1580 +0,0 @@
1
- const INDENT = ' ';
2
- const NEWLINE = '\n';
3
-
4
- function isArr(x) {
5
- return Array.isArray(x)
6
- }
7
-
8
- function arrFrom(x) {
9
- return Array.from(x)
10
- }
11
-
12
- function ind(indentation, addition = 0) {
13
- if (indentation < 0) {
14
- return ''
15
- }
16
- indentation += addition;
17
- if (ind.cache[indentation] === undefined) {
18
- ind.cache[indentation] = INDENT.repeat(indentation);
19
- }
20
- return ind.cache[indentation]
21
- }
22
- ind.cache = ['', INDENT];
23
-
24
- function nl(indentation) {
25
- return indentation < 0 ? '' : NEWLINE
26
- }
27
-
28
- function mapKeyVal(obj, fn) {
29
- return Object.entries(obj).map(([k, v]) => fn(k, v, obj))
30
- }
31
-
32
- function isObj(a) {
33
- return a && typeof a === 'object'
34
- }
35
-
36
- function isStr(a, minLength = 0) {
37
- return typeof a === 'string' && a.length >= minLength
38
- }
39
-
40
- function isNum(a) {
41
- return typeof a === 'number' && Number.isFinite(a)
42
- }
43
-
44
- function isFn(a) {
45
- return typeof a === 'function'
46
- }
47
-
48
- function camel2kebab(str) {
49
- return str.replace(/([A-Z])/g, ch => '-' + ch.toLowerCase())
50
- }
51
-
52
- function embed(start, end, ...contents) {
53
- return start + contents.join('') + end
54
- }
55
-
56
- function qut(...strArr) {
57
- const str = strArr.join('').replace('"', '\\"');
58
- return embed('"', '"', str)
59
- }
60
-
61
- function ent(entity) {
62
- if (isStr(entity)) {
63
- return '&' + entity + ';'
64
- } else if (isNum(entity) && Number.isInteger(entity)) {
65
- return `&#${entity};`
66
- }
67
- throw new TypeError(`Cannot make HTML entity from ${entity}`)
68
- }
69
-
70
- function sqBra(...strArr) {
71
- return embed('[', ']', ...strArr)
72
- }
73
-
74
- function rnd(prefix) {
75
- const randomStr = Math.random().toString(36).substr(2);
76
- // the resulting string should always start with a letter, otherwise it won't work as class or id
77
- return isStr(prefix) ? `${prefix}-${randomStr}` : randomStr
78
- }
79
-
80
- function alias(obj, aliasDic) {
81
- const prt = obj.prototype;
82
-
83
- function assignTarget(dst, src) {
84
- if (prt[dst] !== undefined) {
85
- throw new Error(`${obj.name} already has a method called ${dst}`)
86
- }
87
- prt[dst] = prt[src];
88
- }
89
-
90
- mapKeyVal(aliasDic, (src, dst) => {
91
- if (isArr(dst)) {
92
- dst.forEach(d => assignTarget(d, src));
93
- } else {
94
- assignTarget(dst, src);
95
- }
96
- });
97
- }
98
-
99
- const ranOnce = Symbol('ran once flag');
100
- function runOnce(fn, ...args) {
101
- if (isFn(fn) && !fn[ranOnce]) {
102
- fn.apply(undefined, args);
103
- fn[ranOnce] = true;
104
- }
105
- }
106
-
107
- const doc = {
108
- el(tagName, ns) {
109
- return isStr(ns) ? document.createElementNS(ns, tagName) : document.createElement(tagName)
110
- },
111
- frag() {
112
- return document.createDocumentFragment()
113
- },
114
- text(...strArr) {
115
- return document.createTextNode(String(strArr.flat().join('')))
116
- },
117
- comm(...strArr) {
118
- return document.createComment(String(strArr.flat().join('')))
119
- },
120
- get body() {
121
- return document.body
122
- },
123
- get head() {
124
- return document.body.head
125
- },
126
- };
127
-
128
- function isComponent(obj) {
129
- return isObj(obj) && isObj(obj.root)
130
- }
131
-
132
- class Dim {
133
- constructor(value, unit) {
134
- if (isStr(value)) {
135
- this.parse(value);
136
- } else {
137
- this.value = value;
138
- this.unit = unit;
139
- }
140
- }
141
-
142
- clone() {
143
- return new Dim(this.value, this.unit)
144
- }
145
-
146
- parse(str) {
147
- const parts = str.match(/([-+]?[0-9.]+)([%\w]*)/);
148
- if (parts) {
149
- const [, value, unit] = parts;
150
- this.value = value;
151
- this.unit = unit;
152
- }
153
- throw new SyntaxError(`Could not parse ${str} as a CSS Dimention`)
154
- }
155
-
156
- toString() {
157
- return `${this.value}${this.unit}`
158
- }
159
-
160
- [Symbol.toPrimitive](hint) {
161
- if (hint === 'string') {
162
- return this.toString()
163
- }
164
- return this.value
165
- }
166
- }
167
-
168
- alias(Dim, {
169
- toString: 'toJSON'
170
- });
171
-
172
- function isDim(val) {
173
- return val instanceof Dim
174
- }
175
-
176
- function perc(num) {
177
- return new Dim(num, '%')
178
- }
179
-
180
- function em(num) {
181
- return new Dim(num, 'em')
182
- }
183
-
184
- function rem(num) {
185
- return new Dim(num, 'rem')
186
- }
187
-
188
- function px(num) {
189
- return new Dim(num, 'px')
190
- }
191
-
192
- function vh(num) {
193
- return new Dim(num, 'vh')
194
- }
195
-
196
- function vw(num) {
197
- return new Dim(num, 'vw')
198
- }
199
-
200
- function col(r, g, b, a) {
201
- if (g === undefined && b === undefined && a === undefined) {
202
- if (isStr(r, 1)) {
203
- return `#${r}`
204
- }
205
- }
206
- throw new Error('TODO: Use case not implemented yet')
207
- }
208
-
209
- class Selector {
210
- constructor(selector = '') {
211
- this.selector = selector;
212
- }
213
-
214
- toString() {
215
- return this.selector
216
- }
217
-
218
- css(ruleObj) {
219
- return { [this.selector]: ruleObj }
220
- }
221
-
222
- clone() {
223
- return new Selector(this.selector)
224
- }
225
-
226
- append(...str) {
227
- if (str.length) {
228
- this.selector += str.map(s => isSel(s) ? s.selector : s).join('');
229
- }
230
- return this
231
- }
232
-
233
- at(str) {
234
- return this.append('@', str)
235
- }
236
-
237
- get _() {
238
- return this.append(' ')
239
- }
240
-
241
- // [attribute] [target] Selects all elements with a target attribute
242
- // [attribute=value] [target=_blank] Selects all elements with target="_blank"
243
- attr(attrName, attrValue) {
244
- return attrValue === undefined ?
245
- this.append(sqBra(attrName)) :
246
- this.append(sqBra(attrName, '=', qut(attrValue)))
247
- }
248
-
249
- // [attribute~=value] [title~=flower] Selects all elements with a title attribute containing the word "flower"
250
- attrValArrContains(attrName, attrValue) {
251
- return this.append(sqBra(attrName, '~=', qut(attrValue)))
252
- }
253
-
254
- // [attribute^=value] a[href^="https"] Selects every <a> element whose href attribute value begins with "https"
255
- attrValStartsWith(attrName, attrValue) {
256
- return this.append(sqBra(attrName, '^=', qut(attrValue)))
257
- }
258
-
259
- // [attribute$=value] a[href$=".pdf"] Selects every <a> element whose href attribute value ends with ".pdf"
260
- attrValEndsWith(attrName, attrValue) {
261
- return this.append(sqBra(attrName, '$=', qut(attrValue)))
262
- }
263
-
264
- // [attribute*=value] a[href*="w3schools"] Selects every <a> element whose href attribute value contains the substring "w3schools"
265
- attrValContains(attrName, attrValue) {
266
- return this.append(sqBra(attrName, '*=', qut(attrValue)))
267
- }
268
-
269
- class(...classNames) {
270
- classNames.forEach(c => this.append('.', c));
271
- return this
272
- }
273
-
274
- BEM(block, element, modifier) {
275
- this.B(block);
276
- if (element !== undefined) {
277
- this.E(element);
278
- }
279
- if (modifier !== undefined) {
280
- this.M(modifier);
281
- }
282
- return this
283
- }
284
-
285
- E(element) {
286
- return this.append('__', element)
287
- }
288
-
289
- M(modifier) {
290
- return this.append('--', modifier)
291
- }
292
-
293
- id(idString) {
294
- return this.append('#', idString)
295
- }
296
-
297
- pClass(pseudo) {
298
- return this.append(':', pseudo)
299
- }
300
-
301
- pEl(pseudo) {
302
- return this.append('::', pseudo)
303
- }
304
-
305
- par(...str) {
306
- return this.append('(', ...str, ')')
307
- }
308
-
309
- prop(prop, val) {
310
- return this.par(prop, ':', val)
311
- }
312
-
313
- nthChild(str) {
314
- return this.pClass(`nth-child(${str})`)
315
- }
316
-
317
- firstChild() {
318
- return this.pClass(`first-child`)
319
- }
320
-
321
- rnd(prefix = '') {
322
- return this.append(rnd(prefix))
323
- }
324
-
325
- [Symbol.toPrimitive](hint) {
326
- if (hint === 'string') {
327
- return this.toString()
328
- }
329
- return this.value
330
- }
331
- }
332
-
333
- // B, E, M are for Block Element Modifier: http://getbem.com/introduction/
334
- alias(Selector, {
335
- class: 'B',
336
- append: ['add', 'el', 'tag', 'com', 'cond', 'star', 'all', 'sel', 'concat'],
337
- });
338
-
339
- const shortHands = {
340
- [Symbol.toPrimitive]: 'toString',
341
- '>': ['gt', 'parentOf'],
342
- '*': ['star', 'all'],
343
- '~': ['tilde', 'precedes'],
344
- '+': ['plus', 'followedBy'],
345
- ',': ['comma', 'or'],
346
- // TODO: there's :not() pseudo-class as well and that one takes a selector
347
- 'not': ['not'],
348
- 'only': ['only'],
349
- 'and': ['and'],
350
- };
351
-
352
- mapKeyVal(shortHands, (str, vals) => {
353
- vals.forEach(v => {
354
- Selector.prototype[v] = function () {
355
- return this.append(str)
356
- };
357
- });
358
- });
359
-
360
- function isSel(v) {
361
- return v instanceof Selector
362
- }
363
-
364
- function _sel(param) {
365
- if (isSel(param)) {
366
- return param
367
- }
368
- return new Selector(param)
369
- }
370
-
371
- const sel = new Proxy(_sel, {
372
- get(_sel, prop) {
373
- const selector = new Selector();
374
- if (prop in selector) {
375
- return selector[prop]
376
- } else {
377
- selector.append(prop);
378
- return selector
379
- }
380
- }
381
- });
382
-
383
- function parseRangeArguments(arr) {
384
- if (arr.length < 2) {
385
- throw new TypeError(`Expected at least 2 arguments but got ${arr}`)
386
- }
387
- if (!isNum(arr[0])) {
388
- throw new TypeError(`The first argument must be a number but got ${arr[0]}`)
389
- }
390
- if (isFn(arr[1])) {
391
- // range(end, fn, ...extraParams)
392
- const [ end, fn, ...extraParams ] = arr;
393
- return { start: 0, end, step: 1, fn, extraParams }
394
- } else if (isFn(arr[2])) {
395
- // range(start, end, fn, ...extraParams)
396
- const [ start, end, fn, ...extraParams ] = arr;
397
- return { start, end, step: 1, fn, extraParams }
398
- } else if (isFn(arr[3])) {
399
- // // range(start, end, step, fn, ...extraParams)
400
- const [ start, end, step, fn, ...extraParams ] = arr;
401
- return { start, end, step, fn, extraParams }
402
- }
403
- throw new TypeError(`Which function do you want to run? Got ${arr}`)
404
- }
405
-
406
- const control = {
407
- /**
408
- * @remark if inside the function you need to refer to the tag (exposed as `this`), just remember
409
- * to use a classic function instead of an arrow function
410
- */
411
- if(condition, fn, ...extraParams) {
412
- if (condition) {
413
- return this.run(fn, ...extraParams)
414
- }
415
- return this
416
- },
417
-
418
- forEach(arr, fn, ...extraParams) {
419
- arr.forEach(item => {
420
- this.run(fn, item, ...extraParams);
421
- });
422
-
423
- return this
424
- },
425
-
426
- times(n, fn, ...extraParams) {
427
- return this.range(1, n + 1, 1, fn, ...extraParams)
428
- },
429
-
430
- // range(start, end, step, fn, ...extraParams)
431
- // range(start, end, fn, ...extraParams) // step = 1
432
- // range(end, fn, ...extraParams) // start = 0, step = 1
433
- range() {
434
- const { start, end, step, fn, extraParams } = parseRangeArguments(Array.from(arguments));
435
- if (!isNum(start) || !isNum(end) || !isNum(step)) {
436
- throw new TypeError(`Expected numbers but got: start=${start}, end=${end}, step=${step}`)
437
- }
438
- if (step === 0) {
439
- throw new Error(`The step cannot be zero`)
440
- }
441
- if ((start < end && step < 0) || (start > end && step > 0)) {
442
- throw new Error(`This loop will never end: start=${start}, end=${end}, step=${step}`)
443
- }
444
- for (let i = start; i < end; i += step) {
445
- this.run(fn, i, ...extraParams);
446
- }
447
- return this
448
- },
449
-
450
- run(fn, ...extraParams) {
451
- fn.call(this, this, ...extraParams);
452
- return this
453
- },
454
- };
455
-
456
- const events = {
457
- on(eventName, handler) {
458
- this.el.addEventListener(eventName, handler);
459
- return this
460
- },
461
-
462
- once(eventName, handler) {
463
- this.el.addEventListener(eventName, handler, { once: true });
464
- return this
465
- },
466
-
467
- off(eventName, handler) {
468
- this.el.removeEventListener(eventName, handler);
469
- return this
470
- }
471
- };
472
-
473
- function isAtRule(selectorTxt) {
474
- return selectorTxt.trimLeft().startsWith('@')
475
- }
476
-
477
- function toValue(val) {
478
- if (isStr(val)) {
479
- if (val.trim() === '') {
480
- return qut(val)
481
- }
482
- return val
483
- }
484
- if (isNum(val)) {
485
- return String(val)
486
- }
487
- if (isDim(val)) {
488
- return String(val)
489
- } else if (isArr(val)) {
490
- return val.join(' ')
491
- }
492
- }
493
-
494
- function extractRules(selectorTxt, bodyObj) {
495
- const baseRule = new SimpleRule(selectorTxt);
496
- const ownProps = baseRule.bodyObj;
497
- const nestedRules = [baseRule];
498
- mapKeyVal(bodyObj, (key, val) => {
499
- const v = toValue(val);
500
- if (v !== undefined) {
501
- ownProps[key] = v;
502
- } else if (isAtRule(key)) {
503
- nestedRules.push(new WrapperRule(key, { [selectorTxt]: val }));
504
- } else {
505
- let nestedSelectorTxt = key.replace(/&/g, selectorTxt);
506
- if (nestedSelectorTxt === key) {
507
- // No & was present, so the replacement didn't do anything. Nest the selectors
508
- nestedSelectorTxt = selectorTxt + ' ' + key;
509
- }
510
- nestedRules.push(new NestedRule(nestedSelectorTxt, val));
511
- }
512
- });
513
- return nestedRules
514
- }
515
-
516
- function propVal(indentation, prop, val) {
517
- const colon = indentation < 0 ? ':' : ': ';
518
- return camel2kebab(prop)
519
- + colon
520
- + toValue(val)
521
- + ';'
522
- }
523
-
524
- class SimpleRule {
525
- constructor(selectorTxt, bodyObj = {}) {
526
- this.selectorTxt = selectorTxt;
527
- this.bodyObj = bodyObj;
528
- }
529
-
530
- get isEmpty() {
531
- return Object.keys(this.bodyObj).length === 0
532
- }
533
-
534
- toString(indentation = 0) {
535
- if (this.isEmpty) {
536
- return indentation >= 0 ? ind(indentation) + `/* ${this.selectorTxt} {} */`: ''
537
- }
538
- let ret = ind(indentation) + this.selectorTxt;
539
- if (indentation >= 0) {
540
- ret += ' ';
541
- }
542
- ret += '{' + nl(indentation);
543
- const space = ind(indentation, 1);
544
- ret += mapKeyVal(this.bodyObj, (key, val) => space + propVal(indentation, key, val))
545
- .join(nl(indentation));
546
- if (indentation >= 0) {
547
- ret += nl(indentation) + ind(indentation);
548
- }
549
- ret += '}';
550
- return ret
551
- }
552
- }
553
-
554
- class NestedRule {
555
- constructor(selectorTxt, bodyObj) {
556
- this.selectorTxt = selectorTxt;
557
- this.bodyObj = bodyObj;
558
- }
559
-
560
- toString(indentation = 0) {
561
- if (isObj(this.bodyObj)) {
562
- return extractRules(this.selectorTxt, this.bodyObj)
563
- .map(rule => rule.toString(indentation))
564
- .join(nl(indentation))
565
- }
566
- const v = toValue(this.bodyObj);
567
- if (v !== undefined) {
568
- return ind(indentation) + propVal(indentation, this.selectorTxt, v)
569
- }
570
- return ind(indentation) + this.selectorTxt
571
- }
572
- }
573
-
574
- class WrapperRule {
575
- constructor(selectorTxt, ruleSet) {
576
- this.selectorTxt = selectorTxt;
577
- this.ruleSet = ruleSet;
578
- }
579
-
580
- toString(indentation = 0) {
581
- let ret = ind(indentation) + this.selectorTxt;
582
- if (isObj(this.ruleSet)) {
583
- const childIndentation = indentation >= 0 ? indentation + 1 : -1;
584
- if (indentation >= 0) {
585
- ret += ' ';
586
- }
587
- ret += '{' + nl(indentation);
588
- ret += objToRulesArr(this.ruleSet)
589
- .map(rule => rule.toString(childIndentation))
590
- .join(nl(indentation));
591
- ret += nl(indentation);
592
- ret += ind(indentation) + '}';
593
- } else {
594
- ret += ';';
595
- }
596
- return ret
597
- }
598
- }
599
-
600
- function objToRulesArr(obj) {
601
- if (!isObj(obj)){
602
- if (isStr(obj)) {
603
- obj = { [obj]: null };
604
- } else {
605
- throw new TypeError(`Invalid style descriptor: ${obj}`)
606
- }
607
- }
608
- return mapKeyVal(obj, (selectorTxt, bodyObj) => {
609
- if (isAtRule(selectorTxt)) {
610
- return new WrapperRule(selectorTxt, bodyObj)
611
- }
612
- return new NestedRule(selectorTxt, bodyObj)
613
- })
614
- }
615
-
616
- class Window {
617
- constructor(windowRef) {
618
- this.el = windowRef;
619
- }
620
- }
621
-
622
- Object.assign(Window.prototype, events);
623
-
624
- const win = new Window(window);
625
-
626
- function match(regexp, pathname) {
627
- if(isStr(regexp)) {
628
- console.log('boo', regexp, pathname);
629
- return regexp === pathname
630
- }
631
- if (regexp instanceof RegExp) {
632
- const parseResult = pathname.match(regexp);
633
- return parseResult || false
634
- }
635
- throw new TypeError(`Invalid route regexp: ${regexp}`)
636
- }
637
-
638
- const rootRouterMap = new WeakMap();
639
-
640
- class Router {
641
- constructor(root) {
642
- if (!isObj(root) || !isFn(root.run)) {
643
- throw new Error(`Root must have a run method but got ${root}`)
644
- }
645
- this.routes = [];
646
- this.root = root;
647
- this.isMatched = false;
648
- rootRouterMap.set(root, this);
649
-
650
- const matchThis = (state) => this.runMatches(state);
651
- win.on('popstate', matchThis).on('hashchange', matchThis);
652
- }
653
-
654
- addRoute(regexp, handler) {
655
- if (isFn(this.defRouteHandler)) {
656
- throw new Error(`Cannot add a route after the default route is set`)
657
- }
658
- if (!isFn(handler)) {
659
- throw new TypeError(`Expected a route handler function but got ${handler}`)
660
- }
661
- const newRoute = { regexp, handler };
662
- this.routes.push(newRoute);
663
- if (!this.isMatched) {
664
- this._runRoute(undefined, newRoute);
665
- }
666
- return this
667
- }
668
-
669
- addDefRoute(handler) {
670
- if (isFn(this.defRouteHandler)) {
671
- throw new Error(`There is already a default route handler`)
672
- }
673
- if (!isFn(handler)) {
674
- throw new TypeError(`Expected a default route handler function but got ${handler}`)
675
- }
676
- this.defRouteHandler = handler;
677
- if (!this.isMatched) {
678
- this._runDefRoute();
679
- }
680
- return this
681
- }
682
-
683
- _runRoute(state, { regexp, handler}, pathname = window.location.pathname) {
684
- const matchResult = match(regexp, pathname);
685
- if (matchResult) {
686
- this.isMatched = true;
687
- this.root.run(handler, state, matchResult);
688
- }
689
- return !!matchResult
690
- }
691
-
692
- _runDefRoute() {
693
- this.root.run(this.defRouteHandler);
694
- return this
695
- }
696
-
697
- runMatches(state, pathname = window.location.pathname) {
698
- const someRouteMatched = this.routes.some(route => this._runRoute(state, route, pathname));
699
- if (!someRouteMatched) {
700
- return this._runDefRoute()
701
- }
702
- return this
703
- }
704
- }
705
-
706
- function router(root) {
707
- if (!isObj(root) || !isFn(root.run)) {
708
- throw new TypeError(`root should be a Tag instance. Got ${root}`)
709
- }
710
- return rootRouterMap.get(root) || new Router(root)
711
- }
712
-
713
- const HTTP_WWW_W3_ORG = 'http://www.w3.org/';
714
- const SVG_NS = HTTP_WWW_W3_ORG + '2000/svg';
715
- const MATH_NS = HTTP_WWW_W3_ORG + '1998/mathml';
716
- const jaTag = Symbol('jaTag');
717
-
718
- const STYLE = 'style';
719
- const HIDDEN = 'hidden';
720
- const MOUSE = 'mouse';
721
-
722
- class Node {
723
- constructor(el) {
724
- if (isObj(el) && Node.validNodeTypes.includes(el.nodeType)) {
725
- this.el = el;
726
- } else {
727
- throw new TypeError(`Invalid parameter to Node constructor: ${el}`)
728
- }
729
- }
730
-
731
- mount(rootTagOrEl) {
732
- const root = toTag(rootTagOrEl);
733
- return root.setChild(this)
734
- }
735
-
736
- addTo(targetElement) {
737
- toTag(targetElement).append(this);
738
- return this
739
- }
740
-
741
- addToHead() {
742
- return this.appendTo(document.head)
743
- }
744
-
745
- addToBody() {
746
- return this.appendTo(document.body)
747
- }
748
-
749
- preTo(targetElement) {
750
- toTag(targetElement).prepend(this);
751
- return this
752
- }
753
-
754
- addComment(str) {
755
- this.append(doc.comm(str));
756
- return this.norm()
757
- }
758
-
759
- preComment(str) {
760
- this.prepend(doc.comm(str));
761
- return this.norm()
762
- }
763
-
764
- //#region child
765
- addChildren(...children) {
766
- if (children.length) {
767
- this.el.append(toNativeFrag(...children));
768
- }
769
- return this
770
- }
771
-
772
- preChildren(...children) {
773
- if (children.length) {
774
- this.el.prepend(toNativeFrag(...children));
775
- }
776
- return this
777
- }
778
-
779
- // TODO: Clean data and events
780
- // https://github.com/jquery/jquery/blob/438b1a3e8a52d3e4efd8aba45498477038849c97/src/manipulation.js#L355
781
- // https://github.com/jquery/jquery/blob/438b1a3e8a52d3e4efd8aba45498477038849c97/src/manipulation.js#L265
782
- rmChildren(...children) {
783
- if (children.length) {
784
- children.map(child => toNativeEl(child)).forEach(nativeChild => this.el.removeChild(nativeChild));
785
- } else {
786
- while(this.el.firstChild){
787
- this.el.removeChild(this.el.firstChild);
788
- }
789
- }
790
- return this
791
- }
792
-
793
- setChildren(...children) {
794
- this.empty().addChildren(...children);
795
- return this
796
- }
797
-
798
- getChildren() {
799
- return arrFrom(this.el.childNodes).map(childNode => toTag(childNode))
800
- }
801
-
802
- hasChildren(...children) {
803
- if (children.length === 0) {
804
- return this.el.hasChildren
805
- }
806
- return children.every(child => this.el.contains(toNativeEl(child)))
807
- }
808
- //#endregion child
809
-
810
- //#region text
811
- addText(...strings) {
812
- strings.flat().forEach(str => this.append(doc.text(str)));
813
- return this.norm()
814
- }
815
-
816
- preText(...strings) {
817
- strings.flat().forEach(str => this.prepend(doc.text(str)));
818
- return this.norm()
819
- }
820
-
821
- rmText() {
822
- this.childNodes.filter(c => c instanceof Text).forEach(c => c.remove());
823
- return this
824
- }
825
-
826
- setText(...strings) {
827
- return this.rmText().addText(...strings)
828
- }
829
-
830
- json(obj) {
831
- return this.setText(JSON.stringify(obj, null, 2))
832
- }
833
-
834
- getText() {
835
- return this.childNodes.map(c => c instanceof Text ? c.wholeText : '').join('')
836
- }
837
-
838
- hasText() {
839
- return this.childNodes.some(c => c instanceof Text)
840
- }
841
-
842
- normText() {
843
- this.el.normalize();
844
- return this
845
- }
846
- //#endregion text
847
-
848
- //#region query
849
- queryId(id) {
850
- const result = this.el.getElementById(id);
851
- if (result) {
852
- return toTag(result)
853
- }
854
- }
855
-
856
- query(selector) {
857
- const result = this.el.querySelector(selector);
858
- if (result) {
859
- return toTag(result)
860
- }
861
- }
862
-
863
- queryAll(selector) {
864
- const result = arrFrom(this.el.querySelectorAll(selector));
865
- if (result) {
866
- return result.map(r => toTag(r))
867
- }
868
- }
869
- //#endregion query
870
-
871
- toString() {
872
- return this.el.outerHTML
873
- }
874
- }
875
-
876
- alias(Node, {
877
- addTo: ['appendTo'],
878
- addToHead: 'appendToHead',
879
- addToBody: 'appendToBody',
880
- addComment: 'comment',
881
- preTo: ['prependTo'],
882
- setChildren: ['setChild'],
883
- addChildren: ['append', 'children', 'child', 'addChild'],
884
- preChildren: ['prepend', 'prependChildren', 'prependChild'],
885
- addText: ['text'],
886
- normText: ['norm'],
887
- rmChildren: ['empty', 'clear', 'rmChild'],
888
- toString: 'stringify',
889
- });
890
-
891
- class Frag extends Node {
892
- constructor() {
893
- super(doc.frag());
894
- }
895
-
896
- clone(deep) {
897
- return new Frag(this.el.cloneNode(deep))
898
- }
899
- }
900
-
901
- function frag(...children) {
902
- const ret = new Frag();
903
- ret.append(children);
904
- return ret
905
- }
906
-
907
- // See: https://developer.mozilla.org/en-US/docs/Web/API/Node
908
- Node.validNodeTypes = [1, 9, 11];
909
-
910
- class Tag extends Node {
911
- constructor(x) {
912
- // TODO if x is a Tag, we're essentially creating two tag objects pointing to the same native element!
913
- super(x instanceof Tag ? x.el : x);
914
- }
915
-
916
- clone(deep) {
917
- return new Tag(this.el.cloneNode(deep))
918
- }
919
-
920
- get parent() {
921
- return toTag(this.el.parentElement)
922
- }
923
-
924
- get ns() {
925
- return this.el.namespaceURI
926
- }
927
-
928
- get classList() {
929
- return this.el.classList
930
- }
931
-
932
- get childNodes() {
933
- return arrFrom(this.el.childNodes)
934
- }
935
-
936
- style(styles) {
937
- if (isObj(styles)) {
938
- mapKeyVal(styles, (k, v) => this.el.style[k] = v);
939
- } else {
940
- this.rmProp(STYLE);
941
- }
942
- return this
943
- }
944
-
945
- //#region class
946
- setClasses(...classNames) {
947
- this.el.className = classNames.join(' ');
948
- }
949
-
950
- getClass() {
951
- return this.el.className
952
- }
953
-
954
- getClasses() {
955
- return arrFrom(this.el.className)
956
- }
957
-
958
- hasClasses(...classNames) {
959
- return classNames.every(className => this.classList.contains(className))
960
- }
961
-
962
- addClasses(...classNames) {
963
- this.classList.add(...classNames);
964
- return this
965
- }
966
-
967
- rmClasses(...classNames) {
968
- this.classList.remove(...classNames);
969
- return this
970
- }
971
-
972
- mvClass(oldClassName, newClassName) {
973
- this.classList.replace(oldClassName, newClassName);
974
- return this
975
- }
976
-
977
- mvClasses(classNamesDic) {
978
- mapKeyVal(classNamesDic, (oldClassName, newClassName) => this.mvClass(oldClassName, newClassName));
979
- return this
980
- }
981
-
982
- togClass(className, force) {
983
- this.classList.toggle(className, force);
984
- return this
985
- }
986
-
987
- togClassObj(classNameDic) {
988
- mapKeyVal(classNameDic, (className, force) => this.togClass(className, force));
989
- return this
990
- }
991
-
992
- togClasses(...classNames) {
993
- classNames.forEach(className => this.togClass(className));
994
- return this
995
- }
996
- //#endregion class
997
-
998
- //#region attr
999
- setAttr(attrName, attrValue) {
1000
- if (attrName.toLowerCase() === STYLE) {
1001
- return this.style(attrValue)
1002
- }
1003
- if (attrValue === undefined) {
1004
- attrValue = '';
1005
- }
1006
- this.el.setAttribute(attrName, attrValue);
1007
- return this
1008
- }
1009
-
1010
- setAttrs(attrsDic) {
1011
- if (!isObj(attrsDic)) {
1012
- throw new TypeError(`Expected an object but got ${attrsDic}`)
1013
- }
1014
- mapKeyVal(attrsDic, (attrName, attrValue) => this.setAttr(attrName, attrValue));
1015
- return this
1016
- }
1017
-
1018
- getAttr(attrName) {
1019
- return this.el.getAttribute(attrName)
1020
- }
1021
-
1022
- getAttrs(...attrNames) {
1023
- return Object.fromEntries(
1024
- attrNames.map(attrName => [attrName, this.getAttr(attrName)])
1025
- )
1026
- }
1027
-
1028
- hasAttrs(...attrNames) {
1029
- return attrNames.every(attrName => this.this.el.hasAttribute(attrName))
1030
- }
1031
-
1032
- rmAttrs(...attrNames) {
1033
- attrNames.forEach((attrName) => {
1034
- this.el.removeAttribute(attrName);
1035
- });
1036
- return this
1037
- }
1038
-
1039
- togAttr(attrName, force) {
1040
- this.el.toggleAttribute(attrName, force);
1041
- return this
1042
- }
1043
- //#endregion attr
1044
-
1045
- //#region prop
1046
- setProp(propName, propValue) {
1047
- if (propName.toLowerCase() === STYLE) {
1048
- return this.style(propValue)
1049
- }
1050
- this.el[propName] = propValue;
1051
- return this
1052
- }
1053
-
1054
- setPropsObj(propsDic) {
1055
- mapKeyVal(propsDic, (propName, propValue) => this.setProp(propName, propValue));
1056
- return this
1057
- }
1058
-
1059
- getProp(propName) {
1060
- return this.el[propName]
1061
- }
1062
-
1063
- getPropsObj(...propNames) {
1064
- return Object.fromEntries(
1065
- propNames.map(propName => [propName, this.getProp(propName)])
1066
- )
1067
- }
1068
-
1069
- hasProps(...propNames) {
1070
- return propNames.every(propName => propName in this.el)
1071
- }
1072
-
1073
- rmProps(...propNames) {
1074
- propNames.forEach((propName) => {
1075
- try {
1076
- delete this.el[propName];
1077
- }
1078
- catch (e) {
1079
- this.el[propName] = undefined;
1080
- }
1081
- });
1082
- return this
1083
- }
1084
-
1085
- togProp(propName, force = false) {
1086
- if (arguments.length === 2) {
1087
- this.setProp(propName, !!force);
1088
- } else {
1089
- this.setProp(propName, !!this.getProp(propName));
1090
- }
1091
- return this
1092
- }
1093
- //#endregion prop
1094
-
1095
- //#region data
1096
- setData(name, value) {
1097
- this.el.dataset[name] = value;
1098
- return this
1099
- }
1100
-
1101
- setDataObj(dataDic) {
1102
- mapKeyVal(dataDic, (name, value) => this.setData(name, value));
1103
- return this
1104
- }
1105
-
1106
- getData(name) {
1107
- return this.el.dataset[name]
1108
- }
1109
-
1110
- getDataObj(...names) {
1111
- return Object.fromEntries(names.map(name => [name, this.getData(name)]))
1112
- }
1113
-
1114
- hasData(name) {
1115
- return name in this.el.dataset
1116
- }
1117
-
1118
- rmData(name) {
1119
- return delete this.el.dataset[name]
1120
- }
1121
- //#endregion data
1122
-
1123
- //#region visibility
1124
- tog(show) {
1125
- if (arguments.length === 1) {
1126
- return this.togProp(HIDDEN, !show)
1127
- }
1128
- return this.togProp(HIDDEN)
1129
- }
1130
-
1131
- hide() {
1132
- return this.setProp(HIDDEN, false)
1133
- }
1134
-
1135
- show() {
1136
- return this.setProp(HIDDEN, true)
1137
- }
1138
- //#endregion visibility
1139
-
1140
- //#region query
1141
- closest(selector) {
1142
- return this.el.closest(selector) || undefined
1143
- }
1144
-
1145
- matches(selector) {
1146
- return this.el.matches(selector)
1147
- }
1148
- //#endregion query
1149
-
1150
- //#reguin animation
1151
- animFrame(fn, ...extraParams) {
1152
- // TODO we should throw if a loop is already running (or merge loops)
1153
- const runFn = () => {
1154
- if (this.isAttached()) {
1155
- this.run(fn, ...extraParams);
1156
- }
1157
- scheduleCall();
1158
- };
1159
-
1160
- const scheduleCall = () => {
1161
- this.animFrameRequestId = window.requestAnimationFrame(runFn);
1162
- };
1163
-
1164
- scheduleCall();
1165
- return this
1166
- }
1167
-
1168
- clearAnimFrame() {
1169
- window.requestAnimationFrame(this.animFrameRequestId);
1170
- return this
1171
- }
1172
- //#endregion animation
1173
-
1174
- //#region routing
1175
- route(regex, fn) {
1176
- router(this).addRoute(regex, fn);
1177
- return this
1178
- }
1179
-
1180
- defRoute(fn) {
1181
- router(this).addDefRoute(fn);
1182
- return this
1183
- }
1184
- //#endregion routing
1185
-
1186
- css(cssRef, prefix, styles) {
1187
- if (styles === undefined) {
1188
- styles = prefix;
1189
- prefix = undefined;
1190
- }
1191
- if (!(cssRef instanceof StyleTag)) {
1192
- throw new Error(`Expected an instance of StyleTag but got ${cssRef}`)
1193
- }
1194
- const rndClassName = rnd(prefix);
1195
- this.addClass(rndClassName);
1196
- cssRef.append(
1197
- sel().class(rndClassName).css(styles)
1198
- );
1199
- return this
1200
- }
1201
-
1202
- aria(noun, value) {
1203
- return this.setAttr(`aria-${noun}`, value)
1204
- }
1205
-
1206
- wrap(wrapper) {
1207
- wrapper = toTag(wrapper);
1208
- return wrapper.append(this)
1209
- }
1210
-
1211
- swap(otherTag) {
1212
- this.el.replaceWith(otherTag.el);
1213
- return otherTag
1214
- }
1215
-
1216
- isAttached() {
1217
- return document.documentElement.contains(this.el)
1218
- }
1219
-
1220
- queryId(id) {
1221
- const result = this.el.querySelector('#' + id);
1222
- if (result) {
1223
- return toTag(result)
1224
- }
1225
- }
1226
-
1227
- toString() {
1228
- return this.el.outerHTML
1229
- }
1230
- }
1231
-
1232
- Object.assign(Tag.prototype, control, events);
1233
-
1234
- const attrShorthands = [
1235
- 'alt',
1236
- 'aria-role',
1237
- 'checked',
1238
- 'content',
1239
- 'height',
1240
- HIDDEN,
1241
- 'href',
1242
- 'htmlFor',
1243
- 'id',
1244
- 'is',
1245
- 'label',
1246
- 'lang',
1247
- 'name',
1248
- 'placeholder',
1249
- 'readonly',
1250
- 'rel',
1251
- 'required',
1252
- 'role',
1253
- 'selected',
1254
- 'src',
1255
- 'title',
1256
- 'type',
1257
- 'value',
1258
- 'width',
1259
- ];
1260
-
1261
- attrShorthands.forEach(attrName => {
1262
- Tag.prototype[attrName] = function (attrValue) {
1263
- return this.setAttr(attrName, attrValue)
1264
- };
1265
- });
1266
-
1267
- const eventShorthands = [
1268
- 'attached',
1269
- 'blur',
1270
- 'change',
1271
- 'click',
1272
- 'contextmenu',
1273
- 'dblclick',
1274
- 'detached',
1275
- 'error',
1276
- 'focus',
1277
- 'focusout',
1278
- 'hover',
1279
- 'keydown',
1280
- 'keydpress',
1281
- 'keydup',
1282
- 'load',
1283
- MOUSE + 'down',
1284
- MOUSE + 'enter',
1285
- MOUSE + 'leave',
1286
- MOUSE + 'move',
1287
- MOUSE + 'out',
1288
- MOUSE + 'over',
1289
- MOUSE + 'up',
1290
- 'resize',
1291
- 'scroll',
1292
- 'select',
1293
- 'submit',
1294
- 'unload',
1295
- ];
1296
-
1297
- eventShorthands.forEach(eventName => {
1298
- Tag.prototype[eventName] = function (...handlers) {
1299
- this.on(eventName, ...handlers);
1300
- return this
1301
- };
1302
- });
1303
-
1304
- alias(Tag, {
1305
- addClasses: ['addClass', 'class', 'classes'],
1306
- class: 'className',
1307
- hasClasses: 'hasClass',
1308
- rmClasses: 'rmClass',
1309
- setClasses: 'setClass',
1310
- togClass: 'toggleClass',
1311
-
1312
- hasAttrs: 'hasAttr',
1313
- rmAttrs: 'rmAttr',
1314
- setAttr: 'attr',
1315
- setAttrs: 'attrs',
1316
- togAttr: 'toggleAttr',
1317
-
1318
- hasProps: 'hasProp',
1319
- rmProps: 'rmProp',
1320
- setProp: 'prop',
1321
- setProps: 'props',
1322
-
1323
- tog: 'toggle',
1324
- swap: ['swapWith', 'replaceWith', 'replace'],
1325
-
1326
- value: 'val',
1327
- htmlFor: 'for',
1328
- });
1329
-
1330
- class StyleTag {
1331
- constructor(...rulesetObjArr) {
1332
- this.rulesetObjArr = rulesetObjArr;
1333
- }
1334
-
1335
- get isAttached() {
1336
- return this._root && this._root.isAttached()
1337
- }
1338
-
1339
- get root() {
1340
- if (!this._root) {
1341
- this._root = html(STYLE)
1342
- .type('text/css')
1343
- .rel('stylesheet')
1344
- .on('attached', () => this.update());
1345
- }
1346
- return this._root
1347
- }
1348
-
1349
- appendToHead() {
1350
- if (!document.head.contains(this.root.el)) {
1351
- this.root.appendToHead();
1352
- }
1353
- return this
1354
- }
1355
-
1356
- append(...rulesetObjArr) {
1357
- if (rulesetObjArr.length) {
1358
- rulesetObjArr.flat().forEach(r => this.rulesetObjArr.push(r));
1359
- if (this.isAttached) {
1360
- return this.update()
1361
- }
1362
- }
1363
- return this
1364
- }
1365
-
1366
- get disabled() {
1367
- return this.root.el.disabled
1368
- }
1369
-
1370
- disable(isDisabled = true) {
1371
- this.root.el.disabled = isDisabled;
1372
- return this
1373
- }
1374
-
1375
- enable(isEnabled = true) {
1376
- return this.disable(!isEnabled)
1377
- }
1378
-
1379
- title(tagTitle) {
1380
- this.root.el.title = tagTitle;
1381
- return this
1382
- }
1383
-
1384
- rm() {
1385
- this.root.rm();
1386
- this._root = undefined;
1387
- return this
1388
- }
1389
-
1390
- minified(val) {
1391
- this.minified = val;
1392
- return this
1393
- }
1394
-
1395
- toString(minified = this.minified) {
1396
- const indentation = minified ? -1 : 0;
1397
- const separator = nl(indentation);
1398
- return this.rulesetObjArr
1399
- .map(rule => objToRulesArr(rule)
1400
- .map(rule => rule.toString(indentation))
1401
- .join(separator)
1402
- )
1403
- .join(separator)
1404
- }
1405
-
1406
- update() {
1407
- const content = this.toString();
1408
- // Only if successful, empty it
1409
- this.root.setText(content);
1410
- return this
1411
- }
1412
- }
1413
-
1414
- function css(...rulesetObjArr) {
1415
- return new StyleTag(...rulesetObjArr)
1416
- }
1417
-
1418
- function toTag(x) {
1419
- if (x instanceof Element) {
1420
- return x[jaTag] || new Tag(x)
1421
- }
1422
- if (x instanceof Tag) {
1423
- return x
1424
- }
1425
- if (isComponent(x)) {
1426
- return toTag(x.root)
1427
- }
1428
- if (isTagObj(x)) {
1429
- return objToTag(x)
1430
- }
1431
- throw new Error(`Invalid Tag or Element instance: ${x}`)
1432
- }
1433
-
1434
- function isTagObj(x) {
1435
- return isObj(x) && isStr(x.name)
1436
- }
1437
-
1438
- function objToTag(x) {
1439
- const { name, ns } = x;
1440
- const el = doc.el(name, ns);
1441
- const ret = new Tag(el);
1442
- mapKeyVal(x, (method, param) => {
1443
- if (method !== 'name' && method !== 'ns' && isFn(ret[method])) {
1444
- if (isArr(param)) {
1445
- ret[method](...param);
1446
- } else {
1447
- ret[method](param);
1448
- }
1449
- }
1450
- });
1451
- return ret
1452
- }
1453
-
1454
- function toNativeFrag(...xArr) {
1455
- const ret = doc.frag();
1456
- xArr.forEach(x => x !== undefined && ret.appendChild(toNative(x)));
1457
- return ret
1458
- }
1459
-
1460
- function toNativeEl(x) {
1461
- if (arguments.length === 0 || x === undefined) {
1462
- throw new TypeError(`Cannot convert ${x} to native DOM`)
1463
- }
1464
- if (x instanceof Element || x instanceof Text || x instanceof DocumentFragment || x instanceof Comment) {
1465
- return x
1466
- }
1467
- if (x instanceof Tag || x instanceof Frag) {
1468
- return x.el
1469
- }
1470
- if (isComponent(x)) {
1471
- return toNativeEl(x.root)
1472
- }
1473
- if (isTagObj(x)) {
1474
- return objToTag(x).el
1475
- }
1476
- // Whatever else will convert to a text node
1477
- return doc.text(x)
1478
- }
1479
-
1480
- function toNative(x) {
1481
- if (isArr(x)) {
1482
- return toNativeFrag(...x)
1483
- }
1484
- return toNativeEl(x)
1485
- }
1486
-
1487
- function h(tagName, attrs, children) {
1488
- return html(tagName).setAttrs(attrs).append(children)
1489
- }
1490
-
1491
- function htmlTag(tagName = 'html') {
1492
- return toTag(isStr(tagName) ? doc.el(tagName) : tagName)
1493
- }
1494
-
1495
- function svgTag(tagName = 'svg') {
1496
- return toTag(isStr(tagName) ? doc.el(tagName, SVG_NS) : tagName)
1497
- }
1498
-
1499
- function mathMlTag(tagName = 'math') {
1500
- return toTag(isStr(tagName) ? doc.el(tagName, MATH_NS) : tagName)
1501
- }
1502
-
1503
- const sugarProxy = {
1504
- get(target, tagName) {
1505
- const tag = target(tagName);
1506
- return function proxiedTag(...children) {
1507
- return tag.append(...children)
1508
- }
1509
- }
1510
- };
1511
-
1512
- const html = new Proxy(htmlTag, sugarProxy);
1513
- const svg = new Proxy(svgTag, sugarProxy);
1514
- const mathMl = new Proxy(mathMlTag, sugarProxy);
1515
-
1516
- function queryId(elementId) {
1517
- return toTag(document.getElementById(elementId))
1518
- }
1519
-
1520
- function query(selector, root = document.body) {
1521
- if (isSel(selector)) {
1522
- selector = selector.selector;
1523
- }
1524
- return toTag(root).query(selector)
1525
- }
1526
-
1527
- function queryAll(selector, root = document.body) {
1528
- if (isSel(selector)) {
1529
- selector = selector.selector;
1530
- }
1531
- return toTag(root).queryAll(selector)
1532
- }
1533
-
1534
- // https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Creating_and_triggering_events
1535
- const attachedEvent = new Event('attached');
1536
- const detachedEvent = new Event('detached');
1537
-
1538
- function mutationObservationCb(mutationsList, observer) {
1539
- for (var mutation of mutationsList) {
1540
- if (mutation.type == 'childList') {
1541
- mutation.addedNodes.forEach(n => n.dispatchEvent(attachedEvent));
1542
- mutation.removedNodes.forEach(n => n.dispatchEvent(detachedEvent));
1543
- }
1544
- }
1545
- }
1546
- var mo;
1547
-
1548
- function startObserving(observationRoot = document.documentElement) {
1549
- // https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
1550
- mo = new MutationObserver(mutationObservationCb);
1551
- const config = { childList: true, subtree: true };
1552
- mo.observe(observationRoot, config);
1553
- }
1554
-
1555
- function stopObserving() {
1556
- if (mo) {
1557
- mo.disconnect();
1558
- }
1559
- }
1560
-
1561
- const DOMContentLoaded = 'DOMContentLoaded';
1562
-
1563
- function ready(fn) {
1564
- const { document: { readyState } } = window;
1565
- if (readyState === 'complete' || readyState === 'loaded' || readyState === 'interactive') {
1566
- fn();
1567
- } else {
1568
- function onReady() {
1569
- win.off(DOMContentLoaded, onReady);
1570
- fn();
1571
- }
1572
- win.on(DOMContentLoaded, onReady);
1573
- }
1574
- }
1575
-
1576
- win.on('unload', () => stopObserving());
1577
-
1578
- ready(() => startObserving());
1579
-
1580
- export { col, css, doc, em, ent, frag, h, html, isDim, isSel, mathMl, mathMlTag, perc, px, query, queryAll, queryId, qut, ready, rem, rnd, router, runOnce, sel, svg, svgTag, toTag, vh, vw };