neo.mjs 3.0.1 → 3.0.5
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/examples/list/animate/List.mjs +8 -6
- package/examples/list/animate/MainContainer.mjs +77 -13
- package/examples/list/animate/MainStore.mjs +17 -0
- package/package.json +4 -4
- package/resources/scss/src/examples/list/animate/List.scss +0 -1
- package/src/collection/Base.mjs +21 -4
- package/src/collection/Filter.mjs +7 -2
- package/src/core/Observable.mjs +4 -0
- package/src/list/Base.mjs +4 -4
- package/src/list/plugin/Animate.mjs +209 -31
- package/src/main/addon/Stylesheet.mjs +35 -2
- package/src/plugin/Base.mjs +5 -1
- package/src/util/Css.mjs +19 -5
|
@@ -32,13 +32,15 @@ class List extends BaseList {
|
|
|
32
32
|
* @returns {Object|Object[]|String} Either a config object to assign to the item, a vdom cn array or a html string
|
|
33
33
|
*/
|
|
34
34
|
createItemContent(record, index) {
|
|
35
|
+
let id = this.getItemId(record.id);
|
|
36
|
+
|
|
35
37
|
return [
|
|
36
|
-
{cls: ['neo-list-item-content'], cn: [
|
|
37
|
-
{tag: 'img', src:
|
|
38
|
-
{cls: ['neo-list-item-text'], cn: [
|
|
39
|
-
{html: record.firstname},
|
|
40
|
-
{cls: ['neo-lastname'], html: record.lastname},
|
|
41
|
-
{cls: ['neo-is-online'], removeDom: !record.isOnline}
|
|
38
|
+
{cls: ['neo-list-item-content'], id: `${id}__content`, cn: [
|
|
39
|
+
{tag: 'img', id: `${id}__image`, src: `${Neo.config.resourcesPath}examples/${record.image}`},
|
|
40
|
+
{cls: ['neo-list-item-text'], id: `${id}__content_wrapper`, cn: [
|
|
41
|
+
{html: record.firstname, id: `${id}__firstname`},
|
|
42
|
+
{cls: ['neo-lastname'], id: `${id}__lastname`, html: record.lastname},
|
|
43
|
+
{cls: ['neo-is-online'], id: `${id}__isonline`, removeDom: !record.isOnline}
|
|
42
44
|
]}
|
|
43
45
|
]}
|
|
44
46
|
];
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import CheckBox
|
|
2
|
-
import List
|
|
3
|
-
import MainStore
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import CheckBox from '../../../src/form/field/CheckBox.mjs';
|
|
2
|
+
import List from './List.mjs';
|
|
3
|
+
import MainStore from './MainStore.mjs';
|
|
4
|
+
import NumberField from '../../../src/form/field/Number.mjs';
|
|
5
|
+
import TextField from '../../../src/form/field/Text.mjs';
|
|
6
|
+
import Toolbar from '../../../src/container/Toolbar.mjs';
|
|
7
|
+
import Viewport from '../../../src/container/Viewport.mjs';
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* @class Neo.examples.list.animate.MainContainer
|
|
@@ -12,7 +14,8 @@ class MainContainer extends Viewport {
|
|
|
12
14
|
static getConfig() {return {
|
|
13
15
|
className: 'Neo.examples.list.animate.MainContainer',
|
|
14
16
|
autoMount: true,
|
|
15
|
-
layout : {ntype: 'vbox', align: 'stretch'}
|
|
17
|
+
layout : {ntype: 'vbox', align: 'stretch'},
|
|
18
|
+
sortBy : 'firstname'
|
|
16
19
|
}}
|
|
17
20
|
|
|
18
21
|
/**
|
|
@@ -36,11 +39,16 @@ class MainContainer extends Viewport {
|
|
|
36
39
|
ntype: 'label',
|
|
37
40
|
text : 'Sort by'
|
|
38
41
|
}, {
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
field : 'firstname',
|
|
43
|
+
handler : me.changeSorting.bind(me, 'firstname'),
|
|
44
|
+
iconCls : 'fas fa-arrow-circle-up',
|
|
45
|
+
iconPosition: 'right',
|
|
46
|
+
text : 'Firstname'
|
|
41
47
|
}, {
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
field : 'lastname',
|
|
49
|
+
handler : me.changeSorting.bind(me, 'lastname'),
|
|
50
|
+
iconPosition: 'right',
|
|
51
|
+
text : 'Lastname'
|
|
44
52
|
}, {
|
|
45
53
|
module : CheckBox,
|
|
46
54
|
labelText : 'Is online',
|
|
@@ -48,6 +56,27 @@ class MainContainer extends Viewport {
|
|
|
48
56
|
listeners : {change: me.changeIsOnlineFilter.bind(me)},
|
|
49
57
|
style : {marginLeft: '50px'}
|
|
50
58
|
}]
|
|
59
|
+
}, {
|
|
60
|
+
module : TextField,
|
|
61
|
+
flex : 'none',
|
|
62
|
+
labelText : 'Search',
|
|
63
|
+
labelWidth: 60,
|
|
64
|
+
listeners : {change: me.changeNameFilter.bind(me)},
|
|
65
|
+
style : {marginLeft: '10px'},
|
|
66
|
+
width : 262
|
|
67
|
+
}, {
|
|
68
|
+
module : NumberField,
|
|
69
|
+
clearToOriginalValue: true,
|
|
70
|
+
flex : 'none',
|
|
71
|
+
labelText : 'Transition Duration',
|
|
72
|
+
labelWidth : 150,
|
|
73
|
+
listeners : {change: me.changeTransitionDuration.bind(me)},
|
|
74
|
+
maxValue : 5000,
|
|
75
|
+
minValue : 100,
|
|
76
|
+
stepSize : 100,
|
|
77
|
+
style : {marginLeft: '10px'},
|
|
78
|
+
value : 500,
|
|
79
|
+
width : 262
|
|
51
80
|
}, {
|
|
52
81
|
module: List,
|
|
53
82
|
store : MainStore
|
|
@@ -64,13 +93,48 @@ class MainContainer extends Viewport {
|
|
|
64
93
|
}
|
|
65
94
|
|
|
66
95
|
/**
|
|
67
|
-
* @param {String} field
|
|
68
96
|
* @param {Object} data
|
|
69
97
|
*/
|
|
70
|
-
|
|
98
|
+
changeNameFilter(data) {
|
|
71
99
|
let store = this.down({module: List}).store;
|
|
72
100
|
|
|
73
|
-
store.
|
|
101
|
+
store.getFilter('name').value = data.value;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* @param {String} property
|
|
106
|
+
* @param {Object} data
|
|
107
|
+
*/
|
|
108
|
+
changeSorting(property, data) {
|
|
109
|
+
let me = this,
|
|
110
|
+
buttonFirstName = me.down({field: 'firstname'}),
|
|
111
|
+
buttonLastName = me.down({field: 'lastname'}),
|
|
112
|
+
direction = 'ASC',
|
|
113
|
+
store = me.down({module: List}).store,
|
|
114
|
+
sorter = store.sorters[0],
|
|
115
|
+
button;
|
|
116
|
+
|
|
117
|
+
button = property === 'firstname' ? buttonFirstName : buttonLastName;
|
|
118
|
+
|
|
119
|
+
if (property === me.sortBy) {
|
|
120
|
+
direction = sorter.direction === 'ASC' ? 'DESC' : 'ASC';
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
button.iconCls = `fas fa-arrow-circle-${direction === 'ASC' ? 'up' : 'down'}`;
|
|
124
|
+
|
|
125
|
+
button = button === buttonFirstName ? buttonLastName : buttonFirstName;
|
|
126
|
+
button.iconCls = null;
|
|
127
|
+
|
|
128
|
+
sorter.set({direction, property});
|
|
129
|
+
|
|
130
|
+
me.sortBy = property;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @param {Object} data
|
|
135
|
+
*/
|
|
136
|
+
changeTransitionDuration(data) {
|
|
137
|
+
this.down({module: List}).getPlugin('animate').transitionDuration = data.value;
|
|
74
138
|
}
|
|
75
139
|
}
|
|
76
140
|
|
|
@@ -17,6 +17,23 @@ class MainStore extends Store {
|
|
|
17
17
|
disabled : true,
|
|
18
18
|
property : 'isOnline',
|
|
19
19
|
value : true
|
|
20
|
+
}, {
|
|
21
|
+
property : 'name',
|
|
22
|
+
value : null,
|
|
23
|
+
|
|
24
|
+
filterBy: opts => {
|
|
25
|
+
let record = opts.item,
|
|
26
|
+
value = opts.value?.toLowerCase();
|
|
27
|
+
|
|
28
|
+
if (value) {
|
|
29
|
+
return !(
|
|
30
|
+
record.firstname.toLowerCase().includes(value) ||
|
|
31
|
+
record.lastname .toLowerCase().includes(value)
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
20
37
|
}],
|
|
21
38
|
|
|
22
39
|
sorters: [{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neo.mjs",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.5",
|
|
4
4
|
"description": "The webworkers driven UI framework",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"@fortawesome/fontawesome-free": "^5.15.4",
|
|
37
37
|
"@material/mwc-button": "^0.25.3",
|
|
38
38
|
"@material/mwc-textfield": "^0.25.3",
|
|
39
|
-
"autoprefixer": "^10.4.
|
|
39
|
+
"autoprefixer": "^10.4.2",
|
|
40
40
|
"chalk": "^4.1.2",
|
|
41
41
|
"clean-webpack-plugin": "^4.0.0",
|
|
42
42
|
"commander": "^8.3.0",
|
|
43
|
-
"cssnano": "^5.0.
|
|
43
|
+
"cssnano": "^5.0.15",
|
|
44
44
|
"envinfo": "^7.8.1",
|
|
45
45
|
"fs-extra": "^10.0.0",
|
|
46
46
|
"highlightjs-line-numbers.js": "^2.8.0",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"neo-jsdoc": "^1.0.1",
|
|
49
49
|
"neo-jsdoc-x": "^1.0.4",
|
|
50
50
|
"postcss": "^8.4.5",
|
|
51
|
-
"sass": "^1.
|
|
51
|
+
"sass": "^1.47.0",
|
|
52
52
|
"webpack": "^5.65.0",
|
|
53
53
|
"webpack-cli": "^4.9.1",
|
|
54
54
|
"webpack-dev-server": "4.7.2",
|
package/src/collection/Base.mjs
CHANGED
|
@@ -469,11 +469,13 @@ class Base extends CoreBase {
|
|
|
469
469
|
}
|
|
470
470
|
|
|
471
471
|
/**
|
|
472
|
+
*
|
|
473
|
+
* @param {Object[]} items=this._items
|
|
474
|
+
* @param {Boolean} silent=false
|
|
472
475
|
* @protected
|
|
473
476
|
*/
|
|
474
|
-
doSort() {
|
|
477
|
+
doSort(items=this._items, silent=false) {
|
|
475
478
|
let me = this,
|
|
476
|
-
items = me._items,
|
|
477
479
|
previousItems = [...items],
|
|
478
480
|
sorters = me.sorters,
|
|
479
481
|
sortDirections = me.sortDirections,
|
|
@@ -558,7 +560,7 @@ class Base extends CoreBase {
|
|
|
558
560
|
|
|
559
561
|
me[isSorted] = countSorters > 0;
|
|
560
562
|
|
|
561
|
-
if (me[updatingIndex] === 0) {
|
|
563
|
+
if (!silent && me[updatingIndex] === 0) {
|
|
562
564
|
me.fire('sort', {
|
|
563
565
|
items: me._items,
|
|
564
566
|
previousItems,
|
|
@@ -607,6 +609,8 @@ class Base extends CoreBase {
|
|
|
607
609
|
i = 0,
|
|
608
610
|
countItems = items.length,
|
|
609
611
|
filteredItems = [],
|
|
612
|
+
needsSorting = false,
|
|
613
|
+
oldItems = [...me._items],
|
|
610
614
|
config, isIncluded, item, j, tmpItems;
|
|
611
615
|
|
|
612
616
|
for (; i < countAllFilters; i++) {
|
|
@@ -616,6 +620,10 @@ class Base extends CoreBase {
|
|
|
616
620
|
}
|
|
617
621
|
|
|
618
622
|
if (countFilters === 0 && me.allItems) {
|
|
623
|
+
if (me.sorters.length > 0) {
|
|
624
|
+
needsSorting = true;
|
|
625
|
+
}
|
|
626
|
+
|
|
619
627
|
me.clear();
|
|
620
628
|
|
|
621
629
|
me.items = [...me.allItems._items];
|
|
@@ -682,7 +690,16 @@ class Base extends CoreBase {
|
|
|
682
690
|
|
|
683
691
|
me[isFiltered] = countFilters !== 0;
|
|
684
692
|
|
|
685
|
-
|
|
693
|
+
if (needsSorting) {
|
|
694
|
+
me.doSort(me.items, true);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
me.fire('filter', {
|
|
698
|
+
isFiltered: me[isFiltered],
|
|
699
|
+
items : me.items,
|
|
700
|
+
oldItems,
|
|
701
|
+
scope : me
|
|
702
|
+
});
|
|
686
703
|
}
|
|
687
704
|
|
|
688
705
|
/**
|
|
@@ -40,7 +40,7 @@ class Filter extends Base {
|
|
|
40
40
|
*/
|
|
41
41
|
disabled_: false,
|
|
42
42
|
/**
|
|
43
|
-
* Provide a custom filtering function
|
|
43
|
+
* Provide a custom filtering function which has a higher priority than property, operator & value
|
|
44
44
|
* @member {Function|null} filterBy_=null
|
|
45
45
|
*/
|
|
46
46
|
filterBy_: null,
|
|
@@ -173,7 +173,12 @@ class Filter extends Base {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
if (me._filterBy) {
|
|
176
|
-
return me.filterBy.call(me.scope || me,
|
|
176
|
+
return me.filterBy.call(me.scope || me, {
|
|
177
|
+
allItems,
|
|
178
|
+
filteredItems,
|
|
179
|
+
item,
|
|
180
|
+
value: me._value
|
|
181
|
+
});
|
|
177
182
|
}
|
|
178
183
|
|
|
179
184
|
if (me.includeEmptyValues && (me._value === null || Neo.isEmpty(me._value))) {
|
package/src/core/Observable.mjs
CHANGED
|
@@ -107,6 +107,10 @@ class Observable extends Base {
|
|
|
107
107
|
for (i = 0; i < len; i++) {
|
|
108
108
|
eventConfig = events[i];
|
|
109
109
|
|
|
110
|
+
if (!Neo.isFunction(eventConfig.fn)) {
|
|
111
|
+
eventConfig.fn = eventConfig.scope[eventConfig.fn];
|
|
112
|
+
}
|
|
113
|
+
|
|
110
114
|
eventConfig.fn.apply(eventConfig.scope || me, eventConfig.data ? args.concat(eventConfig.data) : args);
|
|
111
115
|
}
|
|
112
116
|
}
|
package/src/list/Base.mjs
CHANGED
|
@@ -132,7 +132,7 @@ class Base extends Component {
|
|
|
132
132
|
plugins.push({
|
|
133
133
|
module : module.default,
|
|
134
134
|
appName: me.appName,
|
|
135
|
-
|
|
135
|
+
id : 'animate',
|
|
136
136
|
...me.pluginAnimateConfig
|
|
137
137
|
});
|
|
138
138
|
|
|
@@ -191,9 +191,9 @@ class Base extends Component {
|
|
|
191
191
|
let me = this;
|
|
192
192
|
|
|
193
193
|
value?.on({
|
|
194
|
-
filter :
|
|
195
|
-
load :
|
|
196
|
-
recordChange:
|
|
194
|
+
filter : 'onStoreFilter',
|
|
195
|
+
load : 'onStoreLoad',
|
|
196
|
+
recordChange: 'onStoreRecordChange',
|
|
197
197
|
scope : me
|
|
198
198
|
});
|
|
199
199
|
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import Base
|
|
1
|
+
import Base from '../../plugin/Base.mjs';
|
|
2
|
+
import CssUtil from '../../util/Css.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* @class Neo.list.plugin.Animate
|
|
@@ -39,7 +40,17 @@ class Animate extends Base {
|
|
|
39
40
|
* Read only
|
|
40
41
|
* @member {Number|null} rows=null
|
|
41
42
|
*/
|
|
42
|
-
rows: null
|
|
43
|
+
rows: null,
|
|
44
|
+
/**
|
|
45
|
+
* Time in ms. Please ensure to match the CSS based value, in case you change the default.
|
|
46
|
+
* @member {Number} transitionDuration_=500
|
|
47
|
+
*/
|
|
48
|
+
transitionDuration_: 500,
|
|
49
|
+
/**
|
|
50
|
+
* The id of the setTimeout() call which gets triggered after a transition is done.
|
|
51
|
+
* @member {Number|null} transitionTimeoutId=null
|
|
52
|
+
*/
|
|
53
|
+
transitionTimeoutId: null
|
|
43
54
|
}}
|
|
44
55
|
|
|
45
56
|
/**
|
|
@@ -48,14 +59,16 @@ class Animate extends Base {
|
|
|
48
59
|
construct(config) {
|
|
49
60
|
super.construct(config);
|
|
50
61
|
|
|
51
|
-
let me
|
|
62
|
+
let me = this,
|
|
63
|
+
owner = me.owner;
|
|
52
64
|
|
|
53
65
|
me.adjustCreateItem();
|
|
54
66
|
|
|
55
|
-
me.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
owner.onStoreFilter = me.onStoreFilter.bind(me);
|
|
68
|
+
|
|
69
|
+
owner.store.on({
|
|
70
|
+
sort : me.onStoreSort,
|
|
71
|
+
scope: me
|
|
59
72
|
});
|
|
60
73
|
}
|
|
61
74
|
|
|
@@ -70,6 +83,25 @@ class Animate extends Base {
|
|
|
70
83
|
owner.createItem = me.createItem.bind(owner, me);
|
|
71
84
|
}
|
|
72
85
|
|
|
86
|
+
/**
|
|
87
|
+
* Triggered after the transitionDuration config got changed.
|
|
88
|
+
*
|
|
89
|
+
* We do not want to apply the style to each list item itself,
|
|
90
|
+
* so we are using Neo.util.Css
|
|
91
|
+
* @param {Boolean} value
|
|
92
|
+
* @param {Boolean} oldValue
|
|
93
|
+
* @protected
|
|
94
|
+
*/
|
|
95
|
+
afterSetTransitionDuration(value, oldValue) {
|
|
96
|
+
Neo.isNumber(oldValue) && CssUtil.deleteRules(`#${this.owner.id} .neo-list-item`);
|
|
97
|
+
|
|
98
|
+
CssUtil.insertRules([
|
|
99
|
+
`#${this.owner.id} .neo-list-item {`,
|
|
100
|
+
`transition: opacity ${value}ms ease-in-out, transform ${value}ms ease-in-out`,
|
|
101
|
+
'}'
|
|
102
|
+
].join(''));
|
|
103
|
+
}
|
|
104
|
+
|
|
73
105
|
/**
|
|
74
106
|
* @param {Neo.list.plugin.Animate} me
|
|
75
107
|
* @param {Object} record
|
|
@@ -77,27 +109,19 @@ class Animate extends Base {
|
|
|
77
109
|
* @returns {Object}
|
|
78
110
|
*/
|
|
79
111
|
createItem(me, record, index) {
|
|
80
|
-
let item
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
margin = me.itemMargin,
|
|
84
|
-
style = item.style || {},
|
|
85
|
-
column, row, x, y;
|
|
112
|
+
let item = me.ownerCreateItem(record, index),
|
|
113
|
+
position = me.getItemPosition(record, index),
|
|
114
|
+
style = item.style || {};
|
|
86
115
|
|
|
87
116
|
if (!me.ownerRect) {
|
|
88
117
|
return null;
|
|
89
118
|
}
|
|
90
119
|
|
|
91
|
-
column = index % me.columns;
|
|
92
|
-
row = Math.floor(index / me.columns);
|
|
93
|
-
x = column * (margin + itemWidth) + margin;
|
|
94
|
-
y = row * (margin + itemHeight) + margin;
|
|
95
|
-
|
|
96
120
|
Object.assign(style, {
|
|
97
|
-
height : `${itemHeight}px`,
|
|
121
|
+
height : `${me.itemHeight}px`,
|
|
98
122
|
position : 'absolute',
|
|
99
|
-
transform: `translate(${x}px, ${y}px)`,
|
|
100
|
-
width : `${itemWidth}px`
|
|
123
|
+
transform: `translate(${position.x}px, ${position.y}px)`,
|
|
124
|
+
width : `${me.itemWidth}px`
|
|
101
125
|
});
|
|
102
126
|
|
|
103
127
|
item.style = style;
|
|
@@ -106,10 +130,38 @@ class Animate extends Base {
|
|
|
106
130
|
}
|
|
107
131
|
|
|
108
132
|
/**
|
|
109
|
-
*
|
|
133
|
+
*
|
|
134
|
+
* @param {Object} record
|
|
135
|
+
* @param {Number} index
|
|
136
|
+
* @returns {{x: Number, y: Number}}
|
|
110
137
|
*/
|
|
111
|
-
|
|
112
|
-
|
|
138
|
+
getItemPosition(record, index) {
|
|
139
|
+
let me = this,
|
|
140
|
+
column = index % me.columns,
|
|
141
|
+
margin = me.itemMargin,
|
|
142
|
+
row = Math.floor(index / me.columns),
|
|
143
|
+
x = column * (margin + me.itemWidth) + margin,
|
|
144
|
+
y = row * (margin + me.itemHeight) + margin;
|
|
145
|
+
|
|
146
|
+
return {x, y};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
*
|
|
151
|
+
* @param {Object} obj
|
|
152
|
+
* @param {String[]} map
|
|
153
|
+
* @param {Boolean} intercept
|
|
154
|
+
* @returns {Number}
|
|
155
|
+
*/
|
|
156
|
+
getItemIndex(obj, map, intercept) {
|
|
157
|
+
if (!intercept) {
|
|
158
|
+
return obj.index;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
let owner = this.owner,
|
|
162
|
+
key = owner.store.keyProperty;
|
|
163
|
+
|
|
164
|
+
return map.indexOf(owner.getItemId(obj.record[key]));
|
|
113
165
|
}
|
|
114
166
|
|
|
115
167
|
/**
|
|
@@ -127,13 +179,126 @@ class Animate extends Base {
|
|
|
127
179
|
});
|
|
128
180
|
}
|
|
129
181
|
|
|
182
|
+
/**
|
|
183
|
+
* @param {Object} data
|
|
184
|
+
* @param {Boolean} data.isFiltered
|
|
185
|
+
* @param {Object[]} data.items
|
|
186
|
+
* @param {Object[]} data.oldItems
|
|
187
|
+
* @param {Neo.data.Store} data.scope
|
|
188
|
+
*/
|
|
189
|
+
onStoreFilter(data) {
|
|
190
|
+
let me = this,
|
|
191
|
+
owner = me.owner,
|
|
192
|
+
key = owner.store.keyProperty,
|
|
193
|
+
hasAddedItems = false,
|
|
194
|
+
addedItems = [],
|
|
195
|
+
movedItems = [],
|
|
196
|
+
removedItems = [],
|
|
197
|
+
transitionTimeoutId = me.transitionTimeoutId,
|
|
198
|
+
intercept = !!transitionTimeoutId,
|
|
199
|
+
vdom = owner.vdom,
|
|
200
|
+
index, item, map, position;
|
|
201
|
+
|
|
202
|
+
if (transitionTimeoutId) {
|
|
203
|
+
clearTimeout(transitionTimeoutId);
|
|
204
|
+
me.transitionTimeoutId = null;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
map = intercept ? vdom.cn.map(e => e.id) : [];
|
|
208
|
+
|
|
209
|
+
data.items.forEach((record, index) => {
|
|
210
|
+
item = {index, record};
|
|
211
|
+
|
|
212
|
+
if (!data.oldItems.includes(record)) {
|
|
213
|
+
// flag items which are still inside the DOM (running remove OP)
|
|
214
|
+
if (intercept && map.includes(owner.getItemId(record[key]))) {
|
|
215
|
+
item.reAdded = true;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
addedItems.push(item);
|
|
219
|
+
} else {
|
|
220
|
+
movedItems.push(item);
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
data.oldItems.forEach((record, index) => {
|
|
225
|
+
if (!data.items.includes(record)) {
|
|
226
|
+
removedItems.push({index, record});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
addedItems.forEach(obj => {
|
|
231
|
+
if (!obj.reAdded) {
|
|
232
|
+
index = me.getItemIndex(obj, map, intercept);
|
|
233
|
+
|
|
234
|
+
if (index > -1) {
|
|
235
|
+
hasAddedItems = true;
|
|
236
|
+
|
|
237
|
+
vdom.cn.splice(index, 0, me.createItem(me, obj.record, obj.index));
|
|
238
|
+
|
|
239
|
+
obj.item = vdom.cn[index];
|
|
240
|
+
obj.item.style.opacity = 0;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
if (hasAddedItems) {
|
|
246
|
+
owner.vdom = vdom;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// ensure to get into the next animation frame
|
|
250
|
+
setTimeout(() => {
|
|
251
|
+
// get the latest version of the vdom, since this is a delayed callback
|
|
252
|
+
vdom = owner.vdom;
|
|
253
|
+
|
|
254
|
+
// new items are already added into the vdom, while old items are not yet removed
|
|
255
|
+
// => we need a map to ensure getting the correct index
|
|
256
|
+
map = vdom.cn.map(e => e.id);
|
|
257
|
+
|
|
258
|
+
addedItems.forEach(obj => {
|
|
259
|
+
index = me.getItemIndex(obj, map, intercept);
|
|
260
|
+
|
|
261
|
+
if (index > -1) {
|
|
262
|
+
// we can change the opacity for re-added items too => the vdom engine will ignore this
|
|
263
|
+
vdom.cn[index].style.opacity = 1;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
movedItems.forEach(obj => {
|
|
268
|
+
index = me.getItemIndex(obj, map, true); // honor removed items, even without interceptions
|
|
269
|
+
|
|
270
|
+
if (index > -1) {
|
|
271
|
+
position = me.getItemPosition(obj.record, obj.index);
|
|
272
|
+
|
|
273
|
+
Object.assign(vdom.cn[index].style, {
|
|
274
|
+
opacity : 1,
|
|
275
|
+
transform: `translate(${position.x}px, ${position.y}px)`
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
removedItems.forEach(obj => {
|
|
281
|
+
index = me.getItemIndex(obj, map, intercept);
|
|
282
|
+
|
|
283
|
+
if (index > -1) {
|
|
284
|
+
obj.item = vdom.cn[index];
|
|
285
|
+
obj.item.style.opacity = 0;
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
owner.vdom = vdom;
|
|
290
|
+
|
|
291
|
+
me.triggerTransitionCallback();
|
|
292
|
+
}, 50);
|
|
293
|
+
}
|
|
294
|
+
|
|
130
295
|
/**
|
|
131
296
|
* @param {Object} data
|
|
132
297
|
* @param {Object[]} data.items
|
|
133
298
|
* @param {Object[]} data.previousItems
|
|
134
299
|
* @param {Neo.data.Store} data.scope
|
|
135
300
|
*/
|
|
136
|
-
|
|
301
|
+
onStoreSort(data) {
|
|
137
302
|
let me = this,
|
|
138
303
|
hasChange = false,
|
|
139
304
|
keyProperty = data.scope.keyProperty,
|
|
@@ -158,15 +323,28 @@ class Animate extends Base {
|
|
|
158
323
|
if (hasChange) {
|
|
159
324
|
owner.vdom.cn = newVdomCn;
|
|
160
325
|
|
|
161
|
-
owner.
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
});
|
|
326
|
+
owner.vdom = vdom;
|
|
327
|
+
|
|
328
|
+
// we need to ensure to get this call into the next animation frame
|
|
329
|
+
setTimeout(() => {
|
|
330
|
+
owner.createItems();
|
|
331
|
+
}, 50);
|
|
167
332
|
}
|
|
168
333
|
}
|
|
169
334
|
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
*
|
|
338
|
+
*/
|
|
339
|
+
triggerTransitionCallback() {
|
|
340
|
+
let me = this;
|
|
341
|
+
|
|
342
|
+
me.transitionTimeoutId = setTimeout(() => {
|
|
343
|
+
me.transitionTimeoutId = null;
|
|
344
|
+
|
|
345
|
+
me.owner.createItems();
|
|
346
|
+
}, me.transitionDuration);
|
|
347
|
+
}
|
|
170
348
|
}
|
|
171
349
|
|
|
172
350
|
Neo.applyClassConfig(Animate);
|
|
@@ -8,6 +8,12 @@ import Base from '../../core/Base.mjs';
|
|
|
8
8
|
* @singleton
|
|
9
9
|
*/
|
|
10
10
|
class Stylesheet extends Base {
|
|
11
|
+
/**
|
|
12
|
+
* @member {String} dynamicStyleSheetId='neo-dynamic-stylesheet'
|
|
13
|
+
* @protected
|
|
14
|
+
*/
|
|
15
|
+
dynamicStyleSheetId = 'neo-dynamic-stylesheet';
|
|
16
|
+
|
|
11
17
|
static getConfig() {return {
|
|
12
18
|
/**
|
|
13
19
|
* @member {String} className='Neo.main.addon.Stylesheet'
|
|
@@ -23,6 +29,7 @@ class Stylesheet extends Base {
|
|
|
23
29
|
app: [
|
|
24
30
|
'addThemeFiles',
|
|
25
31
|
'createStyleSheet',
|
|
32
|
+
'deleteCssRules',
|
|
26
33
|
'insertCssRules',
|
|
27
34
|
'swapStyleSheet'
|
|
28
35
|
]
|
|
@@ -137,6 +144,32 @@ class Stylesheet extends Base {
|
|
|
137
144
|
document.head.appendChild(link);
|
|
138
145
|
}
|
|
139
146
|
|
|
147
|
+
/**
|
|
148
|
+
* @param {Object} data
|
|
149
|
+
* @param {Array} data.rules
|
|
150
|
+
* @protected
|
|
151
|
+
*/
|
|
152
|
+
deleteCssRules(data) {
|
|
153
|
+
let styleEl = document.getElementById(this.dynamicStyleSheetId),
|
|
154
|
+
styleSheet = styleEl.sheet,
|
|
155
|
+
cssRules = styleSheet.cssRules,
|
|
156
|
+
i = 0,
|
|
157
|
+
len = data.rules.length,
|
|
158
|
+
j, rulesLen;
|
|
159
|
+
|
|
160
|
+
for (; i < len; i++) {
|
|
161
|
+
j = 0;
|
|
162
|
+
rulesLen = cssRules.length;
|
|
163
|
+
|
|
164
|
+
for (; j < rulesLen; j++) {
|
|
165
|
+
if (cssRules[j].selectorText === data.rules[i]) {
|
|
166
|
+
styleSheet.deleteRule(j);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
140
173
|
/**
|
|
141
174
|
* @param {String} token
|
|
142
175
|
* @returns {Boolean}
|
|
@@ -162,7 +195,7 @@ class Stylesheet extends Base {
|
|
|
162
195
|
* @protected
|
|
163
196
|
*/
|
|
164
197
|
insertCssRules(data) {
|
|
165
|
-
let styleEl = document.getElementById(
|
|
198
|
+
let styleEl = document.getElementById(this.dynamicStyleSheetId),
|
|
166
199
|
i = 0,
|
|
167
200
|
len = data.rules.length,
|
|
168
201
|
styleSheet;
|
|
@@ -170,7 +203,7 @@ class Stylesheet extends Base {
|
|
|
170
203
|
if (!styleEl) {
|
|
171
204
|
styleEl = document.createElement('style');
|
|
172
205
|
|
|
173
|
-
styleEl.id =
|
|
206
|
+
styleEl.id = this.dynamicStyleSheetId;
|
|
174
207
|
document.head.appendChild(styleEl);
|
|
175
208
|
}
|
|
176
209
|
|
package/src/plugin/Base.mjs
CHANGED
package/src/util/Css.mjs
CHANGED
|
@@ -14,15 +14,29 @@ class Css extends Base {
|
|
|
14
14
|
}}
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
|
-
*
|
|
17
|
+
* Pass the selectorText of the rules which you want to remove
|
|
18
|
+
* @param {String[]|String} rules
|
|
19
|
+
*/
|
|
20
|
+
static deleteRules(rules) {
|
|
21
|
+
if (!Array.isArray(rules)) {
|
|
22
|
+
rules = [rules];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Neo.main.addon.Stylesheet.deleteCssRules({
|
|
26
|
+
rules: rules
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @param {String[]|String} rules
|
|
18
32
|
*/
|
|
19
33
|
static insertRules(rules) {
|
|
34
|
+
if (!Array.isArray(rules)) {
|
|
35
|
+
rules = [rules];
|
|
36
|
+
}
|
|
37
|
+
|
|
20
38
|
Neo.main.addon.Stylesheet.insertCssRules({
|
|
21
39
|
rules: rules
|
|
22
|
-
}).then(function(data) {
|
|
23
|
-
// console.log('inserted CSS rules', data);
|
|
24
|
-
}).catch(function(err) {
|
|
25
|
-
console.log('App: Got error attempting to insert CSS rules', err, rules);
|
|
26
40
|
});
|
|
27
41
|
}
|
|
28
42
|
}
|