neo.mjs 8.23.0 → 8.25.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/apps/portal/index.html +1 -1
- package/apps/portal/view/home/FeatureSection.mjs +4 -4
- package/apps/portal/view/home/FooterContainer.mjs +1 -1
- package/apps/portal/view/home/MainContainer.mjs +7 -7
- package/apps/portal/view/home/parts/MainNeo.mjs +35 -4
- package/examples/ServiceWorker.mjs +2 -2
- package/examples/component/magicmovetext/MainContainer.mjs +2 -0
- package/package.json +2 -2
- package/resources/scss/src/apps/portal/home/parts/MainNeo.scss +30 -0
- package/resources/scss/src/button/Base.scss +3 -3
- package/resources/scss/src/component/MagicMoveText.scss +9 -15
- package/resources/scss/src/grid/VerticalScrollbar.scss +21 -0
- package/src/DefaultConfig.mjs +2 -2
- package/src/component/MagicMoveText.mjs +228 -40
- package/src/draggable/grid/header/toolbar/SortZone.mjs +1 -1
- package/src/grid/Container.mjs +98 -73
- package/src/grid/ScrollManager.mjs +179 -0
- package/src/grid/{Scrollbar.mjs → VerticalScrollbar.mjs} +11 -9
- package/src/grid/View.mjs +45 -130
- package/src/grid/header/Toolbar.mjs +1 -2
- package/src/selection/grid/CellModel.mjs +9 -9
- package/resources/scss/src/grid/Scrollbar.scss +0 -21
@@ -74,25 +74,98 @@ class MagicMoveText extends Component {
|
|
74
74
|
|
75
75
|
/**
|
76
76
|
* @member {Object[]} chars=[]
|
77
|
+
* @protected
|
77
78
|
*/
|
78
79
|
chars = []
|
80
|
+
/**
|
81
|
+
* @member {Object[]} charsVdom=[]
|
82
|
+
* @protected
|
83
|
+
*/
|
84
|
+
charsVdom = []
|
85
|
+
/**
|
86
|
+
* @member {Number} contentHeight=0
|
87
|
+
* @protected
|
88
|
+
*/
|
89
|
+
contentHeight = 0
|
90
|
+
/**
|
91
|
+
* @member {Number} contentWidth=0
|
92
|
+
* @protected
|
93
|
+
*/
|
94
|
+
contentWidth = 0
|
79
95
|
/**
|
80
96
|
* @member {Number} currentIndex=0
|
97
|
+
* @protected
|
81
98
|
*/
|
82
99
|
currentIndex = 0
|
100
|
+
/**
|
101
|
+
* We do not need the first event to trigger logic, since afterSetMounted() handles this
|
102
|
+
* @member {Boolean} initialResizeEvent=true
|
103
|
+
* @protected
|
104
|
+
*/
|
105
|
+
initialResizeEvent = true
|
83
106
|
/**
|
84
107
|
* @member {Number|null} intervalId=null
|
108
|
+
* @protected
|
85
109
|
*/
|
86
110
|
intervalId = null
|
111
|
+
/**
|
112
|
+
* Internal flag which gets set to true while the animated char transitions are running
|
113
|
+
* @member {Boolean} isTransitioning=false
|
114
|
+
* @protected
|
115
|
+
*/
|
116
|
+
isTransitioning = false
|
117
|
+
/**
|
118
|
+
* @member {Object} measureCache={}
|
119
|
+
* @protected
|
120
|
+
*/
|
121
|
+
measureCache = {}
|
87
122
|
/**
|
88
123
|
* @member {Object[]} previousChars=[]
|
124
|
+
* @protected
|
89
125
|
*/
|
90
126
|
previousChars = []
|
91
127
|
/**
|
92
128
|
* @member {Object} measureElement
|
129
|
+
* @protected
|
93
130
|
*/
|
94
131
|
get measureElement() {
|
95
|
-
return this.
|
132
|
+
return this.measureWrapper.cn[0]
|
133
|
+
}
|
134
|
+
/**
|
135
|
+
* @member {Object} measureElement
|
136
|
+
* @protected
|
137
|
+
*/
|
138
|
+
get measureWrapper() {
|
139
|
+
return this.vdom.cn[1]
|
140
|
+
}
|
141
|
+
|
142
|
+
/**
|
143
|
+
* @param {Object} config
|
144
|
+
*/
|
145
|
+
construct(config) {
|
146
|
+
super.construct(config);
|
147
|
+
|
148
|
+
let me = this;
|
149
|
+
|
150
|
+
me.addDomListeners({
|
151
|
+
resize: me.onResize,
|
152
|
+
scope : me
|
153
|
+
})
|
154
|
+
}
|
155
|
+
|
156
|
+
/**
|
157
|
+
* @param {Boolean} mounted
|
158
|
+
* @protected
|
159
|
+
*/
|
160
|
+
async addResizeObserver(mounted) {
|
161
|
+
let {id, windowId} = this,
|
162
|
+
ResizeObserver = await Neo.currentWorker.getAddon('ResizeObserver', windowId);
|
163
|
+
|
164
|
+
ResizeObserver[mounted ? 'register' : 'unregister']({id, windowId});
|
165
|
+
|
166
|
+
if (mounted) {
|
167
|
+
this.initialResizeEvent = true
|
168
|
+
}
|
96
169
|
}
|
97
170
|
|
98
171
|
/**
|
@@ -127,8 +200,12 @@ class MagicMoveText extends Component {
|
|
127
200
|
* @protected
|
128
201
|
*/
|
129
202
|
afterSetFontFamily(value, oldValue) {
|
130
|
-
|
131
|
-
|
203
|
+
let me = this;
|
204
|
+
|
205
|
+
me.measureCache = {};
|
206
|
+
|
207
|
+
me.vdom.style.fontFamily = value;
|
208
|
+
me.update()
|
132
209
|
}
|
133
210
|
|
134
211
|
/**
|
@@ -139,7 +216,17 @@ class MagicMoveText extends Component {
|
|
139
216
|
*/
|
140
217
|
afterSetMounted(value, oldValue) {
|
141
218
|
super.afterSetMounted(value, oldValue);
|
142
|
-
|
219
|
+
|
220
|
+
let me = this;
|
221
|
+
|
222
|
+
value && me.getDomRect().then(rect => {
|
223
|
+
me.contentHeight = rect.height;
|
224
|
+
me.contentWidth = rect.width;
|
225
|
+
|
226
|
+
me.autoCycle && me.startAutoCycle(value)
|
227
|
+
});
|
228
|
+
|
229
|
+
oldValue !== undefined && me.addResizeObserver(value)
|
143
230
|
}
|
144
231
|
|
145
232
|
/**
|
@@ -165,7 +252,7 @@ class MagicMoveText extends Component {
|
|
165
252
|
me.chars.push({name: char});
|
166
253
|
|
167
254
|
if (char === ' ') {
|
168
|
-
char = '
|
255
|
+
char = ' '
|
169
256
|
}
|
170
257
|
|
171
258
|
measureElement.cn.push({tag: 'span', html: char})
|
@@ -190,44 +277,132 @@ class MagicMoveText extends Component {
|
|
190
277
|
this.update()
|
191
278
|
}
|
192
279
|
|
280
|
+
/**
|
281
|
+
* @param {String[]} letters
|
282
|
+
* @returns {Object[]}
|
283
|
+
* @protected
|
284
|
+
*/
|
285
|
+
createCharsVdom(letters) {
|
286
|
+
let me = this,
|
287
|
+
{chars} = me,
|
288
|
+
charsContainer = [],
|
289
|
+
char;
|
290
|
+
|
291
|
+
letters.forEach((letter, index) => {
|
292
|
+
if (letter !== null) {
|
293
|
+
char = chars[index];
|
294
|
+
|
295
|
+
charsContainer.push({
|
296
|
+
cls : ['neo-char'],
|
297
|
+
html : char.name,
|
298
|
+
style: {color: me.colorFadeIn, left: char.left, opacity: 0, top: char.top}
|
299
|
+
})
|
300
|
+
}
|
301
|
+
});
|
302
|
+
|
303
|
+
return charsContainer
|
304
|
+
}
|
305
|
+
|
306
|
+
/**
|
307
|
+
* @protected
|
308
|
+
*/
|
309
|
+
cycleText() {
|
310
|
+
let me = this;
|
311
|
+
|
312
|
+
me.text = me.cycleTexts[me.currentIndex];
|
313
|
+
me.currentIndex = (me.currentIndex + 1) % me.cycleTexts.length
|
314
|
+
}
|
315
|
+
|
193
316
|
/**
|
194
317
|
* @returns {Promise<void>}
|
318
|
+
* @protected
|
195
319
|
*/
|
196
320
|
async measureChars() {
|
197
321
|
let me = this,
|
198
|
-
{measureElement} = me,
|
322
|
+
{measureCache, measureElement, measureWrapper, text} = me,
|
199
323
|
parentRect, rects;
|
200
324
|
|
201
|
-
|
325
|
+
if (measureCache[text]) {
|
326
|
+
rects = [...measureCache[text]];
|
327
|
+
parentRect = rects.shift()
|
328
|
+
} else {
|
329
|
+
measureWrapper.style = {
|
330
|
+
height: me.contentHeight + 'px',
|
331
|
+
width : me.contentWidth + 'px'
|
332
|
+
};
|
333
|
+
|
334
|
+
delete measureWrapper.removeDom;
|
202
335
|
|
203
|
-
|
204
|
-
|
336
|
+
await me.promiseUpdate();
|
337
|
+
await me.timeout(20);
|
205
338
|
|
206
|
-
|
207
|
-
|
339
|
+
rects = await me.getDomRect([measureWrapper.id, ...measureElement.cn.map(node => node.id)]);
|
340
|
+
parentRect = rects.shift();
|
341
|
+
|
342
|
+
measureCache[text] = [parentRect, ...rects]
|
343
|
+
}
|
208
344
|
|
209
345
|
rects.forEach((rect, index) => {
|
210
346
|
me.chars[index].left = `${rect.left - parentRect.left}px`;
|
211
347
|
me.chars[index].top = `${rect.top - parentRect.top }px`;
|
212
348
|
});
|
213
349
|
|
214
|
-
|
350
|
+
measureWrapper.removeDom = true;
|
215
351
|
await me.promiseUpdate()
|
216
352
|
}
|
217
353
|
|
354
|
+
/**
|
355
|
+
* @param {Object} data
|
356
|
+
* @returns {Promise<void>}
|
357
|
+
* @protected
|
358
|
+
*/
|
359
|
+
async onResize({rect}) {
|
360
|
+
let me = this;
|
361
|
+
|
362
|
+
me.contentHeight = rect.height;
|
363
|
+
me.contentWidth = rect.width;
|
364
|
+
|
365
|
+
me.measureCache = {};
|
366
|
+
|
367
|
+
|
368
|
+
if (!me.initialResizeEvent) {
|
369
|
+
if (!me.isTransitioning) {
|
370
|
+
await me.measureChars();
|
371
|
+
|
372
|
+
me.charsVdom = me.createCharsVdom(me.chars.map(char => char.name))
|
373
|
+
}
|
374
|
+
} else {
|
375
|
+
me.initialResizeEvent = false
|
376
|
+
}
|
377
|
+
}
|
378
|
+
|
379
|
+
/**
|
380
|
+
* @param {Object} a
|
381
|
+
* @param {Object} b
|
382
|
+
* @returns {Number}
|
383
|
+
* @protected
|
384
|
+
*/
|
385
|
+
sortCharacters(a, b) {
|
386
|
+
let deltaTop = parseFloat(a.style.top) - parseFloat(b.style.top);
|
387
|
+
|
388
|
+
if (deltaTop !== 0) {
|
389
|
+
return deltaTop
|
390
|
+
}
|
391
|
+
|
392
|
+
return parseFloat(a.style.left) - parseFloat(b.style.left)
|
393
|
+
}
|
394
|
+
|
218
395
|
/**
|
219
396
|
* @param {Boolean} start=true
|
397
|
+
* @protected
|
220
398
|
*/
|
221
399
|
startAutoCycle(start=true) {
|
222
400
|
let me = this;
|
223
401
|
|
224
402
|
if (start) {
|
225
|
-
me.intervalId = setInterval(()
|
226
|
-
me.text = me.cycleTexts[me.currentIndex];
|
227
|
-
me.currentIndex = (me.currentIndex + 1) % me.cycleTexts.length
|
228
|
-
}, me.autoCycleInterval)
|
403
|
+
me.intervalId = setInterval(me.cycleText.bind(me), me.autoCycleInterval);
|
229
404
|
|
230
|
-
me.
|
405
|
+
me.timeout(20).then(() => {me.cycleText()});
|
231
406
|
} else {
|
232
407
|
clearInterval(me.intervalId)
|
233
408
|
}
|
@@ -235,71 +410,84 @@ class MagicMoveText extends Component {
|
|
235
410
|
|
236
411
|
/**
|
237
412
|
* @returns {Promise<void>}
|
413
|
+
* @protected
|
238
414
|
*/
|
239
415
|
async updateChars() {
|
240
416
|
let me = this,
|
241
417
|
{chars, previousChars} = me,
|
242
|
-
charsContainer = me.vdom.cn[0]
|
418
|
+
charsContainer = me.vdom.cn[0],
|
243
419
|
letters = chars.map(char => char.name),
|
244
|
-
|
420
|
+
charNode, index;
|
421
|
+
|
422
|
+
me.isTransitioning = true;
|
423
|
+
|
424
|
+
if (me.charsVdom.length > 1) {
|
425
|
+
charsContainer.cn = me.charsVdom;
|
426
|
+
await me.promiseUpdate()
|
427
|
+
}
|
245
428
|
|
246
429
|
previousChars.forEach((previousChar, previousIndex) => {
|
247
430
|
index = letters.indexOf(previousChar.name);
|
248
431
|
|
249
432
|
if (index > -1) {
|
250
|
-
charNode = charsContainer[previousIndex];
|
433
|
+
charNode = charsContainer.cn[previousIndex];
|
434
|
+
|
435
|
+
Object.assign(charNode.style, {
|
436
|
+
color: me.colorMove,
|
437
|
+
left : chars[index].left,
|
438
|
+
top : chars[index].top
|
439
|
+
});
|
251
440
|
|
252
|
-
charNode.style.color = me.colorMove;
|
253
|
-
charNode.style.left = chars[index].left;
|
254
441
|
letters[index] = null
|
255
442
|
} else {
|
256
|
-
charNode = charsContainer[previousIndex];
|
443
|
+
charNode = charsContainer.cn[previousIndex];
|
257
444
|
|
258
445
|
charNode.flag = 'remove'
|
259
446
|
}
|
260
447
|
});
|
261
448
|
|
262
|
-
|
263
|
-
if (letter !== null) {
|
264
|
-
char = chars[index];
|
265
|
-
|
266
|
-
charsContainer.push({
|
267
|
-
html : char.name,
|
268
|
-
style: {color: me.colorFadeIn, left: char.left, opacity: 0, top: char.top}
|
269
|
-
})
|
270
|
-
}
|
271
|
-
});
|
449
|
+
charsContainer.cn.push(...me.createCharsVdom(letters));
|
272
450
|
|
273
451
|
await me.promiseUpdate();
|
274
452
|
|
275
|
-
charsContainer.forEach(charNode => {
|
453
|
+
charsContainer.cn.forEach(charNode => {
|
276
454
|
if (charNode.flag === 'remove') {
|
277
455
|
charNode.style.color = me.colorFadeOut;
|
278
456
|
charNode.style.opacity = 0
|
279
457
|
} else {
|
280
|
-
charNode.style.opacity
|
458
|
+
delete charNode.style.opacity
|
281
459
|
}
|
282
460
|
});
|
283
461
|
|
284
462
|
await me.promiseUpdate();
|
285
463
|
await me.timeout(me.transitionTime);
|
286
464
|
|
287
|
-
charsContainer.sort(
|
465
|
+
charsContainer.cn.sort(me.sortCharacters);
|
288
466
|
|
289
|
-
index = charsContainer.length - 1;
|
467
|
+
index = charsContainer.cn.length - 1;
|
290
468
|
|
291
469
|
for (; index >= 0; index--) {
|
292
|
-
charNode = charsContainer[index];
|
470
|
+
charNode = charsContainer.cn[index];
|
293
471
|
|
294
472
|
delete charNode.flag;
|
295
473
|
delete charNode.style.color;
|
296
474
|
|
297
475
|
if (charNode.style.opacity === 0) {
|
298
|
-
charsContainer.splice(index, 1)
|
476
|
+
charsContainer.cn.splice(index, 1)
|
299
477
|
}
|
300
478
|
}
|
301
479
|
|
302
|
-
await me.promiseUpdate()
|
480
|
+
await me.promiseUpdate();
|
481
|
+
await me.timeout(200);
|
482
|
+
|
483
|
+
me.charsVdom = [...charsContainer.cn];
|
484
|
+
|
485
|
+
charsContainer.cn.length = 0;
|
486
|
+
|
487
|
+
charsContainer.cn.push({html: me.text});
|
488
|
+
await me.promiseUpdate();
|
489
|
+
|
490
|
+
me.isTransitioning = false
|
303
491
|
}
|
304
492
|
}
|
305
493
|
|
package/src/grid/Container.mjs
CHANGED
@@ -1,9 +1,10 @@
|
|
1
|
-
import BaseContainer
|
2
|
-
import ClassSystemUtil
|
3
|
-
import
|
4
|
-
import
|
5
|
-
import Store
|
6
|
-
import
|
1
|
+
import BaseContainer from '../container/Base.mjs';
|
2
|
+
import ClassSystemUtil from '../util/ClassSystem.mjs';
|
3
|
+
import GridView from './View.mjs';
|
4
|
+
import ScrollManager from './ScrollManager.mjs';
|
5
|
+
import Store from '../data/Store.mjs';
|
6
|
+
import VerticalScrollbar from './VerticalScrollbar.mjs';
|
7
|
+
import * as header from './header/_export.mjs';
|
7
8
|
|
8
9
|
/**
|
9
10
|
* @class Neo.grid.Container
|
@@ -119,17 +120,10 @@ class GridContainer extends BaseContainer {
|
|
119
120
|
*/
|
120
121
|
initialResizeEvent = true
|
121
122
|
/**
|
122
|
-
*
|
123
|
-
* @member {Boolean} isTouchMoveOwner=false
|
123
|
+
* @member {Neo.grid.ScrollManager|null} scrollManager=null
|
124
124
|
* @protected
|
125
125
|
*/
|
126
|
-
|
127
|
-
/**
|
128
|
-
* Storing touchmove position for mobile envs
|
129
|
-
* @member {Number} lastTouchY=0
|
130
|
-
* @protected
|
131
|
-
*/
|
132
|
-
lastTouchY = 0
|
126
|
+
scrollManager = null
|
133
127
|
|
134
128
|
/**
|
135
129
|
* Convenience method to access the Neo.grid.header.Toolbar
|
@@ -176,7 +170,7 @@ class GridContainer extends BaseContainer {
|
|
176
170
|
}];
|
177
171
|
|
178
172
|
me.scrollbar = Neo.create({
|
179
|
-
module :
|
173
|
+
module : VerticalScrollbar,
|
180
174
|
appName,
|
181
175
|
parentId: me.id,
|
182
176
|
rowHeight,
|
@@ -192,11 +186,29 @@ class GridContainer extends BaseContainer {
|
|
192
186
|
|
193
187
|
me.addDomListeners({
|
194
188
|
resize: me.onResize,
|
195
|
-
scroll: me.onScroll,
|
196
189
|
scope : me
|
197
190
|
})
|
198
191
|
}
|
199
192
|
|
193
|
+
/**
|
194
|
+
* @param {Boolean} mounted
|
195
|
+
* @protected
|
196
|
+
*/
|
197
|
+
async addResizeObserver(mounted) {
|
198
|
+
let me = this,
|
199
|
+
{windowId} = me,
|
200
|
+
ResizeObserver = await Neo.currentWorker.getAddon('ResizeObserver', windowId),
|
201
|
+
resizeParams = {id: me.id, windowId};
|
202
|
+
|
203
|
+
if (mounted) {
|
204
|
+
ResizeObserver.register(resizeParams);
|
205
|
+
await me.passSizeToView()
|
206
|
+
} else {
|
207
|
+
me.initialResizeEvent = true;
|
208
|
+
ResizeObserver.unregister(resizeParams)
|
209
|
+
}
|
210
|
+
}
|
211
|
+
|
200
212
|
/**
|
201
213
|
* Triggered after the cellEditing config got changed
|
202
214
|
* @param {Boolean} value
|
@@ -245,25 +257,6 @@ class GridContainer extends BaseContainer {
|
|
245
257
|
}
|
246
258
|
}
|
247
259
|
|
248
|
-
/**
|
249
|
-
* @param {Boolean} mounted
|
250
|
-
* @protected
|
251
|
-
*/
|
252
|
-
async addResizeObserver(mounted) {
|
253
|
-
let me = this,
|
254
|
-
{windowId} = me,
|
255
|
-
ResizeObserver = await Neo.currentWorker.getAddon('ResizeObserver', windowId),
|
256
|
-
resizeParams = {id: me.id, windowId};
|
257
|
-
|
258
|
-
if (mounted) {
|
259
|
-
ResizeObserver.register(resizeParams);
|
260
|
-
await me.passSizeToView()
|
261
|
-
} else {
|
262
|
-
me.initialResizeEvent = true;
|
263
|
-
ResizeObserver.unregister(resizeParams)
|
264
|
-
}
|
265
|
-
}
|
266
|
-
|
267
260
|
/**
|
268
261
|
* Triggered after the mounted config got changed
|
269
262
|
* @param {Boolean} value
|
@@ -475,6 +468,8 @@ class GridContainer extends BaseContainer {
|
|
475
468
|
destroy(...args) {
|
476
469
|
let me = this;
|
477
470
|
|
471
|
+
me.scrollManager.destroy();
|
472
|
+
|
478
473
|
me.mounted && Neo.main.addon.ResizeObserver.unregister({
|
479
474
|
id : me.id,
|
480
475
|
windowId: me.windowId
|
@@ -513,6 +508,21 @@ class GridContainer extends BaseContainer {
|
|
513
508
|
return `${this.id}__wrapper`
|
514
509
|
}
|
515
510
|
|
511
|
+
/**
|
512
|
+
*
|
513
|
+
*/
|
514
|
+
onConstructed() {
|
515
|
+
super.onConstructed();
|
516
|
+
|
517
|
+
let me = this;
|
518
|
+
|
519
|
+
me.scrollManager = Neo.create({
|
520
|
+
module : ScrollManager,
|
521
|
+
gridContainer: me,
|
522
|
+
gridView : me.view
|
523
|
+
})
|
524
|
+
}
|
525
|
+
|
516
526
|
/**
|
517
527
|
* @param {Object} data
|
518
528
|
*/
|
@@ -530,43 +540,6 @@ class GridContainer extends BaseContainer {
|
|
530
540
|
}
|
531
541
|
}
|
532
542
|
|
533
|
-
/**
|
534
|
-
* @param {Object} data
|
535
|
-
* @param {Number} data.scrollLeft
|
536
|
-
* @param {Object} data.target
|
537
|
-
* @param {Object} data.touches
|
538
|
-
*/
|
539
|
-
onScroll({scrollLeft, target, touches}) {
|
540
|
-
let me = this,
|
541
|
-
deltaY, lastTouchY;
|
542
|
-
|
543
|
-
// We must ignore events for grid-scrollbar
|
544
|
-
if (target.id.includes('grid-container')) {
|
545
|
-
me.headerToolbar.scrollLeft = scrollLeft;
|
546
|
-
me.view.scrollPosition = {x: scrollLeft, y: me.view.scrollPosition.y};
|
547
|
-
|
548
|
-
if (touches) {
|
549
|
-
if (!me.view.isTouchMoveOwner) {
|
550
|
-
me.isTouchMoveOwner = true
|
551
|
-
}
|
552
|
-
|
553
|
-
if (me.isTouchMoveOwner) {
|
554
|
-
lastTouchY = touches.lastTouch.clientY - touches.firstTouch.clientY;
|
555
|
-
deltaY = me.lastTouchY - lastTouchY;
|
556
|
-
|
557
|
-
deltaY !== 0 && Neo.main.DomAccess.scrollTo({
|
558
|
-
direction: 'top',
|
559
|
-
id : me.view.vdom.id,
|
560
|
-
value : me.view.scrollPosition.y + deltaY
|
561
|
-
})
|
562
|
-
|
563
|
-
me.lastTouchY = lastTouchY
|
564
|
-
}
|
565
|
-
}
|
566
|
-
|
567
|
-
}
|
568
|
-
}
|
569
|
-
|
570
543
|
/**
|
571
544
|
* @param {Object} opts
|
572
545
|
* @param {String} opts.direction
|
@@ -657,6 +630,58 @@ class GridContainer extends BaseContainer {
|
|
657
630
|
}
|
658
631
|
})
|
659
632
|
}
|
633
|
+
|
634
|
+
/**
|
635
|
+
* Used for keyboard navigation (selection models)
|
636
|
+
* @param {Number} index
|
637
|
+
* @param {Number} step
|
638
|
+
*/
|
639
|
+
scrollByColumns(index, step) {
|
640
|
+
let me = this,
|
641
|
+
{view} = me,
|
642
|
+
{columnPositions, containerWidth, mountedColumns, visibleColumns} = view,
|
643
|
+
countColumns = columnPositions.getCount(),
|
644
|
+
newIndex = index + step,
|
645
|
+
column, mounted, scrollLeft, visible;
|
646
|
+
|
647
|
+
if (newIndex >= countColumns) {
|
648
|
+
newIndex %= countColumns;
|
649
|
+
step = newIndex - index
|
650
|
+
}
|
651
|
+
|
652
|
+
while (newIndex < 0) {
|
653
|
+
newIndex += countColumns;
|
654
|
+
step += countColumns
|
655
|
+
}
|
656
|
+
|
657
|
+
mounted = newIndex >= mountedColumns[0] && newIndex <= mountedColumns[1];
|
658
|
+
|
659
|
+
// Not using >= or <=, since the first / last column might not be fully visible
|
660
|
+
visible = newIndex > visibleColumns[0] && newIndex < visibleColumns[1];
|
661
|
+
|
662
|
+
if (!visible) {
|
663
|
+
// Leaving the mounted area will re-calculate the visibleColumns for us
|
664
|
+
if (mounted) {
|
665
|
+
visibleColumns[0] += step;
|
666
|
+
visibleColumns[1] += step
|
667
|
+
}
|
668
|
+
|
669
|
+
column = columnPositions.getAt(newIndex);
|
670
|
+
|
671
|
+
if (step < 0) {
|
672
|
+
scrollLeft = column.x
|
673
|
+
} else {
|
674
|
+
scrollLeft = column.x - containerWidth + column.width
|
675
|
+
}
|
676
|
+
|
677
|
+
Neo.main.DomAccess.scrollTo({
|
678
|
+
direction: 'left',
|
679
|
+
id : me.id,
|
680
|
+
value : scrollLeft,
|
681
|
+
windowId : me.windowId
|
682
|
+
})
|
683
|
+
}
|
684
|
+
}
|
660
685
|
}
|
661
686
|
|
662
687
|
export default Neo.setupClass(GridContainer);
|