neo.mjs 6.9.12 → 6.10.1

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 (53) hide show
  1. package/BACKERS.md +0 -30
  2. package/apps/ServiceWorker.mjs +2 -2
  3. package/apps/learnneo/index.html +8 -4
  4. package/apps/learnneo/view/LivePreview.mjs +171 -0
  5. package/apps/learnneo/view/home/ContentTreeList.mjs +91 -8
  6. package/apps/learnneo/view/home/MainContainerController.mjs +5 -20
  7. package/examples/ServiceWorker.mjs +2 -2
  8. package/examples/button/base/neo-config.json +1 -2
  9. package/package.json +4 -8
  10. package/resources/data/deck/learnneo/p/2023-10-01T18-29-19-158Z.md +14 -16
  11. package/resources/data/deck/learnneo/p/2023-10-07T19-18-28-517Z.md +9 -17
  12. package/resources/data/deck/learnneo/p/2023-10-08T20-20-07-934Z.md +7 -5
  13. package/resources/data/deck/learnneo/p/2023-10-14T19-25-08-153Z.md +18 -22
  14. package/resources/data/deck/learnneo/p/2023-10-31T13-59-37-550Z.md +31 -0
  15. package/resources/data/deck/learnneo/p/MainThreadAddonExample.md +15 -0
  16. package/resources/data/deck/learnneo/p/MainThreadAddonIntro.md +46 -0
  17. package/resources/data/deck/learnneo/p/TestLivePreview.md +10 -0
  18. package/resources/data/deck/learnneo/p/stylesheet.md +3 -7
  19. package/resources/data/deck/learnneo/t.json +126 -56
  20. package/resources/images/logos/Github-logo-black.svg +1 -0
  21. package/resources/images/logos/Slack-logo-black.svg +17 -0
  22. package/resources/scss/src/apps/learnneo/home/ContentView.scss +6 -0
  23. package/resources/scss/src/list/Base.scss +5 -1
  24. package/resources/scss/theme-neo-light/Global.scss +7 -5
  25. package/resources/scss/theme-neo-light/button/Base.scss +46 -45
  26. package/resources/scss/theme-neo-light/design-tokens/Component.scss +4 -0
  27. package/resources/scss/theme-neo-light/design-tokens/Core.scss +23 -22
  28. package/resources/scss/theme-neo-light/design-tokens/Semantic.scss +5 -2
  29. package/resources/scss/theme-neo-light/list/Base.scss +2 -4
  30. package/resources/scss/theme-neo-light/tab/header/Button.scss +1 -1
  31. package/src/DefaultConfig.mjs +2 -2
  32. package/src/component/StatusBadge.mjs +194 -246
  33. package/src/component/Video.mjs +19 -25
  34. package/src/controller/Base.mjs +3 -4
  35. package/src/core/Base.mjs +2 -2
  36. package/src/form/field/Text.mjs +2 -2
  37. package/src/form/field/TextArea.mjs +3 -3
  38. package/src/main/DomAccess.mjs +64 -70
  39. package/src/main/DomEvents.mjs +1 -1
  40. package/src/main/addon/HighlightJS.mjs +16 -1
  41. package/src/main/addon/Mwc.mjs +14 -5
  42. package/src/worker/Manager.mjs +8 -3
  43. package/apps/learnneo/view/home/ContentComponent.mjs +0 -24
  44. package/examples/container/dialog/MainContainer.mjs +0 -68
  45. package/examples/container/dialog/MainContainerController.mjs +0 -84
  46. package/examples/container/dialog/app.mjs +0 -6
  47. package/examples/container/dialog/index.html +0 -11
  48. package/examples/container/dialog/neo-config.json +0 -7
  49. package/resources/scss/src/apps/learnneo/home/ContentComponent.scss +0 -61
  50. package/resources/scss/src/apps/newwebsite/MainContainer.css +0 -33
  51. package/resources/scss/theme-neo-light/design-tokens/Components.scss +0 -3
  52. package/src/container/Dialog.mjs +0 -205
  53. package/src/main/addon/Dialog.mjs +0 -68
@@ -27,16 +27,16 @@ class Video extends BaseComponent {
27
27
  baseCls: ['neo-video'],
28
28
  /**
29
29
  * Current state of the video
30
- * @member {Boolean} playing=false
30
+ * @member {Boolean} playing_=false
31
31
  */
32
32
  playing_: false,
33
33
  /**
34
34
  * Type of the video
35
- * @member {Boolean} type='video/mp4'
35
+ * @member {String} type='video/mp4'
36
36
  */
37
37
  type: 'video/mp4',
38
38
  /*
39
- * @member {String} url=null
39
+ * @member {String|null} url_=null
40
40
  */
41
41
  url_: null,
42
42
  /**
@@ -70,18 +70,12 @@ class Video extends BaseComponent {
70
70
  construct(config) {
71
71
  super.construct(config);
72
72
 
73
- let me = this,
74
- domListeners = me.domListeners;
73
+ let me = this;
75
74
 
76
- domListeners.push({
77
- click : me.play,
78
- delegate: '.neo-video-ghost'
79
- }, {
80
- click : me.pause,
81
- delegate: '.neo-video-media'
82
- });
83
-
84
- me.domListeners = domListeners;
75
+ me.addDomListeners(
76
+ {click: me.play, delegate: '.neo-video-ghost'},
77
+ {click: me.pause, delegate: '.neo-video-media'}
78
+ )
85
79
  }
86
80
 
87
81
  /**
@@ -93,10 +87,10 @@ class Video extends BaseComponent {
93
87
  */
94
88
  beforeSetPlaying(value, oldValue) {
95
89
  if (!Neo.isBoolean(value)) {
96
- return oldValue;
90
+ return oldValue
97
91
  }
98
92
 
99
- return value;
93
+ return value
100
94
  }
101
95
 
102
96
  /**
@@ -112,7 +106,7 @@ class Video extends BaseComponent {
112
106
  ghost.removeDom = value;
113
107
  media.removeDom = !value;
114
108
 
115
- this.vdom = vdom;
109
+ this.vdom = vdom
116
110
  }
117
111
 
118
112
  /**
@@ -124,7 +118,7 @@ class Video extends BaseComponent {
124
118
  */
125
119
  afterSetUrl(value, oldValue) {
126
120
  if (!value) {
127
- return;
121
+ return
128
122
  }
129
123
 
130
124
  const me = this;
@@ -137,21 +131,21 @@ class Video extends BaseComponent {
137
131
  type: me.type
138
132
  }];
139
133
 
140
- me.vdom = vdom;
134
+ me.vdom = vdom
141
135
  }
142
136
 
143
137
  /**
144
- * Clicked ghost
138
+ * Clicked media
145
139
  */
146
- play() {
147
- this.playing = true;
140
+ pause() {
141
+ this.playing = false
148
142
  }
149
143
 
150
144
  /**
151
- * Clicked media
145
+ * Clicked ghost
152
146
  */
153
- pause() {
154
- this.playing = false;
147
+ play() {
148
+ this.playing = true
155
149
  }
156
150
  }
157
151
 
@@ -22,7 +22,7 @@ class Base extends CoreBase {
22
22
  */
23
23
  ntype: 'controller',
24
24
  /**
25
- * @member {String} defaultRoute=undefined
25
+ * @member {String|null} defaultRoute=null
26
26
  */
27
27
  defaultRoute: null,
28
28
  /**
@@ -37,7 +37,7 @@ class Base extends CoreBase {
37
37
  * '/users/{userId}/posts/{postId}': 'handlePostRoute',
38
38
  * 'default' : 'handleOtherRoutes'
39
39
  * }
40
- * @member {Object} routes={}
40
+ * @member {Object} routes_={}
41
41
  */
42
42
  routes_: {}
43
43
  }
@@ -83,7 +83,7 @@ class Base extends CoreBase {
83
83
  destroy(...args) {
84
84
  HashHistory.un('change', this.onHashChange, this);
85
85
 
86
- super.destroy(...args);
86
+ super.destroy(...args)
87
87
  }
88
88
 
89
89
  /**
@@ -142,7 +142,6 @@ class Base extends CoreBase {
142
142
  }
143
143
 
144
144
  hasRouteBeenFound = true
145
-
146
145
  }
147
146
 
148
147
  counter++
package/src/core/Base.mjs CHANGED
@@ -216,7 +216,7 @@ class Base {
216
216
 
217
217
  if (cls[item]) {
218
218
  // add to overwrittenMethods
219
- cls.constructor.overwrittenMethods[item] = cls[item];
219
+ cls.constructor.overwrittenMethods[item] = cls[item]
220
220
  }
221
221
  }
222
222
  }
@@ -471,7 +471,7 @@ class Base {
471
471
  // The hasOwnProperty check is intended for configs without a trailing underscore
472
472
  // => they could already have been assigned inside an afterSet-method
473
473
  if (forceAssign || !me.hasOwnProperty(keys[0])) {
474
- me[keys[0]] = me[configSymbol][keys[0]];
474
+ me[keys[0]] = me[configSymbol][keys[0]]
475
475
  }
476
476
 
477
477
  // there is a delete-call inside the config getter as well (Neo.mjs => autoGenerateGetSet())
@@ -1307,7 +1307,7 @@ class Text extends Base {
1307
1307
  onInputValueChange(data) {
1308
1308
  let me = this,
1309
1309
  oldValue = me.value,
1310
- value = data.value ? data.value.toString().trim() : me.emptyValue,
1310
+ value = data.value,
1311
1311
  vnode = VNodeUtil.findChildVnode(me.vnode, {nodeName: 'input'});
1312
1312
 
1313
1313
  if (vnode) {
@@ -1510,7 +1510,7 @@ class Text extends Base {
1510
1510
  minLength = me.minLength,
1511
1511
  required = me.required,
1512
1512
  returnValue = true,
1513
- value = me.value ? me.value.toString().trim() : me.emptyValue,
1513
+ value = me.value,
1514
1514
  valueLength = value?.toString().length,
1515
1515
  inputPattern = me.inputPattern,
1516
1516
  isEmpty = value !== 0 && (!value || valueLength < 1),
@@ -32,7 +32,7 @@ class TextArea extends Text {
32
32
  * any height of text. Bounds can be set using the `minHeight` and `maxHeight` settings.
33
33
  * @member {Boolean} autoGrow=false
34
34
  */
35
- autoGrow_ : false,
35
+ autoGrow_: false,
36
36
  /**
37
37
  * @member {String[]} baseCls=['neo-textarea','neo-textfield']
38
38
  */
@@ -75,7 +75,7 @@ class TextArea extends Text {
75
75
  }
76
76
 
77
77
  afterSetAutoGrow(autoGrow) {
78
- this.syncAutoGrowMonitor();
78
+ autoGrow && this.syncAutoGrowMonitor();
79
79
 
80
80
  // Restore any configured height if autoGrow turned off
81
81
  if (!autoGrow) {
@@ -176,7 +176,7 @@ class TextArea extends Text {
176
176
  }
177
177
 
178
178
  async syncAutoGrowMonitor() {
179
- if (this.mounted) {
179
+ if (this.mounted && this.autoGrow) {
180
180
  // Delegate monitoring of sizes to the VDOM thread.
181
181
  Neo.main.DomAccess.monitorAutoGrow({
182
182
  appName : this.appName,
@@ -42,13 +42,13 @@ const
42
42
 
43
43
  // Hidden elements not tabbable
44
44
  if (style.getPropertyValue('display') === 'none' || style.getPropertyValue('visibility') === 'hidden') {
45
- return false;
45
+ return false
46
46
  }
47
47
 
48
48
  return focusableTags[nodeName] ||
49
49
  ((nodeName === 'A' || nodeName === 'LINK') && !!e.href) ||
50
50
  (tabIndex != null && Number(tabIndex) >= 0) ||
51
- e.contentEditable === 'true';
51
+ e.contentEditable === 'true'
52
52
  };
53
53
 
54
54
  /**
@@ -140,10 +140,10 @@ class DomAccess extends Base {
140
140
  if (!me._modalMask) {
141
141
  me._modalMask = document.createElement('div');
142
142
  me._modalMask.className = 'neo-dialog-modal-mask';
143
- me._modalMask.addEventListener('mousedown', doPreventDefault, { capture : true });
143
+ me._modalMask.addEventListener('mousedown', doPreventDefault, { capture : true })
144
144
  }
145
145
 
146
- return me._modalMask;
146
+ return me._modalMask
147
147
  }
148
148
 
149
149
  /**
@@ -251,7 +251,7 @@ class DomAccess extends Base {
251
251
  lastAlign = me._aligns?.get(data.id);
252
252
 
253
253
  if (lastAlign) {
254
- subject.classList.remove(`neo-aligned-${lastAlign.result.position}`);
254
+ subject.classList.remove(`neo-aligned-${lastAlign.result.position}`)
255
255
  }
256
256
 
257
257
  // Release any constrainTo or matchSize sizing which may have been imposed
@@ -263,12 +263,12 @@ class DomAccess extends Base {
263
263
 
264
264
  if (!align.target) {
265
265
  // Set the Component with id data.id to hidden : true
266
- return Neo.worker.App.setConfigs({ id : data.id, hidden : true });
266
+ return Neo.worker.App.setConfigs({ id : data.id, hidden : true })
267
267
  }
268
268
 
269
269
  data.offsetParent = data.targetElement.offsetParent;
270
270
  if (constrainTo) {
271
- align.constrainTo = me.getBoundingClientRect({ id : data.constrainToElement = me.getElementOrBody(constrainTo) });
271
+ align.constrainTo = me.getBoundingClientRect({ id : data.constrainToElement = me.getElementOrBody(constrainTo) })
272
272
  }
273
273
 
274
274
  // Get an aligned clone of myRect aligned according to the align object
@@ -282,17 +282,17 @@ class DomAccess extends Base {
282
282
  transform : `translate(${result.x}px,${result.y}px)`
283
283
  });
284
284
  if (result.width !== myRect.width) {
285
- style.width = `${result.width}px`;
285
+ style.width = `${result.width}px`
286
286
  }
287
287
  if (result.height !== myRect.height) {
288
- style.height = `${result.height}px`;
288
+ style.height = `${result.height}px`
289
289
  }
290
290
 
291
291
  // Place box shadow at correct edge
292
292
  subject.classList.add(`neo-aligned-${result.position}`);
293
293
 
294
294
  // Register an alignment to be kept in sync
295
- me.addAligned(data);
295
+ me.addAligned(data)
296
296
  }
297
297
 
298
298
  /**
@@ -301,7 +301,7 @@ class DomAccess extends Base {
301
301
  */
302
302
  applyBodyCls(data) {
303
303
  let cls = data.cls || [];
304
- document.body.classList.add(...cls);
304
+ document.body.classList.add(...cls)
305
305
  }
306
306
 
307
307
  /**
@@ -311,8 +311,7 @@ class DomAccess extends Base {
311
311
  */
312
312
  blur(data) {
313
313
  this.getElement(data.id)?.blur();
314
-
315
- return {id: data.id};
314
+ return {id: data.id}
316
315
  }
317
316
 
318
317
  /**
@@ -361,8 +360,8 @@ class DomAccess extends Base {
361
360
  returnData.push(this.getAttributes({
362
361
  attributes: data.attributes,
363
362
  id : id
364
- }));
365
- });
363
+ }))
364
+ })
366
365
  } else {
367
366
  let node = this.getElementOrBody(data.id);
368
367
 
@@ -373,13 +372,13 @@ class DomAccess extends Base {
373
372
  data.attributes = [data.attributes];
374
373
 
375
374
  data.attributes.forEach(attribute => {
376
- returnData[attribute] = node[attribute];
375
+ returnData[attribute] = node[attribute]
377
376
  })
378
377
  }
379
378
  }
380
379
  }
381
380
 
382
- return returnData;
381
+ return returnData
383
382
  }
384
383
 
385
384
  /**
@@ -449,7 +448,7 @@ class DomAccess extends Base {
449
448
  * @protected
450
449
  */
451
450
  getElement(nodeId) {
452
- return nodeId.nodeType ? nodeId : Neo.config.useDomIds ? document.getElementById(nodeId) : document.querySelector(`[data-neo-id='${nodeId}']`);
451
+ return nodeId.nodeType ? nodeId : Neo.config.useDomIds ? document.getElementById(nodeId) : document.querySelector(`[data-neo-id='${nodeId}']`)
453
452
  }
454
453
 
455
454
  /**
@@ -458,7 +457,7 @@ class DomAccess extends Base {
458
457
  * @protected
459
458
  */
460
459
  getElementOrBody(nodeId='document.body') {
461
- return nodeId.nodeType ? nodeId : (nodeId === 'body' || nodeId === 'document.body') ? document.body : this.getElement(nodeId);
460
+ return nodeId.nodeType ? nodeId : (nodeId === 'body' || nodeId === 'document.body') ? document.body : this.getElement(nodeId)
462
461
  }
463
462
 
464
463
  /**
@@ -470,16 +469,16 @@ class DomAccess extends Base {
470
469
  const me = this;
471
470
 
472
471
  if (Array.isArray(data.id)) {
473
- return data.id.map(id => me.getScrollingDimensions({ id }));
472
+ return data.id.map(id => me.getScrollingDimensions({ id }))
474
473
  } else {
475
474
  const node = data.nodeType ? data : me.getElementOrBody(data.id);
476
475
 
477
476
  return {
478
- clientWidth : node?.clientWidth,
479
477
  clientHeight: node?.clientHeight,
480
- scrollWidth : node?.scrollWidth,
481
- scrollHeight: node?.scrollHeight
482
- };
478
+ clientWidth : node?.clientWidth,
479
+ scrollHeight: node?.scrollHeight,
480
+ scrollWidth : node?.scrollWidth
481
+ }
483
482
  }
484
483
  }
485
484
 
@@ -488,7 +487,7 @@ class DomAccess extends Base {
488
487
  * @returns {Boolean}
489
488
  */
490
489
  isAlignSubject(el) {
491
- return [...this._aligns?.values()].some(align => align.subject === el);
490
+ return [...this._aligns?.values()].some(align => align.subject === el)
492
491
  }
493
492
 
494
493
  /**
@@ -510,8 +509,8 @@ class DomAccess extends Base {
510
509
  src
511
510
  });
512
511
 
513
- document.head.appendChild(script);
514
- });
512
+ document.head.appendChild(script)
513
+ })
515
514
  }
516
515
 
517
516
  /**
@@ -533,7 +532,7 @@ class DomAccess extends Base {
533
532
  type : 'text/css'
534
533
  });
535
534
 
536
- document.head.appendChild(link);
535
+ document.head.appendChild(link)
537
536
  })
538
537
  }
539
538
 
@@ -549,7 +548,7 @@ class DomAccess extends Base {
549
548
  if (value.endsWith('%')) {
550
549
  const fraction = parseFloat(value) / 100;
551
550
 
552
- return (node.offsetParent?.getBoundingClientRect().height || 0) * fraction;
551
+ return (node.offsetParent?.getBoundingClientRect().height || 0) * fraction
553
552
  }
554
553
  // If it's any other CSS unit than px, it needs to be measured using the DOM
555
554
  else if (isNaN(value) && !value.endsWith('px')) {
@@ -559,8 +558,9 @@ class DomAccess extends Base {
559
558
 
560
559
  if (!d) {
561
560
  d = this._measuringDiv = document.createElement('div');
562
- d.style = 'position:fixed;top:-10000px;left:-10000px';
561
+ d.style = 'position:fixed;top:-10000px;left:-10000px'
563
562
  }
563
+
564
564
  // In case a DOM update cleared it out
565
565
  document.body.appendChild(d);
566
566
 
@@ -578,15 +578,16 @@ class DomAccess extends Base {
578
578
  }
579
579
  // If it's a number, or ends with px, use the numeric value.
580
580
  else {
581
- value = parseFloat(value);
581
+ value = parseFloat(value)
582
582
  }
583
- return value;
583
+
584
+ return value
584
585
  }
585
586
 
586
587
  /**
587
588
  * Checks the overflow status of a TextAreaField's &lt;textarea> element and updates the
588
589
  * height so that there is never a vertical scrollbar.
589
- * @param {Object} data
590
+ * @param {Object} data
590
591
  */
591
592
  async monitorAutoGrow(data) {
592
593
  const
@@ -597,11 +598,9 @@ class DomAccess extends Base {
597
598
  target[data.autoGrow ? 'addEventListener' : 'removeEventListener']('input', me.monitorAutoGrowHandler);
598
599
 
599
600
  // Fix the height up immediately too
600
- if (data.autoGrow) {
601
- me.monitorAutoGrowHandler({
602
- target
603
- });
604
- }
601
+ data.autoGrow && me.monitorAutoGrowHandler({
602
+ target
603
+ })
605
604
  }
606
605
 
607
606
  monitorAutoGrowHandler({ target }) {
@@ -613,7 +612,7 @@ class DomAccess extends Base {
613
612
  style.height = style.minHeight = 0;
614
613
  inputStyle.setProperty('--textfield-input-height', `${target.scrollHeight + 5}px`);
615
614
  inputStyle.setProperty('height', '');
616
- style.height = style.minHeight = '';
615
+ style.height = style.minHeight = ''
617
616
  }
618
617
 
619
618
  /**
@@ -630,7 +629,7 @@ class DomAccess extends Base {
630
629
  return nodes.every(a => me.isAlignSubject(a))
631
630
  }
632
631
  })) {
633
- me.syncAligns();
632
+ me.syncAligns()
634
633
  }
635
634
  }
636
635
 
@@ -638,9 +637,7 @@ class DomAccess extends Base {
638
637
  *
639
638
  */
640
639
  onDomContentLoaded() {
641
- if (Neo.config.applyBodyCls) {
642
- this.applyBodyCls({cls: ['neo-body']});
643
- }
640
+ Neo.config.applyBodyCls && this.applyBodyCls({cls: ['neo-body']})
644
641
  }
645
642
 
646
643
  /**
@@ -660,7 +657,7 @@ class DomAccess extends Base {
660
657
  data,
661
658
  replyId: data.id,
662
659
  success: true
663
- }, [offscreen]);
660
+ }, [offscreen])
664
661
  }
665
662
 
666
663
  /**
@@ -695,7 +692,7 @@ class DomAccess extends Base {
695
692
 
696
693
  key.params.forEach((param, paramIndex) => {
697
694
  if (key.paramIsDomNode[paramIndex] === true) {
698
- key.params[paramIndex] = this.getElement(key.params[paramIndex]);
695
+ key.params[paramIndex] = this.getElement(key.params[paramIndex])
699
696
  }
700
697
  });
701
698
 
@@ -703,15 +700,15 @@ class DomAccess extends Base {
703
700
  retFunctions[fnName] = scope[key.fn](...key.params);
704
701
 
705
702
  if (key.returnValue) {
706
- retFunctions[fnName] = retFunctions[fnName][key.returnValue];
703
+ retFunctions[fnName] = retFunctions[fnName][key.returnValue]
707
704
  }
708
705
  } else {
709
- retFunctions[key] = element[key]();
706
+ retFunctions[key] = element[key]()
710
707
  }
711
708
  });
712
709
 
713
710
  styles.forEach(key => {
714
- retStyles[key] = element.style[key];
711
+ retStyles[key] = element.style[key]
715
712
  });
716
713
 
717
714
  Object.assign(data, {
@@ -746,7 +743,7 @@ class DomAccess extends Base {
746
743
  treeWalker.currentNode = backwards ? bottomFocusTrap : topFocusTrap;
747
744
  treeWalker[backwards ? 'previousNode' : 'nextNode']();
748
745
 
749
- requestAnimationFrame(() => treeWalker.currentNode.focus());
746
+ requestAnimationFrame(() => treeWalker.currentNode.focus())
750
747
  }
751
748
  }
752
749
 
@@ -755,9 +752,7 @@ class DomAccess extends Base {
755
752
  * @protected
756
753
  */
757
754
  read(data) {
758
- if (typeof data === 'function') {
759
- data()
760
- }
755
+ typeof data === 'function' && data()
761
756
  }
762
757
 
763
758
  /**
@@ -770,12 +765,12 @@ class DomAccess extends Base {
770
765
  resetDimensions(align) {
771
766
  Object.assign(this.getElement(align.id).style, {
772
767
  flex : align.configuredFlex,
773
- width : align.configuredWidth,
774
768
  height : align.configuredHeight,
775
- minWidth : align.configuredMinWidth,
776
- minHeight: align.configuredMinHeight,
769
+ maxHeight: align.configuredMaxHeight,
777
770
  maxWidth : align.configuredMaxWidth,
778
- maxHeight: align.configuredMaxHeight
771
+ minHeight: align.configuredMinHeight,
772
+ minWidth : align.configuredMinWidth,
773
+ width : align.configuredWidth
779
774
  })
780
775
  }
781
776
 
@@ -790,7 +785,7 @@ class DomAccess extends Base {
790
785
  let node = this.getElement(data.id);
791
786
 
792
787
  if (node) {
793
- node[`scroll${Neo.capitalize(data.direction)}`] += data.value;
788
+ node[`scroll${Neo.capitalize(data.direction)}`] += data.value
794
789
  }
795
790
 
796
791
  return {id: data.id}
@@ -827,7 +822,7 @@ class DomAccess extends Base {
827
822
  let node = this.getElement(data.id);
828
823
 
829
824
  if (node) {
830
- node[`scroll${Neo.capitalize(data.direction)}`] = data.value;
825
+ node[`scroll${Neo.capitalize(data.direction)}`] = data.value
831
826
  }
832
827
 
833
828
  return {id: data.id}
@@ -872,7 +867,7 @@ class DomAccess extends Base {
872
867
 
873
868
  if (node) {
874
869
  node.select();
875
- node.setSelectionRange(start, end);
870
+ node.setSelectionRange(start, end)
876
871
  }
877
872
 
878
873
  return {id: data.id}
@@ -885,7 +880,7 @@ class DomAccess extends Base {
885
880
  */
886
881
  setBodyCls(data) {
887
882
  document.body.classList.remove(...data.remove || []);
888
- document.body.classList.add(...data.add || []);
883
+ document.body.classList.add(...data.add || [])
889
884
  }
890
885
 
891
886
  /**
@@ -927,13 +922,13 @@ class DomAccess extends Base {
927
922
 
928
923
  // Align subject and target still in the DOM - correct its alignment
929
924
  if (document.contains(align.subject) && targetPresent) {
930
- me.align(align);
925
+ me.align(align)
931
926
  }
932
927
  // Align subject or target no longer in the DOM - remove it.
933
928
  else {
934
929
  // If target is no longer in the DOM, hide the subject component
935
930
  if (!targetPresent) {
936
- Neo.worker.App.setConfigs({ id: align.id, hidden: true });
931
+ Neo.worker.App.setConfigs({ id: align.id, hidden: true })
937
932
  }
938
933
 
939
934
  const
@@ -966,7 +961,7 @@ class DomAccess extends Base {
966
961
 
967
962
  // If we are visible and modal, the mask needs to be just below this element.
968
963
  if (el && modal && el.ownerDocument.contains(el) && el.ownerDocument.defaultView.getComputedStyle(el).getPropertyValue('display') !== 'none') {
969
- document.body.insertBefore(this.modalMask, el);
964
+ document.body.insertBefore(this.modalMask, el)
970
965
  }
971
966
  // Otherwise, the mask needs to be below the next topmost modal dialog if possible, or hidden
972
967
  else {
@@ -998,7 +993,7 @@ class DomAccess extends Base {
998
993
 
999
994
  // Called before DOM has been created.
1000
995
  if (!subject) {
1001
- return;
996
+ return
1002
997
  }
1003
998
 
1004
999
  let topFocusTrap = subject.$topFocusTrap,
@@ -1007,7 +1002,7 @@ class DomAccess extends Base {
1007
1002
  if (trap) {
1008
1003
  if (!subject.$treeWalker) {
1009
1004
  subject.$treeWalker = document.createTreeWalker(subject, NodeFilter.SHOW_ELEMENT, {
1010
- acceptNode : filterTabbable
1005
+ acceptNode: filterTabbable
1011
1006
  });
1012
1007
  topFocusTrap = subject.$topFocusTrap = document.createElement('div');
1013
1008
  bottomFocusTrap = subject.$bottomFocusTrap = document.createElement('div');
@@ -1018,15 +1013,14 @@ class DomAccess extends Base {
1018
1013
  bottomFocusTrap.setAttribute('tabIndex', 0);
1019
1014
 
1020
1015
  // Listen for when they gain focus and wrap focus within the encapsulating element
1021
- subject.addEventListener('focusin', onTrappedFocusMovement);
1016
+ subject.addEventListener('focusin', onTrappedFocusMovement)
1022
1017
  }
1023
1018
 
1024
1019
  // Ensure content is encapsulated by the focus trap elements
1025
1020
  subject.insertBefore(topFocusTrap, subject.firstChild);
1026
- subject.appendChild(bottomFocusTrap);
1027
- }
1028
- else {
1029
- subject.removeEventListener('focusin', onTrappedFocusMovement);
1021
+ subject.appendChild(bottomFocusTrap)
1022
+ } else {
1023
+ subject.removeEventListener('focusin', onTrappedFocusMovement)
1030
1024
  }
1031
1025
  }
1032
1026
 
@@ -504,7 +504,7 @@ class DomEvents extends Base {
504
504
  */
505
505
  onHashChange() {
506
506
  let manager = Neo.worker.Manager,
507
- hashString = location.hash.substr(1);
507
+ hashString = location.hash.substring(1);
508
508
 
509
509
  manager.sendMessage('app', {
510
510
  action: 'hashChange',
@@ -37,7 +37,8 @@ class HighlightJS extends Base {
37
37
  'syntaxHighlight',
38
38
  'switchTheme',
39
39
  'syntaxHighlightInit',
40
- 'syntaxHighlightLine'
40
+ 'syntaxHighlightLine',
41
+ 'highlightAuto'
41
42
  ]
42
43
  },
43
44
  /**
@@ -139,6 +140,20 @@ class HighlightJS extends Base {
139
140
  }
140
141
  }
141
142
 
143
+ /**
144
+ * See https://highlightjs.readthedocs.io/en/latest/api.html#highlightauto
145
+ * @param {String} html
146
+ * @returns {Object} of the form {language, relevance, value, secondBest}
147
+ */
148
+ highlightAuto(html) {
149
+ if (hljs) {
150
+ return hljs.highlightAuto(html);
151
+ } else {
152
+ console.error('highlight.js is not included inside the main thread.')
153
+ }
154
+ }
155
+
156
+
142
157
  /**
143
158
  * @param {Object} data
144
159
  * @param {Number} data.addLine