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.
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/learnneo/neo-config.json +5 -1
- package/apps/learnneo/store/Content.mjs +1 -1
- package/apps/learnneo/view/Viewport.mjs +12 -1
- package/apps/learnneo/view/home/ContentTreeList.mjs +53 -34
- package/apps/learnneo/view/home/ContentView.mjs +60 -0
- package/apps/learnneo/view/home/MainContainer.mjs +36 -9
- package/apps/learnneo/view/home/MainContainerController.mjs +57 -18
- package/apps/newwebsite/app.mjs +6 -0
- package/apps/newwebsite/index.html +10 -0
- package/apps/newwebsite/neo-config.json +7 -0
- package/apps/newwebsite/view/MainContainer.mjs +59 -0
- package/buildScripts/webpack/json/myApps.template.json +1 -0
- package/examples/ConfigurationViewport.mjs +12 -9
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/button/base/neo-config.json +1 -2
- package/examples/form/field/textarea/MainContainer.mjs +1 -1
- package/package.json +2 -2
- package/resources/data/{learnneo → deck/learnneo}/p/2023-10-01T18-29-19-158Z.md +3 -6
- package/resources/data/deck/learnneo/p/stylesheet.md +40 -0
- package/resources/data/{learnneo → deck/learnneo}/t.json +19 -2
- package/resources/data/deck/training/p/2022-12-27T21-54-52-300Z.md +11 -0
- package/resources/data/deck/training/p/2022-12-27T21-55-23-144Z.md +43 -0
- package/resources/data/deck/training/p/2022-12-27T21-55-30-948Z.md +1 -0
- package/resources/data/deck/training/p/2022-12-27T21-55-43-542Z.md +84 -0
- package/resources/data/deck/training/p/2022-12-27T22-23-55-083Z.md +1 -0
- package/resources/data/deck/training/p/2022-12-27T22-24-07-886Z.md +8 -0
- package/resources/data/deck/training/p/2022-12-27T22-24-52-295Z.md +8 -0
- package/resources/data/deck/training/p/2022-12-27T22-25-03-853Z.md +5 -0
- package/resources/data/deck/training/p/2022-12-27T22-43-58-924Z.md +10 -0
- package/resources/data/deck/training/p/2022-12-27T22-44-28-881Z.md +3 -0
- package/resources/data/deck/training/p/2022-12-27T22-44-41-791Z.md +4 -0
- package/resources/data/deck/training/p/2022-12-27T22-45-21-032Z.md +7 -0
- package/resources/data/deck/training/p/2022-12-27T22-49-22-078Z.md +4 -0
- package/resources/data/deck/training/p/2022-12-27T22-50-20-626Z.md +4 -0
- package/resources/data/deck/training/p/2022-12-28T16-58-47-786Z.md +0 -0
- package/resources/data/deck/training/p/2022-12-28T16-58-55-192Z.md +9 -0
- package/resources/data/deck/training/p/2022-12-28T17-10-18-058Z.md +15 -0
- package/resources/data/deck/training/p/2022-12-28T17-10-42-296Z.md +40 -0
- package/resources/data/deck/training/p/2022-12-28T17-11-34-653Z.md +41 -0
- package/resources/data/deck/training/p/2022-12-28T17-13-09-994Z.md +0 -0
- package/resources/data/deck/training/p/2022-12-28T21-32-14-420Z.md +0 -0
- package/resources/data/deck/training/p/2022-12-29T01-43-32-431Z.md +7 -0
- package/resources/data/deck/training/p/2022-12-29T15-56-54-485Z.md +7 -0
- package/resources/data/deck/training/p/2022-12-29T15-57-11-499Z.md +7 -0
- package/resources/data/deck/training/p/2022-12-29T16-00-13-223Z.md +7 -0
- package/resources/data/deck/training/p/2022-12-29T18-34-25-826Z.md +4 -0
- package/resources/data/deck/training/p/2022-12-29T18-36-08-226Z.md +106 -0
- package/resources/data/deck/training/p/2022-12-29T18-36-56-893Z.md +112 -0
- package/resources/data/deck/training/p/2022-12-29T19-31-30-507Z.md +31 -0
- package/resources/data/deck/training/p/2022-12-29T19-31-55-091Z.md +14 -0
- package/resources/data/deck/training/p/2022-12-29T20-03-42-628Z.md +9 -0
- package/resources/data/deck/training/p/2022-12-29T20-21-20-669Z.md +7 -0
- package/resources/data/deck/training/p/2022-12-29T20-37-08-919Z.md +46 -0
- package/resources/data/deck/training/p/2022-12-29T20-37-20-344Z.md +43 -0
- package/resources/data/deck/training/p/2022-12-30T19-04-30-990Z.md +8 -0
- package/resources/data/deck/training/p/2022-12-31T18-43-56-338Z.md +7 -0
- package/resources/data/deck/training/p/2022-12-31T18-51-50-682Z.md +1 -0
- package/resources/data/deck/training/p/2022-12-31T18-54-04-176Z.md +4 -0
- package/resources/data/deck/training/p/2022-12-31T22-11-55-555Z.md +112 -0
- package/resources/data/deck/training/p/2022-12-31T23-00-41-222Z.md +6 -0
- package/resources/data/deck/training/p/2022-12-31T23-18-55-655Z.md +69 -0
- package/resources/data/deck/training/p/2022-12-31T23-25-40-735Z.md +21 -0
- package/resources/data/deck/training/p/2022-12-31T23-25-51-014Z.md +7 -0
- package/resources/data/deck/training/p/2023-01-01T17-49-18-429Z.md +3 -0
- package/resources/data/deck/training/p/2023-01-01T18-44-07-034Z.md +34 -0
- package/resources/data/deck/training/p/2023-01-01T18-47-39-766Z.md +15 -0
- package/resources/data/deck/training/p/2023-01-01T19-04-22-830Z.md +4 -0
- package/resources/data/deck/training/p/2023-01-01T21-11-58-025Z.md +25 -0
- package/resources/data/deck/training/p/2023-01-01T21-12-37-340Z.md +23 -0
- package/resources/data/deck/training/p/2023-01-01T21-13-13-880Z.md +8 -0
- package/resources/data/deck/training/p/2023-01-01T21-14-45-740Z.md +98 -0
- package/resources/data/deck/training/p/2023-01-01T21-18-23-886Z.md +26 -0
- package/resources/data/deck/training/p/2023-01-01T21-18-31-316Z.md +19 -0
- package/resources/data/deck/training/p/2023-01-01T21-18-42-290Z.md +23 -0
- package/resources/data/deck/training/p/2023-01-01T21-19-57-020Z.md +24 -0
- package/resources/data/deck/training/p/2023-01-01T21-22-31-184Z.md +13 -0
- package/resources/data/deck/training/p/2023-01-01T21-22-38-317Z.md +17 -0
- package/resources/data/deck/training/p/2023-01-01T21-22-47-693Z.md +20 -0
- package/resources/data/deck/training/p/2023-01-01T21-23-17-716Z.md +39 -0
- package/resources/data/deck/training/p/2023-01-01T21-23-28-532Z.md +22 -0
- package/resources/data/deck/training/p/2023-01-01T21-25-23-899Z.md +3 -0
- package/resources/data/deck/training/p/2023-01-01T21-25-59-742Z.md +1 -0
- package/resources/data/deck/training/p/2023-01-01T21-26-53-748Z.md +12 -0
- package/resources/data/deck/training/p/2023-01-01T23-38-42-863Z.md +2 -0
- package/resources/data/deck/training/p/2023-01-03T02-07-19-014Z.md +143 -0
- package/resources/data/deck/training/p/2023-01-04T01-52-23-454Z.md +76 -0
- package/resources/data/deck/training/p/2023-01-06T23-21-12-009Z.md +127 -0
- package/resources/data/deck/training/p/2023-01-06T23-21-31-685Z.md +81 -0
- package/resources/data/deck/training/p/2023-01-06T23-21-59-596Z.md +36 -0
- package/resources/data/deck/training/p/2023-01-06T23-34-13-897Z.md +87 -0
- package/resources/data/deck/training/p/2023-01-06T23-44-02-340Z.md +0 -0
- package/resources/data/deck/training/p/2023-01-06T23-46-36-687Z.md +1 -0
- package/resources/data/deck/training/p/2023-01-06T23-46-45-783Z.md +33 -0
- package/resources/data/deck/training/p/2023-01-08T00-45-11-144Z.md +50 -0
- package/resources/data/deck/training/p/2023-01-08T01-06-31-267Z.md +41 -0
- package/resources/data/deck/training/p/2023-01-08T01-24-21-088Z.md +95 -0
- package/resources/data/deck/training/p/2023-01-08T01-25-12-557Z.md +11 -0
- package/resources/data/deck/training/p/2023-01-08T01-46-50-723Z.md +25 -0
- package/resources/data/deck/training/p/2023-01-08T02-09-07-802Z.md +18 -0
- package/resources/data/deck/training/p/2023-01-08T02-09-19-678Z.md +66 -0
- package/resources/data/deck/training/p/2023-01-08T02-11-26-333Z.md +29 -0
- package/resources/data/deck/training/p/2023-01-08T17-22-48-841Z.md +14 -0
- package/resources/data/deck/training/p/2023-01-08T20-46-11-806Z.md +5 -0
- package/resources/data/deck/training/p/2023-01-08T20-47-23-682Z.md +5 -0
- package/resources/data/deck/training/p/2023-01-08T20-47-32-064Z.md +13 -0
- package/resources/data/deck/training/p/2023-01-08T20-47-57-045Z.md +0 -0
- package/resources/data/deck/training/p/2023-01-08T20-48-03-791Z.md +18 -0
- package/resources/data/deck/training/p/2023-01-08T20-48-32-466Z.md +9 -0
- package/resources/data/deck/training/p/2023-01-08T20-48-51-322Z.md +20 -0
- package/resources/data/deck/training/p/2023-01-08T20-49-52-741Z.md +0 -0
- package/resources/data/deck/training/p/2023-01-08T20-52-03-556Z.md +0 -0
- package/resources/data/deck/training/p/2023-01-08T20-57-36-333Z.md +2 -0
- package/resources/data/deck/training/p/2023-01-08T20-57-51-136Z.md +5 -0
- package/resources/data/deck/training/p/2023-01-09T00-07-37-951Z.md +0 -0
- package/resources/data/deck/training/p/2023-01-09T00-35-40-671Z.md +3 -0
- package/resources/data/deck/training/p/2023-01-10T01-29-38-148Z.md +10 -0
- package/resources/data/deck/training/p/2023-01-10T01-43-12-166Z.md +31 -0
- package/resources/data/deck/training/p/2023-01-10T02-21-54-303Z.md +10 -0
- package/resources/data/deck/training/p/2023-01-12T01-50-54-617Z.md +74 -0
- package/resources/data/deck/training/p/2023-01-13T19-55-24-735Z.md +14 -0
- package/resources/data/deck/training/p/2023-01-13T20-08-27-068Z.md +28 -0
- package/resources/data/deck/training/p/2023-01-13T20-23-38-411Z.md +25 -0
- package/resources/data/deck/training/p/2023-01-13T20-37-06-267Z.md +13 -0
- package/resources/data/deck/training/p/2023-01-13T21-05-57-708Z.md +8 -0
- package/resources/data/deck/training/p/2023-01-13T21-48-17-258Z.md +20 -0
- package/resources/data/deck/training/p/2023-01-13T22-05-05-799Z.md +14 -0
- package/resources/data/deck/training/p/2023-01-13T22-08-30-863Z.md +17 -0
- package/resources/data/deck/training/p/2023-01-13T23-01-50-449Z.md +4 -0
- package/resources/data/deck/training/p/2023-01-14T00-33-05-958Z.md +62 -0
- package/resources/data/deck/training/p/2023-01-14T00-40-27-784Z.md +229 -0
- package/resources/data/deck/training/p/2023-01-14T00-41-59-081Z.md +153 -0
- package/resources/data/deck/training/p/2023-01-14T13-50-28-199Z.md +19 -0
- package/resources/data/deck/training/p/2023-01-14T13-59-20-275Z.md +6 -0
- package/resources/data/deck/training/p/2023-01-14T14-03-29-456Z.md +3 -0
- package/resources/data/deck/training/p/2023-01-14T14-27-57-678Z.md +7 -0
- package/resources/data/deck/training/p/2023-01-14T17-30-18-228Z.md +33 -0
- package/resources/data/deck/training/p/2023-01-14T18-28-39-316Z.md +1 -0
- package/resources/data/deck/training/p/2023-01-14T18-28-44-115Z.md +4 -0
- package/resources/data/deck/training/p/2023-01-14T18-28-49-548Z.md +18 -0
- package/resources/data/deck/training/p/2023-01-14T18-40-13-758Z.md +10 -0
- package/resources/data/deck/training/p/2023-01-14T19-29-15-291Z.md +12 -0
- package/resources/data/deck/training/p/2023-01-15T18-51-52-134Z.md +83 -0
- package/resources/data/deck/training/p/2023-01-15T20-03-30-073Z.md +11 -0
- package/resources/data/deck/training/p/2023-01-15T22-07-52-073Z.md +16 -0
- package/resources/data/deck/training/p/2023-01-15T22-22-13-517Z.md +12 -0
- package/resources/data/deck/training/p/2023-01-15T22-28-57-508Z.md +131 -0
- package/resources/data/deck/training/p/2023-01-15T22-36-30-913Z.md +115 -0
- package/resources/data/deck/training/p/2023-01-16T16-03-40-770Z.md +12 -0
- package/resources/data/deck/training/p/2023-01-16T20-21-56-859Z.md +5 -0
- package/resources/data/deck/training/p/2023-01-16T20-24-09-690Z.md +24 -0
- package/resources/data/deck/training/p/2023-01-20T12-51-22-646Z.md +21 -0
- package/resources/data/deck/training/p/2023-01-20T13-06-46-614Z.md +9 -0
- package/resources/data/deck/training/p/2023-01-20T13-08-51-600Z.md +7 -0
- package/resources/data/deck/training/p/2023-01-20T15-20-13-363Z.md +26 -0
- package/resources/data/deck/training/p/2023-01-20T15-34-58-813Z.md +75 -0
- package/resources/data/deck/training/p/2023-01-21T16-33-20-458Z.md +33 -0
- package/resources/data/deck/training/p/2023-01-21T16-45-28-263Z.md +28 -0
- package/resources/data/deck/training/p/2023-01-21T16-56-25-452Z.md +3 -0
- package/resources/data/deck/training/p/2023-01-21T17-28-31-493Z.md +6 -0
- package/resources/data/deck/training/p/2023-01-21T19-49-51-918Z.md +13 -0
- package/resources/data/deck/training/p/2023-01-21T20-08-24-452Z.md +15 -0
- package/resources/data/deck/training/p/2023-01-21T20-35-54-947Z.md +20 -0
- package/resources/data/deck/training/p/2023-01-21T20-54-47-603Z.md +39 -0
- package/resources/data/deck/training/p/2023-01-21T20-56-28-184Z.md +25 -0
- package/resources/data/deck/training/p/2023-01-21T20-57-32-927Z.md +4 -0
- package/resources/data/deck/training/p/2023-01-21T23-13-33-394Z.md +6 -0
- package/resources/data/deck/training/p/2023-01-28T19-11-37-464Z.md +24 -0
- package/resources/data/deck/training/p/2023-01-28T20-43-41-188Z.md +9 -0
- package/resources/data/deck/training/p/2023-01-28T20-53-56-476Z.md +8 -0
- package/resources/data/deck/training/p/2023-01-28T20-58-43-776Z.md +10 -0
- package/resources/data/deck/training/p/2023-01-28T22-18-41-259Z.md +33 -0
- package/resources/data/deck/training/p/2023-01-28T22-24-34-808Z.md +24 -0
- package/resources/data/deck/training/p/2023-01-29T16-25-24-528Z.md +44 -0
- package/resources/data/deck/training/p/2023-01-29T21-14-32-588Z.md +12 -0
- package/resources/data/deck/training/p/2023-01-31T19-24-53-504Z.md +8 -0
- package/resources/data/deck/training/p/2023-01-31T20-33-55-855Z.md +11 -0
- package/resources/data/deck/training/p/2023-01-31T20-34-30-261Z.md +7 -0
- package/resources/data/deck/training/p/2023-01-31T20-52-53-367Z.md +43 -0
- package/resources/data/deck/training/p/2023-02-04T15-18-35-682Z.md +20 -0
- package/resources/data/deck/training/p/2023-02-04T15-49-47-597Z.md +14 -0
- package/resources/data/deck/training/p/2023-02-04T18-58-57-808Z.md +1 -0
- package/resources/data/deck/training/p/2023-02-04T20-07-11-288Z.md +1 -0
- package/resources/data/deck/training/p/2023-02-04T20-09-50-169Z.md +1 -0
- package/resources/data/deck/training/p/2023-02-04T20-19-42-740Z.md +8 -0
- package/resources/data/deck/training/p/2023-02-04T20-23-56-013Z.md +12 -0
- package/resources/data/deck/training/p/2023-02-04T20-28-12-391Z.md +20 -0
- package/resources/data/deck/training/p/2023-02-05T00-20-32-554Z.md +16 -0
- package/resources/data/deck/training/p/2023-02-05T00-35-56-282Z.md +13 -0
- package/resources/data/deck/training/p/2023-02-05T15-36-57-182Z.md +24 -0
- package/resources/data/deck/training/p/2023-02-05T17-39-51-712Z.md +70 -0
- package/resources/data/deck/training/p/2023-02-05T17-44-53-815Z.md +195 -0
- package/resources/data/deck/training/p/2023-02-05T17-45-40-114Z.md +92 -0
- package/resources/data/deck/training/p/2023-02-05T18-12-14-489Z.md +60 -0
- package/resources/data/deck/training/p/2023-02-06T00-14-54-457Z.md +9 -0
- package/resources/data/deck/training/p/2023-06-28T18-03-14-313Z.md +8 -0
- package/resources/data/deck/training/p/2023-06-28T18-26-17-290Z.md +7 -0
- package/resources/data/deck/training/p/2023-06-28T21-16-24-034Z.md +40 -0
- package/resources/data/deck/training/p/2023-06-28T21-16-34-972Z.md +16 -0
- package/resources/data/deck/training/p/2023-06-28T21-28-28-379Z.md +4 -0
- package/resources/data/deck/training/p/2023-06-29T23-15-10-411Z.md +5 -0
- package/resources/data/deck/training/p/2023-07-01T15-42-45-193Z.md +433 -0
- package/resources/data/deck/training/p/2023-07-01T21-54-31-329Z.md +6 -0
- package/resources/data/deck/training/p/2023-07-02T16-14-06-970Z.md +14 -0
- package/resources/data/deck/training/p/2023-07-31T00-26-03-842Z.md +4 -0
- package/resources/data/deck/training/p/2023-07-31T00-31-51-933Z.md +10 -0
- package/resources/data/deck/training/p/2023-07-31T00-37-21-927Z.md +205 -0
- package/resources/data/deck/training/p/2023-10-01T18-29-19-158Z.md +76 -0
- package/resources/data/deck/training/p/2023-10-07T19-18-28-517Z.md +102 -0
- package/resources/data/deck/training/p/2023-10-08T20-20-07-934Z.md +75 -0
- package/resources/data/deck/training/p/2023-10-08T20-20-37-336Z.md +29 -0
- package/resources/data/deck/training/p/2023-10-08T20-37-30-658Z.md +0 -0
- package/resources/data/deck/training/p/2023-10-08T21-58-25-809Z.md +68 -0
- package/resources/data/deck/training/p/2023-10-08T22-22-11-013Z.md +0 -0
- package/resources/data/deck/training/p/2023-10-14T19-25-08-153Z.md +119 -0
- package/resources/data/deck/training/t.json +1 -0
- package/resources/scss/src/apps/learnneo/Viewport.scss +0 -106
- package/resources/scss/src/apps/learnneo/home/ContentTreeList.scss +37 -0
- package/resources/scss/src/apps/learnneo/home/ContentView.scss +55 -0
- package/resources/scss/src/form/field/FileUpload.scss +4 -4
- package/resources/scss/src/form/field/TextArea.scss +1 -1
- package/resources/scss/theme-neo-light/Global.scss +46 -0
- package/resources/scss/theme-neo-light/design-tokens/Core.scss +7 -0
- package/resources/scss/theme-neo-light/design-tokens/Semantic.scss +0 -0
- package/resources/scss/theme-neo-light/design-tokens/_all.scss +4 -0
- package/src/DefaultConfig.mjs +4 -4
- package/src/form/field/FileUpload.mjs +9 -2
- package/src/form/field/TextArea.mjs +19 -34
- package/src/main/DomAccess.mjs +34 -0
- package/test/components/files/form/field/Select.mjs +1 -1
- /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-07T19-18-28-517Z.md +0 -0
- /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-20-07-934Z.md +0 -0
- /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-20-37-336Z.md +0 -0
- /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T20-37-30-658Z.md +0 -0
- /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T21-58-25-809Z.md +0 -0
- /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-08T22-22-11-013Z.md +0 -0
- /package/resources/data/{learnneo → deck/learnneo}/p/2023-10-14T19-25-08-153Z.md +0 -0
- /package/resources/data/{learnneo → deck/learnneo}/pages/whyneo.md +0 -0
- /package/resources/data/{learnneo → deck/learnneo}/tree.json +0 -0
- /package/resources/{deck → data/deck}/whyneo.md +0 -0
- /package/resources/scss/src/apps/newwebsite/{MainContainer.css → MainContainer.scss} +0 -0
- /package/resources/scss/theme-neo-light/design-tokens/{Components.scss → Component.scss} +0 -0
@@ -0,0 +1,23 @@
|
|
1
|
+
Items are arranged according to a `layout`.
|
2
|
+
|
3
|
+
- `layout:'fit'`
|
4
|
+
- `layout: 'card'`
|
5
|
+
- `layout: 'vbox'`
|
6
|
+
- `layout: 'hbox'`
|
7
|
+
- `layout: 'flexbox'`
|
8
|
+
|
9
|
+
When you need to provide more config details, use this form:
|
10
|
+
|
11
|
+
layout: {
|
12
|
+
ntype:'vbox',
|
13
|
+
align: 'stretch'
|
14
|
+
}
|
15
|
+
|
16
|
+
|
17
|
+
The container base class imports all layouts, which means you
|
18
|
+
can use `ntype` (and don't need to explicitly import the layout class).
|
19
|
+
|
20
|
+
<span style="color: #bbbbbb;">And actually, in the case of layouts, you
|
21
|
+
<i style="color: #bbbbbb;">must</i> use ntype. You do not specify layouts
|
22
|
+
using the <tt>module</tt> config.
|
23
|
+
</span>
|
@@ -0,0 +1,24 @@
|
|
1
|
+
You can procedurally add or remove items.
|
2
|
+
|
3
|
+
- `insert(index, item, [silent])`
|
4
|
+
- `remove(component, [destroyItem], [silent])`
|
5
|
+
- `removeAt(index, [destroyItem], [silent])`
|
6
|
+
|
7
|
+
|
8
|
+
|
9
|
+
<pre class="runnable readonly text 100">
|
10
|
+
this.add({
|
11
|
+
module: Button,
|
12
|
+
text: 'New Button'
|
13
|
+
});
|
14
|
+
</pre>
|
15
|
+
|
16
|
+
<pre class="runnable readonly text 160">
|
17
|
+
this.add([{
|
18
|
+
module: Button,
|
19
|
+
text: 'One'
|
20
|
+
}, {
|
21
|
+
module: Button,
|
22
|
+
text: 'Two'
|
23
|
+
}]);
|
24
|
+
</pre>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Components and other classes fire _events_. Those events run a callback
|
2
|
+
function called the event _listener_ or _handler_.
|
3
|
+
|
4
|
+
For example, buttons fire _click_ events, tables
|
5
|
+
fire _select_ events, and stores fire _load_ events.
|
6
|
+
|
7
|
+
The usual way to configure to an event is with the `listeners` config.
|
8
|
+
|
9
|
+
listeners: {
|
10
|
+
select: 'onTableSelect'
|
11
|
+
},
|
12
|
+
|
13
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
The _listeners_ object is a name value pair, where the name is the
|
2
|
+
name of the event, and the value is either a function or the string
|
3
|
+
name of the function in the view's controller (or controllers up the
|
4
|
+
containment hierarchy).
|
5
|
+
|
6
|
+
listeners: {
|
7
|
+
change: data=>console.log(data),
|
8
|
+
focusChange: data=>console.log(data)
|
9
|
+
},
|
10
|
+
|
11
|
+
|
12
|
+
listeners: {
|
13
|
+
change: 'onChange',
|
14
|
+
focusChange: 'onFocusChange'
|
15
|
+
},
|
16
|
+
|
17
|
+
|
@@ -0,0 +1,20 @@
|
|
1
|
+
You can also add listeners procedurally.
|
2
|
+
|
3
|
+
<pre style="font-size: 14pt">
|
4
|
+
this.getReference('mycomp').addListener(string, function);
|
5
|
+
</pre>
|
6
|
+
|
7
|
+
The string is the name of the event, the function is the callback function.
|
8
|
+
|
9
|
+
The callback function could be an in-line function, or a reference to a function.
|
10
|
+
|
11
|
+
|
12
|
+
<pre style="font-size: 14pt">
|
13
|
+
this.getReference('mycomp').addListener('change', data=>console.log(data));
|
14
|
+
</pre>
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
<pre style="font-size: 14pt">
|
19
|
+
this.getReference('mycomp').addListener('change', this.onChange.bind(this));
|
20
|
+
</pre>
|
@@ -0,0 +1,39 @@
|
|
1
|
+
Internally, listeners are set up as a map, with event names as the key, and and array of
|
2
|
+
function references as the value.
|
3
|
+
|
4
|
+
<img src="resources/images/EventsInMemory.png"/>
|
5
|
+
|
6
|
+
<!--
|
7
|
+
<table>
|
8
|
+
<tr><th>component.listeners</th><th></th><th>Config</th></tr>
|
9
|
+
<tr>
|
10
|
+
<td width="45%"><pre style="font-size:12pt">
|
11
|
+
{
|
12
|
+
change: [ , ]
|
13
|
+
foo: [ ]
|
14
|
+
}
|
15
|
+
|
16
|
+
</pre></td>
|
17
|
+
<td width="5%"></td>
|
18
|
+
<td width="45%"><pre style="font-size:12pt">
|
19
|
+
// Adds the "change" entry and adds 1st array element
|
20
|
+
listeners: {
|
21
|
+
change: data=>console.log(data)
|
22
|
+
}
|
23
|
+
|
24
|
+
// Uses existing "change" entry and adds 2nd array element
|
25
|
+
listeners: {
|
26
|
+
change: data=>console.log(data)
|
27
|
+
}
|
28
|
+
|
29
|
+
// Adds the "foo" entry and adds 1st array element
|
30
|
+
listeners: {
|
31
|
+
foo: data=>console.log(data)
|
32
|
+
}
|
33
|
+
</pre>
|
34
|
+
</td>
|
35
|
+
<td><pre style="font-size:12pt">
|
36
|
+
</pre></td>
|
37
|
+
</tr>
|
38
|
+
</table>
|
39
|
+
-->
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Many Neo classes are observable, and thus, have the `fire()` method.<small><sup>*</sup></small>
|
2
|
+
|
3
|
+
From a view method:
|
4
|
+
|
5
|
+
<pre style="font-size: 14pt;margin:0 0 3em 0;">
|
6
|
+
this.fire('foo', {component:this, prop: 'whatever you want'})
|
7
|
+
</pre>
|
8
|
+
|
9
|
+
From a controller method:
|
10
|
+
|
11
|
+
<pre style="font-size: 14pt;margin:0 0 3em 0;">
|
12
|
+
this.component.fire('foo', {component:this, prop: 'whatever you want'})
|
13
|
+
</pre>
|
14
|
+
|
15
|
+
There's nothing stopping you from firing an event on anything (although
|
16
|
+
there's probably never a reason to do that).
|
17
|
+
|
18
|
+
<pre style="font-size: 14pt;margin:0 0 3em 0;">
|
19
|
+
this.getComponent('myReference').fire('foo', {message: 'yo'});
|
20
|
+
</pre>
|
21
|
+
|
22
|
+
<small>* Document your events so people know how to use your Neo classes!</small>
|
@@ -0,0 +1 @@
|
|
1
|
+
`Ext.component.Base` has a few properties relating to content:
|
@@ -0,0 +1,12 @@
|
|
1
|
+
Earlier, we made a big deal about how Neo components were _declarative_ — where
|
2
|
+
the code is an abstraction that _describes_ what's being created.
|
3
|
+
|
4
|
+
But the code has some procedural code.
|
5
|
+
|
6
|
+
There's _was_ some procedural in the store's fields[], but we moved that into
|
7
|
+
a separate view model class.
|
8
|
+
|
9
|
+
But the event handlers are in the main container. In a normal app you'd have
|
10
|
+
a lot of event listeners with a lot of business logic in them. Except for the
|
11
|
+
most trivial use cases, you don't want that logic in your views.
|
12
|
+
|
@@ -0,0 +1,143 @@
|
|
1
|
+
#Introduction
|
2
|
+
|
3
|
+
In this lab, you'll use a component model to hold the store config.
|
4
|
+
|
5
|
+
#Steps
|
6
|
+
|
7
|
+
??Look at network traffic
|
8
|
+
|
9
|
+
Before doing anything, refresh the app and look at network traffic. Note the two
|
10
|
+
calls to the earthquakes data feed.
|
11
|
+
|
12
|
+
In this lab you'll refactor the code to put the store in a component model,
|
13
|
+
and as a result you'll only only see one call.
|
14
|
+
|
15
|
+
??Modify the `model` block
|
16
|
+
|
17
|
+
At the start of the main container's config add a new block that
|
18
|
+
configures the component model.
|
19
|
+
|
20
|
+
<pre style="color:lightgray;">
|
21
|
+
const config = {
|
22
|
+
className: 'Earthquakes.view.MainView',
|
23
|
+
|
24
|
+
model: {
|
25
|
+
module: ViewModel,
|
26
|
+
<span style="color:blue;">stores: {}</span>
|
27
|
+
},
|
28
|
+
items: [{
|
29
|
+
module: EarthquakesTable,
|
30
|
+
...
|
31
|
+
</pre>
|
32
|
+
|
33
|
+
Then copy the store config to the component model's `stores` block.
|
34
|
+
|
35
|
+
<pre style="color:lightgray;">
|
36
|
+
config = {
|
37
|
+
className: 'Earthquakes.view.MainView',
|
38
|
+
model: {
|
39
|
+
module: ViewModel,
|
40
|
+
<span style="color:blue;">stores: {
|
41
|
+
earthquakes: {
|
42
|
+
module: Store,
|
43
|
+
model: {
|
44
|
+
fields: [{
|
45
|
+
name: 'humanReadableLocation'
|
46
|
+
}, {
|
47
|
+
name: 'size',
|
48
|
+
ntype: 'data-field-float',
|
49
|
+
}, {
|
50
|
+
name: 'timestamp',
|
51
|
+
type: 'Date'
|
52
|
+
}, {
|
53
|
+
name: 'title',
|
54
|
+
calculate: (data, field, item) => item.humanReadableLocation
|
55
|
+
}, {
|
56
|
+
name: 'position',
|
57
|
+
calculate: (data, field, item) => ({ lat: item.latitude, lng: item.longitude })
|
58
|
+
}]
|
59
|
+
},
|
60
|
+
url: 'https://apis.is/earthquake/is',
|
61
|
+
responseRoot: 'results',
|
62
|
+
autoLoad: true
|
63
|
+
}
|
64
|
+
},
|
65
|
+
}</span>,
|
66
|
+
items: [{
|
67
|
+
module: EarthquakesTable,
|
68
|
+
...
|
69
|
+
</pre>
|
70
|
+
|
71
|
+
Save your changes.
|
72
|
+
|
73
|
+
At this point you have the same store config _two_ times:
|
74
|
+
- In the component model's `stores` config
|
75
|
+
- In the grid's `store` config
|
76
|
+
|
77
|
+
If you refresh the browser and look at network traffic you'll see
|
78
|
+
_two_ calls to the `apis.is` web service.
|
79
|
+
|
80
|
+
??Add the binding to the table
|
81
|
+
|
82
|
+
In the main container, remove the `store` config from the table.
|
83
|
+
Then a new config for the table:
|
84
|
+
|
85
|
+
bind: {
|
86
|
+
store: 'stores.earthquakes'
|
87
|
+
}
|
88
|
+
|
89
|
+
Refresh and verify that it's working. If you look at network traffic you should
|
90
|
+
see a single call to the `apis.is` web service.
|
91
|
+
|
92
|
+
??Refactor the model into its own class
|
93
|
+
|
94
|
+
**If you used the _create-app-training_ build script, you already have a view model
|
95
|
+
and can skip this step.**
|
96
|
+
|
97
|
+
IF you don't, define a new source file `MainViewModel.mjs` with this code.
|
98
|
+
|
99
|
+
<pre class="runnable text readonly">
|
100
|
+
import Base from '../../../node_modules/neo.mjs/src/model/Component.mjs';
|
101
|
+
import Store from '../../../node_modules/neo.mjs/src/data/Store.mjs';
|
102
|
+
|
103
|
+
class MainViewModel extends Base {
|
104
|
+
static config = {
|
105
|
+
className: 'Earthquakes.view.MainViewModel',
|
106
|
+
data: {},
|
107
|
+
stores: {}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
|
111
|
+
Neo.applyClassConfig(MainViewModel);
|
112
|
+
export default MainViewModel;
|
113
|
+
</pre>
|
114
|
+
|
115
|
+
??Use the view model
|
116
|
+
|
117
|
+
**If you used the _create-app-training_ build script, you already have a view model
|
118
|
+
and can skip this step.**
|
119
|
+
|
120
|
+
In the main container, import the view model:
|
121
|
+
|
122
|
+
import ViewModel from './MainContainerViewModel.mjs';
|
123
|
+
|
124
|
+
Then simply change the `model` config to use `module: ViewModel,`.
|
125
|
+
Leave the rest of the `model` config alone.
|
126
|
+
|
127
|
+
At this point you're creating an instance of the new view model, but it
|
128
|
+
doesn't really have anything in it. The config from the main container
|
129
|
+
is being applied to it, which means if you save and refresh, everything
|
130
|
+
should still work.
|
131
|
+
|
132
|
+
??Move the store config to view model
|
133
|
+
|
134
|
+
In the main container cut the `stores` config from the view model block,
|
135
|
+
and paste that in the `MainContainerModel`, replacing the `stores` block there.
|
136
|
+
|
137
|
+
Refresh and everything should still work.
|
138
|
+
|
139
|
+
Note how much cleaner the main view is. Classes should be simple. Complexity
|
140
|
+
should be factored out by creating new classes. There should also be a clean
|
141
|
+
separation of concerns, where stores and other view model setup is done in
|
142
|
+
a view model class, the view should be a declarative description of the view,
|
143
|
+
and event handling should be done in a separate controller — which we'll talk about soon.
|
@@ -0,0 +1,76 @@
|
|
1
|
+
<pre class="runnable text readonly">
|
2
|
+
import Table from "../../../node_modules/neo.mjs/src/table/Container.mjs";
|
3
|
+
import Viewport from "../../../node_modules/neo.mjs/src/container/Viewport.mjs";
|
4
|
+
import Store from "../../../node_modules/neo.mjs/src/data/Store.mjs";
|
5
|
+
import Foo from "./earthquakes/Table.mjs";
|
6
|
+
import ComponentModel from '../../../node_modules/neo.mjs/src/model/Component.mjs';
|
7
|
+
|
8
|
+
class MainContainer extends Viewport {
|
9
|
+
static config = {
|
10
|
+
className: "Earthquakes.view.MainContainer",
|
11
|
+
autoMount: true,
|
12
|
+
|
13
|
+
model: {
|
14
|
+
module: ComponentModel,
|
15
|
+
stores: {
|
16
|
+
earthquakes: {
|
17
|
+
module: Store,
|
18
|
+
model: {
|
19
|
+
fields: [{
|
20
|
+
name: "humanReadableLocation",
|
21
|
+
}, {
|
22
|
+
name: "size",
|
23
|
+
ntype: "data-field-float",
|
24
|
+
}, {
|
25
|
+
name: "timestamp",
|
26
|
+
type: "Date",
|
27
|
+
}, {
|
28
|
+
name: "title",
|
29
|
+
calculate: (data, field, item) => item.humanReadableLocation,
|
30
|
+
}, {
|
31
|
+
name: "position",
|
32
|
+
calculate: (data, field, item) => ({
|
33
|
+
lat: item.latitude,
|
34
|
+
lng: item.longitude,
|
35
|
+
}),
|
36
|
+
},
|
37
|
+
],
|
38
|
+
},
|
39
|
+
url: "https://apis.is/earthquake/is",
|
40
|
+
responseRoot: "results",
|
41
|
+
autoLoad: true,
|
42
|
+
}
|
43
|
+
}
|
44
|
+
},
|
45
|
+
items: [{
|
46
|
+
flex: 1,
|
47
|
+
module: Foo,
|
48
|
+
bind: {store: 'stores.earthquakes'},
|
49
|
+
}, {
|
50
|
+
flex: 1,
|
51
|
+
module: Foo,
|
52
|
+
bind: {store: 'stores.earthquakes'},
|
53
|
+
}],
|
54
|
+
layout: {ntype: "vbox"},
|
55
|
+
};
|
56
|
+
|
57
|
+
afterSetMounted(value, oldValue) {
|
58
|
+
super.afterSetMounted(value, oldValue);
|
59
|
+
if (!value) return;
|
60
|
+
this.addDomListeners({
|
61
|
+
"neo-debug-item-select": (event) => {
|
62
|
+
console.log('');
|
63
|
+
event.path.forEach((item) => {
|
64
|
+
const component = Neo.getComponent(item.id);
|
65
|
+
if (component) console.log(component);
|
66
|
+
});
|
67
|
+
},
|
68
|
+
});
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
Neo.applyClassConfig(MainContainer);
|
73
|
+
|
74
|
+
export default MainContainer;
|
75
|
+
|
76
|
+
</pre>
|
@@ -0,0 +1,127 @@
|
|
1
|
+
#Introduction
|
2
|
+
|
3
|
+
In this lab you'll create a container to hold the _city_ and _category_.
|
4
|
+
Eventually, you'll pass that information to the Yelp data feed to get
|
5
|
+
a list of matching businesses.
|
6
|
+
|
7
|
+
#Steps
|
8
|
+
|
9
|
+
??Create the filter container
|
10
|
+
|
11
|
+
Use the command line to navigate to the Neo workspace and generate
|
12
|
+
the filter class.
|
13
|
+
|
14
|
+
npm run create-class
|
15
|
+
|
16
|
+
Name the class `Yelp.view.businesses.Filter`, and have it extend `container.Base`.
|
17
|
+
|
18
|
+
Give it `ntype:'yelp-filter'` and add a the property `html:'This is the new filter container',`.
|
19
|
+
The `html` property is just a placeholder; later we'll be adding input fields for city
|
20
|
+
and category.
|
21
|
+
|
22
|
+
When you're finished the file should look like this:
|
23
|
+
|
24
|
+
<pre class="runnable readonly text 280">
|
25
|
+
import Base from '../../../../node_modules/neo.mjs/src/container/Base.mjs';
|
26
|
+
class Filter extends Base {
|
27
|
+
static config = {
|
28
|
+
className: 'Yelp.view.businesses.Filter',
|
29
|
+
ntype: 'yelp-filter',
|
30
|
+
html: 'This is the new filter container',
|
31
|
+
items: []
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
Neo.applyClassConfig(Filter);
|
36
|
+
|
37
|
+
export default Filter;
|
38
|
+
</pre>
|
39
|
+
|
40
|
+
The `html` config is just a way to make it easier to see that we're
|
41
|
+
using the new component. Once we start using the filter container in
|
42
|
+
the main view we'll remove that property.
|
43
|
+
|
44
|
+
|
45
|
+
??Use the filter container
|
46
|
+
|
47
|
+
Then edit the main view and
|
48
|
+
- Import `FilterPanel`
|
49
|
+
- Change the second top docked item config
|
50
|
+
- Use `module:FilterPanel`
|
51
|
+
- Remove the `html` config
|
52
|
+
|
53
|
+
Save and refresh and you should see that the new filter container is being used.
|
54
|
+
|
55
|
+
??Plan your work
|
56
|
+
|
57
|
+
Don't change `Filter.mjs` yet, but think about the changes you'll be
|
58
|
+
making.
|
59
|
+
|
60
|
+
The filter container needs two text fields, arranged horizontally.
|
61
|
+
|
62
|
+
- An import for the text field component
|
63
|
+
- A `layout` config for the container
|
64
|
+
- Two field component configs in the `items:[]`
|
65
|
+
|
66
|
+
If you were to go to the API docs for `Neo.form.field.Text` you'd see
|
67
|
+
these key configs:
|
68
|
+
|
69
|
+
- `labelText`
|
70
|
+
- `labelWidth`
|
71
|
+
- `clearable`
|
72
|
+
|
73
|
+
When you code, make small changes and refresh frequently.
|
74
|
+
|
75
|
+
Now that it's clear what we need to do, we can start coding...
|
76
|
+
|
77
|
+
??Remove the `html` property
|
78
|
+
|
79
|
+
Before doing anything, edit `Filter.mjs` and delete the `html` config.
|
80
|
+
|
81
|
+
??Import the text field component
|
82
|
+
|
83
|
+
Add an import `TextField` that imports `form/field/Text.mjs`. Be careful
|
84
|
+
to code the relative path correctly. The Neo framework is at the same
|
85
|
+
relative location as the base class, so only the path at the end will differ.
|
86
|
+
|
87
|
+
??Add the city text field
|
88
|
+
|
89
|
+
Add a text field config to `items:[]`.
|
90
|
+
|
91
|
+
items: [{
|
92
|
+
module: TextField,
|
93
|
+
clearable: true,
|
94
|
+
width: 220,
|
95
|
+
labelText: 'City',
|
96
|
+
labelWidth: 40
|
97
|
+
}]
|
98
|
+
|
99
|
+
Save and verify that you see the new text field.
|
100
|
+
|
101
|
+
??Add a category text field
|
102
|
+
|
103
|
+
Add a second item for the category field. It'll be a copy-and-paste
|
104
|
+
of the city config, but you'll have to modify the label and widths.
|
105
|
+
|
106
|
+
Save, refresh, and modify the code until it until it looks the way you want.
|
107
|
+
|
108
|
+
??Separate the two components
|
109
|
+
|
110
|
+
The components touch, so add a `style` to the city field to give it a right margin.
|
111
|
+
|
112
|
+
style: { marginRight: '16px' },
|
113
|
+
|
114
|
+
??Use `itemDefaults`
|
115
|
+
|
116
|
+
Note that the text fields share a couple of properties: they are of the
|
117
|
+
same type, and they both use `clearable:true`. Sharing common configs is
|
118
|
+
what `itemDefaults` is designed to do.
|
119
|
+
|
120
|
+
Add a new config to the filter contaner, and remove the corresponding properties
|
121
|
+
in the child items.
|
122
|
+
|
123
|
+
itemDefaults: {
|
124
|
+
module: TextField,
|
125
|
+
clearable: true,
|
126
|
+
},
|
127
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#Introduction
|
2
|
+
|
3
|
+
In this lab you'll have the filter container fire
|
4
|
+
_cityChange_ and _categoryChange_ events.
|
5
|
+
|
6
|
+
#Steps
|
7
|
+
|
8
|
+
??Fire _cityChange_
|
9
|
+
|
10
|
+
We need to fire an event when city changes.
|
11
|
+
|
12
|
+
Within the `Filter` class, how do we know when that property has changed? Via the `afterSetCity()` method.
|
13
|
+
|
14
|
+
What information should we pass when firing the event? When you design your own classes
|
15
|
+
it's up to you. The question is: what would be useful to the listener? In a change event
|
16
|
+
you'd typically send three three things:
|
17
|
+
- The component firing the event
|
18
|
+
- The new value
|
19
|
+
- The old value
|
20
|
+
|
21
|
+
Edit `yelp/src/view/businesses/Filter.mjs` and modify the `afterSetCity()` method to have
|
22
|
+
a second param — the old value. Then add a statement to fire an event.
|
23
|
+
|
24
|
+
afterSetCity(city, oldCity) {
|
25
|
+
console.log(city);
|
26
|
+
if (!this.rendered) return;
|
27
|
+
this.getReference('city').value = city;
|
28
|
+
this.fire('cityChange', {
|
29
|
+
component: this,
|
30
|
+
city,
|
31
|
+
oldCity
|
32
|
+
});
|
33
|
+
}
|
34
|
+
|
35
|
+
??Test the event in the debugger
|
36
|
+
|
37
|
+
You can procedurally add an event handler via the `on()` method.
|
38
|
+
|
39
|
+
Use the Chrome console to add a listener.
|
40
|
+
|
41
|
+
Neo.findFirst({ntype:'yelp-filter'}).on('cityChange', data=>console.log('listener', data))
|
42
|
+
|
43
|
+
Then enter a city in the text field. After a moment you should see your log message.
|
44
|
+
|
45
|
+
??Have the main view listen for the change
|
46
|
+
|
47
|
+
Now that you know your event is getting fired, edit the main view and add a listener there.
|
48
|
+
|
49
|
+
<pre style="border: thin solid gray; padding: 8px; color: lightgray;">
|
50
|
+
headers: [{
|
51
|
+
module: Banner,
|
52
|
+
dock: 'top',
|
53
|
+
}, {
|
54
|
+
dock: 'top',
|
55
|
+
module: Filter,
|
56
|
+
<span style="color:#b91010;">listeners: {
|
57
|
+
cityChange: data => console.log(data)
|
58
|
+
}</span>
|
59
|
+
}, {
|
60
|
+
dock: 'right',
|
61
|
+
html: 'details',
|
62
|
+
width: 300
|
63
|
+
}],
|
64
|
+
</pre>
|
65
|
+
|
66
|
+
??Test the main view listener
|
67
|
+
|
68
|
+
When you run your app and enter a city you should see its value being logged from the main view.
|
69
|
+
|
70
|
+
<img src="resources/images/yelp/OnCityChangeEvent.png"></pre>
|
71
|
+
|
72
|
+
??Fire _categoryChange_
|
73
|
+
|
74
|
+
Now do the same thing for category.
|
75
|
+
|
76
|
+
- Fire the event from `Yelp.view.businesses.Filter#afterSetCategory'
|
77
|
+
- Test it
|
78
|
+
- Add the listener in the main view
|
79
|
+
|
80
|
+
When you're finished, you should see both city and category changes being logged
|
81
|
+
from the main view.
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#Introduction
|
2
|
+
|
3
|
+
In this lab you'll use the city to update the center.
|
4
|
+
|
5
|
+
#Steps
|
6
|
+
|
7
|
+
??Create a main view model property `city`
|
8
|
+
|
9
|
+
We want a default city, and we want the filter to reflect it.
|
10
|
+
|
11
|
+
- Define a new data property `city:'Oconomowoc, Wisconsin'` in the main view model
|
12
|
+
- In the main view, bind the filter's `city` to the new property
|
13
|
+
|
14
|
+
You should see that as the city fields's initial value.
|
15
|
+
|
16
|
+
??Do the same for category.
|
17
|
+
|
18
|
+
- Define a new data property `category:'pizza'`
|
19
|
+
- Bind the filter's `category` to that property
|
20
|
+
|
21
|
+
??Use two-way binding to reflect user changes to city and category
|
22
|
+
|
23
|
+
In the main view, change each binding to be two-way bound.
|
24
|
+
|
25
|
+
For city it's coded like this. Do the same for category.
|
26
|
+
|
27
|
+
city: { twoWay: true, value: data => data.city }
|
28
|
+
|
29
|
+
Test it by running the app, entering a city and category, then using the
|
30
|
+
the Chrome debugger to confirm that the main view model reflects the values.
|
31
|
+
|
32
|
+
Neo.findFirst({ntype:'yelp-main'}).model.data.city
|
33
|
+
|
34
|
+
Neo.findFirst({ntype:'yelp-main'}).model.data.category
|
35
|
+
|
36
|
+
|