neo.mjs 6.9.8 → 6.9.10

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.
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.9.8'
23
+ * @member {String} version='6.9.10'
24
24
  */
25
- version: '6.9.8'
25
+ version: '6.9.10'
26
26
  }
27
27
 
28
28
  /**
@@ -1,11 +1,16 @@
1
1
  <!DOCTYPE HTML>
2
2
  <html>
3
+
3
4
  <head>
4
5
  <meta name="viewport" content="width=device-width, initial-scale=1">
5
6
  <meta charset="UTF-8">
6
7
  <title>LearnNeo</title>
8
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Open+Sans|Inconsolata">
9
+ </link>
7
10
  </head>
11
+
8
12
  <body>
9
13
  <script src="../../src/MicroLoader.mjs" type="module"></script>
10
14
  </body>
15
+
11
16
  </html>
@@ -0,0 +1,24 @@
1
+ import Base from '../../../../src/component/Base.mjs';
2
+
3
+ /**
4
+ * @class LearnNeo.view.home.ContentComponent
5
+ * @extends Neo.component.Base
6
+ */
7
+ class ContentComponent extends Base {
8
+ static config = {
9
+ /**
10
+ * @member {String} className='LearnNeo.view.home.ContentComponent'
11
+ * @protected
12
+ */
13
+ className: 'LearnNeo.view.home.ContentComponent',
14
+ /**
15
+ * @member {String[]} baseCls=['learn-content']
16
+ * @protected
17
+ */
18
+ baseCls: ['learn-content']
19
+ }
20
+ }
21
+
22
+ Neo.applyClassConfig(ContentComponent);
23
+
24
+ export default ContentComponent;
@@ -12,30 +12,46 @@ class ContentTreeList extends TreeList {
12
12
  * @protected
13
13
  */
14
14
  className: 'LearnNeo.view.home.ContentTreeList',
15
+ /**
16
+ * @member {String[]} cls=['topics-tree']
17
+ */
18
+ cls: ['topics-tree'],
15
19
  /**
16
20
  * @member {Neo.data.Store} store=ContentStore
17
21
  */
18
- store: ContentStore
19
- }
22
+ store: ContentStore,
20
23
 
21
- /**
22
- * todo: createItems() should get triggered onStoreLoad()
23
- */
24
- onConstructed() {
25
- super.onConstructed();
26
- let me = this;
27
- Neo.Main.getByPath({path: 'location.search'})
28
- .then(data => {
29
- const searchString = data?.substr(1) || '';
30
- const search = searchString ? JSON.parse(`{"${decodeURI(searchString.replace(/&/g, "\",\"").replace(/=/g, "\":\""))}"}`) : {};
31
- me.deck = search.deck || 'learnneo';
32
- me.doLoadStore();
33
- console.log(search);
34
- });
24
+ cls: 'topics-tree'
35
25
  }
26
+
36
27
  get contentPath() {
37
28
  return `../../../resources/data/${this.deck}`;
38
29
  }
30
+
31
+ /**
32
+ * @param {Object} record
33
+ * @returns {Promise<void>}
34
+ */
35
+ async doFetchContent(record) {
36
+ let me = this,
37
+ path = `${me.contentPath}`;
38
+
39
+ path += record.path ? `/pages/${record.path}` : `/p/${record.id}.md`;
40
+
41
+ if (record.isLeaf && path) {
42
+ const data = await fetch(path);
43
+ const content = await data.text();
44
+
45
+ await Neo.main.addon.Markdown.markdownToHtml(content)
46
+ .then(
47
+ html => me.fire('contentChange', {component: me, html}),
48
+ () => me.fire('contentChange', {component: me}));
49
+ }
50
+ }
51
+
52
+ /**
53
+ *
54
+ */
39
55
  doLoadStore() {
40
56
  const me = this;
41
57
  Neo.Xhr.promiseJson({
@@ -48,19 +64,30 @@ class ContentTreeList extends TreeList {
48
64
  })
49
65
  }
50
66
 
51
- async doFetchContent(record) {
52
- let me = this,
53
- path = `${me.contentPath}`;
54
- path += record.path ? `/pages/${record.path}` : `/p/${record.id}.md`;
67
+ /**
68
+ * todo: createItems() should get triggered onStoreLoad()
69
+ */
70
+ onConstructed() {
71
+ super.onConstructed();
55
72
 
56
- if (record.isLeaf && path) {
57
- const data = await fetch(path);
58
- const content = await data.text();
59
- await Neo.main.addon.Markdown.markdownToHtml(content)
60
- .then(
61
- html => me.fire('contentChange', {component: me, html}),
62
- () => me.fire('contentChange', {component: me}));
63
- }
73
+ let me = this;
74
+
75
+ Neo.Main.getByPath({path: 'location.search'})
76
+ .then(data => {
77
+ const searchString = data?.substr(1) || '';
78
+ const search = searchString ? JSON.parse(`{"${decodeURI(searchString.replace(/&/g, "\",\"").replace(/=/g, "\":\""))}"}`) : {};
79
+ me.deck = search.deck || 'learnneo';
80
+ me.doLoadStore();
81
+ console.log(search);
82
+ });
83
+ }
84
+
85
+ /**
86
+ * @param {Object} record
87
+ */
88
+ onLeafItemClick(record) {
89
+ super.onLeafItemClick(record);
90
+ this.doFetchContent(record);
64
91
  }
65
92
  }
66
93
 
@@ -1,36 +1,55 @@
1
- import Container from '../../../../src/container/Base.mjs';
2
- import Component from '../../../../src/component/Base.mjs';
3
- import ContentTreeList from './ContentTreeList.mjs';
1
+ import Container from '../../../../src/container/Base.mjs';
2
+ import ContentComponent from './ContentComponent.mjs';
3
+ import ContentTreeList from './ContentTreeList.mjs';
4
4
  import MainContainerController from './MainContainerController.mjs';
5
- import MainContainerModel from './MainContainerModel.mjs';
6
- import Splitter from '../../../../src/component/Splitter.mjs';
5
+ import MainContainerModel from './MainContainerModel.mjs';
6
+ import Splitter from '../../../../src/component/Splitter.mjs';
7
7
 
8
+ /**
9
+ * @class LearnNeo.view.home.MainContainer
10
+ * @extends Neo.container.Base
11
+ */
8
12
  class MainContainer extends Container {
9
13
  static config = {
14
+ /**
15
+ * @member {String} className='LearnNeo.view.home.MainContainer'
16
+ * @protected
17
+ */
10
18
  className: 'LearnNeo.view.home.MainContainer',
11
- model: MainContainerModel,
19
+ /**
20
+ * @member {Neo.controller.Component} controller=MainContainerController
21
+ */
12
22
  controller: MainContainerController,
23
+ /**
24
+ * @member {Object[]} items
25
+ */
13
26
  items: [{
14
- module: Container,
15
- layout: 'fit',
27
+ module : Container,
28
+ layout : 'fit',
16
29
  minWidth: 350,
17
- width: 350,
30
+ width : 350,
18
31
 
19
32
  items: [{
20
- module: ContentTreeList,
33
+ module : ContentTreeList,
21
34
  reference: 'tree',
22
- listeners: {contentChange: 'onContentListLeafClick'},
35
+ listeners: {contentChange: 'onContentListLeafClick'}
23
36
  }]
24
37
  }, {
25
- module: Splitter,
26
- resizeTarget: 'previous'
38
+ module : Splitter,
39
+ resizeTarget: 'previous',
40
+ size : 5
27
41
  }, {
28
- module: Component,
29
- layout: {ntype: 'card', activeIndex: null},
30
- cls: 'learn-content',
42
+ module : ContentComponent,
31
43
  reference: 'content'
32
44
  }],
33
- layout: {ntype: 'hbox', align: 'stretch'}
45
+ /**
46
+ * @member {Object} layout={ntype:'hbox',align:'stretch'}
47
+ */
48
+ layout: {ntype: 'hbox', align: 'stretch'},
49
+ /**
50
+ * @member {Neo.model.Component} model=MainContainerModel
51
+ */
52
+ model: MainContainerModel
34
53
  }
35
54
  }
36
55
 
@@ -20,9 +20,9 @@ class ServiceWorker extends ServiceBase {
20
20
  */
21
21
  singleton: true,
22
22
  /**
23
- * @member {String} version='6.9.8'
23
+ * @member {String} version='6.9.10'
24
24
  */
25
- version: '6.9.8'
25
+ version: '6.9.10'
26
26
  }
27
27
 
28
28
  /**
@@ -181,7 +181,7 @@ class MainContainer extends ConfigurationViewport {
181
181
  createExampleComponent() {
182
182
  return Neo.create(TextAreaField, {
183
183
  clearable : true,
184
- height : 60,
184
+ height : 120,
185
185
  labelText : 'Label',
186
186
  labelWidth: 70,
187
187
  value : 'Hello World',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neo.mjs",
3
- "version": "6.9.8",
3
+ "version": "6.9.10",
4
4
  "description": "The webworkers driven UI framework",
5
5
  "type": "module",
6
6
  "repository": {
@@ -49,7 +49,7 @@
49
49
  "clean-webpack-plugin": "^4.0.0",
50
50
  "commander": "^11.1.0",
51
51
  "cssnano": "^6.0.1",
52
- "envinfo": "^7.10.0",
52
+ "envinfo": "^7.11.0",
53
53
  "fs-extra": "^11.1.1",
54
54
  "highlightjs-line-numbers.js": "^2.8.0",
55
55
  "inquirer": "^9.2.11",
@@ -1,63 +0,0 @@
1
- .learn-content {
2
-
3
- font-size: 13pt;
4
- letter-spacing: 1px;
5
-
6
- em,
7
- i {
8
- font-family: Palatino, "Times New Roman", serif;
9
- font-size: 1.07em;
10
- }
11
-
12
- p {
13
- margin: 0.5em 0em 0.7em 0em ;
14
- }
15
-
16
- mark {
17
- background-color: #B8FCE3;
18
- color: black;
19
- padding: 0.1em 0.2em;
20
- }
21
-
22
- padding: 1em;
23
-
24
- overflow: scroll;
25
-
26
- details summary {
27
- cursor: pointer;
28
- transition: margin 300ms ease-out;
29
- }
30
-
31
- details[open] {
32
- margin-bottom: 2em;
33
- }
34
-
35
- details summary {
36
- list-style: none;
37
- color: #555;
38
- display: flex;
39
- /* also removes the list marker */
40
- align-items: center;
41
- font-weight: bold;
42
- }
43
-
44
- details summary::before {
45
- content: "\f055";
46
- }
47
-
48
- details[open] summary::before {
49
- content: "\f056";
50
- }
51
-
52
- details summary::before {
53
- font-family: var(--fa-style-family, "Font Awesome 6 Free");
54
- font-weight: var(--fa-style, 900);
55
- font-size: 1.3em;
56
- margin: 0.4em 0.4em 0.4em 0;
57
- color: #c4c4c4;
58
- }
59
-
60
- summary::-webkit-details-marker {
61
- display: none;
62
- }
63
- }
@@ -0,0 +1,61 @@
1
+ .learn-content {
2
+ font-family : 'Open Sans';
3
+ font-size : 13pt;
4
+ letter-spacing: 1px;
5
+ overflow : scroll;
6
+ padding : 1em;
7
+
8
+ em,
9
+ i {
10
+ font-family: Palatino, "Times New Roman", serif;
11
+ font-size : 1.07em;
12
+ }
13
+
14
+ p {
15
+ margin: 0.5em 0em 0.7em 0em;
16
+ }
17
+
18
+ mark {
19
+ background-color: #B8FCE3;
20
+ color : black;
21
+ padding : 0.1em 0.2em;
22
+ }
23
+
24
+ details summary {
25
+ cursor: pointer;
26
+ transition: margin 300ms ease-out;
27
+ }
28
+
29
+ details[open] {
30
+ margin-bottom: 2em;
31
+ }
32
+
33
+ details summary {
34
+ list-style: none;
35
+ color: #555;
36
+ display: flex;
37
+ /* also removes the list marker */
38
+ align-items: center;
39
+ font-weight: bold;
40
+ }
41
+
42
+ details summary::before {
43
+ content: "\f055";
44
+ }
45
+
46
+ details[open] summary::before {
47
+ content: "\f056";
48
+ }
49
+
50
+ details summary::before {
51
+ color : #c4c4c4;
52
+ font-family: var(--fa-style-family, "Font Awesome 6 Free");
53
+ font-size : 1.3em;
54
+ font-weight: var(--fa-style, 900);
55
+ margin : 0.4em 0.4em 0.4em 0;
56
+ }
57
+
58
+ summary::-webkit-details-marker {
59
+ display: none;
60
+ }
61
+ }
@@ -0,0 +1,37 @@
1
+ .topics-tree {
2
+ &.neo-tree-list {
3
+ .neo-treelist-collapse-all-icon {
4
+ .neo-treelist-menu-item-content:before {
5
+ content: "\f102" !important;
6
+ }
7
+ }
8
+
9
+ .neo-treelist-expand-all-icon {
10
+ .neo-treelist-menu-item-content:before {
11
+ content: "\f103" !important;
12
+ }
13
+ }
14
+
15
+ .neo-list-container {
16
+ .neo-list-item {
17
+ &.neo-list-item-leaf {
18
+ .neo-list-item-content:before {
19
+ content: none !important;
20
+ }
21
+ }
22
+
23
+ &.neo-list-folder {
24
+ .neo-list-item-content:before {
25
+ content: "\f107" !important;
26
+ }
27
+
28
+ &.neo-folder-open {
29
+ .neo-list-item-content:before {
30
+ content: "\f106" !important;
31
+ }
32
+ }
33
+ }
34
+ }
35
+ }
36
+ }
37
+ }
@@ -136,8 +136,8 @@
136
136
  }
137
137
 
138
138
  // During upload, it's a progress circle.
139
- // Of the upload fails, the process circle stops but remains visible
140
- .neo-file-upload-state-uploading, .neo-file-upload-state-upload-failed {
139
+ // Of the upload fails, the process circle stops but remains visible //todo
140
+ .neo-file-upload-state-uploading, .neo-file-upload-state-upload-failed, .neo-file-upload-state-error {
141
141
  .neo-file-upload-state-icon {
142
142
  background-image : conic-gradient(
143
143
  var(--fileuploadfield-progress-color) 0 var(--upload-progress),
@@ -184,8 +184,8 @@
184
184
  }
185
185
  }
186
186
 
187
- // If the upload or scan failed, we show an error UI and the action button cancels
188
- .neo-file-upload-state-upload-failed, .neo-file-upload-state-scan-failed, .neo-file-upload-field.neo-invalid {
187
+ // If the upload or scan failed, we show an error UI and the action button cancels //todo error
188
+ .neo-file-upload-state-upload-failed, .neo-file-upload-state-scan-failed, .neo-file-upload-field.neo-invalid, .neo-file-upload-state-error {
189
189
  --fileuploadfield-progress-color : var(--fileuploadfield-error-color);
190
190
  border-color : var(--fileuploadfield-error-color);
191
191
 
@@ -12,7 +12,7 @@
12
12
  }
13
13
 
14
14
  .neo-field-trigger {
15
- border-bottom: 1px solid var(--textfield-border-color);
15
+ height : inherit;
16
16
  }
17
17
 
18
18
  .neo-textfield-error {
@@ -236,12 +236,12 @@ const DefaultConfig = {
236
236
  useVdomWorker: true,
237
237
  /**
238
238
  * buildScripts/injectPackageVersion.mjs will update this value
239
- * @default '6.9.8'
239
+ * @default '6.9.10'
240
240
  * @memberOf! module:Neo
241
241
  * @name config.version
242
242
  * @type String
243
243
  */
244
- version: '6.9.8'
244
+ version: '6.9.10'
245
245
  };
246
246
 
247
247
  Object.assign(DefaultConfig, {
@@ -322,7 +322,8 @@ class FileUpload extends Base {
322
322
  malwareFoundInFile : 'Malware found in file',
323
323
  pleaseCheck : 'Please check the file and try again',
324
324
  successfullyUploaded : 'Successfully uploaded',
325
- fileWasDeleted : 'File was deleted'
325
+ fileWasDeleted : 'File was deleted',
326
+ fileIsInAnErrorState : 'File is in an error state'
326
327
  }
327
328
 
328
329
  /**
@@ -565,6 +566,7 @@ class FileUpload extends Base {
565
566
  // saved, so we just go back to ready state
566
567
  case 'upload-failed':
567
568
  case 'scan-failed':
569
+ case 'error':
568
570
  me.clear();
569
571
  me.state = 'ready';
570
572
  break;
@@ -729,7 +731,12 @@ class FileUpload extends Base {
729
731
  case 'deleted':
730
732
  status.innerHTML = me.fileWasDeleted;
731
733
  isChangeEventNeeded = true;
732
- }
734
+ break;
735
+ case 'error':
736
+ status.innerHTML = me.fileIsInAnErrorState;
737
+ me.error = me.pleaseCheck;
738
+ isChangeEventNeeded = true;
739
+ }
733
740
 
734
741
  if (isChangeEventNeeded && oldValue !== undefined) {
735
742
  me.fireChangeEvent(me.file)
@@ -2,6 +2,7 @@ import Base from './Base.mjs';
2
2
  import BaseTrigger from './trigger/Base.mjs';
3
3
  import ClearTrigger from './trigger/Clear.mjs';
4
4
  import NeoArray from '../../util/Array.mjs';
5
+ import StringUtil from '../../util/String.mjs';
5
6
  import VDomUtil from '../../util/VDom.mjs';
6
7
  import VNodeUtil from '../../util/VNode.mjs';
7
8
 
@@ -234,6 +235,14 @@ class Text extends Base {
234
235
  * @member {Function|String|null} validator=null
235
236
  */
236
237
  validator: null,
238
+ /**
239
+ * getVlue can be xssProtected and values are escaped
240
+ * @member {Boolean} xssProtected=false
241
+ */
242
+ xssProtected_: false,
243
+ /**
244
+ * @member {Object} _vdom
245
+ */
237
246
  /**
238
247
  * @member {Object} _vdom
239
248
  */
@@ -1144,6 +1153,17 @@ class Text extends Base {
1144
1153
  return this.id + '-trigger-' + type
1145
1154
  }
1146
1155
 
1156
+ /**
1157
+ * @returns {*}
1158
+ */
1159
+ getValue() {
1160
+ if (this.xssProtected) {
1161
+ return StringUtil.escapeHtml(super.getValue())
1162
+ } else {
1163
+ return super.getValue()
1164
+ }
1165
+ }
1166
+
1147
1167
  /**
1148
1168
  * @returns {Boolean}
1149
1169
  */
@@ -1269,10 +1289,14 @@ class Text extends Base {
1269
1289
  if (centerBorderEl && me.isEmpty()) {
1270
1290
  delete centerBorderEl.width;
1271
1291
  }
1292
+ }
1272
1293
 
1273
- me.update()
1294
+ if (Neo.isString(me.value)) {
1295
+ me.value = me.value.trim()
1274
1296
  }
1275
1297
 
1298
+ me.update();
1299
+
1276
1300
  super.onFocusLeave(data)
1277
1301
  }
1278
1302
 
@@ -1288,7 +1312,11 @@ class Text extends Base {
1288
1312
 
1289
1313
  if (vnode) {
1290
1314
  // required for validation -> revert a wrong user input
1291
- vnode.vnode.attributes.value = value;
1315
+ vnode.vnode.attributes.value = value
1316
+ }
1317
+
1318
+ if (Neo.isString(value)) {
1319
+ value = value.trim()
1292
1320
  }
1293
1321
 
1294
1322
  me.clean = false;
@@ -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
  */
@@ -74,6 +74,15 @@ class TextArea extends Text {
74
74
  wrap_: null
75
75
  }
76
76
 
77
+ afterSetAutoGrow(autoGrow) {
78
+ this.syncAutoGrowMonitor();
79
+
80
+ // Restore any configured height if autoGrow turned off
81
+ if (!autoGrow) {
82
+ this.afterSetHeight(this._height);
83
+ }
84
+ }
85
+
77
86
  /**
78
87
  * Triggered after the cols config got changed
79
88
  * @param {Number|null} value
@@ -102,7 +111,7 @@ class TextArea extends Text {
102
111
  */
103
112
  afterSetMounted(value, oldValue) {
104
113
  super.afterSetMounted(value, oldValue);
105
- this.syncAutoGrowHeight();
114
+ this.syncAutoGrowMonitor();
106
115
  }
107
116
 
108
117
  /**
@@ -143,7 +152,6 @@ class TextArea extends Text {
143
152
  }
144
153
 
145
154
  super.afterSetValue(value, oldValue);
146
- this.syncAutoGrowHeight();
147
155
  }
148
156
 
149
157
  /**
@@ -167,37 +175,14 @@ class TextArea extends Text {
167
175
  return this.beforeSetEnumValue(value, oldValue, 'wrap', 'wrapValues');
168
176
  }
169
177
 
170
- /**
171
- * @param {Object} data
172
- * @protected
173
- */
174
- onInputValueChange(data) {
175
- this.syncAutoGrowHeight();
176
- super.onInputValueChange(data);
177
- }
178
-
179
- /**
180
- * @protected
181
- */
182
- async syncAutoGrowHeight() {
183
- let me = this;
184
-
185
- if (me.mounted && me.autoGrow) {
186
- const
187
- inputEl = me.getInputEl(),
188
- dims = await Neo.main.DomAccess.getScrollingDimensions({
189
- appName : me.appName,
190
- id : me.getInputElId()
191
- });
192
-
193
- // We must not show the scrollbar when autoGrowing
194
- inputEl.style.overflowY = 'hidden';
195
-
196
- if (dims.scrollHeight > dims.clientHeight - 5) {
197
- inputEl.height = dims.scrollHeight;
198
- }
199
-
200
- me.update();
178
+ async syncAutoGrowMonitor() {
179
+ if (this.mounted) {
180
+ // Delegate monitoring of sizes to the VDOM thread.
181
+ Neo.main.DomAccess.monitorAutoGrow({
182
+ appName : this.appName,
183
+ id : this.getInputElId(),
184
+ autoGrow : this.autoGrow
185
+ });
201
186
  }
202
187
  }
203
188
  }
@@ -102,6 +102,7 @@ class DomAccess extends Base {
102
102
  'getBoundingClientRect',
103
103
  'getScrollingDimensions',
104
104
  'measure',
105
+ 'monitorAutoGrow',
105
106
  'scrollBy',
106
107
  'scrollIntoView',
107
108
  'scrollTo',
@@ -582,6 +583,39 @@ class DomAccess extends Base {
582
583
  return value;
583
584
  }
584
585
 
586
+ /**
587
+ * Checks the overflow status of a TextAreaField's &lt;textarea> element and updates the
588
+ * height so that there is never a vertical scrollbar.
589
+ * @param {Object} data
590
+ */
591
+ async monitorAutoGrow(data) {
592
+ const
593
+ me = this,
594
+ target = data.subject = me.getElement(data.id);
595
+
596
+ // We need to update the height on every input event is autoGrow is truthy.
597
+ target[data.autoGrow ? 'addEventListener' : 'removeEventListener']('input', me.monitorAutoGrowHandler);
598
+
599
+ // Fix the height up immediately too
600
+ if (data.autoGrow) {
601
+ me.monitorAutoGrowHandler({
602
+ target
603
+ });
604
+ }
605
+ }
606
+
607
+ monitorAutoGrowHandler({ target }) {
608
+ const
609
+ { style } = target,
610
+ { style : inputStyle } = target.closest('.neo-textarea');
611
+
612
+ // Measure the scrollHeight when forced to overflow, then set height to encompass the scrollHeight
613
+ style.height = style.minHeight = 0;
614
+ inputStyle.setProperty('--textfield-input-height', `${target.scrollHeight + 5}px`);
615
+ inputStyle.setProperty('height', '');
616
+ style.height = style.minHeight = '';
617
+ }
618
+
585
619
  /**
586
620
  * @param {Array} mutations
587
621
  */
@@ -96,18 +96,6 @@ class HighlightJS extends Base {
96
96
  })
97
97
  }
98
98
 
99
- /**
100
- * @param {Object} data
101
- * @returns {Boolean}
102
- */
103
- setConfigs(data) {
104
- delete data.appName;
105
-
106
- this.set(data);
107
-
108
- return true
109
- }
110
-
111
99
  /**
112
100
  * You can pass in 'light', 'dark', or a path for a custom theme
113
101
  * @param {String} theme
@@ -14,18 +14,20 @@ class StringUtil extends Base {
14
14
  '<' : '&lt;',
15
15
  '>' : '&gt;',
16
16
  '"' : '&quot;',
17
- '\'': '&#039;'
17
+ '\'': '&apos;',
18
+ '$' : '&dollar;',
19
+ '\\': '&bsol;'
18
20
  }
19
21
  /**
20
22
  * @member {RegExp} charPattern
21
23
  * @static
22
24
  */
23
- static charPattern = /[&<>"']/g
25
+ static charPattern = /[&<>"'$\\]/g
24
26
  /**
25
27
  * @member {RegExp} entityPattern
26
28
  * @static
27
29
  */
28
- static entityPattern = /(&amp;)|(&lt;)|(&gt;)|(&quot;)|(&#039;)/g
30
+ static entityPattern = /(&amp;)|(&lt;)|(&gt;)|(&quot;)|(&apos;)|(&dollar;)|(&bsol;)/g
29
31
 
30
32
  static config = {
31
33
  /**
@@ -30,6 +30,6 @@ StartTest(t => {
30
30
  }
31
31
  }
32
32
  })
33
- }, 300)
33
+ }, 1000)
34
34
  });
35
35
  });
@@ -1,27 +0,0 @@
1
- {
2
- "data": [{
3
- "id" : 1,
4
- "isLeaf" : true,
5
- "name" : "Why neo.mjs",
6
- "parentId": null,
7
- "path" : "whyneo.md"
8
- }, {
9
- "id" : 2,
10
- "isLeaf" : false,
11
- "name" : "Class Definitions and Config",
12
- "parentId": null,
13
- "path" : null
14
- }, {
15
- "id" : 3,
16
- "isLeaf" : false,
17
- "name" : "Class Basics",
18
- "parentId": 2,
19
- "path" : null
20
- }, {
21
- "id" : 4,
22
- "isLeaf" : true,
23
- "name" : "Classes, Properties, and Methods",
24
- "parentId": 3,
25
- "path" : null
26
- }]
27
- }