neo.mjs 5.16.5 → 5.17.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/apps/ServiceWorker.mjs +2 -2
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/form/field/fileupload/MainContainer.mjs +12 -2
- package/examples/treeSelectionModel/MainContainer.mjs +142 -0
- package/examples/treeSelectionModel/app.mjs +6 -0
- package/examples/treeSelectionModel/index.html +11 -0
- package/examples/treeSelectionModel/neo-config.json +7 -0
- package/examples/treeSelectionModel/tree.json +112 -0
- package/package.json +3 -3
- package/resources/scss/src/examples/treeSelectionModel/MainContainer.scss +24 -0
- package/resources/scss/src/form/field/FileUpload.scss +16 -2
- package/resources/scss/src/tree/Accordion.scss +128 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/core/Base.mjs +6 -0
- package/src/form/field/FileUpload.mjs +130 -43
- package/src/selection/TreeAccordionModel.mjs +293 -0
- package/src/selection/TreeModel.mjs +3 -3
- package/src/tree/Accordion.mjs +280 -0
- package/src/tree/List.mjs +31 -22
@@ -0,0 +1,280 @@
|
|
1
|
+
import TreeList from '../tree/List.mjs';
|
2
|
+
import TreeAccordionModel from "../selection/TreeAccordionModel.mjs";
|
3
|
+
import NeoArray from "../util/Array.mjs";
|
4
|
+
import ClassSystemUtil from "../util/ClassSystem.mjs";
|
5
|
+
|
6
|
+
/**
|
7
|
+
* @class Neo.tree.Accordion
|
8
|
+
* @extends Neo.tree.List
|
9
|
+
*/
|
10
|
+
class AccordionTree extends TreeList {
|
11
|
+
static config = {
|
12
|
+
/**
|
13
|
+
* @member {String} className='Neo.tree.Accordion'
|
14
|
+
* @protected
|
15
|
+
*/
|
16
|
+
className: 'Neo.tree.Accordion',
|
17
|
+
/**
|
18
|
+
* @member {String} ntype='treeaccordion'
|
19
|
+
* @protected
|
20
|
+
*/
|
21
|
+
ntype: 'treeaccordion',
|
22
|
+
/**
|
23
|
+
* @member {String[]} baseCls=['neo-tree-accordion']
|
24
|
+
*/
|
25
|
+
baseCls: ['neo-tree-list'],
|
26
|
+
/**
|
27
|
+
* @member {Boolean} showCollapseExpandAllIcons=true
|
28
|
+
*/
|
29
|
+
showCollapseExpandAllIcons: false,
|
30
|
+
/**
|
31
|
+
* Set to false will auto expand root parent items and disallow collapsing
|
32
|
+
* @member {Boolean} rootParentIsCollapsible=false
|
33
|
+
*/
|
34
|
+
rootParentsAreCollapsible_: false,
|
35
|
+
/**
|
36
|
+
* Set to false to hide the initial root item
|
37
|
+
* @member {Boolean} firstParentIsVisible=true
|
38
|
+
*/
|
39
|
+
firstParentIsVisible_: true,
|
40
|
+
/**
|
41
|
+
* @member {Object} _vdom
|
42
|
+
*/
|
43
|
+
_vdom:
|
44
|
+
{
|
45
|
+
cn: [
|
46
|
+
{tag: 'ul', cls: ['neo-list-container', 'neo-list', 'neo-accordion-style'], tabIndex: -1, cn: []}
|
47
|
+
]
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
onConstructed() {
|
52
|
+
super.onConstructed();
|
53
|
+
let me = this;
|
54
|
+
|
55
|
+
me.addDomListeners({
|
56
|
+
focusin: me.onFocus,
|
57
|
+
scope : me
|
58
|
+
})
|
59
|
+
}
|
60
|
+
|
61
|
+
/**
|
62
|
+
* Called when changing firstParentIsVisible
|
63
|
+
* First store item gets marked and additional css class
|
64
|
+
*
|
65
|
+
* @param {Boolean} value
|
66
|
+
* @param {Boolean} oldValue
|
67
|
+
*/
|
68
|
+
afterSetFirstParentIsVisible(value, oldValue) {
|
69
|
+
const toggleFn = !value ? 'addCls' : 'removeCls';
|
70
|
+
|
71
|
+
this[toggleFn]('first-parent-not-visible');
|
72
|
+
|
73
|
+
if (this.store.first()) {
|
74
|
+
this.store.first().visible = value;
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
/**
|
79
|
+
* Called when changing rootParentsAreCollapsible
|
80
|
+
* Ensures that root items are expanded if not collapsible
|
81
|
+
*
|
82
|
+
* @param {Boolean} value
|
83
|
+
* @param {Boolean} oldValue
|
84
|
+
*/
|
85
|
+
afterSetRootParentsAreCollapsible(value, oldValue) {
|
86
|
+
const me = this,
|
87
|
+
toggleFn = !value ? 'addCls' : 'removeCls';
|
88
|
+
|
89
|
+
me[toggleFn]('root-not-collapsible');
|
90
|
+
|
91
|
+
if (me.rendered && value === false) {
|
92
|
+
const store = me.store;
|
93
|
+
|
94
|
+
store.items.forEach(record => {
|
95
|
+
if (record.parentId === null && !record.isLeaf) {
|
96
|
+
me.expandItem(record);
|
97
|
+
}
|
98
|
+
})
|
99
|
+
}
|
100
|
+
}
|
101
|
+
|
102
|
+
/**
|
103
|
+
* Triggered before the selectionModel config gets changed.
|
104
|
+
* @param {Neo.selection.Model} value
|
105
|
+
* @param {Neo.selection.Model} oldValue
|
106
|
+
* @returns {Neo.selection.Model}
|
107
|
+
* @protected
|
108
|
+
*/
|
109
|
+
beforeSetSelectionModel(value, oldValue) {
|
110
|
+
oldValue?.destroy();
|
111
|
+
|
112
|
+
return ClassSystemUtil.beforeSetInstance(value, TreeAccordionModel);
|
113
|
+
}
|
114
|
+
|
115
|
+
/**
|
116
|
+
* @param {String} [parentId] The parent node
|
117
|
+
* @param {Object} [vdomRoot] The vdom template root for the current sub tree
|
118
|
+
* @param {Number} level The hierarchy level of the tree
|
119
|
+
* @returns {Object} vdomRoot
|
120
|
+
* @protected
|
121
|
+
*/
|
122
|
+
createItems(parentId, vdomRoot, level) {
|
123
|
+
let me = this,
|
124
|
+
items = me.store.find('parentId', parentId),
|
125
|
+
itemCls = me.itemCls,
|
126
|
+
folderCls = me.folderCls,
|
127
|
+
cls, tmpRoot;
|
128
|
+
|
129
|
+
if (items.length > 0) {
|
130
|
+
if (!vdomRoot.cn) {
|
131
|
+
vdomRoot.cn = [];
|
132
|
+
}
|
133
|
+
|
134
|
+
if (parentId !== null) {
|
135
|
+
vdomRoot.cn.push({
|
136
|
+
tag : 'ul',
|
137
|
+
cls : ['neo-list'],
|
138
|
+
cn : [],
|
139
|
+
style: {
|
140
|
+
paddingLeft: '15px'
|
141
|
+
}
|
142
|
+
});
|
143
|
+
|
144
|
+
tmpRoot = vdomRoot.cn[vdomRoot.cn.length - 1];
|
145
|
+
} else {
|
146
|
+
tmpRoot = vdomRoot;
|
147
|
+
}
|
148
|
+
|
149
|
+
items.forEach(item => {
|
150
|
+
cls = [itemCls];
|
151
|
+
|
152
|
+
if (item.isLeaf) {
|
153
|
+
cls.push(itemCls + (item.singleton ? '-leaf-singleton' : '-leaf'));
|
154
|
+
} else {
|
155
|
+
cls.push(folderCls);
|
156
|
+
|
157
|
+
if (!item.parentId && !me.rootParentsAreCollapsible) {
|
158
|
+
|
159
|
+
cls.push('neo-not-collapsible');
|
160
|
+
if (item.collapsed) {
|
161
|
+
item.collapsed = false;
|
162
|
+
}
|
163
|
+
}
|
164
|
+
if (!item.collapsed) {
|
165
|
+
cls.push('neo-folder-open');
|
166
|
+
}
|
167
|
+
}
|
168
|
+
|
169
|
+
tmpRoot.cn.push({
|
170
|
+
tag : 'li',
|
171
|
+
cls,
|
172
|
+
id : me.getItemId(item.id),
|
173
|
+
cn : [{
|
174
|
+
tag : 'span',
|
175
|
+
cls : ['neo-accordion-item-icon', item.iconCls],
|
176
|
+
removeDom: !item.isLeaf
|
177
|
+
}, {
|
178
|
+
cls : [itemCls + '-content'],
|
179
|
+
style: {pointerEvents: 'none'},
|
180
|
+
cn : [{
|
181
|
+
tag : 'span',
|
182
|
+
cls : [itemCls + '-content-header'],
|
183
|
+
innerHTML: item.name
|
184
|
+
}, {
|
185
|
+
tag : 'span',
|
186
|
+
cls : [itemCls + '-content-text'],
|
187
|
+
innerHTML: item.content
|
188
|
+
}]
|
189
|
+
}],
|
190
|
+
style: {
|
191
|
+
padding : '10px',
|
192
|
+
position: item.isLeaf ? null : 'sticky',
|
193
|
+
top : item.isLeaf ? null : (level * 38) + 'px',
|
194
|
+
zIndex : item.isLeaf ? null : (20 / (level + 1)),
|
195
|
+
}
|
196
|
+
});
|
197
|
+
|
198
|
+
tmpRoot = me.createItems(item.id, tmpRoot, level + 1);
|
199
|
+
});
|
200
|
+
}
|
201
|
+
|
202
|
+
return vdomRoot;
|
203
|
+
}
|
204
|
+
|
205
|
+
|
206
|
+
/**
|
207
|
+
* Expands an item based on the reord
|
208
|
+
* @param {Object} record
|
209
|
+
*/
|
210
|
+
expandItem(record) {
|
211
|
+
const me = this,
|
212
|
+
itemId = me.getItemId(record[me.getKeyProperty()]),
|
213
|
+
item = me.getVdomChild(itemId);
|
214
|
+
|
215
|
+
record.collapsed = false;
|
216
|
+
|
217
|
+
NeoArray.add(item.cls, 'neo-folder-open');
|
218
|
+
me.update();
|
219
|
+
}
|
220
|
+
|
221
|
+
/**
|
222
|
+
* @param {Object} item
|
223
|
+
* @param {Object} data
|
224
|
+
*/
|
225
|
+
onItemClick(item, data) {
|
226
|
+
super.onItemClick(item, data);
|
227
|
+
|
228
|
+
const me = this,
|
229
|
+
selectionModel = me.selectionModel,
|
230
|
+
itemId = item.id,
|
231
|
+
// ! todo make it String
|
232
|
+
id = Number(itemId.split('__')[1]),
|
233
|
+
record = me.store.get(id);
|
234
|
+
|
235
|
+
selectionModel.select(item.id);
|
236
|
+
|
237
|
+
if (!record.isLeaf) {
|
238
|
+
/**
|
239
|
+
* The folderItemClick event fires when a click occurs on a list item which does have child items.
|
240
|
+
* Passes the item record to the event handler.
|
241
|
+
* @event folderItemClick
|
242
|
+
* @returns {Object} record
|
243
|
+
*/
|
244
|
+
me.fire('folderItemClick', {record});
|
245
|
+
|
246
|
+
record.collapsed = !record.collapsed
|
247
|
+
}
|
248
|
+
}
|
249
|
+
|
250
|
+
/**
|
251
|
+
* To place the root item at the correct location
|
252
|
+
* @returns {Object}
|
253
|
+
*/
|
254
|
+
getListItemsRoot() {
|
255
|
+
return this.vdom.cn[0];
|
256
|
+
}
|
257
|
+
|
258
|
+
/**
|
259
|
+
* Accordion gaining focus without selection => setSelection
|
260
|
+
* @param {Object} data
|
261
|
+
*/
|
262
|
+
onFocus(data) {
|
263
|
+
const me = this,
|
264
|
+
selModel = me.selectionModel,
|
265
|
+
selection = selModel.getSelection()[0];
|
266
|
+
|
267
|
+
if (!selection) selModel.selectRoot();
|
268
|
+
}
|
269
|
+
|
270
|
+
// Todo Might be needed
|
271
|
+
onStoreLoad() {
|
272
|
+
}
|
273
|
+
|
274
|
+
onStoreRecordChange() {
|
275
|
+
}
|
276
|
+
}
|
277
|
+
|
278
|
+
Neo.applyClassConfig(AccordionTree);
|
279
|
+
|
280
|
+
export default AccordionTree
|
package/src/tree/List.mjs
CHANGED
@@ -32,6 +32,10 @@ class Tree extends Base {
|
|
32
32
|
* @member {Neo.draggable.tree.DragZone|null} dragZone=null
|
33
33
|
*/
|
34
34
|
dragZone: null,
|
35
|
+
/**
|
36
|
+
* @member {String} folderCls='neo-list-folder'
|
37
|
+
*/
|
38
|
+
folderCls: 'neo-list-folder',
|
35
39
|
/**
|
36
40
|
* @member {Boolean} showCollapseExpandAllIcons=true
|
37
41
|
*/
|
@@ -56,9 +60,11 @@ class Tree extends Base {
|
|
56
60
|
* @member {Object} _vdom
|
57
61
|
*/
|
58
62
|
_vdom:
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
{
|
64
|
+
cn: [
|
65
|
+
{tag: 'ul', cls: ['neo-list-container', 'neo-list'], tabIndex: -1, cn: []}
|
66
|
+
]
|
67
|
+
}
|
62
68
|
}
|
63
69
|
|
64
70
|
/**
|
@@ -121,6 +127,7 @@ class Tree extends Base {
|
|
121
127
|
*/
|
122
128
|
beforeSetSelectionModel(value, oldValue) {
|
123
129
|
oldValue?.destroy();
|
130
|
+
|
124
131
|
return ClassSystemUtil.beforeSetInstance(value, TreeModel);
|
125
132
|
}
|
126
133
|
|
@@ -146,7 +153,7 @@ class Tree extends Base {
|
|
146
153
|
* Collapses all folders
|
147
154
|
* @param {Boolean} [silent]=false Set silent to true to prevent a vnode update
|
148
155
|
*/
|
149
|
-
collapseAll(silent=false) {
|
156
|
+
collapseAll(silent = false) {
|
150
157
|
let me = this,
|
151
158
|
vdom = me.vdom,
|
152
159
|
hasMatch = false,
|
@@ -176,8 +183,10 @@ class Tree extends Base {
|
|
176
183
|
* @protected
|
177
184
|
*/
|
178
185
|
createItems(parentId, vdomRoot, level) {
|
179
|
-
let me
|
180
|
-
items
|
186
|
+
let me = this,
|
187
|
+
items = me.store.find('parentId', parentId),
|
188
|
+
itemCls = me.itemCls,
|
189
|
+
folderCls = me.folderCls,
|
181
190
|
cls, tmpRoot;
|
182
191
|
|
183
192
|
if (items.length > 0) {
|
@@ -187,9 +196,9 @@ class Tree extends Base {
|
|
187
196
|
|
188
197
|
if (parentId !== null) {
|
189
198
|
vdomRoot.cn.push({
|
190
|
-
tag: 'ul',
|
191
|
-
cls: ['neo-list'],
|
192
|
-
cn
|
199
|
+
tag : 'ul',
|
200
|
+
cls : ['neo-list'],
|
201
|
+
cn : [],
|
193
202
|
style: {
|
194
203
|
paddingLeft: '15px'
|
195
204
|
}
|
@@ -201,12 +210,12 @@ class Tree extends Base {
|
|
201
210
|
}
|
202
211
|
|
203
212
|
items.forEach(item => {
|
204
|
-
cls = [
|
213
|
+
cls = [itemCls];
|
205
214
|
|
206
215
|
if (item.isLeaf) {
|
207
|
-
cls.push(item.singleton ? '
|
216
|
+
cls.push(itemCls + (item.singleton ? '-leaf-singleton' : '-leaf'));
|
208
217
|
} else {
|
209
|
-
cls.push(
|
218
|
+
cls.push(folderCls);
|
210
219
|
|
211
220
|
if (!item.collapsed) {
|
212
221
|
cls.push('neo-folder-open');
|
@@ -214,14 +223,14 @@ class Tree extends Base {
|
|
214
223
|
}
|
215
224
|
|
216
225
|
tmpRoot.cn.push({
|
217
|
-
tag: 'li',
|
226
|
+
tag : 'li',
|
218
227
|
cls,
|
219
|
-
id
|
220
|
-
cn
|
228
|
+
id : me.getItemId(item.id),
|
229
|
+
cn : [{
|
221
230
|
tag : 'span',
|
222
|
-
cls : ['
|
231
|
+
cls : [itemCls + '-content', item.iconCls],
|
223
232
|
innerHTML: item.name,
|
224
|
-
style: {
|
233
|
+
style : {
|
225
234
|
pointerEvents: 'none'
|
226
235
|
}
|
227
236
|
}],
|
@@ -244,7 +253,7 @@ class Tree extends Base {
|
|
244
253
|
* Expands all folders
|
245
254
|
* @param {Boolean} silent=false Set silent to true to prevent a vnode update
|
246
255
|
*/
|
247
|
-
expandAll(silent=false) {
|
256
|
+
expandAll(silent = false) {
|
248
257
|
let me = this,
|
249
258
|
vdom = me.vdom,
|
250
259
|
hasMatch = false,
|
@@ -274,7 +283,7 @@ class Tree extends Base {
|
|
274
283
|
* @param {Boolean} [parentMatch]=false In case a parent folder matches the filter, show its child items
|
275
284
|
* @returns {Boolean} false if at least one child item is filtered
|
276
285
|
*/
|
277
|
-
filter(property, value, parentId, parentMatch=false) {
|
286
|
+
filter(property, value, parentId, parentMatch = false) {
|
278
287
|
let me = this,
|
279
288
|
isFiltered = true,
|
280
289
|
valueRegEx = new RegExp(value, 'gi'),
|
@@ -287,7 +296,7 @@ class Tree extends Base {
|
|
287
296
|
me.store.items.forEach(item => {
|
288
297
|
if (item.parentId === parentId) {
|
289
298
|
directMatch = false;
|
290
|
-
node
|
299
|
+
node = me.getVdomChild(me.getItemId(item.id), me.vdom);
|
291
300
|
|
292
301
|
node.cn[0].innerHTML = item[property].replace(valueRegEx, match => {
|
293
302
|
directMatch = true;
|
@@ -379,13 +388,13 @@ class Tree extends Base {
|
|
379
388
|
|
380
389
|
if (path.includes(vnodeId)) {
|
381
390
|
record = tmpItem;
|
382
|
-
item
|
391
|
+
item = me.getVdomChild(vnodeId);
|
383
392
|
break;
|
384
393
|
}
|
385
394
|
}
|
386
395
|
|
387
396
|
if (item) {
|
388
|
-
if (item.cls?.includes(
|
397
|
+
if (item.cls?.includes(me.folderCls)) {
|
389
398
|
NeoArray.toggle(item.cls, 'neo-folder-open');
|
390
399
|
me.update();
|
391
400
|
} else {
|