neo.mjs 6.9.10 → 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 (235) 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 +8 -5
  6. package/apps/learnneo/view/home/ContentView.mjs +60 -0
  7. package/apps/learnneo/view/home/MainContainer.mjs +22 -14
  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/package.json +2 -2
  18. package/resources/data/{learnneo → deck/learnneo}/p/2023-10-01T18-29-19-158Z.md +3 -6
  19. package/resources/data/deck/learnneo/p/stylesheet.md +40 -0
  20. package/resources/data/{learnneo → deck/learnneo}/t.json +19 -2
  21. package/resources/data/deck/training/p/2022-12-27T21-54-52-300Z.md +11 -0
  22. package/resources/data/deck/training/p/2022-12-27T21-55-23-144Z.md +43 -0
  23. package/resources/data/deck/training/p/2022-12-27T21-55-30-948Z.md +1 -0
  24. package/resources/data/deck/training/p/2022-12-27T21-55-43-542Z.md +84 -0
  25. package/resources/data/deck/training/p/2022-12-27T22-23-55-083Z.md +1 -0
  26. package/resources/data/deck/training/p/2022-12-27T22-24-07-886Z.md +8 -0
  27. package/resources/data/deck/training/p/2022-12-27T22-24-52-295Z.md +8 -0
  28. package/resources/data/deck/training/p/2022-12-27T22-25-03-853Z.md +5 -0
  29. package/resources/data/deck/training/p/2022-12-27T22-43-58-924Z.md +10 -0
  30. package/resources/data/deck/training/p/2022-12-27T22-44-28-881Z.md +3 -0
  31. package/resources/data/deck/training/p/2022-12-27T22-44-41-791Z.md +4 -0
  32. package/resources/data/deck/training/p/2022-12-27T22-45-21-032Z.md +7 -0
  33. package/resources/data/deck/training/p/2022-12-27T22-49-22-078Z.md +4 -0
  34. package/resources/data/deck/training/p/2022-12-27T22-50-20-626Z.md +4 -0
  35. package/resources/data/deck/training/p/2022-12-28T16-58-47-786Z.md +0 -0
  36. package/resources/data/deck/training/p/2022-12-28T16-58-55-192Z.md +9 -0
  37. package/resources/data/deck/training/p/2022-12-28T17-10-18-058Z.md +15 -0
  38. package/resources/data/deck/training/p/2022-12-28T17-10-42-296Z.md +40 -0
  39. package/resources/data/deck/training/p/2022-12-28T17-11-34-653Z.md +41 -0
  40. package/resources/data/deck/training/p/2022-12-28T17-13-09-994Z.md +0 -0
  41. package/resources/data/deck/training/p/2022-12-28T21-32-14-420Z.md +0 -0
  42. package/resources/data/deck/training/p/2022-12-29T01-43-32-431Z.md +7 -0
  43. package/resources/data/deck/training/p/2022-12-29T15-56-54-485Z.md +7 -0
  44. package/resources/data/deck/training/p/2022-12-29T15-57-11-499Z.md +7 -0
  45. package/resources/data/deck/training/p/2022-12-29T16-00-13-223Z.md +7 -0
  46. package/resources/data/deck/training/p/2022-12-29T18-34-25-826Z.md +4 -0
  47. package/resources/data/deck/training/p/2022-12-29T18-36-08-226Z.md +106 -0
  48. package/resources/data/deck/training/p/2022-12-29T18-36-56-893Z.md +112 -0
  49. package/resources/data/deck/training/p/2022-12-29T19-31-30-507Z.md +31 -0
  50. package/resources/data/deck/training/p/2022-12-29T19-31-55-091Z.md +14 -0
  51. package/resources/data/deck/training/p/2022-12-29T20-03-42-628Z.md +9 -0
  52. package/resources/data/deck/training/p/2022-12-29T20-21-20-669Z.md +7 -0
  53. package/resources/data/deck/training/p/2022-12-29T20-37-08-919Z.md +46 -0
  54. package/resources/data/deck/training/p/2022-12-29T20-37-20-344Z.md +43 -0
  55. package/resources/data/deck/training/p/2022-12-30T19-04-30-990Z.md +8 -0
  56. package/resources/data/deck/training/p/2022-12-31T18-43-56-338Z.md +7 -0
  57. package/resources/data/deck/training/p/2022-12-31T18-51-50-682Z.md +1 -0
  58. package/resources/data/deck/training/p/2022-12-31T18-54-04-176Z.md +4 -0
  59. package/resources/data/deck/training/p/2022-12-31T22-11-55-555Z.md +112 -0
  60. package/resources/data/deck/training/p/2022-12-31T23-00-41-222Z.md +6 -0
  61. package/resources/data/deck/training/p/2022-12-31T23-18-55-655Z.md +69 -0
  62. package/resources/data/deck/training/p/2022-12-31T23-25-40-735Z.md +21 -0
  63. package/resources/data/deck/training/p/2022-12-31T23-25-51-014Z.md +7 -0
  64. package/resources/data/deck/training/p/2023-01-01T17-49-18-429Z.md +3 -0
  65. package/resources/data/deck/training/p/2023-01-01T18-44-07-034Z.md +34 -0
  66. package/resources/data/deck/training/p/2023-01-01T18-47-39-766Z.md +15 -0
  67. package/resources/data/deck/training/p/2023-01-01T19-04-22-830Z.md +4 -0
  68. package/resources/data/deck/training/p/2023-01-01T21-11-58-025Z.md +25 -0
  69. package/resources/data/deck/training/p/2023-01-01T21-12-37-340Z.md +23 -0
  70. package/resources/data/deck/training/p/2023-01-01T21-13-13-880Z.md +8 -0
  71. package/resources/data/deck/training/p/2023-01-01T21-14-45-740Z.md +98 -0
  72. package/resources/data/deck/training/p/2023-01-01T21-18-23-886Z.md +26 -0
  73. package/resources/data/deck/training/p/2023-01-01T21-18-31-316Z.md +19 -0
  74. package/resources/data/deck/training/p/2023-01-01T21-18-42-290Z.md +23 -0
  75. package/resources/data/deck/training/p/2023-01-01T21-19-57-020Z.md +24 -0
  76. package/resources/data/deck/training/p/2023-01-01T21-22-31-184Z.md +13 -0
  77. package/resources/data/deck/training/p/2023-01-01T21-22-38-317Z.md +17 -0
  78. package/resources/data/deck/training/p/2023-01-01T21-22-47-693Z.md +20 -0
  79. package/resources/data/deck/training/p/2023-01-01T21-23-17-716Z.md +39 -0
  80. package/resources/data/deck/training/p/2023-01-01T21-23-28-532Z.md +22 -0
  81. package/resources/data/deck/training/p/2023-01-01T21-25-23-899Z.md +3 -0
  82. package/resources/data/deck/training/p/2023-01-01T21-25-59-742Z.md +1 -0
  83. package/resources/data/deck/training/p/2023-01-01T21-26-53-748Z.md +12 -0
  84. package/resources/data/deck/training/p/2023-01-01T23-38-42-863Z.md +2 -0
  85. package/resources/data/deck/training/p/2023-01-03T02-07-19-014Z.md +143 -0
  86. package/resources/data/deck/training/p/2023-01-04T01-52-23-454Z.md +76 -0
  87. package/resources/data/deck/training/p/2023-01-06T23-21-12-009Z.md +127 -0
  88. package/resources/data/deck/training/p/2023-01-06T23-21-31-685Z.md +81 -0
  89. package/resources/data/deck/training/p/2023-01-06T23-21-59-596Z.md +36 -0
  90. package/resources/data/deck/training/p/2023-01-06T23-34-13-897Z.md +87 -0
  91. package/resources/data/deck/training/p/2023-01-06T23-44-02-340Z.md +0 -0
  92. package/resources/data/deck/training/p/2023-01-06T23-46-36-687Z.md +1 -0
  93. package/resources/data/deck/training/p/2023-01-06T23-46-45-783Z.md +33 -0
  94. package/resources/data/deck/training/p/2023-01-08T00-45-11-144Z.md +50 -0
  95. package/resources/data/deck/training/p/2023-01-08T01-06-31-267Z.md +41 -0
  96. package/resources/data/deck/training/p/2023-01-08T01-24-21-088Z.md +95 -0
  97. package/resources/data/deck/training/p/2023-01-08T01-25-12-557Z.md +11 -0
  98. package/resources/data/deck/training/p/2023-01-08T01-46-50-723Z.md +25 -0
  99. package/resources/data/deck/training/p/2023-01-08T02-09-07-802Z.md +18 -0
  100. package/resources/data/deck/training/p/2023-01-08T02-09-19-678Z.md +66 -0
  101. package/resources/data/deck/training/p/2023-01-08T02-11-26-333Z.md +29 -0
  102. package/resources/data/deck/training/p/2023-01-08T17-22-48-841Z.md +14 -0
  103. package/resources/data/deck/training/p/2023-01-08T20-46-11-806Z.md +5 -0
  104. package/resources/data/deck/training/p/2023-01-08T20-47-23-682Z.md +5 -0
  105. package/resources/data/deck/training/p/2023-01-08T20-47-32-064Z.md +13 -0
  106. package/resources/data/deck/training/p/2023-01-08T20-47-57-045Z.md +0 -0
  107. package/resources/data/deck/training/p/2023-01-08T20-48-03-791Z.md +18 -0
  108. package/resources/data/deck/training/p/2023-01-08T20-48-32-466Z.md +9 -0
  109. package/resources/data/deck/training/p/2023-01-08T20-48-51-322Z.md +20 -0
  110. package/resources/data/deck/training/p/2023-01-08T20-49-52-741Z.md +0 -0
  111. package/resources/data/deck/training/p/2023-01-08T20-52-03-556Z.md +0 -0
  112. package/resources/data/deck/training/p/2023-01-08T20-57-36-333Z.md +2 -0
  113. package/resources/data/deck/training/p/2023-01-08T20-57-51-136Z.md +5 -0
  114. package/resources/data/deck/training/p/2023-01-09T00-07-37-951Z.md +0 -0
  115. package/resources/data/deck/training/p/2023-01-09T00-35-40-671Z.md +3 -0
  116. package/resources/data/deck/training/p/2023-01-10T01-29-38-148Z.md +10 -0
  117. package/resources/data/deck/training/p/2023-01-10T01-43-12-166Z.md +31 -0
  118. package/resources/data/deck/training/p/2023-01-10T02-21-54-303Z.md +10 -0
  119. package/resources/data/deck/training/p/2023-01-12T01-50-54-617Z.md +74 -0
  120. package/resources/data/deck/training/p/2023-01-13T19-55-24-735Z.md +14 -0
  121. package/resources/data/deck/training/p/2023-01-13T20-08-27-068Z.md +28 -0
  122. package/resources/data/deck/training/p/2023-01-13T20-23-38-411Z.md +25 -0
  123. package/resources/data/deck/training/p/2023-01-13T20-37-06-267Z.md +13 -0
  124. package/resources/data/deck/training/p/2023-01-13T21-05-57-708Z.md +8 -0
  125. package/resources/data/deck/training/p/2023-01-13T21-48-17-258Z.md +20 -0
  126. package/resources/data/deck/training/p/2023-01-13T22-05-05-799Z.md +14 -0
  127. package/resources/data/deck/training/p/2023-01-13T22-08-30-863Z.md +17 -0
  128. package/resources/data/deck/training/p/2023-01-13T23-01-50-449Z.md +4 -0
  129. package/resources/data/deck/training/p/2023-01-14T00-33-05-958Z.md +62 -0
  130. package/resources/data/deck/training/p/2023-01-14T00-40-27-784Z.md +229 -0
  131. package/resources/data/deck/training/p/2023-01-14T00-41-59-081Z.md +153 -0
  132. package/resources/data/deck/training/p/2023-01-14T13-50-28-199Z.md +19 -0
  133. package/resources/data/deck/training/p/2023-01-14T13-59-20-275Z.md +6 -0
  134. package/resources/data/deck/training/p/2023-01-14T14-03-29-456Z.md +3 -0
  135. package/resources/data/deck/training/p/2023-01-14T14-27-57-678Z.md +7 -0
  136. package/resources/data/deck/training/p/2023-01-14T17-30-18-228Z.md +33 -0
  137. package/resources/data/deck/training/p/2023-01-14T18-28-39-316Z.md +1 -0
  138. package/resources/data/deck/training/p/2023-01-14T18-28-44-115Z.md +4 -0
  139. package/resources/data/deck/training/p/2023-01-14T18-28-49-548Z.md +18 -0
  140. package/resources/data/deck/training/p/2023-01-14T18-40-13-758Z.md +10 -0
  141. package/resources/data/deck/training/p/2023-01-14T19-29-15-291Z.md +12 -0
  142. package/resources/data/deck/training/p/2023-01-15T18-51-52-134Z.md +83 -0
  143. package/resources/data/deck/training/p/2023-01-15T20-03-30-073Z.md +11 -0
  144. package/resources/data/deck/training/p/2023-01-15T22-07-52-073Z.md +16 -0
  145. package/resources/data/deck/training/p/2023-01-15T22-22-13-517Z.md +12 -0
  146. package/resources/data/deck/training/p/2023-01-15T22-28-57-508Z.md +131 -0
  147. package/resources/data/deck/training/p/2023-01-15T22-36-30-913Z.md +115 -0
  148. package/resources/data/deck/training/p/2023-01-16T16-03-40-770Z.md +12 -0
  149. package/resources/data/deck/training/p/2023-01-16T20-21-56-859Z.md +5 -0
  150. package/resources/data/deck/training/p/2023-01-16T20-24-09-690Z.md +24 -0
  151. package/resources/data/deck/training/p/2023-01-20T12-51-22-646Z.md +21 -0
  152. package/resources/data/deck/training/p/2023-01-20T13-06-46-614Z.md +9 -0
  153. package/resources/data/deck/training/p/2023-01-20T13-08-51-600Z.md +7 -0
  154. package/resources/data/deck/training/p/2023-01-20T15-20-13-363Z.md +26 -0
  155. package/resources/data/deck/training/p/2023-01-20T15-34-58-813Z.md +75 -0
  156. package/resources/data/deck/training/p/2023-01-21T16-33-20-458Z.md +33 -0
  157. package/resources/data/deck/training/p/2023-01-21T16-45-28-263Z.md +28 -0
  158. package/resources/data/deck/training/p/2023-01-21T16-56-25-452Z.md +3 -0
  159. package/resources/data/deck/training/p/2023-01-21T17-28-31-493Z.md +6 -0
  160. package/resources/data/deck/training/p/2023-01-21T19-49-51-918Z.md +13 -0
  161. package/resources/data/deck/training/p/2023-01-21T20-08-24-452Z.md +15 -0
  162. package/resources/data/deck/training/p/2023-01-21T20-35-54-947Z.md +20 -0
  163. package/resources/data/deck/training/p/2023-01-21T20-54-47-603Z.md +39 -0
  164. package/resources/data/deck/training/p/2023-01-21T20-56-28-184Z.md +25 -0
  165. package/resources/data/deck/training/p/2023-01-21T20-57-32-927Z.md +4 -0
  166. package/resources/data/deck/training/p/2023-01-21T23-13-33-394Z.md +6 -0
  167. package/resources/data/deck/training/p/2023-01-28T19-11-37-464Z.md +24 -0
  168. package/resources/data/deck/training/p/2023-01-28T20-43-41-188Z.md +9 -0
  169. package/resources/data/deck/training/p/2023-01-28T20-53-56-476Z.md +8 -0
  170. package/resources/data/deck/training/p/2023-01-28T20-58-43-776Z.md +10 -0
  171. package/resources/data/deck/training/p/2023-01-28T22-18-41-259Z.md +33 -0
  172. package/resources/data/deck/training/p/2023-01-28T22-24-34-808Z.md +24 -0
  173. package/resources/data/deck/training/p/2023-01-29T16-25-24-528Z.md +44 -0
  174. package/resources/data/deck/training/p/2023-01-29T21-14-32-588Z.md +12 -0
  175. package/resources/data/deck/training/p/2023-01-31T19-24-53-504Z.md +8 -0
  176. package/resources/data/deck/training/p/2023-01-31T20-33-55-855Z.md +11 -0
  177. package/resources/data/deck/training/p/2023-01-31T20-34-30-261Z.md +7 -0
  178. package/resources/data/deck/training/p/2023-01-31T20-52-53-367Z.md +43 -0
  179. package/resources/data/deck/training/p/2023-02-04T15-18-35-682Z.md +20 -0
  180. package/resources/data/deck/training/p/2023-02-04T15-49-47-597Z.md +14 -0
  181. package/resources/data/deck/training/p/2023-02-04T18-58-57-808Z.md +1 -0
  182. package/resources/data/deck/training/p/2023-02-04T20-07-11-288Z.md +1 -0
  183. package/resources/data/deck/training/p/2023-02-04T20-09-50-169Z.md +1 -0
  184. package/resources/data/deck/training/p/2023-02-04T20-19-42-740Z.md +8 -0
  185. package/resources/data/deck/training/p/2023-02-04T20-23-56-013Z.md +12 -0
  186. package/resources/data/deck/training/p/2023-02-04T20-28-12-391Z.md +20 -0
  187. package/resources/data/deck/training/p/2023-02-05T00-20-32-554Z.md +16 -0
  188. package/resources/data/deck/training/p/2023-02-05T00-35-56-282Z.md +13 -0
  189. package/resources/data/deck/training/p/2023-02-05T15-36-57-182Z.md +24 -0
  190. package/resources/data/deck/training/p/2023-02-05T17-39-51-712Z.md +70 -0
  191. package/resources/data/deck/training/p/2023-02-05T17-44-53-815Z.md +195 -0
  192. package/resources/data/deck/training/p/2023-02-05T17-45-40-114Z.md +92 -0
  193. package/resources/data/deck/training/p/2023-02-05T18-12-14-489Z.md +60 -0
  194. package/resources/data/deck/training/p/2023-02-06T00-14-54-457Z.md +9 -0
  195. package/resources/data/deck/training/p/2023-06-28T18-03-14-313Z.md +8 -0
  196. package/resources/data/deck/training/p/2023-06-28T18-26-17-290Z.md +7 -0
  197. package/resources/data/deck/training/p/2023-06-28T21-16-24-034Z.md +40 -0
  198. package/resources/data/deck/training/p/2023-06-28T21-16-34-972Z.md +16 -0
  199. package/resources/data/deck/training/p/2023-06-28T21-28-28-379Z.md +4 -0
  200. package/resources/data/deck/training/p/2023-06-29T23-15-10-411Z.md +5 -0
  201. package/resources/data/deck/training/p/2023-07-01T15-42-45-193Z.md +433 -0
  202. package/resources/data/deck/training/p/2023-07-01T21-54-31-329Z.md +6 -0
  203. package/resources/data/deck/training/p/2023-07-02T16-14-06-970Z.md +14 -0
  204. package/resources/data/deck/training/p/2023-07-31T00-26-03-842Z.md +4 -0
  205. package/resources/data/deck/training/p/2023-07-31T00-31-51-933Z.md +10 -0
  206. package/resources/data/deck/training/p/2023-07-31T00-37-21-927Z.md +205 -0
  207. package/resources/data/deck/training/p/2023-10-01T18-29-19-158Z.md +76 -0
  208. package/resources/data/deck/training/p/2023-10-07T19-18-28-517Z.md +102 -0
  209. package/resources/data/deck/training/p/2023-10-08T20-20-07-934Z.md +75 -0
  210. package/resources/data/deck/training/p/2023-10-08T20-20-37-336Z.md +29 -0
  211. package/resources/data/deck/training/p/2023-10-08T20-37-30-658Z.md +0 -0
  212. package/resources/data/deck/training/p/2023-10-08T21-58-25-809Z.md +68 -0
  213. package/resources/data/deck/training/p/2023-10-08T22-22-11-013Z.md +0 -0
  214. package/resources/data/deck/training/p/2023-10-14T19-25-08-153Z.md +119 -0
  215. package/resources/data/deck/training/t.json +1 -0
  216. package/resources/scss/src/apps/learnneo/home/{ContentComponent.scss → ContentView.scss} +9 -15
  217. package/resources/scss/theme-neo-light/Global.scss +46 -0
  218. package/resources/scss/theme-neo-light/design-tokens/Core.scss +7 -0
  219. package/resources/scss/theme-neo-light/design-tokens/Semantic.scss +0 -0
  220. package/resources/scss/theme-neo-light/design-tokens/_all.scss +4 -0
  221. package/src/DefaultConfig.mjs +4 -4
  222. package/src/form/field/Text.mjs +2 -2
  223. package/apps/learnneo/view/home/ContentComponent.mjs +0 -24
  224. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-07T19-18-28-517Z.md +0 -0
  225. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-20-07-934Z.md +0 -0
  226. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-20-37-336Z.md +0 -0
  227. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-37-30-658Z.md +0 -0
  228. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T21-58-25-809Z.md +0 -0
  229. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T22-22-11-013Z.md +0 -0
  230. /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-14T19-25-08-153Z.md +0 -0
  231. /package/resources/data/{learnneo → deck/learnneo}/pages/whyneo.md +0 -0
  232. /package/resources/data/{learnneo → deck/learnneo}/tree.json +0 -0
  233. /package/resources/{deck → data/deck}/whyneo.md +0 -0
  234. /package/resources/scss/src/apps/newwebsite/{MainContainer.css → MainContainer.scss} +0 -0
  235. /package/resources/scss/theme-neo-light/design-tokens/{Components.scss → Component.scss} +0 -0
@@ -0,0 +1,83 @@
1
+ #Introduction
2
+
3
+ In this lab you'll add `city` and `category` properties.
4
+
5
+ #Steps
6
+
7
+ ??Define a city_ property
8
+
9
+ Add a `city_:''` config.
10
+
11
+ As you know, this creates a get/set property.
12
+
13
+ Save your changes, then in the Chrome debugger's app-worker context
14
+ get a reference to the filter component and confirm that the property
15
+ exists.
16
+
17
+ Is the property there? This statement should evaluate to '' (and not undefined).
18
+
19
+ Neo.findFirst({ntype:'yelp-filter'}).city
20
+
21
+ Assign a value.
22
+
23
+ Neo.findFirst({ntype:'yelp-filter'}).city = 'Madison'
24
+
25
+ Read the value. This should evaluate the city you assigned above.
26
+
27
+ Neo.findFirst({ntype:'yelp-filter'}).city
28
+
29
+ None of this is very surprising yet. The `city` property would behave
30
+ the same whether it was a simple property or a get/set property.
31
+
32
+
33
+ ??Detect when `city` changes
34
+
35
+ We need a function to be run when the city property changes. Later,
36
+ we'll use that function to update the text field.
37
+
38
+ How do you detect a change to a get/set property? Via its `afterSet...`
39
+ method!
40
+
41
+ Add that method, with a single statement that logs the passed value.
42
+
43
+ <pre class="runnable readonly text 320">
44
+ import Base from '../../../../node_modules/neo.mjs/src/container/Base.mjs';
45
+ import TextField from '../../../../node_modules/neo.mjs/src/form/field/Text.mjs';
46
+ class Filter extends Base {
47
+ static config = {
48
+ ...
49
+ }
50
+
51
+ afterSetCity(city) {
52
+ console.log(city);
53
+ }
54
+ }
55
+
56
+ Neo.applyClassConfig(Filter);
57
+
58
+ export default Filter;
59
+ </pre>
60
+
61
+ ??Test the filter on the command line
62
+
63
+ Use the debugger's console (in the app worker context) and verify that
64
+ you see the value logged. In other words, runing the following should result
65
+ in `afterSetCity()` being run.
66
+
67
+ Neo.findFirst({ntype:'yelp-filter'}).city = 'Madison'
68
+
69
+
70
+ ??Add a `category` get/set
71
+
72
+ Now add a `category_:'',` config, and a corresponding `afterSetCategory()`
73
+ method. The code will be almost identical to what you did for city.
74
+
75
+ Test your code by setting and getting `category` on the command line.
76
+
77
+ Neo.findFirst({ntype:'yelp-filter'}).category
78
+
79
+ Neo.findFirst({ntype:'yelp-filter'}).category = 'pizza'
80
+
81
+ Neo.findFirst({ntype:'yelp-filter'}).category
82
+
83
+ You should see the value updating and the value being logged.
@@ -0,0 +1,11 @@
1
+ `Neo.component.Base` also has a `reference` config.
2
+
3
+ If you code a component with `reference:'foo',`, then you can get
4
+ a reference from the view or controller via `this.getReference('foo')`.
5
+
6
+ This is similar to using the Neo find methods, but references are
7
+ resolved in a more efficient manner and the scope is limited to
8
+ what the view can "see".
9
+
10
+ <span style="color:lightgray">(Controllers keep a map of references, keyed by the reference name. The <code style="color:lightgray">getReference()</code> method
11
+ uses bracket notiation to retrieve the value from the map &mdash; it's lighting fast.)</span>
@@ -0,0 +1,16 @@
1
+ Those labs were lengthy because we worked _very_ slowly and methodically.
2
+
3
+ On a project, encapsulating code like this isn't usually needed. You code
4
+ views that show data, and you nest those in containers.
5
+
6
+ But if you need a propertly encapsulated class you'll do something like you
7
+ did with the `Yelp.view.businesses.Filter`.
8
+
9
+ But there isn't much code in there!
10
+
11
+ - It has a property
12
+ - Updates to the properties are reflected in the view
13
+ - Updates to the view are reflected in the properies
14
+
15
+ After you code a couple of such classes it becomes a matter of minutes
16
+ to code them.
@@ -0,0 +1,12 @@
1
+ The following four labs are elaborate.
2
+
3
+ They give you
4
+ practice with a common coding task: creating a de-coupled
5
+ class with a well-defined API.
6
+
7
+ Neo has features that makes this easy. Later we'll cover
8
+ additional techniques for having a de-coupled class interact
9
+ with the rest of an application via events and bindings.
10
+
11
+ The labs feature common coding use-cases. Take your time &mdash;
12
+ make sure everything makes sense!
@@ -0,0 +1,131 @@
1
+ #Introduction
2
+
3
+ In this lab you'll udpate the text fields as the properties change.
4
+
5
+ #Steps
6
+
7
+ ??Add `reference` to the fields
8
+
9
+ First, add a `reference:'city',` to the city field config
10
+ and `reference:'category',` to the category field.
11
+
12
+ As you recall from lecture, `reference` is used in component
13
+ or controller methods to get a reference to the field via
14
+ `this.getReference()`.
15
+
16
+ ??Update the city field
17
+ You already have an `afterSetCity()` method.
18
+
19
+ Modify it to udpdate the city.
20
+
21
+ this.getReference('city').value = city;
22
+
23
+ If you save and run the code you get a runtime error!
24
+ That happens because when the value is first applied (to assign
25
+ the initial defined in `city_:'',`) the view hasn't
26
+ been rendered yet! `Neo.component.Base` has a `rendered` property.
27
+ We need a statement to test that. Add this statement before
28
+ you assign the city to the field.
29
+
30
+ if (!this.rendered) return;
31
+
32
+ <pre style="border: thin solid gray; padding: 8px; color: lightgray; font-size:14pt;">
33
+ import Base from '../../../../node_modules/neo.mjs/src/container/Base.mjs';
34
+ import TextField from '../../../../node_modules/neo.mjs/src/form/field/Text.mjs';
35
+ import Function from '../../util/Function.mjs';
36
+ class Filter extends Base {
37
+ static config = {
38
+ className: 'Yelp.view.businesses.Filter',
39
+ ntype: 'yelp-filter',
40
+
41
+ city_: '',
42
+ category_: '',
43
+
44
+ layout: { ntype: 'hbox' },
45
+ itemDefaults: {module: TextField, clearable: true,},
46
+ items: [
47
+ ...
48
+ ]
49
+ }
50
+ afterSetCity(city) {
51
+ console.log(city);
52
+ <span style="color:#b91010;">if (!this.rendered) return;
53
+ this.getReference('city').value = city;</span>
54
+ }
55
+ afterSetCategory(category) {
56
+ console.log(category);
57
+ }
58
+ }
59
+
60
+ Neo.applyClassConfig(Filter);
61
+
62
+ export default Filter;
63
+ </pre>
64
+
65
+ ??Test the code
66
+
67
+ In the Chrome debugger update the city property. You should see the
68
+ text field update to reflect the change.
69
+
70
+ Neo.findFirst({ntype:'yelp-filter'}).city = 'Madison'
71
+
72
+ ??Add the same logic for category
73
+
74
+ Modify the `afterSetCategory()` method to work like the after city method.
75
+
76
+ Test it in the Chrome debugger. You should see the category text field updating.
77
+
78
+ Neo.findFirst({ntype:'yelp-filter'}).category = 'pizza'
79
+
80
+ ??Notice a timing issue
81
+
82
+ Currently, the initial city and category are just empty strings.
83
+ But if there had some other values we'd want the city and category
84
+ text fields to reflect those values as we start the app.
85
+
86
+ For example, change the city and category like this:
87
+
88
+ city_: 'Madison',
89
+ category_: 'pizza',
90
+
91
+ Upon refresh these values are _not_ seen in the fields, but you _will_
92
+ see the values in the Crome debugger
93
+
94
+ console.log(Neo.findFirst({ntype:'yelp-filter'}).city); // Logs "Madison"
95
+
96
+ The initial values _are_ assigned, and the `afterSet...` methods are run,
97
+ but since the view hasn't been rendered the `after` methods can't initialize
98
+ the fields.
99
+
100
+ ??Fix the issue
101
+
102
+ We need to detect when the view is rendered, then update
103
+ the text fields to their initial values.
104
+
105
+ Since `Neo.component.Base` has a `mounted` get/set,
106
+ there's a corresponding `afterSetMounted()` method. We'll add the code
107
+ there.
108
+
109
+ Use the following code. Note the 20ms delay. That's there because
110
+ after a view is mounted, the DOM may not update until one "frame"
111
+ later, which is about 18ms.
112
+
113
+ afterSetMounted() {
114
+ // Wait for one "frame" using a framerate of 60 per second = 17.7 ms
115
+ setTimeout(() => {
116
+ this.afterSetCity(this.city);
117
+ this.afterSetCategory(this.category);
118
+ }, 20);
119
+ }
120
+
121
+ Save and refresh. You should see the new default values as the initial
122
+ values for the city and category text fields.
123
+
124
+ ??Make sure `city` and `category` have their normal default values
125
+
126
+ Change city and category back to their normal default values.
127
+
128
+ city_: '',
129
+ category_: '',
130
+
131
+ In an upcoming lab we'll use another method of initializing the city and category.
@@ -0,0 +1,115 @@
1
+ #Introduction
2
+
3
+ In this lab you'll update the property as the text fields change.
4
+
5
+ #Steps
6
+
7
+ ??Update `city` as the user types.
8
+
9
+ We want changes in the text field to be reflected in the filter's `city` property.
10
+
11
+ To do that, listen to the field's `change` event, and in the handler get a
12
+ reference to the parent container, and assign the value to it's `city` property.
13
+
14
+ listeners: {
15
+ change: (data) => data.component.up('yelp-filter').city = data.value
16
+ }
17
+
18
+ Test this by entering text in the city field &mdash; you should see a the console
19
+ log being run on each keypress.
20
+
21
+ ??Do the same for `category`
22
+
23
+ Add a similer `listeners` config to the category field.
24
+
25
+ Test this by entering text in the category field &mdash; you should see a the console
26
+ log being run on each keypress.
27
+
28
+ ??Plan a way to buffer or _debounce_ the updates
29
+
30
+ Conceptually, `Yelp.view.business.Filter` has `city` and `category` properties.
31
+
32
+ "Madison" is a city, but "M" and "Ma" and "Mad" are not cities, so the
33
+ _city_ property shouldn't reflect those intermediate values. Therefore,
34
+ we need code to defer updating the property until the user appears to have
35
+ finished typing.
36
+
37
+ There are various ways to create a _buffer_ or _debouce_ fuctions, and
38
+ we found one via an internet search. We need a place to hold our implementation.
39
+
40
+ ??Add a utility class with a `debounce` function
41
+
42
+ Use a terminal to navigate to the Neo workspace, and run `npm run create-class`.
43
+
44
+ - Name the class "Yelp.util.Function"
45
+ - Extend `Neo.core.Base
46
+ - Make it a singleton
47
+
48
+ Edit the new file and add the debounce routine highlighted below.
49
+
50
+ <pre style="border: thin solid gray; padding: 8px; color: lightgray;font-size:14pt;">
51
+ import Base from '../../../node_modules/neo.mjs/src/core/Base.mjs';
52
+
53
+ class Function extends Base {
54
+ static config = {
55
+ className: 'Yelp.util.Function',
56
+ singleton: true
57
+ }
58
+ <span style="color:#b91010;">debounce(func, wait, immediate) {
59
+ let timeout
60
+ return function (...args) {
61
+ clearTimeout(timeout)
62
+ timeout = setTimeout(() => {
63
+ timeout = null
64
+ if (!immediate) func.apply(this, args)
65
+ }, wait)
66
+ if (immediate && !timeout) func.apply(this, [...args])
67
+ }
68
+ }</span>
69
+ }
70
+
71
+ Neo.applyClassConfig(Function);
72
+
73
+ let instance = Neo.create(Function);
74
+
75
+ Neo.applyToGlobalNs(instance);
76
+
77
+ export default instance;
78
+ </pre>
79
+
80
+ ??Buffer the updates
81
+
82
+ Edit `view/businesses/Filter.mjs` and add this import.
83
+
84
+ import Function from '../../util/Function.mjs';
85
+
86
+ And add a method designed to do a buffered update to a property.
87
+
88
+ doBufferedUpdate(property, value) {
89
+ this._bufferedUpdate = this._bufferedUpdate || Function.debounce((property, value) => this[property] = value, 500);
90
+ this._bufferedUpdate(property, value);
91
+ }
92
+
93
+ ??Use the new function when the city text field changes
94
+
95
+ Modify the city's `change` listener to use the new function.
96
+
97
+ listeners: {
98
+ change: (data) => data.component.up('yelp-filter').doBufferedUpdate('city', data.value)
99
+ }
100
+
101
+ Test the changes by running the app, and type a city name. After the 500ms delay
102
+ you should see the city name logged. Note that running
103
+
104
+ Neo.findFirst({ntype:'yelp-filter'}).city = 'Madison'
105
+
106
+ logs the city name immediately. Changing the city to a new value updates
107
+ immediately. We only need to buffer changes when the user is typing.
108
+
109
+ ??Have the category field do the same thing
110
+
111
+ Make a similar change to the category field config.
112
+
113
+ listeners: {
114
+ change: (data) => data.component.up('yelp-filter').doBufferedUpdate('category', data.value)
115
+ }
@@ -0,0 +1,12 @@
1
+ You simply assign or read values to access a property.
2
+
3
+ console.log(component.bar); // Results in the secret getter being run
4
+ component.bar = 'hi'; // Results in the secret setter being run
5
+
6
+ You can set multiple values simultaneously via `Neo.component.Bases#set({})`
7
+
8
+ component.set({
9
+ bar: 'hi',
10
+ baz: 'there'
11
+ });
12
+
@@ -0,0 +1,5 @@
1
+ The `headers:[{}]` // An array of component configs
2
+
3
+ Components in the headers array are tagged with a `dock` property
4
+ used to specify where the header is placed: top, right, bottom, or left.
5
+
@@ -0,0 +1,24 @@
1
+ A tab container is a card-layout container with a tab bar and styled buttons.
2
+ Do not specify a `layout` for tab containers.
3
+
4
+ The buttons are configured via `tabButtonConfig`
5
+
6
+ activeIndex: 2,
7
+ tabBarPosition: 'left', // top, right, bottom, left
8
+ itemDefaults: { module: Button },
9
+ items: [{
10
+ tabButtonConfig: {
11
+ iconCls: 'fa fa-home',
12
+ text: 'Tab 1'
13
+ }
14
+ }, {
15
+ tabButtonConfig: {
16
+ iconCls: 'fa fa-play-circle',
17
+ text: 'Tab 2'
18
+ }
19
+ }, {
20
+ tabButtonConfig: {
21
+ iconCls: 'fa fa-bell',
22
+ text: 'Tab 3'
23
+ }
24
+ }]
@@ -0,0 +1,21 @@
1
+
2
+
3
+ <div class="expander" caption="High-level Goal">
4
+ <h2>To learn how to properly encapsulate a class with a well defined API.</h2>
5
+ <p>
6
+ You'll code a class that's encapsulated and de-coupled, where the code creating
7
+ the instance uses class properties and otherwise has no awareness of its
8
+ implementation details.
9
+ </p>
10
+ </div>
11
+
12
+
13
+ <div class="expander" caption="Low-level Goal">
14
+ <h2>To get practice using the syntax and features we just learned.</h2>
15
+ <ul>
16
+ <li>Defining get/set properties
17
+ <li>Using `afterSet` methods to detect property change
18
+ <li>Using `reference` and `getReference()`
19
+ </ul>
20
+ </div>
21
+
@@ -0,0 +1,9 @@
1
+ - A view controller holds a view's event handlers
2
+ - The controller can hold any other logic you might need
3
+
4
+
5
+ The existence of a controller should be unknown outside of the class.
6
+ The decision of the view's author to use (or not use) a controller
7
+ should be transparent outside of the class.
8
+
9
+ this.lookup('someComponent').controller.someMethod(); // This is bad
@@ -0,0 +1,7 @@
1
+ Within controller methods you can get a reference to a view component
2
+ via
3
+
4
+ - `this.getReference('name')` returns a component with the specified reference
5
+ - In the view, you specify the reference via `reference: 'somename`
6
+
7
+ - `onComponentConstructed()` is a controller lifecycle method you can override if you need to do something at time of component creation
@@ -0,0 +1,26 @@
1
+ #Introduction
2
+
3
+ In this lab you'll put the view model into its own class.
4
+
5
+ #Steps
6
+
7
+
8
+ ??Create the view model
9
+
10
+ Use `npm run create-class` to create`Yelp.view.MainViewModel` that extends `model/Component`.
11
+
12
+ ??Use it
13
+
14
+ Move the `data` property from the main view to the view model.
15
+
16
+ Then import the view model, and change the `model` config to use the new class.
17
+
18
+ ??Create and use a controller
19
+
20
+ We don't need controller logic yet, but we will, so while we're at it, create a
21
+ `Yelp.view.MainViewController` that extends `controller/Component`. Import it in the
22
+ main view, and configure a controller block to use it.
23
+
24
+ controller: {
25
+ module: MainViewController
26
+ }
@@ -0,0 +1,75 @@
1
+ #Introduction
2
+
3
+ In this lab you'll detect changes to city and category.
4
+ When city changes you'll geocode it to find its latitude and longitude.
5
+
6
+ #Steps
7
+
8
+ ??Remove the view model listener in the main view
9
+
10
+ To avoid being overwhelmed with `console.log()` output, edit
11
+ the main view and remove the `listeners` config in the
12
+ view model config. From now on on the view model listening logic
13
+ will be set up in the main view controller.
14
+
15
+ ??Detect view model property changes
16
+
17
+ In the main view controller override the `onComponentConstructed()` method. The method
18
+ should check for changes to _city_ and if so, call a new method `onCityChange(city)`.
19
+
20
+ onComponentConstructed() {
21
+ const model = this.getModel();
22
+ this.onCityChange(model.data.city);
23
+ model.on('dataPropertyChange', data => {
24
+ if (data.key === 'city') this.onCityChange(data.value);
25
+ });
26
+ }
27
+ onCityChange(city) {
28
+ if (!city) return;
29
+ // The code to geocode the city goes here.
30
+ console.log(city);
31
+ }
32
+
33
+ Save, change the city, and look for the console log in the debugger console.
34
+
35
+ ??Geocode the city
36
+
37
+ Use the following call to `Neo.main.addon.GoogleMaps.geocode`. The details of the
38
+ call and the response aren't important right now, although if you're curious you
39
+ can read <a href="https://developers.google.com/maps/documentation/geocoding/requests-geocoding" target="_blank">the Google Maps geocoding API</a>.
40
+
41
+ <pre style='padding: 4px; font-size: 13.5pt; border: thin solid gray; color:lightgray'>
42
+ onCityChange(city) {
43
+ if (!city) return;
44
+ <span style='color:firebrick'>Neo.main.addon.GoogleMaps.geocode({ address: city })
45
+ .then(data => this.getModel().data.center = data.results[0].geometry.location);</span>
46
+ }
47
+ </pre>
48
+
49
+
50
+
51
+ ??Stub out a method that will eventually be fetching Yelp data
52
+
53
+ Add this method.
54
+
55
+ doFetchYelpData() {
56
+ const model = this.getModel();
57
+ console.log('Fetch yelp data', model.data.center, model.data.category);
58
+ }
59
+
60
+ And modify `onComponentConstructed()` to check for changes to _center_ and _category_.
61
+
62
+ <pre style='padding: 4px; border: thin solid gray; color:lightgray'>
63
+ onComponentConstructed() {
64
+ const model = this.getModel();
65
+ this.onCityChange(model.getData('city'));
66
+ model.on('dataPropertyChange', data => {
67
+ if (data.key === 'city') this.onCityChange(data.value);
68
+ <span style='color:firebrick'>if (data.key === 'center') this.doFetchYelpData();
69
+ if (data.key === 'category') this.doFetchYelpData();</span>
70
+ });
71
+ }
72
+ </pre>
73
+
74
+ Save, refresh, and verify that `doFetchYelpData()` is logging changes to the map center
75
+ (via changes to city), and category.
@@ -0,0 +1,33 @@
1
+ Some components, such as `Neo.table.Container`, have a `store` config.
2
+
3
+ <pre style="padding: 8px; border: thin solid lightgray; font-size: 11pt; ">
4
+ {
5
+ module: EarthquakesTable,
6
+ listeners: {
7
+ select: 'onTableSelect'
8
+ },
9
+ store: {
10
+ module: Store,
11
+ model: {
12
+ fields: [{
13
+ name: 'humanReadableLocation'
14
+ }, {
15
+ name: 'size',
16
+ ntype: 'data-field-float',
17
+ }, {
18
+ name: 'timestamp',
19
+ type: 'Date'
20
+ }, {
21
+ name: 'title',
22
+ calculate: (data, field, item) => item.humanReadableLocation
23
+ }, {
24
+ name: 'position',
25
+ calculate: (data, field, item) => ({ lat: item.latitude, lng: item.longitude })
26
+ }]
27
+ },
28
+ url: 'https://apis.is/earthquake/is',
29
+ responseRoot: 'results',
30
+ autoLoad: true
31
+ }
32
+ }
33
+ </pre>
@@ -0,0 +1,28 @@
1
+
2
+ <pre style="padding: 8px; border: thin solid lightgray; font-size: 13pt; ">
3
+ class MainViewModel extends Base {
4
+ static getConfig() {
5
+ return {
6
+ className: 'Earthquakes.view.MainViewModel',
7
+ data: {},
8
+ stores: {
9
+ earthquakes: {
10
+ module: Store,
11
+ model: {
12
+ ...
13
+ },
14
+ ...
15
+ }
16
+ }
17
+ }
18
+ }
19
+ }</pre>
20
+
21
+ <pre style="padding: 8px; border: thin solid lightgray; font-size: 13pt; ">
22
+ {
23
+ module: EarthquakesTable,
24
+ bind: {
25
+ store: 'stores.earthquakes'
26
+ },
27
+ }
28
+ </pre>
@@ -0,0 +1,3 @@
1
+ You may also define the store as a class. You might do this if you need to create multiple instances.
2
+ Once you've defined the type you can use it the same way you'd create any store &mdash; in a config or a view model
3
+
@@ -0,0 +1,6 @@
1
+ Finally, you can procedurally create a store via Neo.create(). But it's always preferable to create a store — or any object — declaratively.
2
+
3
+ const store = Neo.create({
4
+ module : Store,
5
+ });
6
+ this.getReference('mytable').store = store;
@@ -0,0 +1,13 @@
1
+ If the record's value isn't a simple conversion from the value in the feed
2
+ you can provide a `calculate` method. For example:
3
+
4
+ {
5
+ name: 'position',
6
+ calculate: (record, field, data) => ({ lat: data.latitude, lng: data.longitude })
7
+ }
8
+
9
+ - _record_ is the record instance
10
+ - _field_ is the field config
11
+ - _data_ is the value from the data feed
12
+
13
+ You can use `calculate` to convert a value from the feed, or to define a new record value.
@@ -0,0 +1,15 @@
1
+ A recod config contains a `fields:[]` that describes the record's fields.
2
+
3
+ The field config can have these values:
4
+
5
+ | Config Property | Description |
6
+ |-----------------|--------------------------------------------------------------------|
7
+ |`name` | Required. The name of the feed value. |
8
+ |`type` | Date/html/string |
9
+ |`mapping` | The path to feed property. |
10
+ |&nbsp; | |
11
+ |`calculate` | A function used to calculate the value of the field. |
12
+ |&nbsp; | |
13
+ |`maxLength` | Limits values to the specific length. |
14
+ |`minLength` | Limits values to the specific length. |
15
+ |`nullable` | Flags whether the value can be null/undefined. |