neo.mjs 8.21.2 → 8.22.0
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/.github/CODEBASE_OVERVIEW.md +0 -1
- package/.github/CODE_OF_CONDUCT.md +0 -1
- package/.github/CONCEPT.md +0 -1
- package/.github/GETTING_STARTED.md +0 -1
- package/.github/NEOMJS_HISTORY.md +0 -1
- package/.github/STORY.md +0 -1
- package/.github/VISION.md +2 -126
- package/BACKERS.md +0 -1
- package/CONTRIBUTING.md +0 -1
- package/LICENSE +1 -1
- package/README.md +0 -1
- package/apps/ServiceWorker.mjs +2 -2
- package/apps/portal/index.html +1 -1
- package/apps/portal/view/about/Container.mjs +1 -1
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/apps/portal/view/services/Component.mjs +0 -9
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/grid/bigData/ControlsContainer.mjs +142 -84
- package/package.json +8 -6
- package/resources/scss/src/examples/grid/bigData/ControlsContainer.scss +10 -1
- package/src/DefaultConfig.mjs +2 -2
- package/src/grid/View.mjs +117 -19
- package/src/main/DomAccess.mjs +18 -24
- package/src/selection/grid/RowModel.mjs +2 -0
- package/src/selection/grid/_export.mjs +8 -0
- package/src/util/ClassSystem.mjs +4 -4
package/.github/CONCEPT.md
CHANGED
package/.github/STORY.md
CHANGED
package/.github/VISION.md
CHANGED
@@ -1,142 +1,18 @@
|
|
1
1
|
# The neo.mjs vision
|
2
2
|
|
3
|
-
At this point I (Tobias) can not commit to adding dates to
|
4
|
-
After investing
|
3
|
+
At this point I (Tobias) can not commit to adding dates to planned items.
|
4
|
+
After investing 5 years of my full and unpaid working time I am in need to make up on the financial side of things.
|
5
5
|
So as long as the project is not properly funded, I can only afford to continue working on it in my spare time.
|
6
6
|
|
7
7
|
To speed up the current development there are two options:
|
8
8
|
1. Help promoting neo.mjs or jump in as a contributor (see <a href="../CONTRIBUTING.md">Contributing</a>)
|
9
9
|
2. Jump in as a sponsor to ensure I can spend more time on the neo.mjs coding side (see <a href="../BACKERS.md">Sponsors & Backers</a>)
|
10
10
|
|
11
|
-
The following items are ***not*** ordered by priority. In case certain topics are important to you, please use the issues
|
12
|
-
tracker to create an awareness (like / comment on current tickets or create new ones as needed).
|
13
11
|
|
14
12
|
Thanks for your support!
|
15
13
|
|
16
|
-
* Real World app version 2
|
17
|
-
1. Version 1 is definitely worth a look to see how to craft custom components and connect to an API,
|
18
|
-
but it is not the best starting point to see how to craft an neo.mjs app. Since the requirement was to use a given
|
19
|
-
Bootstrap theme, only component.Base is in use (since more advanced components require a neo.mjs CSS theme).
|
20
|
-
At this point I recommend to take a look at the Docs app to learn how to craft an neo.mjs app.
|
21
|
-
2. Version 2 is intended to fill this gap and will not use the Bootstrap based theme.
|
22
|
-
3. This allows us to use the full range of neo.mjs components (Toolbar, Button, List, TabContainer, Gallery, Helix, etc.)
|
23
|
-
4. Once this app is finished, it will be the perfect starting point to learn how to use neo.mjs,
|
24
|
-
so right now this item has the highest priority for me.
|
25
|
-
5. The RW2 app requires a 3rd neo.mjs theme => based on the conduit styles
|
26
|
-
6. Add the ability to switch themes inside the app
|
27
|
-
* Drag & Drop (see <a href="https://github.com/neomjs/neo/issues/16">#16</a>)
|
28
|
-
1. This ticket is definitely an epic, since DD operations happen inside the main thread, while the handlers will
|
29
|
-
live inside the app thread.
|
30
|
-
2. Once DD is in place, we can create a real slider component (see <a href="https://github.com/neomjs/neo/issues/18">#18</a>)
|
31
|
-
3. We can create Dialogs (Windows), which can get moved and resized (see <a href="https://github.com/neomjs/neo/issues/15">#15</a>)
|
32
|
-
4. We can create sortable tabs (see <a href="https://github.com/neomjs/neo/issues/23">#23</a>)
|
33
|
-
* Docs App version 2
|
34
|
-
1. I am not planning to re-create the existing app, but enhance it with more features:
|
35
|
-
2. Support for showing mixins inside the class views (<a href="https://github.com/neomjs/neo/issues/99">#99</a>)
|
36
|
-
3. Add tooltips (especially for the Configs, Methods & Events buttons => navigation shortcut)
|
37
|
-
4. Expandable class member items (add the ability to expand or collapse items to make the list shorter)
|
38
|
-
5. Writing more guides
|
39
|
-
6. Enhance the example views:
|
40
|
-
1. The example components should get shown inside a tabContainer: first tab containing the component,
|
41
|
-
second tab a source code view of the example
|
42
|
-
2. It should be possible to export the current configs (e.g. 3rd tab, configs as JSON)
|
43
|
-
3. The configuration container should be collapsible (using a sliding animation)
|
44
|
-
4. Add a second tab to the config area to show theme css vars and make them changeable
|
45
|
-
7. class member inheritance: when overriding a config or assigning a value to a parent one, the parent config
|
46
|
-
should get listed (including its initial value)
|
47
|
-
* Build Scripts
|
48
|
-
1. The current scripts work fine inside the neo repository. Since neo.mjs can now get used as a node module,
|
49
|
-
enhancements feel necessary.
|
50
|
-
1. An npx create-app script (see <a href="https://github.com/neomjs/neo/issues/90">#90</a>)
|
51
|
-
2. The build-my-apps scripts should work as well, when used outside of the repo (manually hacked this into the
|
52
|
-
Real World app version 1)
|
53
|
-
* Mobile Support
|
54
|
-
1. Add touch based events (swipe, long-tap, etc.) to the global domListeners
|
55
|
-
2. Split the current events into desktop & mobile and add a Neo.config to choose which ones to use
|
56
|
-
3. Use the events based on the browser feature detection
|
57
|
-
4. Create new components and adjust current ones to better work on mobile
|
58
|
-
* Mobile Docs App
|
59
|
-
1. Create a new UI or make the current one responsive
|
60
|
-
* Make the Data worker more meaningful
|
61
|
-
1. Right now, the data worker only executes the XHR requests
|
62
|
-
2. Rich originally planned to let stores live inside this thread, but this would create a lot more async logic inside
|
63
|
-
the app thread, plus it does not make sense for stores with little data
|
64
|
-
3. What should be possible: for remote stores which need to parse the data getting back from an API, these transformations
|
65
|
-
should happen inside the app thread (like a data reader)
|
66
|
-
4. Remote stores with local sorting: this sorting could happen inside the data worker as well
|
67
|
-
* Data Package version 2
|
68
|
-
1. The collection class is already very powerful (needs some polishing though). For the first version of the data
|
69
|
-
package, stores were extending collection.Base. Afterwards records were introduced (not instances of data.Model,
|
70
|
-
but a super lightweight extension of a JS Object). At this point, stores should no longer extend a collection,
|
71
|
-
but use one instance instead (e.g. a collection config).
|
72
|
-
2. More polishing of Sorters & Filters & add the ability for stores to sort & filter per remote (adding params to
|
73
|
-
each request).
|
74
|
-
3. Enhance the API for stores: when using a collection, several methods need to get bound to the collection, but
|
75
|
-
ensuring that data objects get transformed into records.
|
76
|
-
4. use data fields: each store should exactly use one instance of data.Model. Inside a model, you can define fields.
|
77
|
-
Fields should either be a singleton or a class with static methods. We need to provide parsing methods, e.g. toString()
|
78
|
-
for a field type "String".
|
79
|
-
* Finish the implementation for Tooltips; Rectangle utility class (see <a href="https://github.com/neomjs/neo/issues/51">#51</a>)
|
80
|
-
* Finish the implementation for form.field.Chip (see <a href="https://github.com/neomjs/neo/issues/31">#31</a>)
|
81
|
-
* Create a coding style guide (see <a href="https://github.com/neomjs/neo/issues/93">#93</a>)
|
82
|
-
* Virtual Dom Engine enhancements
|
83
|
-
1. Add a 2nd mode where ids do get ignored (e.g. for comparing content on fixed positions like grid rows)
|
84
|
-
2. Add an option to specify the the tree depth to compare (e.g. only the first level for containers)
|
85
|
-
3. Refactor vdom.Helper: createDeltas
|
86
|
-
* Create a buffered Grid
|
87
|
-
1. So far I mostly focused on table.Container. Since tables are not good for buffering (too many layout reflows),
|
88
|
-
it is time to pick up the grid.Container implementation again.
|
89
|
-
2. The grid.Container will use divs only. grids need a rowHeight config, since it has to be fixed for buffering.
|
90
|
-
3. Add 1-2 more rows as the visible area can show and adjust the content when scrolling (move the top row div to
|
91
|
-
the bottom or vice versa)
|
92
|
-
4. when clicking on the scrollbar, adjust the full grid cell content
|
93
|
-
5. add column reordering via DD (relies on the DD implementation)
|
94
|
-
6. add cell-editing
|
95
|
-
7. add action columns
|
96
|
-
8. add buffering for horizontal scrolling as well
|
97
|
-
* Create a Router
|
98
|
-
* Enable neo.mjs to run in node
|
99
|
-
1. There are some uses of "self", which work fine inside the main thread & inside the worker scope, but not in node
|
100
|
-
* neo.mjs based middle-ware (see <a href="https://github.com/neomjs/neo/issues/19">#19</a>)
|
101
|
-
* Enhance the Siesta tests to run inside a node env
|
102
|
-
* Write more tests (Epic!)
|
103
|
-
* main.mixins.FeatureDetection
|
104
|
-
1. Add meaningful checks for relevant features
|
105
|
-
* Create a Website for the neo.mjs project
|
106
|
-
1. Right now, only Online Examples are in place
|
107
|
-
2. The examples need to support mobile
|
108
|
-
3. Intro Texts are needed (see <a href="https://github.com/neomjs/neo/issues/7">#7</a>)
|
109
|
-
4. A Logo for neo.mjs is needed
|
110
|
-
* Create a MarketPlace for User Extensions / Custom Components
|
111
|
-
1. for UX which don't fit into the framework repo
|
112
|
-
2. for custom themes
|
113
|
-
3. add the ability for developers / companies to sell their extensions vs a fee (similar to the apple app store)
|
114
|
-
* Create a Chrome extension to make the debugging / working with neo.mjs more easy
|
115
|
-
1. see all created stores & their data
|
116
|
-
2. Access to the component manager
|
117
|
-
3. Ability to click on the screen and receive the closest neo.mjs component
|
118
|
-
4. Ability to see the full component tree of your app
|
119
|
-
* Use SharedWorker(s)
|
120
|
-
1. Optional
|
121
|
-
2. Once Chrome supports using JS modules inside shared workers
|
122
|
-
3. This will allow us to create ***multi screen apps***
|
123
|
-
4. Imagine dragging a dialog outside of your browser tab and it appears in another one
|
124
|
-
|
125
|
-
***TL-BR***: This list is most likely not even complete.
|
126
|
-
You don't need to be a genius in math to figure out that this is a massive amount of work.
|
127
|
-
If I would create neo.mjs just for myself, there would be no Docs app, no Real World 1 or 2 app.
|
128
|
-
I already put in a massive amount of time to enable you to use neo.mjs as well and I don't expect anyone to say thank
|
129
|
-
you for doing this (although it is nice to hear :)).
|
130
|
-
|
131
|
-
I would even be willing to continue this project on my own, but I would run bankrupt rather sooner than later without
|
132
|
-
funding. So, assuming you know how the romantic idea of Open Source works, let me repeat the first part again:
|
133
|
-
|
134
|
-
To speed up the current development there are two options:
|
135
|
-
1. Help promoting neo.mjs or jump in as a contributor (see <a href="../CONTRIBUTING.md">Contributing</a>)
|
136
|
-
2. Jump in as a sponsor to ensure I can spend more time on the neo.mjs coding side (see <a href="../BACKERS.md">Sponsors & Backers</a>)
|
137
14
|
|
138
15
|
Best regards, Tobias
|
139
16
|
|
140
17
|
<br><br>
|
141
18
|
Copyright (c) 2015 - today, <a href="https://www.linkedin.com/in/tobiasuhlig/">Tobias Uhlig</a>
|
142
|
-
& <a href="https://www.linkedin.com/in/richwaters/">Rich Waters</a>
|
package/BACKERS.md
CHANGED
package/CONTRIBUTING.md
CHANGED
package/LICENSE
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
MIT License
|
2
2
|
|
3
|
-
Copyright (c) 2015 - today, Tobias Uhlig
|
3
|
+
Copyright (c) 2015 - today, Tobias Uhlig
|
4
4
|
|
5
5
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
6
|
of this software and associated documentation files (the "Software"), to deal
|
package/README.md
CHANGED
package/apps/ServiceWorker.mjs
CHANGED
package/apps/portal/index.html
CHANGED
@@ -37,7 +37,7 @@ class Container extends Base {
|
|
37
37
|
picture : 'rwaters.png',
|
38
38
|
profileGitHub : 'https://github.com/rwaters',
|
39
39
|
profileLinkedIn: 'https://www.linkedin.com/in/rwaters/',
|
40
|
-
teamRole : '
|
40
|
+
teamRole : 'Contributor'
|
41
41
|
}, {
|
42
42
|
module : MemberContainer,
|
43
43
|
location : 'Germany',
|
@@ -21,15 +21,6 @@ class Component extends BaseComponent {
|
|
21
21
|
vdom:
|
22
22
|
{cn: [
|
23
23
|
{tag: 'h1', cls: ['neo-h1'], html: 'Services'},
|
24
|
-
{cls: ['info-block'], cn: [
|
25
|
-
{tag: 'h2', cls: ['neo-h2'], html: 'Weekly Workshops'},
|
26
|
-
{tag: 'p', html: [
|
27
|
-
'We are doing weekly workshops on Thursdays 18:30 CEST (12:30am EST) for 60m free of charge.</br>',
|
28
|
-
'Ping us inside our ',
|
29
|
-
'<a href="https://join.slack.com/t/neomjs/shared_invite/zt-6c50ueeu-3E1~M4T9xkNnb~M_prEEOA">Slack Channel</a>, ',
|
30
|
-
'in case you would like to join us.'
|
31
|
-
].join('')},
|
32
|
-
]},
|
33
24
|
{cls: ['info-block'], cn: [
|
34
25
|
{tag: 'h2', cls: ['neo-h2'], html: 'Professional Trainings'},
|
35
26
|
{tag: 'p', html: [
|
@@ -1,6 +1,8 @@
|
|
1
|
-
import
|
2
|
-
import
|
3
|
-
import
|
1
|
+
import * as selection from '../../../src/selection/grid/_export.mjs';
|
2
|
+
import ComboBox from '../../../src/form/field/ComboBox.mjs';
|
3
|
+
import Container from '../../../src/container/Base.mjs';
|
4
|
+
import Radio from '../../../src/form/field/Radio.mjs';
|
5
|
+
import TabContainer from '../../../src/tab/Container.mjs';
|
4
6
|
|
5
7
|
/**
|
6
8
|
* @class Neo.examples.grid.bigData.ControlsContainer
|
@@ -26,91 +28,137 @@ class ControlsContainer extends Container {
|
|
26
28
|
handler: 'up.onControlsToggleButtonClick',
|
27
29
|
iconCls: 'fas fa-bars'
|
28
30
|
}, {
|
29
|
-
module:
|
31
|
+
module: TabContainer,
|
30
32
|
cls : ['neo-examples-bigdata-controls-container-content'],
|
31
|
-
layout: 'vbox',
|
32
|
-
|
33
|
-
itemDefaults: {
|
34
|
-
module : ComboBox,
|
35
|
-
clearable : false,
|
36
|
-
displayField: 'id',
|
37
|
-
editable : false
|
38
|
-
},
|
39
33
|
|
40
34
|
items: [{
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
35
|
+
module: Container,
|
36
|
+
header: {text: 'Settings'},
|
37
|
+
layout: 'vbox',
|
38
|
+
|
39
|
+
itemDefaults: {
|
40
|
+
module : ComboBox,
|
41
|
+
clearable : false,
|
42
|
+
displayField: 'id',
|
43
|
+
editable : false
|
44
|
+
},
|
45
|
+
|
46
|
+
items: [{
|
47
|
+
labelText : 'Amount Rows',
|
48
|
+
labelWidth: 120,
|
49
|
+
listeners : {change: 'up.onAmountRowsChange'},
|
50
|
+
store : ['1000', '5000', '10000', '20000', '50000'],
|
51
|
+
value : '1000',
|
52
|
+
width : 200
|
53
|
+
}, {
|
54
|
+
labelText : 'Amount Columns',
|
55
|
+
labelWidth: 145,
|
56
|
+
listeners : {change: 'up.onAmountColumnsChange'},
|
57
|
+
store : ['10', '25', '50', '75', '100'],
|
58
|
+
value : '50',
|
59
|
+
width : 200
|
60
|
+
}, {
|
61
|
+
labelText : 'Buffer Rows',
|
62
|
+
labelWidth: 145,
|
63
|
+
listeners : {change: 'up.onBufferRowRangeChange'},
|
64
|
+
store : ['0', '3', '5', '10', '25', '50'],
|
65
|
+
value : '5',
|
66
|
+
width : 200
|
67
|
+
}, {
|
68
|
+
labelText : 'Buffer Columns',
|
69
|
+
labelWidth: 145,
|
70
|
+
listeners : {change: 'up.onBufferColumnRangeChange'},
|
71
|
+
store : ['0', '3', '5', '10', '20'],
|
72
|
+
value : '3',
|
73
|
+
width : 200
|
74
|
+
}, {
|
75
|
+
module : Radio,
|
76
|
+
checked : true,
|
77
|
+
labelText : 'Theme',
|
78
|
+
labelWidth : 70,
|
79
|
+
listeners : {change: 'up.onThemeRadioChange'},
|
80
|
+
name : 'theme',
|
81
|
+
style : {marginTop: '2em'},
|
82
|
+
value : 'neo-theme-dark',
|
83
|
+
valueLabelText: 'Dark'
|
84
|
+
}, {
|
85
|
+
module : Radio,
|
86
|
+
labelText : '',
|
87
|
+
labelWidth : 70,
|
88
|
+
listeners : {change: 'up.onThemeRadioChange'},
|
89
|
+
name : 'theme',
|
90
|
+
style : {marginTop: '.3em'},
|
91
|
+
value : 'neo-theme-light',
|
92
|
+
valueLabelText: 'Light'
|
93
|
+
}, {
|
94
|
+
ntype: 'label',
|
95
|
+
style: {marginTop: '2em'},
|
96
|
+
text : 'Filters'
|
97
|
+
}, {
|
98
|
+
ntype : 'textfield',
|
99
|
+
clearable : true,
|
100
|
+
editable : true,
|
101
|
+
labelText : 'Firstname',
|
102
|
+
labelWidth: 90,
|
103
|
+
listeners : {change: 'up.onFilterFieldChange'},
|
104
|
+
name : 'firstname',
|
105
|
+
style : {marginTop: '.3em'},
|
106
|
+
width : 200
|
107
|
+
}, {
|
108
|
+
ntype : 'textfield',
|
109
|
+
clearable : true,
|
110
|
+
editable : true,
|
111
|
+
labelText : 'Lastname',
|
112
|
+
labelWidth: 90,
|
113
|
+
listeners : {change: 'up.onFilterFieldChange'},
|
114
|
+
name : 'lastname',
|
115
|
+
width : 200
|
116
|
+
}, {
|
117
|
+
ntype : 'label',
|
118
|
+
reference: 'count-rows-label',
|
119
|
+
style : {marginTop: '1em'}
|
120
|
+
}]
|
110
121
|
}, {
|
111
|
-
|
112
|
-
|
113
|
-
|
122
|
+
module: Container,
|
123
|
+
header: {text: 'Selection'},
|
124
|
+
layout: 'vbox',
|
125
|
+
|
126
|
+
itemDefaults: {
|
127
|
+
module : Radio,
|
128
|
+
hideLabel : true,
|
129
|
+
hideValueLabel: false,
|
130
|
+
labelText : '',
|
131
|
+
listeners : {change: 'up.onSelectionModelChange'},
|
132
|
+
name : 'selectionModel',
|
133
|
+
style : {marginTop: '.3em'},
|
134
|
+
width : 200
|
135
|
+
},
|
136
|
+
|
137
|
+
items: [{
|
138
|
+
ntype: 'label',
|
139
|
+
style: {marginTop: 0},
|
140
|
+
text : 'Pick the Selection Model'
|
141
|
+
}, {
|
142
|
+
style : {marginTop: '1em'},
|
143
|
+
selectionModel: selection.CellModel,
|
144
|
+
valueLabelText: 'Cell'
|
145
|
+
}, {
|
146
|
+
selectionModel: selection.ColumnModel,
|
147
|
+
valueLabelText: 'Column'
|
148
|
+
}, {
|
149
|
+
checked : true,
|
150
|
+
selectionModel: selection.RowModel,
|
151
|
+
valueLabelText: 'Row'
|
152
|
+
}, {
|
153
|
+
selectionModel: selection.CellColumnModel,
|
154
|
+
valueLabelText: 'Cell & Column'
|
155
|
+
}, {
|
156
|
+
selectionModel: selection.CellRowModel,
|
157
|
+
valueLabelText: 'Cell & Row'
|
158
|
+
}, {
|
159
|
+
selectionModel: selection.CellColumnRowModel,
|
160
|
+
valueLabelText: 'Cell & Column & Row'
|
161
|
+
}]
|
114
162
|
}]
|
115
163
|
}],
|
116
164
|
/**
|
@@ -204,6 +252,16 @@ class ControlsContainer extends Container {
|
|
204
252
|
this.grid.store.getFilter(data.component.name).value = data.value
|
205
253
|
}
|
206
254
|
|
255
|
+
/**
|
256
|
+
* @param {Object} data
|
257
|
+
*/
|
258
|
+
onSelectionModelChange(data) {
|
259
|
+
this.grid.view.selectionModel = data.component.selectionModel
|
260
|
+
}
|
261
|
+
|
262
|
+
/**
|
263
|
+
*
|
264
|
+
*/
|
207
265
|
updateRowsLabel() {
|
208
266
|
let {store} = this.grid;
|
209
267
|
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "neo.mjs",
|
3
|
-
"version": "8.
|
3
|
+
"version": "8.22.0",
|
4
4
|
"description": "The webworkers driven UI framework",
|
5
5
|
"type": "module",
|
6
6
|
"repository": {
|
@@ -36,9 +36,11 @@
|
|
36
36
|
"webworker",
|
37
37
|
"ecmascript",
|
38
38
|
"css",
|
39
|
-
"json"
|
39
|
+
"json",
|
40
|
+
"react-alternative",
|
41
|
+
"angular-alternative"
|
40
42
|
],
|
41
|
-
"author": "Tobias Uhlig
|
43
|
+
"author": "Tobias Uhlig",
|
42
44
|
"license": "MIT",
|
43
45
|
"bugs": {
|
44
46
|
"url": "https://github.com/neomjs/neo/issues"
|
@@ -54,16 +56,16 @@
|
|
54
56
|
"envinfo": "^7.14.0",
|
55
57
|
"fs-extra": "^11.3.0",
|
56
58
|
"highlightjs-line-numbers.js": "^2.9.0",
|
57
|
-
"inquirer": "^12.4.
|
59
|
+
"inquirer": "^12.4.2",
|
58
60
|
"marked": "^15.0.7",
|
59
61
|
"monaco-editor": "0.50.0",
|
60
62
|
"neo-jsdoc": "1.0.1",
|
61
63
|
"neo-jsdoc-x": "1.0.5",
|
62
64
|
"postcss": "^8.5.2",
|
63
|
-
"sass": "^1.
|
65
|
+
"sass": "^1.85.0",
|
64
66
|
"siesta-lite": "5.5.2",
|
65
67
|
"url": "^0.11.4",
|
66
|
-
"webpack": "^5.
|
68
|
+
"webpack": "^5.98.0",
|
67
69
|
"webpack-cli": "^6.0.1",
|
68
70
|
"webpack-dev-server": "^5.2.0",
|
69
71
|
"webpack-hook-plugin": "^1.0.7",
|
@@ -15,8 +15,17 @@
|
|
15
15
|
.neo-examples-bigdata-controls-container-content {
|
16
16
|
box-shadow: 0 5px 10px rgba(75,75,75,.3);
|
17
17
|
opacity : 0;
|
18
|
-
padding : .5em 1em;
|
19
18
|
transition: opacity 250ms ease-out;
|
19
|
+
|
20
|
+
> .neo-container {
|
21
|
+
overflow-y: auto;
|
22
|
+
padding : .5em 1em;
|
23
|
+
|
24
|
+
> .neo-container {
|
25
|
+
flex : none;
|
26
|
+
height: fit-content;
|
27
|
+
}
|
28
|
+
}
|
20
29
|
}
|
21
30
|
|
22
31
|
&.neo-expanded {
|
package/src/DefaultConfig.mjs
CHANGED
@@ -263,12 +263,12 @@ const DefaultConfig = {
|
|
263
263
|
useVdomWorker: true,
|
264
264
|
/**
|
265
265
|
* buildScripts/injectPackageVersion.mjs will update this value
|
266
|
-
* @default '8.
|
266
|
+
* @default '8.22.0'
|
267
267
|
* @memberOf! module:Neo
|
268
268
|
* @name config.version
|
269
269
|
* @type String
|
270
270
|
*/
|
271
|
-
version: '8.
|
271
|
+
version: '8.22.0'
|
272
272
|
};
|
273
273
|
|
274
274
|
Object.assign(DefaultConfig, {
|
package/src/grid/View.mjs
CHANGED
@@ -81,6 +81,12 @@ class GridView extends Component {
|
|
81
81
|
* @member {Object} keys
|
82
82
|
*/
|
83
83
|
keys: {},
|
84
|
+
/**
|
85
|
+
* Stores the indexes of the first & last mounted rows, including bufferRowRange
|
86
|
+
* @member {Number[]} mountedRows=[0,0]
|
87
|
+
* @protected
|
88
|
+
*/
|
89
|
+
mountedRows: [0, 0],
|
84
90
|
/**
|
85
91
|
* @member {String} role='rowgroup'
|
86
92
|
*/
|
@@ -116,6 +122,12 @@ class GridView extends Component {
|
|
116
122
|
* @protected
|
117
123
|
*/
|
118
124
|
visibleColumns_: [0, 0],
|
125
|
+
/**
|
126
|
+
* Stores the indexes of the first & last visible rows, excluding bufferRowRange
|
127
|
+
* @member {Number[]} visibleRows=[0,0]
|
128
|
+
* @protected
|
129
|
+
*/
|
130
|
+
visibleRows: [0, 0],
|
119
131
|
/**
|
120
132
|
* @member {String[]} wrapperCls=[]
|
121
133
|
*/
|
@@ -146,6 +158,19 @@ class GridView extends Component {
|
|
146
158
|
*/
|
147
159
|
scrollTimeoutId = null
|
148
160
|
|
161
|
+
/**
|
162
|
+
* @member {String[]} selectedRows
|
163
|
+
*/
|
164
|
+
get selectedCells() {
|
165
|
+
let {selectionModel} = this;
|
166
|
+
|
167
|
+
if (selectionModel.ntype.includes('cell')) {
|
168
|
+
return selectionModel.items
|
169
|
+
}
|
170
|
+
|
171
|
+
return []
|
172
|
+
}
|
173
|
+
|
149
174
|
/**
|
150
175
|
* @member {String[]} selectedRows
|
151
176
|
*/
|
@@ -193,7 +218,7 @@ class GridView extends Component {
|
|
193
218
|
*/
|
194
219
|
afterSetAvailableHeight(value, oldValue) {
|
195
220
|
if (value > 0) {
|
196
|
-
this.availableRows = Math.ceil(value / this.rowHeight)
|
221
|
+
this.availableRows = Math.ceil(value / this.rowHeight) - 1
|
197
222
|
}
|
198
223
|
}
|
199
224
|
|
@@ -308,10 +333,11 @@ class GridView extends Component {
|
|
308
333
|
if (value.y !== oldValue?.y) {
|
309
334
|
newStartIndex = Math.floor(value.y / me.rowHeight);
|
310
335
|
|
311
|
-
if (newStartIndex
|
312
|
-
me.startIndex = 0
|
313
|
-
} else if (Math.abs(me.startIndex - newStartIndex) >= bufferRowRange) {
|
336
|
+
if (Math.abs(me.startIndex - newStartIndex) >= bufferRowRange) {
|
314
337
|
me.startIndex = newStartIndex
|
338
|
+
} else {
|
339
|
+
me.visibleRows[0] = newStartIndex;
|
340
|
+
me.visibleRows[1] = newStartIndex + me.availableRows
|
315
341
|
}
|
316
342
|
}
|
317
343
|
}
|
@@ -359,13 +385,13 @@ class GridView extends Component {
|
|
359
385
|
*/
|
360
386
|
applyRendererOutput(data) {
|
361
387
|
let {cellId, column, columnIndex, record, rowIndex} = data,
|
362
|
-
me
|
363
|
-
gridContainer
|
364
|
-
{store}
|
365
|
-
cellCls
|
366
|
-
colspan
|
367
|
-
{dataField}
|
368
|
-
fieldValue
|
388
|
+
me = this,
|
389
|
+
gridContainer = me.parent,
|
390
|
+
{selectedCells, store} = me,
|
391
|
+
cellCls = ['neo-grid-cell'],
|
392
|
+
colspan = record[me.colspanField],
|
393
|
+
{dataField} = column,
|
394
|
+
fieldValue = record[dataField],
|
369
395
|
cellConfig, rendererOutput;
|
370
396
|
|
371
397
|
if (fieldValue === null || fieldValue === undefined) {
|
@@ -421,6 +447,10 @@ class GridView extends Component {
|
|
421
447
|
cellId = me.getCellId(record, column.dataField)
|
422
448
|
}
|
423
449
|
|
450
|
+
if (selectedCells.includes(cellId)) {
|
451
|
+
cellCls.push('neo-selected')
|
452
|
+
}
|
453
|
+
|
424
454
|
cellConfig = {
|
425
455
|
'aria-colindex': columnIndex + 1, // 1 based
|
426
456
|
id : cellId,
|
@@ -553,11 +583,10 @@ class GridView extends Component {
|
|
553
583
|
*
|
554
584
|
*/
|
555
585
|
createViewData() {
|
556
|
-
let me
|
557
|
-
{
|
558
|
-
|
559
|
-
|
560
|
-
endIndex, i;
|
586
|
+
let me = this,
|
587
|
+
{mountedRows, store} = me,
|
588
|
+
rows = [],
|
589
|
+
i;
|
561
590
|
|
562
591
|
if (
|
563
592
|
store.isLoading ||
|
@@ -569,10 +598,10 @@ class GridView extends Component {
|
|
569
598
|
return
|
570
599
|
}
|
571
600
|
|
572
|
-
|
573
|
-
|
601
|
+
// Creates the new start & end indexes
|
602
|
+
me.updateMountedAndVisibleRows();
|
574
603
|
|
575
|
-
for (i=
|
604
|
+
for (i=mountedRows[0]; i < mountedRows[1]; i++) {
|
576
605
|
rows.push(me.createRow({record: store.items[i], rowIndex: i}))
|
577
606
|
}
|
578
607
|
|
@@ -823,6 +852,7 @@ class GridView extends Component {
|
|
823
852
|
/**
|
824
853
|
* Only triggers for vertical scrolling
|
825
854
|
* @param {Object} data
|
855
|
+
* @protected
|
826
856
|
*/
|
827
857
|
onScroll({scrollTop, touches}) {
|
828
858
|
let me = this,
|
@@ -940,6 +970,55 @@ class GridView extends Component {
|
|
940
970
|
parent.lastTouchY = 0
|
941
971
|
}
|
942
972
|
|
973
|
+
/**
|
974
|
+
* Used for keyboard navigation (selection models)
|
975
|
+
* @param {Number} index
|
976
|
+
* @param {Number} step
|
977
|
+
*/
|
978
|
+
scrollByRows(index, step) {
|
979
|
+
let me = this,
|
980
|
+
{mountedRows, visibleRows} = me,
|
981
|
+
countRecords = me.store.getCount(),
|
982
|
+
newIndex = index + step,
|
983
|
+
lastRowGap, mounted, scrollPosition, visible;
|
984
|
+
|
985
|
+
if (newIndex >= countRecords) {
|
986
|
+
newIndex %= countRecords;
|
987
|
+
step = newIndex - index
|
988
|
+
}
|
989
|
+
|
990
|
+
while (newIndex < 0) {
|
991
|
+
newIndex += countRecords;
|
992
|
+
step += countRecords
|
993
|
+
}
|
994
|
+
|
995
|
+
mounted = newIndex >= mountedRows[0] && newIndex <= mountedRows[1];
|
996
|
+
|
997
|
+
// Not using >= or <=, since the first / last row might not be fully visible
|
998
|
+
visible = newIndex > visibleRows[0] && newIndex < visibleRows[1];
|
999
|
+
|
1000
|
+
if (!visible) {
|
1001
|
+
// Leaving the mounted area will re-calculate the visibleRows for us
|
1002
|
+
if (mounted) {
|
1003
|
+
visibleRows[0] += step;
|
1004
|
+
visibleRows[1] += step
|
1005
|
+
}
|
1006
|
+
|
1007
|
+
if (step < 0) {
|
1008
|
+
scrollPosition = newIndex * me.rowHeight
|
1009
|
+
} else {
|
1010
|
+
lastRowGap = me.rowHeight - (me.availableHeight % me.rowHeight);
|
1011
|
+
scrollPosition = (newIndex - me.availableRows) * me.rowHeight + lastRowGap
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
Neo.main.DomAccess.scrollTo({
|
1015
|
+
id : me.vdom.id,
|
1016
|
+
value : scrollPosition,
|
1017
|
+
windowId: me.windowId
|
1018
|
+
})
|
1019
|
+
}
|
1020
|
+
}
|
1021
|
+
|
943
1022
|
/**
|
944
1023
|
* @param {Boolean} silent=false
|
945
1024
|
*/
|
@@ -954,6 +1033,25 @@ class GridView extends Component {
|
|
954
1033
|
}
|
955
1034
|
}
|
956
1035
|
|
1036
|
+
/**
|
1037
|
+
*
|
1038
|
+
*/
|
1039
|
+
updateMountedAndVisibleRows() {
|
1040
|
+
let me = this,
|
1041
|
+
{bufferRowRange, startIndex, store} = me,
|
1042
|
+
countRecords = store.getCount(),
|
1043
|
+
endIndex = Math.min(countRecords, startIndex + me.availableRows);
|
1044
|
+
|
1045
|
+
me.visibleRows[0] = startIndex; // update the array inline
|
1046
|
+
me.visibleRows[1] = endIndex;
|
1047
|
+
|
1048
|
+
startIndex = Math.max(0, startIndex - bufferRowRange);
|
1049
|
+
endIndex = Math.min(countRecords, endIndex + bufferRowRange);
|
1050
|
+
|
1051
|
+
me.mountedRows[0] = startIndex; // update the array inline
|
1052
|
+
me.mountedRows[1] = endIndex;
|
1053
|
+
}
|
1054
|
+
|
957
1055
|
/**
|
958
1056
|
*
|
959
1057
|
*/
|
package/src/main/DomAccess.mjs
CHANGED
@@ -888,20 +888,17 @@ class DomAccess extends Base {
|
|
888
888
|
}
|
889
889
|
|
890
890
|
/**
|
891
|
+
* See: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollBy
|
891
892
|
* @param {Object} data
|
892
|
-
* @param {String} data.
|
893
|
+
* @param {String} data.behavior='auto' auto, instant, smooth
|
894
|
+
* @param {String} data.direction='top' left, top
|
893
895
|
* @param {String} data.id
|
894
896
|
* @param {Number} data.value
|
895
897
|
* @returns {Object} obj.id => the passed id
|
896
898
|
*/
|
897
|
-
scrollBy(
|
898
|
-
|
899
|
-
|
900
|
-
if (node) {
|
901
|
-
node[`scroll${Neo.capitalize(data.direction)}`] += data.value
|
902
|
-
}
|
903
|
-
|
904
|
-
return {id: data.id}
|
899
|
+
scrollBy({behavior='auto', direction='top', id, value}) {
|
900
|
+
this.getElement(id)?.scrollBy({behavior, [direction]: value});
|
901
|
+
return {id}
|
905
902
|
}
|
906
903
|
|
907
904
|
/**
|
@@ -928,7 +925,7 @@ class DomAccess extends Base {
|
|
928
925
|
if (node) {
|
929
926
|
let hasListener = 'scrollend' in window;
|
930
927
|
|
931
|
-
hasListener && document.addEventListener('scrollend', () =>resolve(), {capture: true, once: true});
|
928
|
+
hasListener && document.addEventListener('scrollend', () => resolve(), {capture: true, once: true});
|
932
929
|
|
933
930
|
node.scrollIntoView(opts);
|
934
931
|
|
@@ -941,31 +938,28 @@ class DomAccess extends Base {
|
|
941
938
|
}
|
942
939
|
|
943
940
|
/**
|
941
|
+
* See: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollTo
|
944
942
|
* @param {Object} data
|
943
|
+
* @param {String} data.behavior='auto' auto, instant, smooth
|
945
944
|
* @param {String} data.direction='top' left, top
|
946
945
|
* @param {String} data.id
|
947
946
|
* @param {Number} data.value
|
948
947
|
* @returns {Object} obj.id => the passed id
|
949
948
|
*/
|
950
|
-
scrollTo({direction='top', id, value}) {
|
951
|
-
|
952
|
-
|
953
|
-
if (node) {
|
954
|
-
node[`scroll${Neo.capitalize(direction)}`] = value
|
955
|
-
}
|
956
|
-
|
949
|
+
scrollTo({behavior='auto', direction='top', id, value}) {
|
950
|
+
this.getElement(id)?.scrollTo({behavior, [direction]: value});
|
957
951
|
return {id}
|
958
952
|
}
|
959
953
|
|
960
954
|
/**
|
961
955
|
* @param {Object} data
|
962
956
|
* @param {String} data.id
|
963
|
-
* @param {String}
|
964
|
-
* @param {
|
957
|
+
* @param {String} data.behavior='smooth'
|
958
|
+
* @param {Number} data.offset=34
|
965
959
|
* @returns {Object} obj.id => the passed id
|
966
960
|
*/
|
967
|
-
scrollToTableRow(
|
968
|
-
let node = this.getElement(
|
961
|
+
scrollToTableRow({id, behavior='smooth', offset=34}) {
|
962
|
+
let node = this.getElement(id); // tr tag
|
969
963
|
|
970
964
|
if (node) {
|
971
965
|
let tableNode = node.parentNode.parentNode,
|
@@ -974,12 +968,12 @@ class DomAccess extends Base {
|
|
974
968
|
top = node.getBoundingClientRect().top;
|
975
969
|
|
976
970
|
wrapperNode.scrollTo({
|
977
|
-
behavior
|
978
|
-
top
|
971
|
+
behavior,
|
972
|
+
top: top - tableTop - offset
|
979
973
|
})
|
980
974
|
}
|
981
975
|
|
982
|
-
return {id
|
976
|
+
return {id}
|
983
977
|
}
|
984
978
|
|
985
979
|
/**
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import CellColumnModel from './CellColumnModel.mjs';
|
2
|
+
import CellColumnRowModel from './CellColumnRowModel.mjs';
|
3
|
+
import CellModel from './CellModel.mjs';
|
4
|
+
import CellRowModel from './CellRowModel.mjs';
|
5
|
+
import ColumnModel from './ColumnModel.mjs';
|
6
|
+
import RowModel from './RowModel.mjs';
|
7
|
+
|
8
|
+
export {CellColumnModel, CellColumnRowModel, CellModel, CellRowModel, ColumnModel, RowModel};
|
package/src/util/ClassSystem.mjs
CHANGED
@@ -21,7 +21,7 @@ class ClassSystem extends Base {
|
|
21
21
|
* @returns {Neo.core.Base} instance
|
22
22
|
*/
|
23
23
|
static beforeSetInstance(config, DefaultClass=null, defaultValues={}) {
|
24
|
-
let
|
24
|
+
let configType = Neo.typeOf(config);
|
25
25
|
|
26
26
|
if (Neo.isString(DefaultClass)) {
|
27
27
|
DefaultClass = Neo.ns(DefaultClass)
|
@@ -29,9 +29,9 @@ class ClassSystem extends Base {
|
|
29
29
|
|
30
30
|
if (!config && DefaultClass) {
|
31
31
|
config = Neo.create(DefaultClass, defaultValues)
|
32
|
-
} else if (
|
32
|
+
} else if (configType === 'NeoClass') {
|
33
33
|
config = Neo.create(config, defaultValues)
|
34
|
-
} else if (
|
34
|
+
} else if (configType === 'Object') {
|
35
35
|
if (config.ntype) {
|
36
36
|
config = Neo.ntype({
|
37
37
|
...defaultValues,
|
@@ -51,7 +51,7 @@ class ClassSystem extends Base {
|
|
51
51
|
|
52
52
|
config = Neo.create(newConfig)
|
53
53
|
}
|
54
|
-
} else if (
|
54
|
+
} else if (configType === 'NeoInstance') {
|
55
55
|
if (defaultValues?.listeners) {
|
56
56
|
config.on(defaultValues.listeners)
|
57
57
|
}
|