neo.mjs 10.0.0-alpha.4 → 10.0.0-beta.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 (98) hide show
  1. package/ServiceWorker.mjs +2 -2
  2. package/apps/portal/index.html +1 -1
  3. package/apps/portal/resources/data/examples_devmode.json +26 -27
  4. package/apps/portal/resources/data/examples_dist_dev.json +26 -27
  5. package/apps/portal/resources/data/examples_dist_esm.json +26 -27
  6. package/apps/portal/resources/data/examples_dist_prod.json +27 -28
  7. package/apps/portal/view/blog/List.mjs +1 -1
  8. package/apps/portal/view/home/FooterContainer.mjs +1 -1
  9. package/apps/portal/view/learn/ContentComponent.mjs +102 -111
  10. package/buildScripts/buildThemes.mjs +1 -1
  11. package/examples/grid/animatedRowSorting/Viewport.mjs +4 -4
  12. package/examples/grid/bigData/ControlsContainer.mjs +3 -3
  13. package/examples/grid/bigData/GridContainer.mjs +8 -8
  14. package/examples/grid/cellEditing/MainContainer.mjs +5 -5
  15. package/examples/grid/container/MainContainer.mjs +4 -4
  16. package/examples/grid/nestedRecordFields/Viewport.mjs +5 -5
  17. package/examples/table/cellEditing/MainContainer.mjs +1 -1
  18. package/examples/table/container/MainContainer.mjs +3 -3
  19. package/examples/table/nestedRecordFields/Viewport.mjs +6 -6
  20. package/examples/tableFiltering/MainContainer.mjs +1 -1
  21. package/examples/tablePerformance/MainContainer.mjs +1 -1
  22. package/examples/tablePerformance/MainContainer2.mjs +1 -1
  23. package/examples/tablePerformance/MainContainer3.mjs +2 -2
  24. package/examples/tableStore/MainContainer.mjs +2 -2
  25. package/learn/UsingTheseTopics.md +2 -2
  26. package/learn/benefits/ConfigSystem.md +2 -2
  27. package/learn/benefits/FormsEngine.md +14 -14
  28. package/learn/benefits/MultiWindow.md +2 -2
  29. package/learn/benefits/OffTheMainThread.md +2 -2
  30. package/learn/benefits/Speed.md +2 -2
  31. package/learn/gettingstarted/ComponentModels.md +4 -4
  32. package/learn/gettingstarted/Config.md +6 -6
  33. package/learn/gettingstarted/DescribingTheUI.md +4 -4
  34. package/learn/gettingstarted/Events.md +6 -6
  35. package/learn/gettingstarted/Extending.md +4 -4
  36. package/learn/gettingstarted/References.md +6 -6
  37. package/learn/gettingstarted/Workspaces.md +6 -6
  38. package/learn/guides/ApplicationBootstrap.md +40 -42
  39. package/learn/guides/ComponentsAndContainers.md +12 -12
  40. package/learn/guides/CustomComponents.md +2 -2
  41. package/learn/guides/MainThreadAddonIntro.md +2 -2
  42. package/learn/guides/PortalApp.md +2 -2
  43. package/learn/guides/StateProviders.md +12 -12
  44. package/learn/guides/events/CustomEvents.md +16 -16
  45. package/learn/guides/events/DomEvents.md +12 -12
  46. package/learn/javascript/ClassFeatures.md +3 -2
  47. package/learn/javascript/Classes.md +8 -8
  48. package/learn/javascript/NewNode.md +4 -4
  49. package/learn/javascript/Overrides.md +8 -8
  50. package/learn/javascript/Super.md +10 -8
  51. package/learn/tutorials/Earthquakes.md +54 -57
  52. package/learn/tutorials/TodoList.md +4 -4
  53. package/package.json +1 -1
  54. package/resources/scss/src/apps/portal/learn/ContentComponent.scss +12 -0
  55. package/resources/scss/src/grid/{View.scss → Body.scss} +2 -2
  56. package/resources/scss/src/grid/VerticalScrollbar.scss +1 -1
  57. package/resources/scss/src/grid/plugin/AnimateRows.scss +1 -1
  58. package/resources/scss/src/grid/plugin/CellEditing.scss +1 -1
  59. package/resources/scss/src/table/{View.scss → Body.scss} +1 -1
  60. package/resources/scss/src/table/plugin/CellEditing.scss +1 -1
  61. package/resources/scss/theme-dark/grid/{View.scss → Body.scss} +1 -1
  62. package/resources/scss/theme-dark/table/{View.scss → Body.scss} +1 -1
  63. package/resources/scss/theme-light/grid/{View.scss → Body.scss} +1 -1
  64. package/resources/scss/theme-light/table/{View.scss → Body.scss} +1 -1
  65. package/resources/scss/theme-neo-light/Global.scss +1 -2
  66. package/resources/scss/theme-neo-light/grid/{View.scss → Body.scss} +1 -1
  67. package/resources/scss/theme-neo-light/table/{View.scss → Body.scss} +1 -1
  68. package/src/DefaultConfig.mjs +2 -2
  69. package/src/core/Base.mjs +59 -12
  70. package/src/core/Util.mjs +14 -2
  71. package/src/draggable/grid/header/toolbar/SortZone.mjs +21 -21
  72. package/src/draggable/table/header/toolbar/SortZone.mjs +1 -1
  73. package/src/grid/{View.mjs → Body.mjs} +19 -20
  74. package/src/grid/Container.mjs +58 -58
  75. package/src/grid/ScrollManager.mjs +56 -56
  76. package/src/grid/VerticalScrollbar.mjs +2 -2
  77. package/src/grid/_export.mjs +2 -2
  78. package/src/grid/column/AnimatedChange.mjs +5 -5
  79. package/src/grid/column/Base.mjs +1 -1
  80. package/src/grid/column/Component.mjs +6 -6
  81. package/src/grid/header/Toolbar.mjs +9 -9
  82. package/src/grid/plugin/AnimateRows.mjs +1 -2
  83. package/src/main/addon/AmCharts.mjs +8 -11
  84. package/src/main/addon/Base.mjs +150 -42
  85. package/src/main/addon/GoogleMaps.mjs +9 -16
  86. package/src/main/addon/HighlightJS.mjs +2 -13
  87. package/src/main/addon/IntersectionObserver.mjs +21 -21
  88. package/src/main/addon/MonacoEditor.mjs +1 -6
  89. package/src/table/{View.mjs → Body.mjs} +19 -20
  90. package/src/table/Container.mjs +43 -43
  91. package/src/table/_export.mjs +2 -2
  92. package/src/table/plugin/CellEditing.mjs +19 -19
  93. package/src/util/Style.mjs +2 -6
  94. package/src/vdom/Helper.mjs +10 -13
  95. package/src/worker/App.mjs +6 -18
  96. package/src/worker/Base.mjs +1 -1
  97. package/src/worker/Manager.mjs +4 -8
  98. package/src/worker/mixin/RemoteMethodAccess.mjs +1 -1
@@ -1,145 +1,144 @@
1
1
  [{
2
2
  "id" : 24,
3
3
  "environments": ["Desktop", "Mobile"],
4
- "image" : "devmode/liquid-glass.png",
5
- "name" : "Liquid Glass effect",
6
- "sourceUrl" : "https://github.com/neomjs/liquid-glass-demo/blob/main/apps/myapp/view/GlassComponent.mjs",
7
- "url" : "https://neomjs.github.io/pages2/workspace/neo-liquid-glass-demo/dist/production/apps/myapp/index.html"
8
- }, {
9
- "id" : 23,
10
- "environments": ["Desktop", "Mobile"],
11
4
  "image" : "devmode/bigData.png",
12
5
  "name" : "Buffered Data Grid with 5M cells",
13
6
  "sourceUrl" : "examples/grid/bigData",
14
7
  "url" : "dist/production/examples/grid/bigData/index.html"
15
8
  }, {
16
- "id" : 22,
9
+ "id" : 23,
17
10
  "image" : "devmode/sharedcovid.png",
18
11
  "name" : "Multi Window Covid App",
19
12
  "sharedWorkers": true,
20
13
  "sourceUrl" : "apps/sharedcovid",
21
14
  "url" : "dist/production/apps/sharedcovid/index.html#mainview=table"
22
15
  }, {
23
- "id" : 21,
16
+ "id" : 22,
24
17
  "image" : "devmode/calendar-preview.png",
25
18
  "name" : "Calendar",
26
19
  "sourceUrl": "src/calendar",
27
20
  "url" : "dist/production/examples/calendar/basic/index.html"
28
21
  }, {
29
- "id" : 20,
22
+ "id" : 21,
30
23
  "image" : "devmode/helix.png",
31
24
  "name" : "component.Helix",
32
25
  "sourceUrl": "examples/component/helix",
33
26
  "url" : "dist/production/examples/component/helix/index.html"
34
27
  }, {
35
- "id" : 19,
28
+ "id" : 20,
36
29
  "image" : "devmode/mwCoronaGallery.png",
37
30
  "name" : "Multi Window Covid Gallery",
38
31
  "sharedWorkers": true,
39
32
  "sourceUrl" : "examples/component/multiWindowCoronaGallery",
40
33
  "url" : "dist/production/examples/component/multiWindowCoronaGallery/index.html"
41
34
  }, {
42
- "id" : 18,
35
+ "id" : 19,
43
36
  "image" : "devmode/offscreenCanvas.png",
44
37
  "name" : "OffscreenCanvas",
45
38
  "sourceUrl": "https://github.com/neomjs/offscreen-canvas/tree/main/apps/myapp",
46
39
  "url" : "https://neomjs.github.io/pages2/workspace/neo-offscreen-canvas-demo/dist/production/apps/myapp/index.html"
47
40
  }, {
48
- "id" : 17,
41
+ "id" : 18,
49
42
  "image" : "devmode/sharedOffscreenCanvas.png",
50
43
  "name" : "Multi-Window OffscreenCanvas",
51
44
  "sharedWorkers": true,
52
45
  "sourceUrl" : "https://github.com/neomjs/shared-offscreen",
53
46
  "url" : "https://neomjs.github.io/pages2/workspace/neo-shared-offscreen-canvas-demo/dist/production/apps/mainapp/index.html"
54
47
  }, {
55
- "id" : 16,
48
+ "id" : 17,
56
49
  "image" : "devmode/multi_window_dd.png",
57
50
  "name" : "Multi-Window Drag&Drop",
58
51
  "sharedWorkers": true,
59
52
  "sourceUrl" : "apps/shareddialog",
60
53
  "url" : "dist/production/apps/shareddialog/index.html"
61
54
  }, {
62
- "id" : 15,
55
+ "id" : 16,
63
56
  "image" : "devmode/tabContainer.png",
64
57
  "name" : "tab.Container",
65
58
  "sourceUrl": "examples/tab/container",
66
59
  "url" : "dist/production/examples/tab/container/index.html"
67
60
  }, {
68
- "id" : 14,
61
+ "id" : 15,
69
62
  "image" : "devmode/model-component-example.png",
70
63
  "name" : "State Provider Example",
71
64
  "sourceUrl": "examples/stateProvider/advanced",
72
65
  "url" : "dist/production/examples/stateProvider/advanced/index.html"
73
66
  }, {
74
- "id" : 13,
67
+ "id" : 14,
75
68
  "image" : "devmode/dragdrop.png",
76
69
  "name" : "Dialog drag&drop",
77
70
  "sourceUrl": "examples/dialog",
78
71
  "url" : "dist/production/examples/dialog/"
79
72
  }, {
80
- "id" : 12,
73
+ "id" : 13,
81
74
  "image" : "dist_prod/colorsApp.png",
82
75
  "name" : "Colors Dashboard",
83
76
  "sharedWorkers": true,
84
77
  "sourceUrl" : "apps/colors",
85
78
  "url" : "dist/production/apps/colors/index.html"
86
79
  }, {
87
- "id" : 11,
80
+ "id" : 12,
88
81
  "image" : "devmode/covidDashboard.png",
89
82
  "name" : "Covid Dashboard",
90
83
  "sourceUrl": "apps/covid",
91
84
  "url" : "dist/production/apps/covid/index.html#mainview=table"
92
85
  }, {
93
- "id" : 10,
86
+ "id" : 11,
94
87
  "image" : "devmode/coronaHelix.png",
95
88
  "name" : "COVID-19 Helix",
96
89
  "sourceUrl": "examples/component/coronaHelix",
97
90
  "url" : "dist/production/examples/component/coronaHelix/index.html"
98
91
  }, {
99
- "id" : 9,
92
+ "id" : 10,
100
93
  "image" : "devmode/coronaGallery.png",
101
94
  "name" : "COVID-19 Gallery",
102
95
  "sourceUrl": "examples/component/coronaGallery",
103
96
  "url" : "dist/production/examples/component/coronaGallery/index.html"
104
97
  }, {
105
- "id" : 8,
98
+ "id" : 9,
106
99
  "image" : "devmode/gallery.png",
107
100
  "name" : "component.Gallery",
108
101
  "sourceUrl": "examples/component/gallery",
109
102
  "url" : "dist/production/examples/component/gallery/index.html"
110
103
  }, {
111
- "id" : 7,
104
+ "id" : 8,
112
105
  "image" : "devmode/tableFiltering.png",
113
106
  "name" : "Table Filtering",
114
107
  "sourceUrl": "examples/tableFiltering",
115
108
  "url" : "dist/production/examples/tableFiltering/"
116
109
  }, {
117
- "id" : 6,
110
+ "id" : 7,
118
111
  "image" : "devmode/dateSelector.png",
119
112
  "name" : "component.DateSelector",
120
113
  "sourceUrl": "examples/component/dateSelector",
121
114
  "url" : "dist/production/examples/component/dateSelector/index.html"
122
115
  }, {
123
- "id" : 5,
116
+ "id" : 6,
124
117
  "image" : "devmode/dateField.png",
125
118
  "name" : "form.field.Date",
126
119
  "sourceUrl": "examples/form/field/date",
127
120
  "url" : "dist/production/examples/form/field/date/index.html"
128
121
  }, {
129
- "id" : 4,
122
+ "id" : 5,
130
123
  "image" : "devmode/selectField.png",
131
124
  "name" : "form.field.ComboBox",
132
125
  "sourceUrl": "examples/form/field/combobox",
133
126
  "url" : "dist/production/examples/form/field/combobox/index.html"
134
127
  }, {
135
- "id" : 3,
128
+ "id" : 4,
136
129
  "environments" : ["Desktop", "Mobile"],
137
130
  "image" : "dist_prod/portalApp.png",
138
131
  "name" : "Portal App",
139
132
  "sharedWorkers": true,
140
133
  "sourceUrl" : "apps/portal",
141
134
  "url" : "dist/production/apps/portal/index.html"
142
- }, {
135
+ },{
136
+ "id" : 3,
137
+ "image" : "devmode/liquid-glass.png",
138
+ "name" : "Liquid Glass effect",
139
+ "sourceUrl": "https://github.com/neomjs/liquid-glass-demo/blob/main/apps/myapp/view/GlassComponent.mjs",
140
+ "url" : "https://neomjs.github.io/pages2/workspace/neo-liquid-glass-demo/dist/production/apps/myapp/index.html"
141
+ }, , {
143
142
  "hidden" : true,
144
143
  "id" : 2,
145
144
  "image" : "devmode/realworldApp.png",
@@ -174,7 +174,7 @@ class List extends BaseList {
174
174
  record = store.getAt(index);
175
175
  name = record.name.replace(List.nameRegEx, "$1");
176
176
 
177
- item.style = item.style || {};
177
+ item.style ??= {};
178
178
 
179
179
  if (emptyValue) {
180
180
  itemName.html = name;
@@ -107,7 +107,7 @@ class FooterContainer extends Container {
107
107
  }, {
108
108
  module: Component,
109
109
  cls : ['neo-version'],
110
- html : 'v10.0.0-alpha.4'
110
+ html : 'v10.0.0-beta.1'
111
111
  }]
112
112
  }],
113
113
  /**
@@ -5,9 +5,9 @@ import {marked} from '../../../../node_modules/marked/lib/marked.esm.js';
5
5
  const
6
6
  labCloseRegex = /<!--\s*\/lab\s*-->/g,
7
7
  labOpenRegex = /<!--\s*lab\s*-->/g,
8
- preLivePreviewRegex = /<pre\s+data-code-livepreview\s*>([\s\S]*?)<\/pre>/g,
9
- preJsRegex = /<pre\s+data-code-readonly\s*>([\s\S]*?)<\/pre>/g,
10
- preNeoComponentRegex = /<pre\s+data-neo-component\s*>([\s\S]*?)<\/pre>/g;
8
+ regexLivePreview = /```(javascript|html|css|json)\s+live-preview\s*\n([\s\S]*?)\n```/g,
9
+ regexNeoComponent = /```json\s+neo-component\s*\n([\s\S]*?)\n```/g,
10
+ regexReadonly = /```(javascript|html|css|json)\s+readonly\s*\n([\s\S]*?)\n```/g;
11
11
 
12
12
  /**
13
13
  * @class Portal.view.learn.ContentComponent
@@ -164,48 +164,48 @@ class ContentComponent extends Component {
164
164
  {appName, windowId} = me,
165
165
  path = me.getStateProvider().getData('contentPath'),
166
166
  pagesFolder = path.includes('/learn/') ? '' : 'pages/',
167
- baseConfigs, content, data, html, instance, modifiedHtml, neoComponents, neoDivs;
167
+ baseConfigs, content, data, html, instance, neoComponents, neoDivs;
168
168
 
169
169
  path += `${pagesFolder + record.id.replaceAll('.', '/')}.md`;
170
170
 
171
171
  if (record.isLeaf && path) {
172
- baseConfigs = {appName, autoMount: true, autoRender: true, parentComponent: me, windowId};
173
- data = await fetch(path);
174
- content = await data.text();
175
- content = me.updateContentSectionsStore(content); // also replaces ## with h2 tags
176
- content = `<h1 class='neo-h1'>${record.name}</h1>\n${content}`;
177
- modifiedHtml = await me.highlightPreContent(content);
172
+ baseConfigs = {appName, autoMount: true, autoRender: true, parentComponent: me, windowId};
173
+ data = await fetch(path);
174
+ content = await data.text();
175
+ // Update content sections (modifies markdown content with h2/h3 tags and IDs)
176
+ content = me.updateContentSectionsStore(content);
177
+ content = `<h1 class='neo-h1'>${record.name}</h1>\n${content}`;
178
+ // Initialize maps for custom components and live previews
178
179
  neoComponents = {};
179
180
  neoDivs = {};
180
-
181
- // Replace <pre neo-component></pre> with <div id='neo-component-x'/>
182
- // and create a map keyed by ID, whose value is the javascript
183
- // from the <pre>
184
- modifiedHtml = me.extractNeoComponents(modifiedHtml, neoComponents);
185
-
186
- // Replace <pre data-neo></pre> with <div id='neo-preview-1'/>
187
- // and create a map keyed by ID, whose value is the javascript
188
- // from the <pre>
189
- modifiedHtml = me.extractLivePreviewContent(modifiedHtml, neoDivs);
190
-
191
- html = marked.parse(modifiedHtml);
192
- html = me.insertLabDivs(html);
193
-
194
- me.toggleCls('lab', record.name?.startsWith('Lab:'));
195
-
196
- me.html = html;
181
+ // Process custom Neo.mjs component blocks (synchronous)
182
+ content = me.processNeoComponentsBlocks(content, neoComponents);
183
+ // Process custom Live Preview blocks (synchronous)
184
+ content = me.processLivePreviewBlocks(content, neoDivs);
185
+ // Process custom Readonly Code blocks (asynchronous due to HighlightJS)
186
+ // This will replace the markdown fenced block with the highlighted HTML <pre> tag.
187
+ content = await me.processReadonlyCodeBlocks(content, windowId);
188
+ // Parse the (now modified) markdown content into HTML
189
+ // This content string now contains standard markdown PLUS the HTML divs/pres we injected.
190
+ html = marked.parse(content);
191
+ // Insert lab divs (these are markdown comments, so process on the final HTML)
192
+ html = me.insertLabDivs(html); // Keep existing method
193
+
194
+ me.toggleCls('lab', record.name?.startsWith('Lab:')); // Keep existing method
195
+
196
+ me.html = html; // Set the component's HTML
197
197
 
198
198
  await me.timeout(Neo.config.environment === 'development' ? 100 : 150);
199
199
 
200
+ // Create instances for custom components and live previews (keep existing logic)
200
201
  Object.keys(neoComponents).forEach(key => {
201
202
  instance = Neo.create({
202
203
  ...baseConfigs,
203
- className: 'Neo.component.Base',
204
+ className: 'Neo.component.Base', // Adjust if specific component classes are implied by JSON
204
205
  parentId : key,
205
206
  ...neoComponents[key]
206
207
  });
207
-
208
- me.customComponents.push(instance)
208
+ me.customComponents.push(instance);
209
209
  });
210
210
 
211
211
  Object.keys(neoDivs).forEach(key => {
@@ -213,10 +213,9 @@ class ContentComponent extends Component {
213
213
  ...baseConfigs,
214
214
  module : LivePreview,
215
215
  parentId: key,
216
- value : neoDivs[key]
216
+ value : neoDivs[key].code // Pass the extracted code content
217
217
  });
218
-
219
- me.livePreviews.push(instance)
218
+ me.livePreviews.push(instance);
220
219
  });
221
220
 
222
221
  Neo.main.addon.IntersectionObserver.observe({
@@ -224,87 +223,10 @@ class ContentComponent extends Component {
224
223
  id : me.id,
225
224
  observe : ['.neo-h2', '.neo-h3'],
226
225
  windowId : me.windowId
227
- })
226
+ });
228
227
  }
229
228
  }
230
229
 
231
- /**
232
- * @param {String} htmlString
233
- * @param {Object} map
234
- * @returns {String}
235
- */
236
- extractNeoComponents(htmlString, map) {
237
- // 1. Replace <pre data-neo-component> with <div id='neo-learn-content-component-x'/>
238
- // and update map with key/value pairs, where the key is the ID and the value is the <pre> contents.
239
- // Replace the content with tokens, and create a promise to update the corresponding content
240
- return htmlString.replace(preNeoComponentRegex, (match, preContent) => {
241
- const key = Neo.core.IdGenerator.getId('learn-content-component');
242
- map[key] = JSON.parse(preContent);
243
- return `<div id="${key}"></div>`
244
- })
245
- }
246
-
247
- /**
248
- * @param {String} htmlString
249
- * @param {Object} map
250
- * @returns {String}
251
- */
252
- extractLivePreviewContent(htmlString, map) {
253
- // 1. Replace <pre data-neo> with <div id='neo-pre-live-preview-x'/>
254
- // and update map with key/value pairs, where the key is the ID and the value is the <pre> contents.
255
- // Replace the content with tokens, and create a promise to update the corresponding content
256
- return htmlString.replace(preLivePreviewRegex, (match, preContent) => {
257
- const key = Neo.core.IdGenerator.getId('pre-live-preview');
258
- map[key] = preContent;
259
- return `<div id="${key}"></div>`
260
- })
261
- }
262
-
263
- /**
264
- * @param preContent
265
- * @param token
266
- * @param id
267
- * @returns {Object}
268
- */
269
- getHighlightPromise(preContent, token, id) {
270
- // Resolves to an object of the form {after, token}, where after is the updated <pre> tag content
271
- return Neo.main.addon.HighlightJS.highlightAuto({html: preContent, windowId: this.windowId})
272
- .then(value => ({after: `<pre data-javascript id="${id}">${value}</pre>`, token}))
273
- }
274
-
275
- /**
276
- * @param {String} htmlString
277
- * @returns {Promise<*>}
278
- */
279
- async highlightPreContent(htmlString) {
280
- // 1. Replace <pre data-javascript> with unique tokens and create a HighlightJS.highlightAuto promise for each
281
- // 2. When all promises are resolved, use their values to replace the tokens.
282
-
283
- // Note that if we were to import HighlightJS directly, we wouldn't need all this async code.
284
-
285
- // Create an array to store promises for each replacement
286
- const replacementPromises = [];
287
- let count = 0;
288
-
289
- // Replace the content with tokens, and create a promise to update the corresponding content
290
- let updatedHtml = htmlString.replace(preJsRegex, (match, preContent) => {
291
- const token = `__NEO-PRE-TOKEN-${++count}__`;
292
- replacementPromises.push(this.getHighlightPromise(preContent, token, `pre-preview-${Neo.core.IdGenerator.getId()}`));
293
- return token
294
- });
295
-
296
- // Assert: updateHtml is the original, but with <pre data-javascript> replaced with tokens.
297
-
298
- // Wait for all replacement promises to resolve
299
- let replacements = await Promise.all(replacementPromises)
300
-
301
- // Replace each token with the resolved content
302
- replacements.forEach((replacement) => updatedHtml = updatedHtml.replace(replacement.token, replacement.after));
303
-
304
- // Return the final updated HTML string
305
- return updatedHtml
306
- }
307
-
308
230
  /**
309
231
  * @param {String} inputString
310
232
  * @returns {String}
@@ -335,6 +257,75 @@ class ContentComponent extends Component {
335
257
  }
336
258
  }
337
259
 
260
+ /**
261
+ * Extracts live preview code blocks from Markdown content before marked.js parsing.
262
+ * Replaces them with HTML placeholders.
263
+ * @param {String} contentString The raw Markdown content string.
264
+ * @param {Object} map A map to store the extracted code content keyed by placeholder ID.
265
+ * @returns {String} The modified Markdown content string with placeholders.
266
+ */
267
+ processLivePreviewBlocks(contentString, map) {
268
+ return contentString.replace(regexLivePreview, (match, language, code) => {
269
+ const key = Neo.core.IdGenerator.getId('pre-live-preview');
270
+ map[key] = {code, language};
271
+ return `<div id="${key}"></div>`
272
+ })
273
+ }
274
+
275
+ /**
276
+ * Extracts Neo.mjs component config blocks from Markdown content before marked.js parsing.
277
+ * Replaces them with HTML placeholders.
278
+ * @param {String} contentString The raw Markdown content string.
279
+ * @param {Object} map A map to store the extracted JSON config keyed by placeholder ID.
280
+ * @returns {String} The modified Markdown content string with placeholders.
281
+ */
282
+ processNeoComponentsBlocks(contentString, map) {
283
+ return contentString.replace(regexNeoComponent, (match, code) => {
284
+ const key = Neo.core.IdGenerator.getId('learn-content-component');
285
+ map[key] = JSON.parse(code);
286
+ return `<div id="${key}"></div>`
287
+ })
288
+ }
289
+
290
+ /**
291
+ * Highlights readonly code blocks using HighlightJS.
292
+ * Replaces the Markdown fenced block with the highlighted HTML <pre> tag.
293
+ * @param {String} contentString The raw Markdown content string.
294
+ * @param {String} windowId The ID of the current window for HighlightJS.
295
+ * @returns {Promise<String>} A promise that resolves to the modified Markdown string with highlighted HTML.
296
+ */
297
+ async processReadonlyCodeBlocks(contentString, windowId) {
298
+ let replacementPromises = [],
299
+ count = 0,
300
+ replacements;
301
+
302
+ // Replace the content with tokens, and create a promise to update the corresponding content
303
+ let updatedContent = contentString.replace(regexReadonly, (match, language, code) => {
304
+ const token = `__NEO-READONLY-TOKEN-${++count}__`;
305
+ // Call HighlightJS.highlightAuto for each block.
306
+ // The result will be HTML. We'll wrap it in a <pre data-javascript> later.
307
+ replacementPromises.push(
308
+ Neo.main.addon.HighlightJS.highlightAuto({html: code, windowId})
309
+ .then(highlightedHtml => ({
310
+ after: `<pre data-javascript id="pre-readonly-${Neo.core.IdGenerator.getId()}">${highlightedHtml}</pre>`,
311
+ token: token
312
+ }))
313
+ );
314
+
315
+ return token; // Replace the original Markdown block with a temporary token
316
+ });
317
+
318
+ // Wait for all highlighting promises to resolve
319
+ replacements = await Promise.all(replacementPromises);
320
+
321
+ // Replace each token with the resolved highlighted HTML content
322
+ replacements.forEach(replacement => {
323
+ updatedContent = updatedContent.replace(replacement.token, replacement.after)
324
+ });
325
+
326
+ return updatedContent
327
+ }
328
+
338
329
  /**
339
330
  * Updates the contentSections VM store and replaces ## with h2 tags
340
331
  * @param {String} content
@@ -12,7 +12,7 @@ import * as sass from 'sass';
12
12
  const
13
13
  __dirname = path.resolve(),
14
14
  cwd = process.cwd(),
15
- requireJson = path => JSON.parse(fs.readFileSync((path))),
15
+ requireJson = path => JSON.parse(fs.readFileSync(path)),
16
16
  packageJson = requireJson(path.resolve(cwd, 'package.json')),
17
17
  insideNeo = packageJson.name.includes('neo.mjs'),
18
18
  neoPath = path.resolve(insideNeo ? './' : './node_modules/neo.mjs/'),
@@ -52,12 +52,12 @@ class Viewport extends BaseViewport {
52
52
  store : MainStore,
53
53
  wrapperStyle: {maxWidth: '902px'},
54
54
 
55
- columnDefaults: {
56
- width: 200
55
+ bodyConfig: {
56
+ animatedRowSorting: true
57
57
  },
58
58
 
59
- viewConfig: {
60
- animatedRowSorting: true
59
+ columnDefaults: {
60
+ width: 200
61
61
  },
62
62
 
63
63
  columns: [
@@ -207,7 +207,7 @@ class ControlsContainer extends Container {
207
207
  */
208
208
  onBufferColumnRangeChange(data) {
209
209
  if (data.oldValue) {
210
- this.grid.view.bufferColumnRange = parseInt(data.value.id)
210
+ this.grid.body.bufferColumnRange = parseInt(data.value.id)
211
211
  }
212
212
  }
213
213
 
@@ -216,7 +216,7 @@ class ControlsContainer extends Container {
216
216
  */
217
217
  onBufferRowRangeChange(data) {
218
218
  if (data.oldValue) {
219
- this.grid.view.bufferRowRange = parseInt(data.value.id)
219
+ this.grid.body.bufferRowRange = parseInt(data.value.id)
220
220
  }
221
221
  }
222
222
 
@@ -263,7 +263,7 @@ class ControlsContainer extends Container {
263
263
  * @param {Object} data
264
264
  */
265
265
  onSelectionModelChange(data) {
266
- this.grid.view.selectionModel = data.component.selectionModel
266
+ this.grid.body.selectionModel = data.component.selectionModel
267
267
  }
268
268
 
269
269
  /**
@@ -17,6 +17,13 @@ class GridContainer extends BaseGridContainer {
17
17
  * @member {Number} amountColumns_=50
18
18
  */
19
19
  amountColumns_: 50,
20
+ /**
21
+ * @member {Object} bodyConfig
22
+ */
23
+ bodyConfig: {
24
+ bufferColumnRange: 3,
25
+ bufferRowRange : 5
26
+ },
20
27
  /**
21
28
  * Default configs for each column
22
29
  * @member {Object} columnDefaults
@@ -29,14 +36,7 @@ class GridContainer extends BaseGridContainer {
29
36
  /**
30
37
  * @member {Object[]} store=MainStore
31
38
  */
32
- store: MainStore,
33
- /**
34
- * @member {Object} viewConfig
35
- */
36
- viewConfig: {
37
- bufferColumnRange: 3,
38
- bufferRowRange : 5
39
- }
39
+ store: MainStore
40
40
  }
41
41
 
42
42
  /**
@@ -114,6 +114,10 @@ class MainContainer extends ConfigurationViewport {
114
114
  store : MainStore,
115
115
  wrapperStyle: {maxWidth: '1002px'},
116
116
 
117
+ bodyConfig: {
118
+ selectionModel: CellModel
119
+ },
120
+
117
121
  columnDefaults: {
118
122
  editable: true,
119
123
  width : 200
@@ -160,11 +164,7 @@ class MainContainer extends ConfigurationViewport {
160
164
  dataField: 'githubId',
161
165
  editable : false,
162
166
  text : 'Github Id (Non-editable)'
163
- }],
164
-
165
- viewConfig: {
166
- selectionModel: CellModel
167
- }
167
+ }]
168
168
  }
169
169
  }
170
170
 
@@ -88,6 +88,10 @@ class MainContainer extends ConfigurationViewport {
88
88
  width: 200
89
89
  },
90
90
 
91
+ bodyConfig: {
92
+ selectionModel: CellModel
93
+ },
94
+
91
95
  columns: [
92
96
  {dataField: 'firstname', text: 'Firstname'},
93
97
  {dataField: 'lastname', text: 'Lastname'},
@@ -95,10 +99,6 @@ class MainContainer extends ConfigurationViewport {
95
99
  {dataField: 'country', text: 'Country'}
96
100
  ],
97
101
 
98
- viewConfig: {
99
- selectionModel: CellModel
100
- },
101
-
102
102
  wrapperStyle: {
103
103
  height: '250px'
104
104
  }
@@ -51,6 +51,10 @@ class Viewport extends BaseViewport {
51
51
  bind : {store: 'stores.mainStore'},
52
52
  reference: 'grid',
53
53
 
54
+ bodyConfig: {
55
+ highlightModifiedCells: true
56
+ },
57
+
54
58
  columnDefaults: {
55
59
  width: 200
56
60
  },
@@ -66,11 +70,7 @@ class Viewport extends BaseViewport {
66
70
  handler: 'editButtonHandler',
67
71
  text : 'Edit'
68
72
  }}
69
- ],
70
-
71
- viewConfig: {
72
- highlightModifiedCells: true
73
- }
73
+ ]
74
74
  }]
75
75
  }
76
76
  }
@@ -113,7 +113,7 @@ class MainContainer extends ConfigurationViewport {
113
113
  parentId : this.id,
114
114
  store : MainStore,
115
115
 
116
- viewConfig: {
116
+ bodyConfig: {
117
117
  selectionModel: CellModel
118
118
  },
119
119
 
@@ -115,7 +115,7 @@ class MainContainer extends ConfigurationViewport {
115
115
  id : 'myTableStoreContainer',
116
116
  store: MainStore,
117
117
 
118
- viewConfig: {
118
+ bodyConfig: {
119
119
  selectionModel: CellModel
120
120
  },
121
121
 
@@ -139,7 +139,7 @@ class MainContainer extends ConfigurationViewport {
139
139
  text : 'Edit'
140
140
  }));
141
141
 
142
- me.view.updateDepth = -1;
142
+ me.body.updateDepth = -1;
143
143
 
144
144
  return button.createVdomReference()
145
145
  }
@@ -168,7 +168,7 @@ class MainContainer extends ConfigurationViewport {
168
168
  }
169
169
  }));
170
170
 
171
- me.view.updateDepth = -1;
171
+ me.body.updateDepth = -1;
172
172
 
173
173
  return button.createVdomReference()
174
174
  }