neo.mjs 6.15.4 → 6.15.6

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 (67) hide show
  1. package/apps/ServiceWorker.mjs +2 -2
  2. package/apps/form/view/FormContainerController.mjs +1 -1
  3. package/apps/form/view/ViewportController.mjs +2 -2
  4. package/apps/portal/view/home/MainContainer.mjs +2 -2
  5. package/apps/portal/view/learn/ContentView.mjs +1 -1
  6. package/apps/portal/view/learn/LivePreview.mjs +0 -27
  7. package/apps/realworld2/view/user/LoginFormContainer.mjs +1 -1
  8. package/docs/app/view/MainContainer.mjs +1 -11
  9. package/examples/ServiceWorker.mjs +2 -2
  10. package/examples/component/timer/MainContainerController.mjs +2 -2
  11. package/examples/component/toast/MainContainerController.mjs +2 -2
  12. package/examples/date/selectorContainer/MainContainer.mjs +215 -0
  13. package/examples/date/selectorContainer/app.mjs +6 -0
  14. package/examples/date/selectorContainer/index.html +11 -0
  15. package/examples/date/selectorContainer/neo-config.json +6 -0
  16. package/package.json +5 -5
  17. package/resources/data/deck/learnneo/pages/TestLivePreview.md +1 -2
  18. package/resources/data/deck/learnneo/pages/Welcome.md +68 -0
  19. package/resources/data/deck/learnneo/pages/WhyNeo-Multi-Threaded.md +2 -0
  20. package/resources/data/deck/learnneo/pages/WhyNeo-Multi-Window.md +3 -3
  21. package/resources/data/deck/learnneo/pages/WhyNeo-Speed.md +36 -12
  22. package/resources/data/deck/learnneo/tree.json +5 -4
  23. package/resources/scss/src/apps/portal/learn/PageContainer.scss +4 -3
  24. package/resources/scss/src/date/SelectorContainer.scss +120 -0
  25. package/resources/scss/theme-dark/date/SelectorContainer.scss +24 -0
  26. package/resources/scss/theme-light/date/SelectorContainer.scss +24 -0
  27. package/resources/scss/theme-neo-light/date/SelectorContainer.scss +24 -0
  28. package/src/DefaultConfig.mjs +2 -2
  29. package/src/Neo.mjs +5 -5
  30. package/src/component/Base.mjs +1 -1
  31. package/src/container/Base.mjs +42 -17
  32. package/src/controller/Component.mjs +5 -4
  33. package/src/core/Observable.mjs +30 -5
  34. package/src/core/Util.mjs +1 -1
  35. package/src/date/DayViewComponent.mjs +251 -0
  36. package/src/date/SelectorContainer.mjs +352 -0
  37. package/src/date/SelectorContainerModel.mjs +33 -0
  38. package/src/form/Container.mjs +10 -2
  39. package/src/form/field/Base.mjs +10 -2
  40. package/src/form/field/CheckBox.mjs +13 -5
  41. package/src/form/field/ComboBox.mjs +21 -15
  42. package/src/form/field/Date.mjs +2 -2
  43. package/src/form/field/Text.mjs +18 -17
  44. package/src/main/addon/IntersectionObserver.mjs +27 -20
  45. package/src/tab/Container.mjs +56 -55
  46. package/test/components/app.mjs +1 -0
  47. package/test/components/files/component/Base.mjs +88 -0
  48. package/test/components/siesta.js +1 -0
  49. package/docs/app/model/Tutorial.mjs +0 -41
  50. package/docs/app/store/Tutorials.mjs +0 -28
  51. package/docs/app/view/TutorialsTreeList.mjs +0 -51
  52. package/docs/tutorials/01_Concept.html +0 -45
  53. package/docs/tutorials/01_Concept.json +0 -123
  54. package/docs/tutorials/01_Concept.md +0 -55
  55. package/docs/tutorials/02_ClassSystem.html +0 -171
  56. package/docs/tutorials/02_ClassSystem.md +0 -187
  57. package/docs/tutorials/03_ComponentLifecycle.html +0 -28
  58. package/docs/tutorials/03_ComponentLifecycle.md +0 -23
  59. package/docs/tutorials/04_VdomVnode.html +0 -161
  60. package/docs/tutorials/05_RemoteMethodAccess.html +0 -82
  61. package/docs/tutorials/06_EcmaScript6Plus.html +0 -10
  62. package/docs/tutorials/07_WebWorkers.html +0 -9
  63. package/docs/tutorials/08_DomEvents.html +0 -7
  64. package/docs/tutorials/09_TodoList_version1.html +0 -503
  65. package/docs/tutorials/11_CreateApp.html +0 -94
  66. package/docs/tutorials/tutorials.json +0 -100
  67. package/resources/scss/src/apps/docs/TutorialsTreeList.scss +0 -7
@@ -0,0 +1,88 @@
1
+ StartTest(t => {
2
+ t.it('Checking colliding style updates', async t => {
3
+ const containerId = await Neo.worker.App.createNeoInstance({
4
+ ntype : 'container',
5
+ height: 250,
6
+ style : {backgroundColor: 'red'},
7
+ width : 300
8
+ });
9
+
10
+ t.is(containerId, 'neo-container-1');
11
+
12
+ await t.waitForSelector('.neo-container');
13
+ t.diag('Container got rendered.');
14
+
15
+ const componentId = await Neo.worker.App.createNeoInstance({
16
+ ntype : 'component',
17
+ height : 150,
18
+ parentId: containerId,
19
+ style : {backgroundColor: 'blue'},
20
+ width : 150
21
+ });
22
+
23
+ t.is(componentId, 'neo-component-1');
24
+ t.diag('Component got rendered.');
25
+
26
+ t.diag('Child update before parent update');
27
+ Neo.worker.App.setConfigs({id: componentId, style: {backgroundColor: 'green'}});
28
+ Neo.worker.App.setConfigs({id: containerId, style: {backgroundColor: 'orange'}});
29
+
30
+ await t.waitFor(100);
31
+
32
+ t.is(document.getElementById(componentId).style.backgroundColor, 'green');
33
+ t.is(document.getElementById(containerId).style.backgroundColor, 'orange');
34
+
35
+ t.diag('Parent update before child update');
36
+ Neo.worker.App.setConfigs({id: containerId, style: {backgroundColor: 'pink'}});
37
+ Neo.worker.App.setConfigs({id: componentId, style: {backgroundColor: 'purple'}});
38
+
39
+ await t.waitFor(100);
40
+
41
+ t.is(document.getElementById(containerId).style.backgroundColor, 'pink');
42
+ t.is(document.getElementById(componentId).style.backgroundColor, 'purple');
43
+
44
+ await Neo.worker.App.destroyNeoInstance(containerId)
45
+ });
46
+
47
+ t.it('Checking colliding vdom updates', async t => {
48
+ const toolbarId = await Neo.worker.App.createNeoInstance({
49
+ ntype : 'toolbar',
50
+ height: 200,
51
+ width : 300
52
+ });
53
+
54
+ t.is(toolbarId, 'neo-toolbar-1');
55
+
56
+ await t.waitForSelector('.neo-toolbar');
57
+ t.diag('Toolbar got rendered.');
58
+
59
+ const buttonId = await Neo.worker.App.createNeoInstance({
60
+ ntype : 'button',
61
+ parentId: toolbarId,
62
+ text : 'hello'
63
+ });
64
+
65
+ t.is(buttonId, 'neo-button-1');
66
+
67
+ await t.waitForSelector('.neo-button');
68
+ t.diag('Button got rendered.');
69
+
70
+ t.diag('Child update before parent update');
71
+ Neo.worker.App.setConfigs({id: buttonId, text : 'world'});
72
+ Neo.worker.App.setConfigs({id: toolbarId, height: 300});
73
+
74
+ await t.waitFor(100);
75
+
76
+ t.is(document.getElementById(toolbarId).style.height, '300px');
77
+ t.is(document.getElementById(buttonId).firstChild.innerHTML, 'world');
78
+
79
+ t.diag('Parent update before child update');
80
+ Neo.worker.App.setConfigs({id: toolbarId, height: 200});
81
+ Neo.worker.App.setConfigs({id: buttonId, text : 'hello'});
82
+
83
+ await t.waitFor(100);
84
+
85
+ t.is(document.getElementById(toolbarId).style.height, '200px');
86
+ t.is(document.getElementById(buttonId).firstChild.innerHTML, 'hello');
87
+ });
88
+ });
@@ -75,6 +75,7 @@ project.plan({
75
75
  }, {
76
76
  group: 'component',
77
77
  items: [
78
+ 'files/component/Base.mjs',
78
79
  'files/component/DateSelector.mjs'
79
80
  ]
80
81
  }, {
@@ -1,41 +0,0 @@
1
- import Model from '../../../src/data/Model.mjs';
2
-
3
- /**
4
- * @class Docs.app.model.Tutorial
5
- * @extends Neo.data.Model
6
- */
7
- class Tutorial extends Model {
8
- static config = {
9
- /**
10
- * @member {String} className='Docs.app.model.Tutorial'
11
- * @protected
12
- */
13
- className: 'Docs.app.model.Tutorial',
14
- /**
15
- * @member {Object[]} fields
16
- */
17
- fields: [{
18
- name: 'fileName',
19
- type: 'String'
20
- }, {
21
- name: 'id',
22
- type: 'Integer'
23
- }, {
24
- name: 'isLeaf',
25
- type: 'Boolean'
26
- }, {
27
- name: 'name',
28
- type: 'String'
29
- }, {
30
- name: 'parentId',
31
- type: 'Integer'
32
- }, {
33
- name: 'type',
34
- type: 'String'
35
- }]
36
- }
37
- }
38
-
39
- Neo.setupClass(Tutorial);
40
-
41
- export default Tutorial;
@@ -1,28 +0,0 @@
1
- import Store from '../../../src/data/Store.mjs';
2
- import Tutorial from '../model/Tutorial.mjs';
3
-
4
- /**
5
- * @class Docs.app.store.Tutorials
6
- * @extends Neo.data.Store
7
- */
8
- class Tutorials extends Store {
9
- static config = {
10
- /**
11
- * @member {String} className='Docs.app.store.Tutorials'
12
- * @protected
13
- */
14
- className: 'Docs.app.store.Tutorials',
15
- /**
16
- * @member {String} keyProperty='id'
17
- */
18
- keyProperty: 'id',
19
- /**
20
- * @member {Neo.data.Model} model=Tutorial
21
- */
22
- model: Tutorial
23
- }
24
- }
25
-
26
- Neo.setupClass(Tutorials);
27
-
28
- export default Tutorials;
@@ -1,51 +0,0 @@
1
- import TreeList from '../../../src/tree/List.mjs';
2
- import TutorialsStore from '../store/Tutorials.mjs';
3
-
4
- /**
5
- * @class Docs.view.TutorialsTreeList
6
- * @extends Neo.tree.List
7
- */
8
- class TutorialsTreeList extends TreeList {
9
- static config = {
10
- /**
11
- * @member {String} className='Docs.view.TutorialsTreeList'
12
- * @protected
13
- */
14
- className: 'Docs.view.TutorialsTreeList',
15
- /**
16
- * @member {String} ntype='tutorials-treelist'
17
- * @protected
18
- */
19
- ntype: 'tutorials-treelist',
20
- /**
21
- * @member {String[]} cls=['docs-tutorials-treelist']
22
- */
23
- cls: ['docs-tutorials-treelist'],
24
- /**
25
- * @member {Neo.data.Store|null} store=TutorialsStore
26
- * @protected
27
- */
28
- store: TutorialsStore
29
- }
30
-
31
- /**
32
- *
33
- */
34
- onConstructed() {
35
- super.onConstructed();
36
-
37
- let me = this;
38
-
39
- Neo.Xhr.promiseJson({
40
- url: '../../docs/tutorials/tutorials.json'
41
- }).then(data => {
42
- me.store.data = data.json;
43
- me.createItems(null, me.getListItemsRoot(), 0);
44
- me.update();
45
- });
46
- }
47
- }
48
-
49
- Neo.setupClass(TutorialsTreeList);
50
-
51
- export default TutorialsTreeList;
@@ -1,45 +0,0 @@
1
- <div class="neo-header-text-container">
2
- <span class="neo-header-text">Tutorial: Concept</span>
3
- </div>
4
- <article>
5
- <h4>Why yet another Javascript framework?</h4>
6
- <ol>
7
- <li>neo.mjs is web workers driven</li>
8
- <li>neo.mjs does not need any cryptic XML markups</li>
9
- <li>neo.mjs uses a custom blazing fast virtual dom engine</li>
10
- <li>neo.mjs is based on EcmaScript 8 (ES8)</li>
11
- <li>neo.mjs uses HTML5 and CSS3 to the fullest</li>
12
- <li>Simplicity</li>
13
- <li>No transpiled code</li>
14
- </ol>
15
- <hr>
16
- <p>(1) neo.mjs uses 3 web workers:</p>
17
- <ul>
18
- <li>App</li>
19
- <li>Data</li>
20
- <li>Vdom</li>
21
- </ul>
22
- <p>The main reason is that browsers by default only use 1 CPU core, while most computers and mobile devices have
23
- more. Multi-Threading solves this performance bottleneck and it will ensure that there are no hidden
24
- background-tasks in the main thread, which mess with your beautiful animations.</p>
25
- <p>In short: Most parts of neo.mjs as well as all apps you will create are inside the App worker.</p>
26
- <p>The main thread is only responsible to manipulate the DOM and delegate DOM events to the App worker.</p>
27
- <p>The Data worker will perform all Ajax requests to your backend and host the Store instances.</p>
28
- <p>The Vdom worker parses your JSON based markup (Vdom) into a virtual node (Vnode) and creates deltas
29
- when you dynamically change your Vdom.</p>
30
- <p>(2) Did you ever enjoy writing pseudo-html including curly braces like {tpl if}, {tpl for} or even better
31
- {[this.doSomething()]}? Those XML templates evolved to a point, where they try to do everything what
32
- Javascript itself is capable of and you will most likely have encountered scoping issues (where does &quot;this&quot;
33
- point to now?). The solution is as simple as it should have been obvious for quite a while: JSON. You can easily manipulate Javascript objects with Javascript.</p>
34
- <p>(3) Since neo.mjs does not need to parse XML templates back into JSON and then create virtual DOM nodes,
35
- the custom Vdom engine is blazing fast. The algorithms to create deltas are highly efficient and
36
- recognise moved DOM subtrees immediately.</p>
37
- <p>(4) neo.mjs is most likely the first UI framework out there which does not only allow devs to create
38
- ES6 classes on top of ES5 prototypes, but is itself fully written in ES6.</p>
39
- <p>(5) neo.mjs uses the latest web APIs and CSS features to the fullest and give you an easy and intuitive
40
- access to them.</p>
41
- <p>(6) The first and most important design goal of neo.mjs is simplicity. This does not only mean to keep the
42
- code base as clean and simple as possible, but also to keep the created DOM as lightweight and minimal as
43
- possible.</p>
44
- <p>(7) neo.mjs does not use Babel or any other tool to transpile code (which does not mean you can't use it for your own apps).</p>
45
- </article>
@@ -1,123 +0,0 @@
1
- [
2
- {
3
- "tag": "div",
4
- "cls": ["neo-header-text-container"],
5
- "cn" : [
6
- {
7
- "tag" : "span",
8
- "cls" : ["neo-header-text"],
9
- "innerHTML": "Tutorial: Concept"
10
- }
11
- ]
12
- },
13
- {
14
- "tag": "article",
15
- "cn" : [
16
- {
17
- "tag" : "h4",
18
- "innerHTML": "Why yet another Javascript framework?"
19
- },
20
- {
21
- "tag": "ol",
22
- "cn" : [
23
- {
24
- "tag" : "li",
25
- "innerHTML": "neo.mjs is web workers driven"
26
- },
27
- {
28
- "tag" : "li",
29
- "innerHTML": "neo.mjs does not need any cryptic XML markups"
30
- },
31
- {
32
- "tag" : "li",
33
- "innerHTML": "neo.mjs uses a custom blazing fast virtual dom engine"
34
- },
35
- {
36
- "tag" : "li",
37
- "innerHTML": "neo.mjs is based on EcmaScript 8 (ES8)"
38
- },
39
- {
40
- "tag" : "li",
41
- "innerHTML": "neo.mjs uses HTML5 and CSS3 to the fullest"
42
- },
43
- {
44
- "tag" : "li",
45
- "innerHTML": "Simplicity"
46
- },
47
- {
48
- "tag" : "li",
49
- "innerHTML": "No transpiled code"
50
- }
51
- ]
52
- },
53
- {
54
- "tag": "hr"
55
- },
56
- {
57
- "tag" : "p",
58
- "innerHTML": "(1) neo.mjs uses 3 web workers:"
59
- },
60
- {
61
- "tag": "ul",
62
- "cn": [
63
- {
64
- "tag" : "li",
65
- "innerHTML": "App"
66
- },
67
- {
68
- "tag" : "li",
69
- "innerHTML": "Data"
70
- },
71
- {
72
- "tag" : "li",
73
- "innerHTML": "Vdom"
74
- }
75
- ]
76
- },
77
- {
78
- "tag" : "p",
79
- "innerHTML": "The main reason is that browsers by default only use 1 CPU core, while most computers and mobile devices have more. Multi-Threading solves this performance bottleneck and it will ensure that there are no hidden background-tasks in the main thread, which mess with your beautiful animations."
80
- },
81
- {
82
- "tag" : "p",
83
- "innerHTML": "In short: Most parts of neo.mjs as well as all apps you will create are inside the App worker."
84
- },
85
- {
86
- "tag" : "p",
87
- "innerHTML": "The main thread is only responsible to manipulate the DOM and delegate DOM events to the App worker."
88
- },
89
- {
90
- "tag" : "p",
91
- "innerHTML": "The Data worker will perform all Ajax requests to your backend and host the Store instances."
92
- },
93
- {
94
- "tag" : "p",
95
- "innerHTML": "The Vdom worker parses your JSON based markup (Vdom) into a virtual node (Vnode) and creates deltas when you dynamically change your Vdom."
96
- },
97
- {
98
- "tag" : "p",
99
- "innerHTML": "(2) Did you ever enjoy writing pseudo-html including curly braces like {tpl if}, {tpl for} or even better {[this.doSomething()]}? Those XML templates evolved to a point, where they try to do everything what Javascript itself is capable of and you will most likely have encountered scoping issues (where does &quot;this&quot; point to now?). The solution is as simple as it should have been obvious for quite a while: JSON. You can easily manipulate Javascript objects with Javascript."
100
- },
101
- {
102
- "tag" : "p",
103
- "innerHTML": "(3) Since neo.mjs does not need to parse XML templates back into JSON and then create virtual DOM nodes, the custom Vdom engine is blazing fast. The algorithms to create deltas are highly efficient and recognise moved DOM subtrees immediately."
104
- },
105
- {
106
- "tag" : "p",
107
- "innerHTML": "(4) neo.mjs is most likely the first UI framework out there which does not only allow devs to create ES8 classes on top of ES5 prototypes, but is itself fully written in ES8."
108
- },
109
- {
110
- "tag" : "p",
111
- "innerHTML": "(5) neo.mjs uses the latest web APIs and CSS features to the fullest and give you an easy and intuitive access to them."
112
- },
113
- {
114
- "tag" : "p",
115
- "innerHTML": "(6) The first and most important design goal of neo.mjs is simplicity. This does not only mean to keep the code base as clean and simple as possible, but also to keep the created DOM as lightweight and minimal as possible."
116
- },
117
- {
118
- "tag" : "p",
119
- "innerHTML": "(7) neo.mjs does not use Babel or any other tool to transpile code (which does not mean you can't use it for your own apps)."
120
- }
121
- ]
122
- }
123
- ]
@@ -1,55 +0,0 @@
1
- #### Why yet another Javascript framework?
2
-
3
- 1. neo.mjs is web workers driven
4
- 2. neo.mjs does not need any cryptic XML markups
5
- 3. neo.mjs uses a custom blazing fast virtual dom engine
6
- 4. neo.mjs is based on EcmaScript 8 (ES8)
7
- 5. neo.mjs uses HTML5 and CSS3 to the fullest
8
- 6. Simplicity
9
- 7. No transpiled code
10
-
11
- ____
12
-
13
- (1) neo.mjs uses 3 web workers:
14
- * App
15
- * Data
16
- * Vdom
17
-
18
- The main reason is that browsers by default only use 1 CPU core, while most computers and mobile devices have
19
- more. Multi-Threading solves this performance bottleneck and it will ensure that there are no hidden
20
- background-tasks in the main thread, which mess with your beautiful animations.
21
-
22
- In short: Most parts of neo.mjs as well as all apps you will create are inside the App worker.
23
-
24
- The main thread is only responsible to manipulate the DOM and delegate DOM events to the App worker.
25
-
26
- The Data worker will perform all Ajax requests to your backend and host the Store instances.
27
-
28
- The Vdom worker parses your JSON based markup (Vdom) into a virtual node (Vnode) and creates deltas
29
- when you dynamically change your Vdom.
30
-
31
-
32
- (2) Did you ever enjoy writing pseudo-html including curly braces like {tpl if}, {tpl for} or even better
33
- {[this.doSomething()]}? Those XML templates evolved to a point, where they try to do everything what
34
- Javascript itself is capable of and you will most likely have encountered scoping issues (where does "this"
35
- point to now?). The solution is as simple as it should have been obvious for quite a while: JSON. You can easily manipulate Javascript objects with Javascript.
36
-
37
-
38
- (3) Since neo.mjs does not need to parse XML templates back into JSON and then create virtual DOM nodes,
39
- the custom Vdom engine is blazing fast. The algorithms to create deltas are highly efficient and
40
- recognise moved DOM subtrees immediately.
41
-
42
-
43
- (4) neo.mjs is most likely the first UI framework out there which does not only allow devs to create
44
- ES6 classes on top of ES5 prototypes, but is itself fully written in ES6.
45
-
46
-
47
- (5) neo.mjs uses the latest web APIs and CSS features to the fullest and give you an easy and intuitive
48
- access to them.
49
-
50
-
51
- (6) The first and most important design goal of neo.mjs is simplicity. This does not only mean to keep the
52
- code base as clean and simple as possible, but also to keep the created DOM as lightweight and minimal as
53
- possible.
54
-
55
- (7) neo.mjs does not use Babel or any other tool to transpile code (which does not mean you can't use it for your own apps).
@@ -1,171 +0,0 @@
1
- <div class="neo-header-text-container">
2
- <span class="neo-header-text">Tutorial: Class System</span>
3
- </div>
4
- <article>
5
- <ol>
6
- <li>Flaws of the ES6+ class system
7
- <ol>
8
- <li>No &quot;this&quot; inside constructors before the parent call</li>
9
- <li>It is not possible to define properties inside the class body without using get &amp; set</li>
10
- <li>No private methods or properties</li>
11
- <li>No support for mixins</li>
12
- </ol>
13
- </li>
14
- <li>Neo Modules &amp; Classes
15
- <ol>
16
- <li>One Class per File</li>
17
- <li>Each Class is &quot;wrapped&quot; inside a JS Module</li>
18
- <li>Private Class methods</li>
19
- <li>*.mjs</li>
20
- </ol>
21
- </li>
22
- <li>Neo ES6+ Class Enhancements
23
- <ol>
24
- <li>Neo.applyClassConfig</li>
25
- <li>Reducing boiler plate code</li>
26
- </ol>
27
- </li>
28
- </ol>
29
- <h4>(1) Flaws of the ES6+ class system</h4>
30
- <p>(1.1.) This might not sound like a big deal at first, but it does prevent any pre-processing inside the
31
- constructor chain.</p>
32
- <pre><code>class TabContainer extends Container {
33
- construct(config) {
34
- //let me = this; // breaks!
35
- super.construct(config);
36
- let me = this; //ok
37
- }
38
- }</code></pre>
39
- <p>(1.2.) The most likely biggest flaw is that you can not define any properties directly inside the class body,
40
- as well as a missing config system.</p>
41
- <pre><code>class TabContainer extends Container {
42
- activeIndex: 1 // nope
43
- static foo: 'bar' // impossible as well
44
- }</code></pre>
45
- <p>There is hope: <a target="_blank" href="https://tc39.github.io/proposal-class-fields/#sec-private-bound-names">https://tc39.github.io/proposal-class-fields/#sec-private-bound-names</a>
46
- </p>
47
- <p>(1.3.) Although there are some proposals out there for many years, still not implemented.</p>
48
- <p>(1.4.) Independant whether you like the mixin pattern or not, it is just not possible.</p>
49
- <hr>
50
- <h4>(2) Neo Modules &amp; Classes</h4>
51
- <p>(2.1.) One Class per File. Might sound trivial from classic OOP concepts, but we do stick to it and recommend you
52
- to
53
- do the same for your application files.</p>
54
- <p>(2.2) As soon as you want to extend an ES6+ class, you need to ensure that the base class is available.
55
- One good way to achieve this is to use import:</p>
56
- <p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import</a>
57
- </p>
58
- <p>This automatially makes the file a JS module and you will notice that we will at least export the Class
59
- at the end of of each module.</p>
60
- <p>(2.3) Having the JS Module around each Class definition allows us to place methods outside of the class
61
- deinition,
62
- but still between the import and export statements. A nice place for &quot;private&quot; methods or attributes
63
- which can get
64
- accessed from Class methods easily, but not as easy from the outside world.</p>
65
- <p>(2.4.) In case you missed it, *.mjs is not something we came up with, but the new standard file extension name
66
- for
67
- Javascript Modules. You can find more details e.g. in Axels Blog:</p>
68
- <p>
69
- <a target="_blank" href="http://2ality.com/2017/05/es-module-specifiers.html">http://2ality.com/2017/05/es-module-specifiers.html</a>
70
- </p>
71
- <hr>
72
- <h4>(3) Neo ES6+ Class Enhancements</h4>
73
- <p>(3.1.) To reduce the issue of 1.2. we created Neo.applyClassConfig (Neo.mjs),
74
- which does get called in every Class File at the very bottom (before the export statement).
75
- If you look at Neo Class / Module files, like component/Button.mjs, you will notice 2 methods at the top of the
76
- class body:</p>
77
- <h5>getStaticConfig</h5><h5>getConfig</h5>
78
- <p>Both methods simply return an object. Put all static keys into getStaticConfig and all other ones into getConfig.
79
- Neo.applyClassConfig <strong>(strongly recommended to look at the source code)</strong> will apply all static
80
- configs to the class
81
- constructor (as well as adding the staticConfig object itself there) and all non static configs will get added
82
- using
83
- Object.defineProperty() on the Class prototype.</p>
84
- <p>So, why is a &quot;config system&quot; useful, you might ask yourself at this point.
85
- This can easily get showcased using a simple example:</p>
86
- <pre><code>class TabContainer extends Container {
87
- get activeIndex() {
88
- return this._activeIndex || 0;
89
- }
90
- set activeIndex(value) {
91
- this._activeIndex = value;
92
- }
93
- }</code></pre>
94
- <p>So far so good, we now have an activeIndex property which will use _activeIndex to read &amp; save its value.
95
- Now you might want to extend this class:</p>
96
- <pre><code>class MyTabContainer extends TabContainer {
97
- static getConfig() {return {
98
- _activeIndex: 1
99
- }}
100
- }</code></pre>
101
- <p>Ok, this one was easy. _activeIndex will get applied as a class property.
102
- Neither the first version with 0 nor the second one using the underscore and the value of 1 will trigger the
103
- setter.
104
- When you call:</p>
105
- <pre><code>Neo.create(MyTabContainer);</code></pre>
106
- <p>the constructor of our Base Class (Neo.core.Base) will call initConfig(),
107
- which will apply _activeIndex to the instance, silently setting the value</p>
108
- <pre><code>class MyTabContainer2 extends TabContainer {
109
- static getConfig() {return {
110
- activeIndex: 1
111
- }}
112
- }</code></pre>
113
- <p>Now it does get more interesting. You want to trigger the setter when creating an instance,
114
- but you definitely do <strong>not</strong> want to override the activeIndex property defined via get &amp; set
115
- with the new one.
116
- No worries, Neo.applyClassConfig will check the base class prototype chain and in case it does find a property
117
- with the
118
- same name, it will not override the version having the setter. Instead it will only apply activeIndex inside the
119
- config
120
- object itself.
121
- Now, when you call:</p>
122
- <pre><code>Neo.create(MyTabContainer2);</code></pre>
123
- <p>the constructor of our Base Class (Neo.core.Base) will call initConfig(),
124
- which will apply activeIndex to your instance and this will call the setter.</p>
125
- <pre><code>Neo.create(MyTabContainer2, {
126
- activeIndex: 2
127
- });</code></pre>
128
- <p>This will also call the setter <strong>once</strong>, this time using the value of 2
129
- (initConfig does merge the prototype config object with the one you pass into Neo.create -&gt; the constructor)
130
- </p>
131
- <p>(3.2.) Reducing boiler plate code. When looking back at the first TabContainer example you will probably think:
132
- Damn, in case I want to define many properties via get&amp;set which all just save&amp;get their value inside an
133
- undercored
134
- version of its name key, this will create quite some overhead.</p>
135
- <p>To avoid this and make your code more beautiful, we added a trailing underscore for class configs:</p>
136
- <pre><code>class TabContainer extends Container {
137
- static getConfig() {return {
138
- activeIndex_: 0
139
- }}
140
- }</code></pre>
141
- <p>Look close: activeIndex<span style="color:red;font-size:200%;">_</span> .This gets you the exact same result as
142
- the previous example:</p>
143
- <pre><code>class TabContainer extends Container {
144
- get activeIndex() {
145
- return this._activeIndex || 0;
146
- }
147
- set activeIndex(value) {
148
- this._activeIndex = value;
149
- }
150
- }</code></pre>
151
- <p>Even better, this also <strong>optionally</strong> gives you support for 3 more methods you can use:</p>
152
- <pre><code>class TabContainer extends Container {
153
- static getConfig() {return {
154
- activeIndex_: 0
155
- }}
156
-
157
- beforeSetActiveIndex(value, oldValue) {
158
- return 42; // the answer to Life, the Universe, and Everything
159
- }
160
-
161
- beforeGetActiveIndex(value) {
162
- return 5; // but hey, why tell anyone?
163
- }
164
-
165
- // this one would only get called in case value !== oldValue
166
- afterSetActiveIndex(value, oldValue) {
167
- // update the UI
168
- }
169
- }</code></pre>
170
- <p><a href="module-Neo.html#~autoGenerateGetSet">Details here</a></p>
171
- </article>