neo.mjs 6.9.9 → 6.9.11

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 (242) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/learnneo/neo-config.json +5 -1
  3. package/apps/learnneo/store/Content.mjs +1 -1
  4. package/apps/learnneo/view/Viewport.mjs +12 -1
  5. package/apps/learnneo/view/home/ContentTreeList.mjs +53 -34
  6. package/apps/learnneo/view/home/ContentView.mjs +60 -0
  7. package/apps/learnneo/view/home/MainContainer.mjs +36 -9
  8. package/apps/learnneo/view/home/MainContainerController.mjs +57 -18
  9. package/apps/newwebsite/app.mjs +6 -0
  10. package/apps/newwebsite/index.html +10 -0
  11. package/apps/newwebsite/neo-config.json +7 -0
  12. package/apps/newwebsite/view/MainContainer.mjs +59 -0
  13. package/buildScripts/webpack/json/myApps.template.json +1 -0
  14. package/examples/ConfigurationViewport.mjs +12 -9
  15. package/examples/ServiceWorker.mjs +2 -2
  16. package/examples/button/base/neo-config.json +1 -2
  17. package/examples/form/field/textarea/MainContainer.mjs +1 -1
  18. package/package.json +2 -2
  19. package/resources/data/{learnneo → deck/learnneo}/p/2023-10-01T18-29-19-158Z.md +3 -6
  20. package/resources/data/deck/learnneo/p/stylesheet.md +40 -0
  21. package/resources/data/{learnneo → deck/learnneo}/t.json +19 -2
  22. package/resources/data/deck/training/p/2022-12-27T21-54-52-300Z.md +11 -0
  23. package/resources/data/deck/training/p/2022-12-27T21-55-23-144Z.md +43 -0
  24. package/resources/data/deck/training/p/2022-12-27T21-55-30-948Z.md +1 -0
  25. package/resources/data/deck/training/p/2022-12-27T21-55-43-542Z.md +84 -0
  26. package/resources/data/deck/training/p/2022-12-27T22-23-55-083Z.md +1 -0
  27. package/resources/data/deck/training/p/2022-12-27T22-24-07-886Z.md +8 -0
  28. package/resources/data/deck/training/p/2022-12-27T22-24-52-295Z.md +8 -0
  29. package/resources/data/deck/training/p/2022-12-27T22-25-03-853Z.md +5 -0
  30. package/resources/data/deck/training/p/2022-12-27T22-43-58-924Z.md +10 -0
  31. package/resources/data/deck/training/p/2022-12-27T22-44-28-881Z.md +3 -0
  32. package/resources/data/deck/training/p/2022-12-27T22-44-41-791Z.md +4 -0
  33. package/resources/data/deck/training/p/2022-12-27T22-45-21-032Z.md +7 -0
  34. package/resources/data/deck/training/p/2022-12-27T22-49-22-078Z.md +4 -0
  35. package/resources/data/deck/training/p/2022-12-27T22-50-20-626Z.md +4 -0
  36. package/resources/data/deck/training/p/2022-12-28T16-58-47-786Z.md +0 -0
  37. package/resources/data/deck/training/p/2022-12-28T16-58-55-192Z.md +9 -0
  38. package/resources/data/deck/training/p/2022-12-28T17-10-18-058Z.md +15 -0
  39. package/resources/data/deck/training/p/2022-12-28T17-10-42-296Z.md +40 -0
  40. package/resources/data/deck/training/p/2022-12-28T17-11-34-653Z.md +41 -0
  41. package/resources/data/deck/training/p/2022-12-28T17-13-09-994Z.md +0 -0
  42. package/resources/data/deck/training/p/2022-12-28T21-32-14-420Z.md +0 -0
  43. package/resources/data/deck/training/p/2022-12-29T01-43-32-431Z.md +7 -0
  44. package/resources/data/deck/training/p/2022-12-29T15-56-54-485Z.md +7 -0
  45. package/resources/data/deck/training/p/2022-12-29T15-57-11-499Z.md +7 -0
  46. package/resources/data/deck/training/p/2022-12-29T16-00-13-223Z.md +7 -0
  47. package/resources/data/deck/training/p/2022-12-29T18-34-25-826Z.md +4 -0
  48. package/resources/data/deck/training/p/2022-12-29T18-36-08-226Z.md +106 -0
  49. package/resources/data/deck/training/p/2022-12-29T18-36-56-893Z.md +112 -0
  50. package/resources/data/deck/training/p/2022-12-29T19-31-30-507Z.md +31 -0
  51. package/resources/data/deck/training/p/2022-12-29T19-31-55-091Z.md +14 -0
  52. package/resources/data/deck/training/p/2022-12-29T20-03-42-628Z.md +9 -0
  53. package/resources/data/deck/training/p/2022-12-29T20-21-20-669Z.md +7 -0
  54. package/resources/data/deck/training/p/2022-12-29T20-37-08-919Z.md +46 -0
  55. package/resources/data/deck/training/p/2022-12-29T20-37-20-344Z.md +43 -0
  56. package/resources/data/deck/training/p/2022-12-30T19-04-30-990Z.md +8 -0
  57. package/resources/data/deck/training/p/2022-12-31T18-43-56-338Z.md +7 -0
  58. package/resources/data/deck/training/p/2022-12-31T18-51-50-682Z.md +1 -0
  59. package/resources/data/deck/training/p/2022-12-31T18-54-04-176Z.md +4 -0
  60. package/resources/data/deck/training/p/2022-12-31T22-11-55-555Z.md +112 -0
  61. package/resources/data/deck/training/p/2022-12-31T23-00-41-222Z.md +6 -0
  62. package/resources/data/deck/training/p/2022-12-31T23-18-55-655Z.md +69 -0
  63. package/resources/data/deck/training/p/2022-12-31T23-25-40-735Z.md +21 -0
  64. package/resources/data/deck/training/p/2022-12-31T23-25-51-014Z.md +7 -0
  65. package/resources/data/deck/training/p/2023-01-01T17-49-18-429Z.md +3 -0
  66. package/resources/data/deck/training/p/2023-01-01T18-44-07-034Z.md +34 -0
  67. package/resources/data/deck/training/p/2023-01-01T18-47-39-766Z.md +15 -0
  68. package/resources/data/deck/training/p/2023-01-01T19-04-22-830Z.md +4 -0
  69. package/resources/data/deck/training/p/2023-01-01T21-11-58-025Z.md +25 -0
  70. package/resources/data/deck/training/p/2023-01-01T21-12-37-340Z.md +23 -0
  71. package/resources/data/deck/training/p/2023-01-01T21-13-13-880Z.md +8 -0
  72. package/resources/data/deck/training/p/2023-01-01T21-14-45-740Z.md +98 -0
  73. package/resources/data/deck/training/p/2023-01-01T21-18-23-886Z.md +26 -0
  74. package/resources/data/deck/training/p/2023-01-01T21-18-31-316Z.md +19 -0
  75. package/resources/data/deck/training/p/2023-01-01T21-18-42-290Z.md +23 -0
  76. package/resources/data/deck/training/p/2023-01-01T21-19-57-020Z.md +24 -0
  77. package/resources/data/deck/training/p/2023-01-01T21-22-31-184Z.md +13 -0
  78. package/resources/data/deck/training/p/2023-01-01T21-22-38-317Z.md +17 -0
  79. package/resources/data/deck/training/p/2023-01-01T21-22-47-693Z.md +20 -0
  80. package/resources/data/deck/training/p/2023-01-01T21-23-17-716Z.md +39 -0
  81. package/resources/data/deck/training/p/2023-01-01T21-23-28-532Z.md +22 -0
  82. package/resources/data/deck/training/p/2023-01-01T21-25-23-899Z.md +3 -0
  83. package/resources/data/deck/training/p/2023-01-01T21-25-59-742Z.md +1 -0
  84. package/resources/data/deck/training/p/2023-01-01T21-26-53-748Z.md +12 -0
  85. package/resources/data/deck/training/p/2023-01-01T23-38-42-863Z.md +2 -0
  86. package/resources/data/deck/training/p/2023-01-03T02-07-19-014Z.md +143 -0
  87. package/resources/data/deck/training/p/2023-01-04T01-52-23-454Z.md +76 -0
  88. package/resources/data/deck/training/p/2023-01-06T23-21-12-009Z.md +127 -0
  89. package/resources/data/deck/training/p/2023-01-06T23-21-31-685Z.md +81 -0
  90. package/resources/data/deck/training/p/2023-01-06T23-21-59-596Z.md +36 -0
  91. package/resources/data/deck/training/p/2023-01-06T23-34-13-897Z.md +87 -0
  92. package/resources/data/deck/training/p/2023-01-06T23-44-02-340Z.md +0 -0
  93. package/resources/data/deck/training/p/2023-01-06T23-46-36-687Z.md +1 -0
  94. package/resources/data/deck/training/p/2023-01-06T23-46-45-783Z.md +33 -0
  95. package/resources/data/deck/training/p/2023-01-08T00-45-11-144Z.md +50 -0
  96. package/resources/data/deck/training/p/2023-01-08T01-06-31-267Z.md +41 -0
  97. package/resources/data/deck/training/p/2023-01-08T01-24-21-088Z.md +95 -0
  98. package/resources/data/deck/training/p/2023-01-08T01-25-12-557Z.md +11 -0
  99. package/resources/data/deck/training/p/2023-01-08T01-46-50-723Z.md +25 -0
  100. package/resources/data/deck/training/p/2023-01-08T02-09-07-802Z.md +18 -0
  101. package/resources/data/deck/training/p/2023-01-08T02-09-19-678Z.md +66 -0
  102. package/resources/data/deck/training/p/2023-01-08T02-11-26-333Z.md +29 -0
  103. package/resources/data/deck/training/p/2023-01-08T17-22-48-841Z.md +14 -0
  104. package/resources/data/deck/training/p/2023-01-08T20-46-11-806Z.md +5 -0
  105. package/resources/data/deck/training/p/2023-01-08T20-47-23-682Z.md +5 -0
  106. package/resources/data/deck/training/p/2023-01-08T20-47-32-064Z.md +13 -0
  107. package/resources/data/deck/training/p/2023-01-08T20-47-57-045Z.md +0 -0
  108. package/resources/data/deck/training/p/2023-01-08T20-48-03-791Z.md +18 -0
  109. package/resources/data/deck/training/p/2023-01-08T20-48-32-466Z.md +9 -0
  110. package/resources/data/deck/training/p/2023-01-08T20-48-51-322Z.md +20 -0
  111. package/resources/data/deck/training/p/2023-01-08T20-49-52-741Z.md +0 -0
  112. package/resources/data/deck/training/p/2023-01-08T20-52-03-556Z.md +0 -0
  113. package/resources/data/deck/training/p/2023-01-08T20-57-36-333Z.md +2 -0
  114. package/resources/data/deck/training/p/2023-01-08T20-57-51-136Z.md +5 -0
  115. package/resources/data/deck/training/p/2023-01-09T00-07-37-951Z.md +0 -0
  116. package/resources/data/deck/training/p/2023-01-09T00-35-40-671Z.md +3 -0
  117. package/resources/data/deck/training/p/2023-01-10T01-29-38-148Z.md +10 -0
  118. package/resources/data/deck/training/p/2023-01-10T01-43-12-166Z.md +31 -0
  119. package/resources/data/deck/training/p/2023-01-10T02-21-54-303Z.md +10 -0
  120. package/resources/data/deck/training/p/2023-01-12T01-50-54-617Z.md +74 -0
  121. package/resources/data/deck/training/p/2023-01-13T19-55-24-735Z.md +14 -0
  122. package/resources/data/deck/training/p/2023-01-13T20-08-27-068Z.md +28 -0
  123. package/resources/data/deck/training/p/2023-01-13T20-23-38-411Z.md +25 -0
  124. package/resources/data/deck/training/p/2023-01-13T20-37-06-267Z.md +13 -0
  125. package/resources/data/deck/training/p/2023-01-13T21-05-57-708Z.md +8 -0
  126. package/resources/data/deck/training/p/2023-01-13T21-48-17-258Z.md +20 -0
  127. package/resources/data/deck/training/p/2023-01-13T22-05-05-799Z.md +14 -0
  128. package/resources/data/deck/training/p/2023-01-13T22-08-30-863Z.md +17 -0
  129. package/resources/data/deck/training/p/2023-01-13T23-01-50-449Z.md +4 -0
  130. package/resources/data/deck/training/p/2023-01-14T00-33-05-958Z.md +62 -0
  131. package/resources/data/deck/training/p/2023-01-14T00-40-27-784Z.md +229 -0
  132. package/resources/data/deck/training/p/2023-01-14T00-41-59-081Z.md +153 -0
  133. package/resources/data/deck/training/p/2023-01-14T13-50-28-199Z.md +19 -0
  134. package/resources/data/deck/training/p/2023-01-14T13-59-20-275Z.md +6 -0
  135. package/resources/data/deck/training/p/2023-01-14T14-03-29-456Z.md +3 -0
  136. package/resources/data/deck/training/p/2023-01-14T14-27-57-678Z.md +7 -0
  137. package/resources/data/deck/training/p/2023-01-14T17-30-18-228Z.md +33 -0
  138. package/resources/data/deck/training/p/2023-01-14T18-28-39-316Z.md +1 -0
  139. package/resources/data/deck/training/p/2023-01-14T18-28-44-115Z.md +4 -0
  140. package/resources/data/deck/training/p/2023-01-14T18-28-49-548Z.md +18 -0
  141. package/resources/data/deck/training/p/2023-01-14T18-40-13-758Z.md +10 -0
  142. package/resources/data/deck/training/p/2023-01-14T19-29-15-291Z.md +12 -0
  143. package/resources/data/deck/training/p/2023-01-15T18-51-52-134Z.md +83 -0
  144. package/resources/data/deck/training/p/2023-01-15T20-03-30-073Z.md +11 -0
  145. package/resources/data/deck/training/p/2023-01-15T22-07-52-073Z.md +16 -0
  146. package/resources/data/deck/training/p/2023-01-15T22-22-13-517Z.md +12 -0
  147. package/resources/data/deck/training/p/2023-01-15T22-28-57-508Z.md +131 -0
  148. package/resources/data/deck/training/p/2023-01-15T22-36-30-913Z.md +115 -0
  149. package/resources/data/deck/training/p/2023-01-16T16-03-40-770Z.md +12 -0
  150. package/resources/data/deck/training/p/2023-01-16T20-21-56-859Z.md +5 -0
  151. package/resources/data/deck/training/p/2023-01-16T20-24-09-690Z.md +24 -0
  152. package/resources/data/deck/training/p/2023-01-20T12-51-22-646Z.md +21 -0
  153. package/resources/data/deck/training/p/2023-01-20T13-06-46-614Z.md +9 -0
  154. package/resources/data/deck/training/p/2023-01-20T13-08-51-600Z.md +7 -0
  155. package/resources/data/deck/training/p/2023-01-20T15-20-13-363Z.md +26 -0
  156. package/resources/data/deck/training/p/2023-01-20T15-34-58-813Z.md +75 -0
  157. package/resources/data/deck/training/p/2023-01-21T16-33-20-458Z.md +33 -0
  158. package/resources/data/deck/training/p/2023-01-21T16-45-28-263Z.md +28 -0
  159. package/resources/data/deck/training/p/2023-01-21T16-56-25-452Z.md +3 -0
  160. package/resources/data/deck/training/p/2023-01-21T17-28-31-493Z.md +6 -0
  161. package/resources/data/deck/training/p/2023-01-21T19-49-51-918Z.md +13 -0
  162. package/resources/data/deck/training/p/2023-01-21T20-08-24-452Z.md +15 -0
  163. package/resources/data/deck/training/p/2023-01-21T20-35-54-947Z.md +20 -0
  164. package/resources/data/deck/training/p/2023-01-21T20-54-47-603Z.md +39 -0
  165. package/resources/data/deck/training/p/2023-01-21T20-56-28-184Z.md +25 -0
  166. package/resources/data/deck/training/p/2023-01-21T20-57-32-927Z.md +4 -0
  167. package/resources/data/deck/training/p/2023-01-21T23-13-33-394Z.md +6 -0
  168. package/resources/data/deck/training/p/2023-01-28T19-11-37-464Z.md +24 -0
  169. package/resources/data/deck/training/p/2023-01-28T20-43-41-188Z.md +9 -0
  170. package/resources/data/deck/training/p/2023-01-28T20-53-56-476Z.md +8 -0
  171. package/resources/data/deck/training/p/2023-01-28T20-58-43-776Z.md +10 -0
  172. package/resources/data/deck/training/p/2023-01-28T22-18-41-259Z.md +33 -0
  173. package/resources/data/deck/training/p/2023-01-28T22-24-34-808Z.md +24 -0
  174. package/resources/data/deck/training/p/2023-01-29T16-25-24-528Z.md +44 -0
  175. package/resources/data/deck/training/p/2023-01-29T21-14-32-588Z.md +12 -0
  176. package/resources/data/deck/training/p/2023-01-31T19-24-53-504Z.md +8 -0
  177. package/resources/data/deck/training/p/2023-01-31T20-33-55-855Z.md +11 -0
  178. package/resources/data/deck/training/p/2023-01-31T20-34-30-261Z.md +7 -0
  179. package/resources/data/deck/training/p/2023-01-31T20-52-53-367Z.md +43 -0
  180. package/resources/data/deck/training/p/2023-02-04T15-18-35-682Z.md +20 -0
  181. package/resources/data/deck/training/p/2023-02-04T15-49-47-597Z.md +14 -0
  182. package/resources/data/deck/training/p/2023-02-04T18-58-57-808Z.md +1 -0
  183. package/resources/data/deck/training/p/2023-02-04T20-07-11-288Z.md +1 -0
  184. package/resources/data/deck/training/p/2023-02-04T20-09-50-169Z.md +1 -0
  185. package/resources/data/deck/training/p/2023-02-04T20-19-42-740Z.md +8 -0
  186. package/resources/data/deck/training/p/2023-02-04T20-23-56-013Z.md +12 -0
  187. package/resources/data/deck/training/p/2023-02-04T20-28-12-391Z.md +20 -0
  188. package/resources/data/deck/training/p/2023-02-05T00-20-32-554Z.md +16 -0
  189. package/resources/data/deck/training/p/2023-02-05T00-35-56-282Z.md +13 -0
  190. package/resources/data/deck/training/p/2023-02-05T15-36-57-182Z.md +24 -0
  191. package/resources/data/deck/training/p/2023-02-05T17-39-51-712Z.md +70 -0
  192. package/resources/data/deck/training/p/2023-02-05T17-44-53-815Z.md +195 -0
  193. package/resources/data/deck/training/p/2023-02-05T17-45-40-114Z.md +92 -0
  194. package/resources/data/deck/training/p/2023-02-05T18-12-14-489Z.md +60 -0
  195. package/resources/data/deck/training/p/2023-02-06T00-14-54-457Z.md +9 -0
  196. package/resources/data/deck/training/p/2023-06-28T18-03-14-313Z.md +8 -0
  197. package/resources/data/deck/training/p/2023-06-28T18-26-17-290Z.md +7 -0
  198. package/resources/data/deck/training/p/2023-06-28T21-16-24-034Z.md +40 -0
  199. package/resources/data/deck/training/p/2023-06-28T21-16-34-972Z.md +16 -0
  200. package/resources/data/deck/training/p/2023-06-28T21-28-28-379Z.md +4 -0
  201. package/resources/data/deck/training/p/2023-06-29T23-15-10-411Z.md +5 -0
  202. package/resources/data/deck/training/p/2023-07-01T15-42-45-193Z.md +433 -0
  203. package/resources/data/deck/training/p/2023-07-01T21-54-31-329Z.md +6 -0
  204. package/resources/data/deck/training/p/2023-07-02T16-14-06-970Z.md +14 -0
  205. package/resources/data/deck/training/p/2023-07-31T00-26-03-842Z.md +4 -0
  206. package/resources/data/deck/training/p/2023-07-31T00-31-51-933Z.md +10 -0
  207. package/resources/data/deck/training/p/2023-07-31T00-37-21-927Z.md +205 -0
  208. package/resources/data/deck/training/p/2023-10-01T18-29-19-158Z.md +76 -0
  209. package/resources/data/deck/training/p/2023-10-07T19-18-28-517Z.md +102 -0
  210. package/resources/data/deck/training/p/2023-10-08T20-20-07-934Z.md +75 -0
  211. package/resources/data/deck/training/p/2023-10-08T20-20-37-336Z.md +29 -0
  212. package/resources/data/deck/training/p/2023-10-08T20-37-30-658Z.md +0 -0
  213. package/resources/data/deck/training/p/2023-10-08T21-58-25-809Z.md +68 -0
  214. package/resources/data/deck/training/p/2023-10-08T22-22-11-013Z.md +0 -0
  215. package/resources/data/deck/training/p/2023-10-14T19-25-08-153Z.md +119 -0
  216. package/resources/data/deck/training/t.json +1 -0
  217. package/resources/scss/src/apps/learnneo/Viewport.scss +0 -106
  218. package/resources/scss/src/apps/learnneo/home/ContentTreeList.scss +37 -0
  219. package/resources/scss/src/apps/learnneo/home/ContentView.scss +55 -0
  220. package/resources/scss/src/form/field/FileUpload.scss +4 -4
  221. package/resources/scss/src/form/field/TextArea.scss +1 -1
  222. package/resources/scss/theme-neo-light/Global.scss +46 -0
  223. package/resources/scss/theme-neo-light/design-tokens/Core.scss +7 -0
  224. package/resources/scss/theme-neo-light/design-tokens/Semantic.scss +0 -0
  225. package/resources/scss/theme-neo-light/design-tokens/_all.scss +4 -0
  226. package/src/DefaultConfig.mjs +4 -4
  227. package/src/form/field/FileUpload.mjs +9 -2
  228. package/src/form/field/TextArea.mjs +19 -34
  229. package/src/main/DomAccess.mjs +34 -0
  230. package/test/components/files/form/field/Select.mjs +1 -1
  231. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-07T19-18-28-517Z.md +0 -0
  232. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-20-07-934Z.md +0 -0
  233. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-20-37-336Z.md +0 -0
  234. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-37-30-658Z.md +0 -0
  235. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T21-58-25-809Z.md +0 -0
  236. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T22-22-11-013Z.md +0 -0
  237. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-14T19-25-08-153Z.md +0 -0
  238. /package/resources/data/{learnneo → deck/learnneo}/pages/whyneo.md +0 -0
  239. /package/resources/data/{learnneo → deck/learnneo}/tree.json +0 -0
  240. /package/resources/{deck → data/deck}/whyneo.md +0 -0
  241. /package/resources/scss/src/apps/newwebsite/{MainContainer.css → MainContainer.scss} +0 -0
  242. /package/resources/scss/theme-neo-light/design-tokens/{Components.scss → Component.scss} +0 -0
@@ -0,0 +1,433 @@
1
+ #Introduction
2
+
3
+ During class you'll create three or four apps. The built-in _create-app_ script
4
+ isn't suitable for this course, so in this lab you'll create a new _create-app-training_
5
+ script that creates a starter app with content thats' a good starting
6
+ point for our labs.
7
+
8
+
9
+ #Steps
10
+
11
+ ??Create the file `workspace/buildScripts/createAppTraining.mjs`
12
+
13
+ Use this content. The details don't matter. (Frankly, it's a bit of a mess.)
14
+ But in a nutshell, the script creates an app with an empty view, view model,
15
+ and controller. It'll be easier to work with than the default _create-app_ script.
16
+
17
+ This is long. Make sure you scroll and copy the entire contents.
18
+ <pre style="border: thin solid gray; color:gray; padding: 8px; height:200px">
19
+ import chalk from 'chalk';
20
+ import {spawnSync} from 'child_process';
21
+ import {Command} from 'commander/esm.mjs';
22
+ import envinfo from 'envinfo';
23
+ import fs from 'fs-extra';
24
+ import inquirer from 'inquirer';
25
+ import os from 'os';
26
+ import path from 'path';
27
+
28
+ const __dirname = path.resolve(),
29
+ cwd = process.cwd(),
30
+ requireJson = path => JSON.parse(fs.readFileSync((path))),
31
+ packageJson = requireJson(path.join(__dirname, 'package.json')),
32
+ insideNeo = packageJson.name === 'neo.mjs',
33
+ neoPath = insideNeo ? './' : './node_modules/neo.mjs/',
34
+ addonChoices = fs.readdirSync(path.join(neoPath, '/src/main/addon')).map(item => item.slice(0, -4)),
35
+ program = new Command(),
36
+ programName = `${packageJson.name} create-app`,
37
+ questions = [],
38
+ scssFolders = fs.readdirSync(path.join(neoPath, '/resources/scss')),
39
+ themeFolders = [];
40
+
41
+ scssFolders.forEach(folder => {
42
+ if (folder.includes('theme')) {
43
+ themeFolders.push(`neo-${folder}`);
44
+ }
45
+ });
46
+
47
+ program
48
+ .name(programName)
49
+ .version(packageJson.version)
50
+ .option('-i, --info', 'print environment debug info')
51
+ .option('-a, --appName &lt;value>')
52
+ .option('-m, --mainThreadAddons &lt;value>', `Comma separated list of:\n${addonChoices.join(', ')}\nDefaults to DragDrop, Stylesheet`)
53
+ .option('-s, --useServiceWorker &lt;value>', '"yes", "no"')
54
+ .option('-t, --themes &lt;value>', ['all', ...themeFolders, 'none'].join(", "))
55
+ .option('-u, --useSharedWorkers &lt;value>', '"yes", "no"')
56
+ .allowUnknownOption()
57
+ .on('--help', () => {
58
+ console.log('\nIn case you have any issues, please create a ticket here:');
59
+ console.log(chalk.cyan(process.env.npm_package_bugs_url));
60
+ })
61
+ .parse(process.argv);
62
+
63
+ const programOpts = program.opts();
64
+
65
+ if (programOpts.info) {
66
+ console.log(chalk.bold('\nEnvironment Info:'));
67
+ console.log(`\n current version of ${packageJson.name}: ${packageJson.version}`);
68
+ console.log(` running from ${__dirname}`);
69
+
70
+ envinfo
71
+ .run({
72
+ System: ['OS', 'CPU'],
73
+ Binaries: ['Node', 'npm', 'Yarn'],
74
+ Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
75
+ npmPackages: ['neo.mjs']
76
+ }, {
77
+ duplicates: true,
78
+ showNotFound: true
79
+ })
80
+ .then(console.log);
81
+ } else {
82
+ console.log(chalk.green(programName));
83
+
84
+ if (programOpts.mainThreadAddons) {
85
+ programOpts.mainThreadAddons = programOpts.mainThreadAddons.split(',');
86
+ }
87
+
88
+ if (!programOpts.appName) {
89
+ questions.push({
90
+ type: 'input',
91
+ name: 'appName',
92
+ message: 'Please choose a name for your neo app:',
93
+ default: 'MyApp'
94
+ });
95
+ }
96
+
97
+ if (!programOpts.themes) {
98
+ questions.push({
99
+ type: 'list',
100
+ name: 'themes',
101
+ message: 'Please choose a theme for your neo app:',
102
+ choices: ['all', ...themeFolders, 'none'],
103
+ default: 'all'
104
+ });
105
+ }
106
+
107
+ if (!programOpts.mainThreadAddons) {
108
+ questions.push({
109
+ type: 'checkbox',
110
+ name: 'mainThreadAddons',
111
+ message: 'Please choose your main thread addons:',
112
+ choices: addonChoices,
113
+ default: ['DragDrop', 'Stylesheet']
114
+ });
115
+ }
116
+
117
+ if (!programOpts.useSharedWorkers) {
118
+ questions.push({
119
+ type: 'list',
120
+ name: 'useSharedWorkers',
121
+ message: 'Do you want to use SharedWorkers? Pick yes for multiple main threads (Browser Windows):',
122
+ choices: ['yes', 'no'],
123
+ default: 'no'
124
+ });
125
+ }
126
+
127
+ if (!programOpts.useServiceWorker) {
128
+ questions.push({
129
+ type: 'list',
130
+ name: 'useServiceWorker',
131
+ message: 'Do you want to use a ServiceWorker for caching assets?',
132
+ choices: ['yes', 'no'],
133
+ default: 'no'
134
+ });
135
+ }
136
+
137
+ inquirer.prompt(questions).then(answers => {
138
+ let appName = programOpts.appName || answers.appName,
139
+ mainThreadAddons = programOpts.mainThreadAddons || answers.mainThreadAddons,
140
+ themes = programOpts.themes || answers.themes,
141
+ useSharedWorkers = programOpts.useSharedWorkers || answers.useSharedWorkers,
142
+ useServiceWorker = programOpts.useServiceWorker || answers.useServiceWorker,
143
+ lAppName = appName.toLowerCase(),
144
+ appPath = 'apps/' + lAppName + '/',
145
+ dir = 'apps/' + lAppName,
146
+ folder = path.resolve(cwd, dir),
147
+ startDate = new Date();
148
+
149
+ if (!Array.isArray(themes)) {
150
+ themes = [themes];
151
+ }
152
+
153
+ if (themes.length > 0 && !themes.includes('none') && !mainThreadAddons.includes('Stylesheet')) {
154
+ console.error('ERROR! The Stylesheet mainThreadAddon is mandatory in case you are using themes');
155
+ console.log('Exiting with error.');
156
+ process.exit(1);
157
+ }
158
+
159
+ fs.mkdir(path.join(folder, '/view'), {recursive: true}, (err) => {
160
+ if (err) {
161
+ throw err;
162
+ }
163
+
164
+ let content, className;
165
+ const neoSrcPath = `../../../${insideNeo ? '' : 'node_modules/neo.mjs/'}src`;
166
+
167
+ const appContent = [
168
+ "import Viewport from './view/Viewport.mjs';",
169
+ "",
170
+ "export const onStart = () => Neo.app({",
171
+ " mainView: Viewport,",
172
+ " name : '" + appName + "'",
173
+ "});"
174
+ ].join(os.EOL);
175
+
176
+ fs.writeFileSync(folder + '/app.mjs', appContent);
177
+
178
+ const indexContent = `
179
+ &lt;!DOCTYPE HTML>
180
+ &lt;html>
181
+ &lt;head>
182
+ &lt;meta name="viewport" content="width=device-width, initial-scale=1">
183
+ &lt;meta charset="UTF-8">
184
+ &lt;title>${appName}&lt;/title>
185
+ &lt;/head>
186
+ &lt;body>
187
+ &lt;script src="../../src/MicroLoader.mjs" type="module">&lt;/script>
188
+ &lt;script>
189
+ new MutationObserver((mutationsList, observer) => {
190
+ for (let mutation of mutationsList) {
191
+ for (let addedNode of mutation.addedNodes) {
192
+ if (addedNode.className && addedNode.className.includes(\'neo-viewport\')) {
193
+ addedNode.addEventListener("contextmenu", function (e) {
194
+ if (!(e.ctrlKey || e.metaKey)) return;
195
+ e.stopPropagation();
196
+ e.preventDefault();
197
+ const event = new Event('neo-debug-item-select', {bubbles: true});
198
+ e.target.dispatchEvent(event);
199
+ });
200
+ observer.disconnect(); // We found the viewport so we\'re finished listening
201
+ }
202
+ }
203
+ }
204
+ }).observe(document.body, {childList: true, subtree: false});
205
+ &lt;/script>
206
+ &lt;/body>
207
+ &lt;/html>
208
+ `;
209
+ fs.writeFileSync(path.join(folder, 'index.html'), indexContent);
210
+
211
+
212
+
213
+ let neoConfig = {
214
+ appPath: `${insideNeo ? '' : '../../'}${appPath}app.mjs`,
215
+ basePath: '../../',
216
+ environment: 'development',
217
+ mainPath: `${insideNeo ? './' : '../node_modules/neo.mjs/src/'}Main.mjs`
218
+ };
219
+
220
+ if (!(mainThreadAddons.includes('DragDrop') && mainThreadAddons.includes('Stylesheet') && mainThreadAddons.length === 2)) {
221
+ neoConfig.mainThreadAddons = mainThreadAddons;
222
+ }
223
+
224
+ if (!themes.includes('all')) { // default value
225
+ if (themes.includes('none')) {
226
+ neoConfig.themes = [];
227
+ } else {
228
+ neoConfig.themes = themes;
229
+ }
230
+ }
231
+
232
+ if (useSharedWorkers !== 'no') {
233
+ neoConfig.useSharedWorkers = true;
234
+ }
235
+
236
+ if (useServiceWorker !== 'no') {
237
+ neoConfig.useServiceWorker = true;
238
+ }
239
+
240
+ if (!insideNeo) {
241
+ neoConfig.workerBasePath = '../../node_modules/neo.mjs/src/worker/';
242
+ }
243
+
244
+ let configs = Object.entries(neoConfig).sort((a, b) => a[0].localeCompare(b[0]));
245
+ neoConfig = {};
246
+
247
+ configs.forEach(([key, value]) => {
248
+ neoConfig[key] = value;
249
+ });
250
+
251
+ fs.writeFileSync(path.join(folder, 'neo-config.json'), JSON.stringify(neoConfig, null, 4));
252
+
253
+ // App source files: viewport and main view
254
+
255
+
256
+
257
+
258
+ // -------------------------------------------------------------------------
259
+
260
+ className = 'Viewport';
261
+ content = `
262
+ import Base from '${neoSrcPath}/container/Viewport.mjs';
263
+ import MainView from './MainView.mjs';
264
+
265
+ class ${className} extends Base {
266
+ static config = {
267
+ className: '${appName}.view.${className}',
268
+ autoMount: true,
269
+ layout: {ntype: 'fit'},
270
+ items: [{module:MainView}],
271
+ }
272
+ afterSetMounted(value, oldValue) {
273
+ super.afterSetMounted(value, oldValue);
274
+ if (!value) return;
275
+ this.addDomListeners({
276
+ "neo-debug-item-select": (event) => {
277
+ event.path.forEach((item) => {
278
+ const component = Neo.getComponent(item.id);
279
+ if (component) console.log(component);
280
+ });
281
+ },
282
+ });
283
+ }
284
+ }
285
+ Neo.applyClassConfig(${className});
286
+ export default ${className};
287
+ `;
288
+ fs.writeFileSync(path.join(`${folder}/view/${className}.mjs`), content);
289
+
290
+
291
+
292
+
293
+ // -------------------------------------------------------------------------
294
+
295
+ className = 'MainView';
296
+ content = `
297
+ import Base from '${neoSrcPath}/container/Base.mjs';
298
+ import Controller from './${className}Controller.mjs';
299
+ import ViewModel from './${className}Model.mjs';
300
+
301
+ class ${className} extends Base {
302
+ static config = {
303
+ className: '${appName}.view.${className}',
304
+ controller: {module: Controller},
305
+ model: {module: ViewModel},
306
+
307
+ layout: {ntype: 'fit'},
308
+ items: [],
309
+ }
310
+ }
311
+
312
+ Neo.applyClassConfig(${className});
313
+
314
+ export default ${className};
315
+ `;
316
+ fs.writeFileSync(path.join(`${folder}/view/${className}.mjs`), content);
317
+
318
+
319
+
320
+
321
+
322
+ // -------------------------------------------------------------------------
323
+
324
+ className = 'MainViewController';
325
+ content = `
326
+ import Base from '${neoSrcPath}/controller/Component.mjs';
327
+
328
+ class ${className} extends Base {
329
+ static config = {
330
+ className: '${appName}.view.${className}',
331
+ }
332
+ }
333
+
334
+ Neo.applyClassConfig(${className});
335
+
336
+ export default ${className};
337
+ `;
338
+ fs.writeFileSync(path.join(`${folder}/view/${className}.mjs`), content);
339
+
340
+
341
+
342
+
343
+
344
+ // -------------------------------------------------------------------------
345
+
346
+ className = 'MainViewModel';
347
+ content = `
348
+ import Base from '${neoSrcPath}/model/Component.mjs';
349
+
350
+ class ${className} extends Base {
351
+ static config = {
352
+ className: '${appName}.view.${className}',
353
+
354
+ data: {}
355
+ }
356
+ }
357
+
358
+ Neo.applyClassConfig(${className});
359
+
360
+ export default ${className};
361
+ `;
362
+ fs.writeFileSync(path.join(`${folder}/view/${className}.mjs`), content);
363
+
364
+
365
+
366
+
367
+
368
+ // -------------------------------------------------------------------------
369
+
370
+ let appJsonPath = path.resolve(cwd, 'buildScripts/myApps.json'),
371
+ appJson;
372
+
373
+ if (fs.existsSync(appJsonPath)) {
374
+ appJson = requireJson(appJsonPath);
375
+ } else {
376
+ appJsonPath = path.resolve(__dirname, 'buildScripts/webpack/json/myApps.json');
377
+
378
+ if (fs.existsSync(appJsonPath)) {
379
+ appJson = requireJson(appJsonPath);
380
+ } else {
381
+ appJson = requireJson(path.resolve(__dirname, 'buildScripts/webpack/json/myApps.template.json'));
382
+ }
383
+ }
384
+
385
+ if (!appJson.apps.includes(appName)) {
386
+ appJson.apps.push(appName);
387
+ appJson.apps.sort();
388
+ }
389
+
390
+ fs.writeFileSync(appJsonPath, JSON.stringify(appJson, null, 4));
391
+
392
+ if (mainThreadAddons.includes('HighlightJS')) {
393
+ spawnSync('node', [
394
+ './buildScripts/copyFolder.mjs',
395
+ '-s',
396
+ path.resolve(neoPath, 'docs/resources'),
397
+ '-t',
398
+ path.resolve(folder, 'resources'),
399
+ ], {env: process.env, cwd: process.cwd(), stdio: 'inherit'});
400
+ }
401
+
402
+ const processTime = (Math.round((new Date - startDate) * 100) / 100000).toFixed(2);
403
+ console.log(`\nTotal time for ${programName}: ${processTime} s`);
404
+
405
+ process.exit();
406
+ });
407
+ });
408
+ }
409
+ </pre>
410
+
411
+ ??Add an entry in `workspace/package.json`
412
+
413
+ Edit `workspace.package` and add an entry for the new script.
414
+
415
+ <pre style="font-size:80%; color:lightgray;border:thin solid gray; padding: 8px;">
416
+ "scripts": {
417
+ "add-config": "node ./node_modules/neo.mjs/buildScripts/addConfig.mjs",
418
+ "build-all": "node ./node_modules/neo.mjs/buildScripts/buildAll.mjs -n",
419
+ "build-all-questions": "node ./node_modules/neo.mjs/buildScripts/buildAll.mjs",
420
+ "build-my-apps": "node ./node_modules/neo.mjs/buildScripts/webpack/buildMyApps.mjs",
421
+ "build-themes": "node ./node_modules/neo.mjs/buildScripts/buildThemes.mjs",
422
+ "build-threads": "node ./node_modules/neo.mjs/buildScripts/webpack/buildThreads.mjs",
423
+ "copy-examples": "node ./buildScripts/copyExamples.mjs",
424
+ "create-app": "node ./node_modules/neo.mjs/buildScripts/createApp.mjs",
425
+ <span style="color:blue">"create-app-training": "node ./buildScripts/createAppTraining.mjs",</span>
426
+ "create-class": "node ./node_modules/neo.mjs/buildScripts/createClass.mjs",
427
+ "generate-docs-json": "node ./node_modules/neo.mjs/buildScripts/docs/jsdocx.mjs",
428
+ "inject-package-version": "node ./buildScripts/injectPackageVersion.mjs",
429
+ "server-start": "webpack serve -c ./node_modules/neo.mjs/buildScripts/webpack/webpack.server.config.mjs --open",
430
+ "test": "echo \"Error: no test specified\" && exit 1",
431
+ "watch-themes": "node ./node_modules/neo.mjs/buildScripts/watchThemes.mjs"
432
+ },
433
+ </pre>
@@ -0,0 +1,6 @@
1
+ Keep in mind that `Neo.manager.Component.items`, `Neo.find()` and `Neo.findFirst()`
2
+ are debugging aids _only_, and _should never be used in app logic_.
3
+
4
+ Why? There's nothing stopping you from using then, and they would work fine,
5
+ but those methods completely break encapsulation and scoping
6
+ rules! Their use would make an application brittle and hard to maintain.
@@ -0,0 +1,14 @@
1
+ The `config:{}` is special.
2
+
3
+ When you describe a class instance &mdash; like we've been doing in `items:[]` or
4
+ setting up the view model &mdash; you're using a config block. That block is applied to
5
+ the instance being created.
6
+
7
+ In a class definition the `static config = {}` is processed by the
8
+ framework<sup><small>*</small></sup> in order to set up the get/set
9
+ and lifecycle hooks.
10
+
11
+ <br><br><br>
12
+
13
+ <small>* via the Neo.applyClassConfig() found at the bottom of each class.</small>
14
+
@@ -0,0 +1,4 @@
1
+ One of the unique feature of Neo is the ability to have an app run in multiple windows.
2
+
3
+ This means your code can let the user can spawn windows, and run your views &mdash; all as
4
+ part of a single application, with shared data and integrated events.
@@ -0,0 +1,10 @@
1
+ Neo takes advantage of the _SharedWorker_ feature supported by most browsers
2
+ (including Chrome, Firefox, Edge, and Safari). <small><sup>*</sup></small>
3
+
4
+ A shared worker is a special web worker that can be access by multiple browsing windows.
5
+
6
+ Neo.mjs has the advantage of representing dom content via its vdom &mdash; that vdom hierarchy can be
7
+ trivially mounted in any container, even the shared window's viewport.
8
+
9
+ <br><br><br>
10
+ <small>* <a href="https://developer.mozilla.org/en-US/docs/Web/API/SharedWorker" target="_blank">SharedWorker documentation</a></small>
@@ -0,0 +1,205 @@
1
+ #Introduction
2
+
3
+ In this lab you'll have the table and map open in their own windows.
4
+
5
+ #Steps
6
+
7
+ ??Create a second app that provides the second window viewport
8
+
9
+ Use a terminal window, navigate to your workspace, and run `npm run create-app`.
10
+
11
+ Name it **EarthquakesTableWindow**,
12
+ and **answer Yes** when asked "Do you want to use SharedWorkers?"
13
+
14
+ ??Inspect the app's `neo-config.json`
15
+
16
+ Open `apps/earthquakestablewindow/neo-config.json` and note the `useSharedWorkers` entry
17
+
18
+ <pre style="color:lightgray">
19
+ {
20
+ "appPath": "../../apps/earthquakestablewindow/app.mjs",
21
+ "basePath": "../../",
22
+ "environment": "development",
23
+ "mainPath": "../node_modules/neo.mjs/src/Main.mjs",
24
+ <span style="color:blue">"useSharedWorkers": true,</span>
25
+ "workerBasePath": "../../node_modules/neo.mjs/src/worker/"
26
+ }
27
+ </pre>
28
+
29
+ ??Clean up the new app
30
+
31
+ The only thing we need the new app for is its viewport.
32
+
33
+ Edit `apps/earthquakestablewindow/MainContainer.mjs` and remove everything except the `className` and the `layout`, and
34
+ change the layout to `layout:{ntype:'fit'}`. When you're finished it should look like this.
35
+
36
+ <pre style="border:thin solid gray; color:gray; font-size:0.8em; padding:1em">
37
+ import Viewport from '../../../node_modules/neo.mjs/src/container/Viewport.mjs';
38
+
39
+ /**
40
+ * @class EarthquakesTableWindow.view.MainContainer
41
+ * @extends Neo.container.Viewport
42
+ */
43
+ class MainContainer extends Viewport {
44
+ static config = {
45
+ /**
46
+ * @member {String} className='EarthquakesTableWindow.view.MainContainer'
47
+ * @protected
48
+ */
49
+ className: 'EarthquakesTableWindow.view.MainContainer',
50
+ /*
51
+ * @member {Object} layout={ntype:'fit'}
52
+ */
53
+ layout: {ntype: 'fit'}
54
+ }
55
+ }
56
+
57
+ Neo.applyClassConfig(MainContainer);
58
+
59
+ export default MainContainer;
60
+ </pre>
61
+
62
+ You're completly finished with EarthquakesTableWindow.
63
+ To avoid confusion, you might want to close any EarthquakesTableWindow
64
+ files you have open in your code editor.
65
+
66
+
67
+
68
+ ??Have our Earthquakes app use a shared worker too
69
+
70
+ Both apps need to use a shared worker. To enable that in Earthquakes, edit `apps/earthquakes/neo-config.json` and add the entry for _useSharedWorkers_.
71
+
72
+ <pre style="color:lightgray">
73
+ {
74
+ "appPath": "../../apps/earthquakes/app.mjs",
75
+ "basePath": "../../",
76
+ "environment": "development",
77
+ "mainPath": "../node_modules/neo.mjs/src/Main.mjs",
78
+ <span style="color:blue">"useSharedWorkers": true,</span>
79
+ "workerBasePath": "../../node_modules/neo.mjs/src/worker/"
80
+ }
81
+ </pre>
82
+
83
+ ??Note a change in how you debug
84
+
85
+ Chrome Devtools lets you inspect shared workers via the special url `chrome://inspect`. To use it,
86
+ open a new browser window and enter (or copy-and-paste) that exact URL.
87
+
88
+ Then select the "Shared workers" option on the left, then click on `inspect` by the entry for _neomjs-app-worker_.
89
+
90
+ <img src="resources/images/debugging/ChromeDevToolsInspectWorkers.png"/>
91
+
92
+ Clicking `inspect` opens a standard debug window, but with a single execution context.
93
+
94
+ <img src="resources/images/debugging/ChromeDevToolsSharedWorkerContext.png"/>
95
+
96
+ If you run the app and click on a map item, or a table row, you should see the
97
+ console logs being run from your event handlers.
98
+
99
+ ??Add a button used to launch the window
100
+
101
+ Edit `MainContainer` and add a second item to the items array. This will be after
102
+ the map config and before the table config.
103
+
104
+ {
105
+ module: Button,
106
+ reference: 'openWindowButton',
107
+ style: {flex: 'none'},
108
+ text: 'Open table in window',
109
+ handler: 'onOpenWindowClick'
110
+ },
111
+
112
+ Save and refresh and you should see the new button between the map and table.
113
+ It occupies the full width because the main container is using `align:'stretch'` for
114
+ its vbox layout.
115
+
116
+ ??Create the event handler
117
+
118
+ Now edit `MainContainerController` and add a new member function `onOpenWindowClick`.
119
+
120
+ The code needs to add a new window using the URL for the EarthquakesTableWindow app.
121
+ Neo has a method that runs `window.open()` in the main thread. Here's the code.
122
+
123
+ onOpenWindowClick() {
124
+ Neo.Main.windowOpen({
125
+ url: `../earthquakestablewindow`,
126
+ windowName: 'earthquakestablewindow' // This could be _blank or whatever you want
127
+ });
128
+ }
129
+
130
+ Save and refresh, then click the button &mdash; a browser tab will open running the
131
+ empty EarthquakesTableWindow app.
132
+
133
+ Close the EarthquakesTableWindow tab.
134
+
135
+ (Note that we're not bothering adding logic to see if EarthquakesTableWindow is
136
+ already open when launching the Earthquakes app. Therefore, before refreshing
137
+ Earthquakes make sure you've closed EarthquakesTableWindow first.)
138
+
139
+ ??Detect when the new window launches
140
+
141
+ Neo fires an event when applications are connected to the appworker. We need to add a listener
142
+ to that event. We'll do that in the main controller's `construct` method. Add this as a
143
+ member method to `MainContainerController`. As you can see, the code adds two listeners
144
+ to the appworker: `onAppConnect` and `onAppDisconnect`.
145
+
146
+ construct(config) {
147
+ super.construct(config);
148
+
149
+ let me = this;
150
+ Neo.currentWorker.on({
151
+ connect: me.onAppConnect,
152
+ disconnect: me.onAppDisconnect,
153
+ scope: me
154
+ });
155
+ }
156
+
157
+ The disconnect method will run if the user closes the EarthquakesTableWindow window.
158
+ We'll use that to move the table back to the main app.
159
+
160
+ The connect method runs if the EarthquakesTableWindow launches. In other words,
161
+ when `onOpenWindowClick` is run, it opens the EarthquakesTableWindow, which in
162
+ turn triggers the _connect_ event.
163
+
164
+ ??Code `onAppConnect`
165
+
166
+ This is the code you've been waiting for! And it's pretty simple.
167
+
168
+ If the newly opened window is EarthquakesTableWindow, then simply remove
169
+ the table from the Earthquakes main view, and add it to the EarthquakesTableWindow
170
+ main view. Add this instance method to MainContainerController.
171
+
172
+ onAppConnect(data) {
173
+ let me = this;
174
+ NeoArray.add(me.connectedApps, data.appName);
175
+ if (data.appName === 'EarthquakesTableWindow'){
176
+ let table = me.getReference('table');
177
+ me.component.remove(table, false) // Params: component, destroy, silent
178
+ Neo.apps.EarthquakesTableWindow.mainView.add(table);
179
+ me.getReference('openWindowButton').hidden = true;
180
+ }
181
+ }
182
+
183
+ Save your changes, and verify that the EarthquakesTableWindow is _not_ open.
184
+ Then click on the _Open table in window_ button. A new tab should appear, holding
185
+ the table. The Earthquakes window will just hold the map.
186
+
187
+ Click on a table row, then look on the map: the corresponding marker highlights!
188
+
189
+ ??Contemplate the moment
190
+
191
+ This is pretty cool. Seriously.
192
+
193
+ There's no special code. We're just moving a component from one container to another.
194
+ Events are preserved.
195
+
196
+ (Note that the map would _not_ have moved in the same way, because the Google map and
197
+ markers are maintained via Google Maps APIs. In contrast, the Earthquakes table is a
198
+ normal Neo component &mdash; Neo components know their own view structure, so can
199
+ easily be mounted in any container, including the new window's viewport. To move the
200
+ map we'd have to write code to fully delete the map in the main view, then add it as
201
+ a new component in EarthquakesTableWindow. It would only be a few lines of code, but
202
+ the difference between the map and table provides some insight into how Neo works.)
203
+
204
+
205
+ ??Move the table back when the EarthquakesTableWindow closes