neo.mjs 10.0.0-alpha.5 → 10.0.0-beta.2

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 (188) hide show
  1. package/ServiceWorker.mjs +2 -2
  2. package/apps/colors/view/GridContainer.mjs +1 -1
  3. package/apps/covid/view/AttributionComponent.mjs +1 -1
  4. package/apps/covid/view/HeaderContainer.mjs +6 -6
  5. package/apps/covid/view/MainContainerController.mjs +5 -5
  6. package/apps/covid/view/TableContainerController.mjs +1 -1
  7. package/apps/covid/view/country/Gallery.mjs +13 -13
  8. package/apps/covid/view/country/Helix.mjs +13 -13
  9. package/apps/covid/view/country/HistoricalDataTable.mjs +1 -1
  10. package/apps/email/view/Viewport.mjs +2 -2
  11. package/apps/form/view/SideNavList.mjs +1 -1
  12. package/apps/portal/index.html +1 -1
  13. package/apps/portal/resources/data/examples_devmode.json +26 -27
  14. package/apps/portal/resources/data/examples_dist_dev.json +26 -27
  15. package/apps/portal/resources/data/examples_dist_esm.json +25 -26
  16. package/apps/portal/resources/data/examples_dist_prod.json +26 -27
  17. package/apps/portal/view/HeaderToolbar.mjs +3 -3
  18. package/apps/portal/view/about/Container.mjs +2 -2
  19. package/apps/portal/view/about/MemberContainer.mjs +3 -3
  20. package/apps/portal/view/blog/List.mjs +7 -7
  21. package/apps/portal/view/examples/List.mjs +4 -4
  22. package/apps/portal/view/home/ContentBox.mjs +2 -2
  23. package/apps/portal/view/home/FeatureSection.mjs +3 -3
  24. package/apps/portal/view/home/FooterContainer.mjs +7 -7
  25. package/apps/portal/view/home/parts/AfterMath.mjs +3 -3
  26. package/apps/portal/view/home/parts/MainNeo.mjs +3 -3
  27. package/apps/portal/view/home/parts/References.mjs +6 -6
  28. package/apps/portal/view/learn/ContentComponent.mjs +102 -111
  29. package/apps/portal/view/learn/PageSectionsContainer.mjs +1 -1
  30. package/apps/portal/view/learn/PageSectionsList.mjs +2 -2
  31. package/apps/portal/view/services/Component.mjs +16 -16
  32. package/apps/realworld/view/FooterComponent.mjs +1 -1
  33. package/apps/realworld/view/HeaderComponent.mjs +8 -8
  34. package/apps/realworld/view/HomeComponent.mjs +6 -6
  35. package/apps/realworld/view/article/CommentComponent.mjs +4 -4
  36. package/apps/realworld/view/article/Component.mjs +14 -14
  37. package/apps/realworld/view/article/CreateCommentComponent.mjs +3 -3
  38. package/apps/realworld/view/article/CreateComponent.mjs +3 -3
  39. package/apps/realworld/view/article/PreviewComponent.mjs +1 -1
  40. package/apps/realworld/view/article/TagListComponent.mjs +2 -2
  41. package/apps/realworld/view/user/ProfileComponent.mjs +8 -8
  42. package/apps/realworld/view/user/SettingsComponent.mjs +4 -4
  43. package/apps/realworld/view/user/SignUpComponent.mjs +4 -4
  44. package/apps/realworld2/view/FooterComponent.mjs +1 -1
  45. package/apps/realworld2/view/HomeContainer.mjs +3 -3
  46. package/apps/realworld2/view/article/DetailsContainer.mjs +1 -1
  47. package/apps/realworld2/view/article/PreviewComponent.mjs +7 -7
  48. package/apps/realworld2/view/article/TagListComponent.mjs +2 -2
  49. package/apps/realworld2/view/user/ProfileContainer.mjs +1 -1
  50. package/apps/route/view/center/CardAdministration.mjs +2 -2
  51. package/apps/route/view/center/CardAdministrationDenied.mjs +1 -1
  52. package/apps/route/view/center/CardContact.mjs +2 -2
  53. package/apps/route/view/center/CardHome.mjs +1 -1
  54. package/apps/route/view/center/CardSection1.mjs +1 -1
  55. package/apps/route/view/center/CardSection2.mjs +1 -1
  56. package/apps/sharedcovid/view/AttributionComponent.mjs +1 -1
  57. package/apps/sharedcovid/view/HeaderContainer.mjs +6 -6
  58. package/apps/sharedcovid/view/MainContainerController.mjs +5 -5
  59. package/apps/sharedcovid/view/TableContainerController.mjs +1 -1
  60. package/apps/sharedcovid/view/country/Gallery.mjs +13 -13
  61. package/apps/sharedcovid/view/country/Helix.mjs +13 -13
  62. package/apps/sharedcovid/view/country/HistoricalDataTable.mjs +1 -1
  63. package/apps/shareddialog/childapps/shareddialog2/view/MainContainer.mjs +1 -1
  64. package/apps/shareddialog/view/MainContainer.mjs +1 -1
  65. package/buildScripts/createApp.mjs +2 -2
  66. package/examples/table/cellEditing/MainContainer.mjs +1 -1
  67. package/examples/table/container/MainContainer.mjs +3 -3
  68. package/examples/table/nestedRecordFields/Viewport.mjs +6 -6
  69. package/examples/tableFiltering/MainContainer.mjs +1 -1
  70. package/examples/tablePerformance/MainContainer.mjs +1 -1
  71. package/examples/tablePerformance/MainContainer2.mjs +1 -1
  72. package/examples/tablePerformance/MainContainer3.mjs +2 -2
  73. package/examples/tableStore/MainContainer.mjs +2 -2
  74. package/learn/Glossary.md +261 -0
  75. package/learn/UsingTheseTopics.md +2 -2
  76. package/learn/benefits/ConfigSystem.md +538 -28
  77. package/learn/benefits/Effort.md +47 -2
  78. package/learn/benefits/Features.md +50 -32
  79. package/learn/benefits/FormsEngine.md +68 -38
  80. package/learn/benefits/MultiWindow.md +33 -7
  81. package/learn/benefits/OffTheMainThread.md +2 -2
  82. package/learn/benefits/Quick.md +45 -12
  83. package/learn/benefits/RPCLayer.md +75 -0
  84. package/learn/benefits/Speed.md +16 -11
  85. package/learn/gettingstarted/ComponentModels.md +4 -4
  86. package/learn/gettingstarted/Config.md +6 -6
  87. package/learn/gettingstarted/DescribingTheUI.md +4 -4
  88. package/learn/gettingstarted/Events.md +6 -6
  89. package/learn/gettingstarted/Extending.md +4 -4
  90. package/learn/gettingstarted/References.md +6 -6
  91. package/learn/gettingstarted/Workspaces.md +6 -6
  92. package/learn/guides/ApplicationBootstrap.md +26 -26
  93. package/learn/guides/ComponentsAndContainers.md +12 -12
  94. package/learn/guides/ConfigSystemDeepDive.md +280 -0
  95. package/learn/guides/CustomComponents.md +2 -2
  96. package/learn/guides/DeclarativeComponentTreesVsImperativeVdom.md +17 -17
  97. package/learn/guides/InstanceLifecycle.md +295 -1
  98. package/learn/guides/MainThreadAddons.md +475 -0
  99. package/learn/guides/PortalApp.md +2 -2
  100. package/learn/guides/StateProviders.md +12 -12
  101. package/learn/guides/WorkingWithVDom.md +14 -14
  102. package/learn/guides/events/CustomEvents.md +16 -16
  103. package/learn/guides/events/DomEvents.md +12 -12
  104. package/learn/javascript/ClassFeatures.md +3 -2
  105. package/learn/javascript/Classes.md +8 -8
  106. package/learn/javascript/NewNode.md +4 -4
  107. package/learn/javascript/Overrides.md +8 -8
  108. package/learn/javascript/Super.md +10 -8
  109. package/learn/tree.json +52 -51
  110. package/learn/tutorials/Earthquakes.md +54 -57
  111. package/learn/tutorials/TodoList.md +4 -4
  112. package/package.json +2 -2
  113. package/resources/scss/src/apps/portal/learn/ContentComponent.scss +12 -0
  114. package/resources/scss/src/table/{View.scss → Body.scss} +1 -1
  115. package/resources/scss/src/table/plugin/CellEditing.scss +1 -1
  116. package/resources/scss/theme-dark/table/{View.scss → Body.scss} +1 -1
  117. package/resources/scss/theme-light/table/{View.scss → Body.scss} +1 -1
  118. package/resources/scss/theme-neo-light/Global.scss +1 -2
  119. package/resources/scss/theme-neo-light/table/{View.scss → Body.scss} +1 -1
  120. package/src/DefaultConfig.mjs +2 -2
  121. package/src/Main.mjs +8 -7
  122. package/src/Neo.mjs +16 -2
  123. package/src/button/Base.mjs +2 -2
  124. package/src/calendar/view/SettingsContainer.mjs +2 -2
  125. package/src/calendar/view/YearComponent.mjs +9 -9
  126. package/src/calendar/view/calendars/ColorsList.mjs +1 -1
  127. package/src/calendar/view/calendars/List.mjs +1 -1
  128. package/src/calendar/view/month/Component.mjs +15 -15
  129. package/src/calendar/view/week/Component.mjs +12 -12
  130. package/src/calendar/view/week/EventDragZone.mjs +4 -4
  131. package/src/calendar/view/week/TimeAxisComponent.mjs +3 -3
  132. package/src/component/Base.mjs +17 -2
  133. package/src/component/Carousel.mjs +2 -2
  134. package/src/component/Chip.mjs +3 -3
  135. package/src/component/Circle.mjs +2 -2
  136. package/src/component/DateSelector.mjs +8 -8
  137. package/src/component/Helix.mjs +1 -1
  138. package/src/component/Label.mjs +3 -18
  139. package/src/component/Legend.mjs +3 -3
  140. package/src/component/MagicMoveText.mjs +6 -14
  141. package/src/component/Process.mjs +3 -3
  142. package/src/component/Progress.mjs +1 -1
  143. package/src/component/StatusBadge.mjs +2 -2
  144. package/src/component/Timer.mjs +2 -2
  145. package/src/component/Toast.mjs +5 -3
  146. package/src/container/AccordionItem.mjs +2 -2
  147. package/src/container/Base.mjs +1 -1
  148. package/src/core/Base.mjs +77 -14
  149. package/src/core/Util.mjs +14 -2
  150. package/src/date/DayViewComponent.mjs +2 -2
  151. package/src/date/SelectorContainer.mjs +1 -1
  152. package/src/draggable/grid/header/toolbar/SortZone.mjs +21 -21
  153. package/src/draggable/table/header/toolbar/SortZone.mjs +1 -1
  154. package/src/form/field/CheckBox.mjs +4 -4
  155. package/src/form/field/FileUpload.mjs +25 -39
  156. package/src/form/field/Range.mjs +1 -1
  157. package/src/form/field/Text.mjs +3 -3
  158. package/src/form/field/TextArea.mjs +2 -3
  159. package/src/grid/Body.mjs +8 -5
  160. package/src/grid/_export.mjs +1 -1
  161. package/src/list/Color.mjs +2 -2
  162. package/src/main/DeltaUpdates.mjs +157 -98
  163. package/src/main/addon/AmCharts.mjs +61 -84
  164. package/src/main/addon/Base.mjs +161 -42
  165. package/src/main/addon/GoogleMaps.mjs +9 -16
  166. package/src/main/addon/HighlightJS.mjs +2 -13
  167. package/src/main/addon/IntersectionObserver.mjs +21 -21
  168. package/src/main/addon/MonacoEditor.mjs +32 -64
  169. package/src/manager/ClassHierarchy.mjs +114 -0
  170. package/src/menu/List.mjs +1 -1
  171. package/src/plugin/Popover.mjs +2 -2
  172. package/src/sitemap/Component.mjs +1 -1
  173. package/src/table/{View.mjs → Body.mjs} +25 -22
  174. package/src/table/Container.mjs +43 -43
  175. package/src/table/_export.mjs +2 -2
  176. package/src/table/plugin/CellEditing.mjs +19 -19
  177. package/src/tooltip/Base.mjs +1 -6
  178. package/src/tree/Accordion.mjs +3 -3
  179. package/src/vdom/Helper.mjs +19 -22
  180. package/src/worker/App.mjs +1 -2
  181. package/src/worker/Base.mjs +7 -5
  182. package/src/worker/Canvas.mjs +2 -3
  183. package/src/worker/Data.mjs +5 -7
  184. package/src/worker/Task.mjs +2 -3
  185. package/src/worker/VDom.mjs +3 -4
  186. package/src/worker/mixin/RemoteMethodAccess.mjs +5 -2
  187. package/learn/guides/MainThreadAddonExample.md +0 -15
  188. package/learn/guides/MainThreadAddonIntro.md +0 -44
@@ -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\s*```/g,
9
+ regexNeoComponent = /```json\s+neo-component\s*\n([\s\S]*?)\n\s*```/g,
10
+ regexReadonly = /```(javascript|html|css|json)\s+readonly\s*\n([\s\S]*?)\n\s*```/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
@@ -33,7 +33,7 @@ class PageSectionsContainer extends Container {
33
33
  }, {
34
34
  vdom:
35
35
  {cn: [
36
- {tag: 'h3', html: 'On this page'}
36
+ {tag: 'h3', text: 'On this page'}
37
37
  ]}
38
38
  }, {
39
39
  module : PageSectionsList,
@@ -32,12 +32,12 @@ class PageSectionsList extends List {
32
32
  /**
33
33
  * @param {Object} record
34
34
  * @param {Number} index
35
- * @returns {Object|Object[]|String} Either a config object to assign to the item, a vdom cn array or a html string
35
+ * @returns {Object|Object[]|String} Either a config object to assign to the item, a vdom cn array or a string.
36
36
  */
37
37
  createItemContent(record, index) {
38
38
  return {
39
39
  cls : `neo-${record.tag}`,
40
- html: record[this.displayField]
40
+ text: record[this.displayField]
41
41
  }
42
42
  }
43
43
 
@@ -20,36 +20,36 @@ class Component extends BaseComponent {
20
20
  */
21
21
  vdom:
22
22
  {cn: [
23
- {tag: 'h1', cls: ['neo-h1'], html: 'Services'},
23
+ {tag: 'h1', cls: ['neo-h1'], text: 'Services'},
24
24
  {cls: ['info-block'], cn: [
25
- {tag: 'h2', cls: ['neo-h2'], html: 'Professional Trainings'},
26
- {tag: 'p', html: [
25
+ {tag: 'h2', cls: ['neo-h2'], text: 'Professional Trainings'},
26
+ {tag: 'p', text: [
27
27
  'While we do have a self-study based Learning Section online, you can also hire us ',
28
28
  'in case you prefer an Instructor-led Training for bringing your team up to speed.'
29
29
  ].join('')},
30
30
  {tag: 'ul', cn: [
31
- {tag: 'li', html: 'One week packed with 40h of intense training.'},
32
- {tag: 'li', html: 'Including hands-on Labs'},
33
- {tag: 'li', html: '6 - 12 attendees'},
34
- {tag: 'li', html: 'While Remote Trainings are possible, we strongly recommend On-Site Trainings instead.'},
31
+ {tag: 'li', text: 'One week packed with 40h of intense training.'},
32
+ {tag: 'li', text: 'Including hands-on Labs'},
33
+ {tag: 'li', text: '6 - 12 attendees'},
34
+ {tag: 'li', text: 'While Remote Trainings are possible, we strongly recommend On-Site Trainings instead.'},
35
35
  ]},
36
36
  {tag: 'p', html: [
37
37
  'Feel free to send us an <a href="mailto:trainings@neomjs.com">Email</a> to plan your training timeframe.',
38
38
  ].join('')},
39
39
  ]},
40
40
  {cls: ['info-block'], cn: [
41
- {tag: 'h2', cls: ['neo-h2'], html: 'Professional Services'},
42
- {tag: 'p', html: [
41
+ {tag: 'h2', cls: ['neo-h2'], text: 'Professional Services'},
42
+ {tag: 'p', text: [
43
43
  'We can help you to ensure your Neo.mjs based projects run successfully.',
44
44
  ].join('')},
45
45
  {tag: 'ul', cn: [
46
- {tag: 'li', html: 'Feasibility Analysis: Is Neo.mjs a good fit for your project needs?'},
47
- {tag: 'li', html: 'Creating a Neo.mjs PoC which matches your specific needs'},
48
- {tag: 'li', html: 'Code Reviews'},
49
- {tag: 'li', html: 'Frontend-Architecture Guidance'},
50
- {tag: 'li', html: 'Application & Framework Debugging'},
51
- {tag: 'li', html: 'Creation of Custom Components, Design Themes & new Features'},
52
- {tag: 'li', html: 'Hands-On Application Development Support'}
46
+ {tag: 'li', text: 'Feasibility Analysis: Is Neo.mjs a good fit for your project needs?'},
47
+ {tag: 'li', text: 'Creating a Neo.mjs PoC which matches your specific needs'},
48
+ {tag: 'li', text: 'Code Reviews'},
49
+ {tag: 'li', text: 'Frontend-Architecture Guidance'},
50
+ {tag: 'li', text: 'Application & Framework Debugging'},
51
+ {tag: 'li', text: 'Creation of Custom Components, Design Themes & new Features'},
52
+ {tag: 'li', text: 'Hands-On Application Development Support'}
53
53
  ]},
54
54
  {tag: 'p', html: [
55
55
  'In case you need help, send us an <a href="mailto:services@neomjs.com">Email</a>.',
@@ -17,7 +17,7 @@ class FooterComponent extends Component {
17
17
  _vdom:
18
18
  {tag: 'footer', cn: [
19
19
  {cls: ['container'], cn: [
20
- {tag: 'a', cls: ['logo-font'], href: '#/', html: 'conduit'},
20
+ {tag: 'a', cls: ['logo-font'], href: '#/', text: 'conduit'},
21
21
  {tag: 'span', cls: 'attribution', html: 'An interactive learning project from <a href="https://thinkster.io">Thinkster</a>. Code &amp; design licensed under MIT.'}
22
22
  ]}
23
23
  ]}
@@ -38,34 +38,34 @@ class HeaderComponent extends Component {
38
38
  _vdom:
39
39
  {tag: 'nav', cls: ['navbar navbar-light'], cn: [
40
40
  {cls: ['container'], cn: [
41
- {tag: 'a', cls: ['navbar-brand'], href: '#/', html: 'conduit'},
41
+ {tag: 'a', cls: ['navbar-brand'], href: '#/', text: 'conduit'},
42
42
  {tag: 'ul', cls: ['nav navbar-nav', 'pull-xs-right'], cn: [
43
43
  {tag: 'li', cls: ['nav-item'], cn: [
44
- {tag: 'a', cls: ['nav-link'], href: '#/', html: 'Home'}
44
+ {tag: 'a', cls: ['nav-link'], href: '#/', text: 'Home'}
45
45
  ]},
46
46
  {tag: 'li', cls: ['nav-item'], removeDom: true, cn: [
47
47
  {tag: 'a', cls: ['nav-link'], href: '#/editor', cn: [
48
48
  {tag: 'i', cls: 'ion-compose'},
49
- {vtype: 'text', html: '&nbsp;New Article'}
49
+ {vtype: 'text', text: '&nbsp;New Article'}
50
50
  ]}
51
51
  ]},
52
52
  {tag: 'li', cls: ['nav-item'], removeDom: true, cn: [
53
53
  {tag: 'a', cls: ['nav-link'], href: '#/settings', cn: [
54
54
  {tag: 'i', cls: 'ion-gear-a'},
55
- {vtype: 'text', html: '&nbsp;Settings'}
55
+ {vtype: 'text', text: '&nbsp;Settings'}
56
56
  ]}
57
57
  ]},
58
58
  {tag: 'li', cls: ['nav-item'], removeDom: true, cn: [
59
59
  {tag: 'a', cls : ['nav-link'], href: '#/profile', cn: [
60
60
  {tag: 'img', cls: ['user-pic']},
61
- {vtype: 'text', html: '&nbsp;Profile'}
61
+ {vtype: 'text', text: ' Profile'}
62
62
  ]}
63
63
  ]},
64
64
  {tag: 'li', cls: ['nav-item'], cn: [
65
- {tag : 'a', cls : ['nav-link'], href: '#/login', html: 'Sign in'}
65
+ {tag : 'a', cls : ['nav-link'], href: '#/login', text: 'Sign in'}
66
66
  ]},
67
67
  {tag: 'li', cls: ['nav-item'], cn: [
68
- {tag: 'a', cls : ['nav-link'], href: '#/register', html: 'Sign up'}
68
+ {tag: 'a', cls : ['nav-link'], href: '#/register', text: 'Sign up'}
69
69
  ]}
70
70
  ]}
71
71
  ]}
@@ -140,7 +140,7 @@ class HeaderComponent extends Component {
140
140
  profileLink = me.vdom.cn[0].cn[1].cn[3].cn[0];
141
141
 
142
142
  profileLink.href = '#/profile/' + value;
143
- profileLink.cn[1].html = '&nbsp;' + value;
143
+ profileLink.cn[1].text = ' ' + value;
144
144
 
145
145
  me.update();
146
146
  }
@@ -65,8 +65,8 @@ class HomeComponent extends Component {
65
65
  {cn: [
66
66
  {cls: ['banner'], cn: [
67
67
  {cls: ['container'], cn: [
68
- {tag: 'h1', cls: ['logo-font'], html: 'conduit'},
69
- {tag: 'p', html: 'A place to share your knowledge.'}
68
+ {tag: 'h1', cls: ['logo-font'], text: 'conduit'},
69
+ {tag: 'p', text: 'A place to share your knowledge.'}
70
70
  ]}
71
71
  ]},
72
72
  {cls: ['container', 'page'], cn: [
@@ -211,7 +211,7 @@ class HomeComponent extends Component {
211
211
  cls : ['page-link', 'prevent-click'],
212
212
  id : me.getNavLinkVdomId(i),
213
213
  href: '',
214
- html: i
214
+ text: i
215
215
  }]
216
216
  });
217
217
  }
@@ -274,7 +274,7 @@ class HomeComponent extends Component {
274
274
  tag : 'a',
275
275
  cls : cls,
276
276
  href: '',
277
- html: item.name,
277
+ text: item.name,
278
278
  id : me.id + '__nav-item-link_' + index,
279
279
  }]
280
280
  });
@@ -376,7 +376,7 @@ class HomeComponent extends Component {
376
376
  opts = {};
377
377
 
378
378
  if (!el.vdom.cls.includes('disabled')) {
379
- switch (el.vdom.html) {
379
+ switch (el.vdom.text) {
380
380
  case 'Global Feed':
381
381
  me.activeTag = null;
382
382
  break;
@@ -387,7 +387,7 @@ class HomeComponent extends Component {
387
387
  };
388
388
  break;
389
389
  default: // tag
390
- me.activeTag = el.vdom.html.substring(2); // remove the '# '
390
+ me.activeTag = el.vdom.text.substring(2); // remove the '# '
391
391
  break;
392
392
  }
393
393
 
@@ -49,7 +49,7 @@ class CommentComponent extends Component {
49
49
  {tag: 'a', cls : ['comment-author'], href: '', cn: [
50
50
  {tag: 'img', cls: ['comment-author-img']}
51
51
  ]},
52
- {vtype: 'text', html: '&nbsp;'},
52
+ {vtype: 'text', text: ' '},
53
53
  {tag: 'a', cls: ['comment-author'], href: ''},
54
54
  {tag: 'span', cls : ['date-posted']},
55
55
  {tag: 'span', cls : ['mod-options'], flag: 'mod-options', cn: [
@@ -90,7 +90,7 @@ class CommentComponent extends Component {
90
90
  let me = this;
91
91
 
92
92
  me.vdom.cn[1].cn[0].cn[0].src = value.image;
93
- me.vdom.cn[1].cn[2].html = value.username;
93
+ me.vdom.cn[1].cn[2].text = value.username;
94
94
 
95
95
  me.update();
96
96
  me.onCurrentUserChange();
@@ -105,7 +105,7 @@ class CommentComponent extends Component {
105
105
  */
106
106
  afterSetBody(value, oldValue) {
107
107
  if (value) {
108
- this.vdom.cn[0].cn[0].html = value;
108
+ this.vdom.cn[0].cn[0].text = value;
109
109
  this.update();
110
110
  }
111
111
  }
@@ -118,7 +118,7 @@ class CommentComponent extends Component {
118
118
  */
119
119
  afterSetCreatedAt(value, oldValue) {
120
120
  if (value) {
121
- this.vdom.cn[1].cn[3].html = new Intl.DateTimeFormat('en-US', {
121
+ this.vdom.cn[1].cn[3].text = new Intl.DateTimeFormat('en-US', {
122
122
  day : 'numeric',
123
123
  month: 'long',
124
124
  year : 'numeric'
@@ -87,19 +87,19 @@ class Component extends BaseComponent {
87
87
  ]},
88
88
  {tag: 'button', cls: ['btn', 'btn-sm', 'btn-outline-secondary', 'edit-button'], flag: 'edit-button', removeDom: true, cn: [
89
89
  {tag: 'i', cls: ['ion-edit']},
90
- {vtype: 'text', html: ' Edit Article'}
90
+ {vtype: 'text', text: ' Edit Article'}
91
91
  ]},
92
92
  {vtype: 'text', html: '&nbsp;&nbsp;'},
93
93
  {tag: 'button', cls: ['btn', 'btn-sm', 'btn-outline-primary', 'favorite-button'], flag: 'favorited', cn: [
94
94
  {tag: 'i', cls: ['ion-heart']},
95
95
  {vtype: 'text', html: '&nbsp;'},
96
96
  {vtype: 'text'},
97
- {vtype: 'text', html: ' Post '},
97
+ {vtype: 'text', text: ' Post '},
98
98
  {tag: 'span', cls: ['counter'], flag: 'favoritesCount'}
99
99
  ]},
100
100
  {tag: 'button', cls: ['btn', 'btn-sm', 'btn-outline-danger', 'delete-button'], flag: 'delete-button', removeDom: true, cn: [
101
101
  {tag: 'i', cls: ['ion-trash-a']},
102
- {vtype: 'text', html: ' Delete Article'}
102
+ {vtype: 'text', text: ' Delete Article'}
103
103
  ]}
104
104
  ]}
105
105
  ]}
@@ -114,7 +114,7 @@ class Component extends BaseComponent {
114
114
  {tag: 'a', flag: 'userimage', cn: [{tag: 'img'}]},
115
115
  {cls: ['info'], cn: [
116
116
  {tag: 'a', cls: ['author'], flag: 'username'},
117
- {tag: 'span', cls: ['date'], html: 'January 20th'}
117
+ {tag: 'span', cls: ['date'], text: 'January 20th'}
118
118
  ]},
119
119
  {tag: 'button', cls: ['btn', 'btn-sm', 'btn-outline-secondary', 'follow-button'], cn: [
120
120
  {tag: 'i', flag: 'followIcon'},
@@ -126,7 +126,7 @@ class Component extends BaseComponent {
126
126
  {tag: 'i', cls: ['ion-heart']},
127
127
  {vtype: 'text', html: '&nbsp;'},
128
128
  {vtype: 'text'},
129
- {vtype: 'text', html: ' Post '},
129
+ {vtype: 'text', text: ' Post '},
130
130
  {tag: 'span', cls: ['counter'], flag: 'favoritesCount'}
131
131
  ]}
132
132
  ]}
@@ -190,7 +190,7 @@ class Component extends BaseComponent {
190
190
  vdom = me.vdom;
191
191
 
192
192
  VDomUtil.getFlags(vdom, 'followAuthor').forEach(node => {
193
- node.html = value.following ? ' Unfollow ' : ' Follow ';
193
+ node.text = value.following ? ' Unfollow ' : ' Follow ';
194
194
  });
195
195
 
196
196
  VDomUtil.getFlags(vdom, 'followIcon').forEach(node => {
@@ -204,7 +204,7 @@ class Component extends BaseComponent {
204
204
 
205
205
  VDomUtil.getFlags(vdom, 'username').forEach(node => {
206
206
  node.href = '#/profile/' + value.username;
207
- node.html = value.username;
207
+ node.text = value.username;
208
208
  });
209
209
 
210
210
  me.update();
@@ -286,7 +286,7 @@ class Component extends BaseComponent {
286
286
  */
287
287
  afterSetCreatedAt(value, oldValue) {
288
288
  if (value) {
289
- VDomUtil.getByFlag(this.vdom, 'createdAt').html = new Intl.DateTimeFormat('en-US', {
289
+ VDomUtil.getByFlag(this.vdom, 'createdAt').text = new Intl.DateTimeFormat('en-US', {
290
290
  day : 'numeric',
291
291
  month: 'long',
292
292
  year : 'numeric'
@@ -306,7 +306,7 @@ class Component extends BaseComponent {
306
306
  let me = this;
307
307
 
308
308
  VDomUtil.getFlags(me.vdom, 'favorited').forEach(node => {
309
- node.cn[2].html = value ? 'Unfavorite' : 'Favorite';
309
+ node.cn[2].text = value ? 'Unfavorite' : 'Favorite';
310
310
 
311
311
  NeoArray.add(node.cls, value ? 'btn-primary' : 'btn-outline-primary');
312
312
  NeoArray.remove(node.cls, value ? 'btn-outline-primary' : 'btn-primary');
@@ -331,10 +331,10 @@ class Component extends BaseComponent {
331
331
  afterSetFavoritesCount(value, oldValue) {
332
332
  if (Neo.isNumber(value)) {
333
333
  VDomUtil.getFlags(this.vdom, 'favoritesCount').forEach(node => {
334
- node.html = `(${value})`;
334
+ node.text = `(${value})`;
335
335
  });
336
336
 
337
- this.update();
337
+ this.update()
338
338
  }
339
339
  }
340
340
 
@@ -360,7 +360,7 @@ class Component extends BaseComponent {
360
360
  tagList.cn.push({
361
361
  tag : 'li',
362
362
  cls : ['tag-default', 'tag-pill', 'tag-outline'],
363
- html: item
363
+ text: item
364
364
  })
365
365
  });
366
366
 
@@ -381,8 +381,8 @@ class Component extends BaseComponent {
381
381
  * @protected
382
382
  */
383
383
  afterSetTitle(value, oldValue) {
384
- VDomUtil.getByFlag(this.vdom, 'title').html = value;
385
- this.update();
384
+ VDomUtil.getByFlag(this.vdom, 'title').text = value;
385
+ this.update()
386
386
  }
387
387
 
388
388
  /**
@@ -35,7 +35,7 @@ class CreateCommentComponent extends Component {
35
35
  {tag: 'img', cls: ['comment-author-img'], src: 'https://static.productionready.io/images/smiley-cyrus.jpg'}, // https://github.com/gothinkster/realworld/issues/442
36
36
  {vtype: 'text', html: '&nbsp;'},
37
37
  {tag: 'span', cls: ['comment-author']},
38
- {tag: 'button', cls: ['btn', 'btn-sm', 'btn-primary'], html: 'Post Comment', type: 'button'}
38
+ {tag: 'button', cls: ['btn', 'btn-sm', 'btn-primary'], text: 'Post Comment', type: 'button'}
39
39
  ]}
40
40
  ]}
41
41
  }
@@ -86,8 +86,8 @@ class CreateCommentComponent extends Component {
86
86
  */
87
87
  afterSetUserName(value, oldValue) {
88
88
  if (value) {
89
- this.vdom.cn[1].cn[2].html = value;
90
- this.update();
89
+ this.vdom.cn[1].cn[2].text = value;
90
+ this.update()
91
91
  }
92
92
  }
93
93
 
@@ -66,7 +66,7 @@ class CreateComponent extends Component {
66
66
  {tag: 'input', cls: ['form-control', 'field-tags'], flag: 'tags', name: 'tags', placeholder: 'Enter tags', type: 'text'},
67
67
  {cls: ['tag-list'], flag: 'tag-list'}
68
68
  ]},
69
- {tag: 'button', cls: ['btn', 'btn-lg', 'btn-primary', 'pull-xs-right'], html: 'Publish Article', type: 'button'}
69
+ {tag: 'button', cls: ['btn', 'btn-lg', 'btn-primary', 'pull-xs-right'], text: 'Publish Article', type: 'button'}
70
70
  ]}
71
71
  ]}
72
72
  ]}
@@ -128,7 +128,7 @@ class CreateComponent extends Component {
128
128
  Object.entries(value || {}).forEach(([key, value]) => {
129
129
  list.cn.push({
130
130
  tag : 'li',
131
- html: key + ' ' + value.join(' and ')
131
+ text: key + ' ' + value.join(' and ')
132
132
  });
133
133
  });
134
134
 
@@ -159,7 +159,7 @@ class CreateComponent extends Component {
159
159
  'data-value': value,
160
160
  }, {
161
161
  vtype: 'text',
162
- html : value
162
+ text : value
163
163
  }]
164
164
  });
165
165
  });