ember-sortable 2.4.0 → 3.0.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/ISSUE_TEMPLATE/bug_report.md +2 -2
- package/.github/workflows/github_ci.yml +15 -13
- package/CHANGELOG.md +203 -108
- package/MIGRATION_GUIDE_MODIFIERS.md +20 -13
- package/MIGRATION_GUIDE_V2.md +20 -8
- package/README.md +74 -151
- package/V2_MIGRATION_RFC.md +188 -222
- package/addon/modifiers/sortable-group.js +38 -40
- package/addon/modifiers/sortable-handle.js +16 -18
- package/addon/modifiers/sortable-item.js +101 -74
- package/addon/services/ember-sortable.js +3 -6
- package/addon/system/scroll-parent.js +1 -1
- package/addon/utils/coordinate.js +1 -1
- package/addon/utils/css-calculation.js +2 -2
- package/addon/utils/defaults.js +4 -3
- package/addon/utils/keyboard.js +3 -12
- package/addon-test-support/helpers/drag.js +3 -11
- package/addon-test-support/helpers/index.js +1 -4
- package/addon-test-support/helpers/reorder.js +4 -6
- package/addon-test-support/utils/keyboard.js +3 -12
- package/addon-test-support/utils/offset.js +6 -6
- package/config/environment.js +2 -2
- package/index.js +0 -20
- package/package.json +31 -17
- package/addon/components/sortable-group.js +0 -741
- package/addon/components/sortable-handle.js +0 -30
- package/addon/components/sortable-item.js +0 -770
- package/addon/styles/components/sortable-group.css +0 -9
- package/addon/templates/components/sortable-group.hbs +0 -16
- package/addon/templates/components/sortable-handle.hbs +0 -1
- package/addon/templates/components/sortable-item.hbs +0 -2
- package/addon/utils/transitionend.js +0 -22
- package/app/components/sortable-group.js +0 -3
- package/app/components/sortable-handle.js +0 -4
- package/app/components/sortable-item.js +0 -3
- package/vendor/polyfills/closest.js +0 -21
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
/* eslint-disable ember/no-computed-properties-in-native-classes */
|
|
2
|
+
/* eslint-disable ember/no-incorrect-calls-with-inline-anonymous-functions */
|
|
1
3
|
import Modifier from 'ember-modifier';
|
|
2
|
-
import {action, computed, set} from '@ember/object';
|
|
4
|
+
import { action, computed, set } from '@ember/object';
|
|
3
5
|
import {
|
|
4
6
|
isDownArrowKey,
|
|
5
7
|
isEnterKey,
|
|
@@ -7,12 +9,12 @@ import {
|
|
|
7
9
|
isLeftArrowKey,
|
|
8
10
|
isRightArrowKey,
|
|
9
11
|
isSpaceKey,
|
|
10
|
-
isUpArrowKey
|
|
11
|
-
} from
|
|
12
|
-
import {ANNOUNCEMENT_ACTION_TYPES} from
|
|
13
|
-
import { defaultA11yAnnouncementConfig } from
|
|
12
|
+
isUpArrowKey,
|
|
13
|
+
} from '../utils/keyboard';
|
|
14
|
+
import { ANNOUNCEMENT_ACTION_TYPES } from '../utils/constant';
|
|
15
|
+
import { defaultA11yAnnouncementConfig } from '../utils/defaults';
|
|
14
16
|
import { next, schedule, scheduleOnce, later } from '@ember/runloop';
|
|
15
|
-
import {inject as service} from '@ember/service';
|
|
17
|
+
import { inject as service } from '@ember/service';
|
|
16
18
|
|
|
17
19
|
const NO_MODEL = {};
|
|
18
20
|
|
|
@@ -37,7 +39,6 @@ const NO_MODEL = {};
|
|
|
37
39
|
* </ol>
|
|
38
40
|
*/
|
|
39
41
|
export default class SortableGroupModifier extends Modifier {
|
|
40
|
-
|
|
41
42
|
/** Primary keyboard utils */
|
|
42
43
|
// Tracks the currently selected item
|
|
43
44
|
_selectedItem = null;
|
|
@@ -91,7 +92,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
91
92
|
}
|
|
92
93
|
|
|
93
94
|
get itemVisualClass() {
|
|
94
|
-
return this.args.named.itemVisualClass ||
|
|
95
|
+
return this.args.named.itemVisualClass || 'is-activated';
|
|
95
96
|
}
|
|
96
97
|
|
|
97
98
|
get a11yItemName() {
|
|
@@ -179,7 +180,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
179
180
|
|
|
180
181
|
// switch direction values to notify sortedItems to update, so it sorts by direction.
|
|
181
182
|
let value;
|
|
182
|
-
const dimension = direction ===
|
|
183
|
+
const dimension = direction === 'y' ? 'height' : 'width';
|
|
183
184
|
// DOWN or RIGHT
|
|
184
185
|
if (toIndex > fromIndex) {
|
|
185
186
|
value = item[direction];
|
|
@@ -206,13 +207,13 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
206
207
|
const direction = this.direction;
|
|
207
208
|
const selectedItem = this._selectedItem;
|
|
208
209
|
|
|
209
|
-
if (direction ===
|
|
210
|
+
if (direction === 'y' && isDownArrowKey(event)) {
|
|
210
211
|
this.moveItem(selectedItem, 1);
|
|
211
|
-
} else if (direction ===
|
|
212
|
+
} else if (direction === 'y' && isUpArrowKey(event)) {
|
|
212
213
|
this.moveItem(selectedItem, -1);
|
|
213
|
-
} else if (direction ===
|
|
214
|
+
} else if (direction === 'x' && isLeftArrowKey(event)) {
|
|
214
215
|
this.moveItem(selectedItem, -1);
|
|
215
|
-
} else if (direction ===
|
|
216
|
+
} else if (direction === 'x' && isRightArrowKey(event)) {
|
|
216
217
|
this.moveItem(selectedItem, 1);
|
|
217
218
|
} else if (isEnterKey(event) || isSpaceKey(event)) {
|
|
218
219
|
// confirm will reset the selectedItem, so caching it here before we remove it.
|
|
@@ -233,7 +234,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
233
234
|
const moves = this.moves;
|
|
234
235
|
if (moves && moves.length > 0) {
|
|
235
236
|
const sortedItems = this.sortedItems;
|
|
236
|
-
const itemElement = sortedItems[moves[0].fromIndex].element
|
|
237
|
+
const itemElement = sortedItems[moves[0].fromIndex].element;
|
|
237
238
|
this._focusItem(itemElement);
|
|
238
239
|
} else {
|
|
239
240
|
this._focusItem(_selectedItemElement);
|
|
@@ -285,7 +286,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
285
286
|
const moves = this.moves;
|
|
286
287
|
while (moves.length > 0) {
|
|
287
288
|
const move = moves.pop();
|
|
288
|
-
this._move(move[1], move[0])
|
|
289
|
+
this._move(move[1], move[0]);
|
|
289
290
|
}
|
|
290
291
|
this._tearDownA11yApplicationContainer();
|
|
291
292
|
this._updateItemVisualIndicators(_selectedItem, false);
|
|
@@ -306,7 +307,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
306
307
|
this.moves = [];
|
|
307
308
|
this._disableKeyboardReorderMode();
|
|
308
309
|
this._tearDownA11yApplicationContainer();
|
|
309
|
-
set(_selectedItem,
|
|
310
|
+
set(_selectedItem, 'wasDropped', true);
|
|
310
311
|
this.commit();
|
|
311
312
|
this._updateItemVisualIndicators(_selectedItem, false);
|
|
312
313
|
this._updateHandleVisualIndicators(_selectedItem, false);
|
|
@@ -335,7 +336,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
335
336
|
const config = {
|
|
336
337
|
a11yItemName,
|
|
337
338
|
index: index,
|
|
338
|
-
maxLength
|
|
339
|
+
maxLength: sortedItems.length,
|
|
339
340
|
direction: this.direction,
|
|
340
341
|
delta,
|
|
341
342
|
};
|
|
@@ -363,7 +364,6 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
363
364
|
* @param {Boolean} isActive to activate or deactivate the class.
|
|
364
365
|
*/
|
|
365
366
|
_updateItemVisualIndicators(item, isActive) {
|
|
366
|
-
|
|
367
367
|
const itemVisualClass = this.itemVisualClass;
|
|
368
368
|
|
|
369
369
|
if (!itemVisualClass || !item) {
|
|
@@ -397,7 +397,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
397
397
|
const visualHandle = handle ? handle : item.element;
|
|
398
398
|
const visualKeys = direction === 'y' ? ['UP', 'DOWN'] : ['LEFT', 'RIGHT'];
|
|
399
399
|
|
|
400
|
-
visualKeys.forEach(visualKey => {
|
|
400
|
+
visualKeys.forEach((visualKey) => {
|
|
401
401
|
visualHandle.classList.remove(handleVisualClass[visualKey]);
|
|
402
402
|
});
|
|
403
403
|
|
|
@@ -447,7 +447,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
447
447
|
* Sets up the group as an application and make it programmatically focusable.
|
|
448
448
|
*/
|
|
449
449
|
_setupA11yApplicationContainer() {
|
|
450
|
-
this.element.setAttribute(
|
|
450
|
+
this.element.setAttribute('role', 'application');
|
|
451
451
|
this.element.tabIndex = -1;
|
|
452
452
|
}
|
|
453
453
|
|
|
@@ -455,8 +455,8 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
455
455
|
* Tears down the `role=application` container.
|
|
456
456
|
*/
|
|
457
457
|
_tearDownA11yApplicationContainer() {
|
|
458
|
-
this.element.removeAttribute(
|
|
459
|
-
this.element.removeAttribute(
|
|
458
|
+
this.element.removeAttribute('role');
|
|
459
|
+
this.element.removeAttribute('tabIndex');
|
|
460
460
|
}
|
|
461
461
|
|
|
462
462
|
_prepareKeyboardReorderMode() {
|
|
@@ -472,7 +472,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
472
472
|
@default y
|
|
473
473
|
*/
|
|
474
474
|
get direction() {
|
|
475
|
-
return this.args.named.direction ||
|
|
475
|
+
return this.args.named.direction || 'y';
|
|
476
476
|
}
|
|
477
477
|
|
|
478
478
|
/**
|
|
@@ -499,7 +499,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
499
499
|
* @returns {*|string}
|
|
500
500
|
*/
|
|
501
501
|
get groupName() {
|
|
502
|
-
return this.args.named.groupName ||
|
|
502
|
+
return this.args.named.groupName || '_EmberSortableGroup';
|
|
503
503
|
}
|
|
504
504
|
|
|
505
505
|
_groupDef = this.sortableService.fetchGroup(this.groupName);
|
|
@@ -530,7 +530,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
530
530
|
@property firstItemPosition
|
|
531
531
|
@type Number
|
|
532
532
|
*/
|
|
533
|
-
@computed(
|
|
533
|
+
@computed('direction', 'sortedItems')
|
|
534
534
|
get firstItemPosition() {
|
|
535
535
|
const direction = this.direction;
|
|
536
536
|
const sortedItems = this.sortedItems;
|
|
@@ -552,7 +552,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
552
552
|
* Enables keyboard navigation
|
|
553
553
|
*/
|
|
554
554
|
@action
|
|
555
|
-
activateKeyDown(selectedItem){
|
|
555
|
+
activateKeyDown(selectedItem) {
|
|
556
556
|
this._selectedItem = selectedItem;
|
|
557
557
|
this.isKeyDownEnabled = true;
|
|
558
558
|
}
|
|
@@ -616,7 +616,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
616
616
|
position = this.firstItemPosition;
|
|
617
617
|
}
|
|
618
618
|
|
|
619
|
-
sortedItems.forEach(item => {
|
|
619
|
+
sortedItems.forEach((item) => {
|
|
620
620
|
let dimension;
|
|
621
621
|
let direction = this.direction;
|
|
622
622
|
|
|
@@ -646,8 +646,8 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
646
646
|
@action
|
|
647
647
|
commit() {
|
|
648
648
|
const items = this.sortedItems;
|
|
649
|
-
const itemModels = items.map(item => item.model);
|
|
650
|
-
const draggedItem = items.find(item => item.wasDropped);
|
|
649
|
+
const itemModels = items.map((item) => item.model);
|
|
650
|
+
const draggedItem = items.find((item) => item.wasDropped);
|
|
651
651
|
let draggedModel;
|
|
652
652
|
|
|
653
653
|
if (draggedItem) {
|
|
@@ -676,16 +676,16 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
676
676
|
delete this._firstItemPosition;
|
|
677
677
|
|
|
678
678
|
schedule('render', () => {
|
|
679
|
-
items.forEach(item => item.freeze());
|
|
679
|
+
items.forEach((item) => item.freeze());
|
|
680
680
|
});
|
|
681
681
|
|
|
682
682
|
schedule('afterRender', () => {
|
|
683
|
-
items.forEach(item => item.reset());
|
|
683
|
+
items.forEach((item) => item.reset());
|
|
684
684
|
});
|
|
685
685
|
|
|
686
686
|
next(() => {
|
|
687
687
|
schedule('render', () => {
|
|
688
|
-
items.forEach(item => item.thaw());
|
|
688
|
+
items.forEach((item) => item.thaw());
|
|
689
689
|
});
|
|
690
690
|
});
|
|
691
691
|
}
|
|
@@ -701,13 +701,13 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
701
701
|
// end of API
|
|
702
702
|
|
|
703
703
|
addEventListener() {
|
|
704
|
-
this.element.addEventListener(
|
|
705
|
-
this.element.addEventListener(
|
|
704
|
+
this.element.addEventListener('keydown', this.keyDown);
|
|
705
|
+
this.element.addEventListener('focusout', this.focusOut);
|
|
706
706
|
}
|
|
707
707
|
|
|
708
708
|
removeEventListener() {
|
|
709
|
-
this.element.removeEventListener(
|
|
710
|
-
this.element.removeEventListener(
|
|
709
|
+
this.element.removeEventListener('keydown', this.keyDown);
|
|
710
|
+
this.element.removeEventListener('focusout', this.focusOut);
|
|
711
711
|
}
|
|
712
712
|
|
|
713
713
|
didReceiveArguments() {
|
|
@@ -720,8 +720,7 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
720
720
|
this.addEventListener();
|
|
721
721
|
}
|
|
722
722
|
|
|
723
|
-
didUpdateArguments() {
|
|
724
|
-
}
|
|
723
|
+
didUpdateArguments() {}
|
|
725
724
|
|
|
726
725
|
didInstall() {
|
|
727
726
|
this.announcer = this._createAnnouncer();
|
|
@@ -732,12 +731,11 @@ export default class SortableGroupModifier extends Modifier {
|
|
|
732
731
|
|
|
733
732
|
willRemove() {
|
|
734
733
|
// todo cleanup the announcer
|
|
735
|
-
if(this.announcer.parentNode) {
|
|
734
|
+
if (this.announcer.parentNode) {
|
|
736
735
|
this.announcer.parentNode.removeChild(this.announcer);
|
|
737
736
|
}
|
|
738
737
|
this.removeEventListener();
|
|
739
738
|
|
|
740
739
|
this.sortableService.deregisterGroup(this.groupName, this);
|
|
741
740
|
}
|
|
742
|
-
|
|
743
741
|
}
|
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
import Modifier from 'ember-modifier';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Modifier to to mark the handle of an item. If this is not supplied the item will be the handle
|
|
5
|
-
*
|
|
6
|
-
* @module drag-drop/draggable-group
|
|
7
|
-
* @example*
|
|
8
|
-
* <ol {{sortable-group onChange=this.update a11yAnnouncementConfig=this.myA11yConfig}}>
|
|
9
|
-
* {{#each model.items as |item|}}
|
|
10
|
-
* <li {{sortable-item model=item}}>
|
|
11
|
-
* {{item.name}}
|
|
12
|
-
* <span class="handle" {{sortable-handle}}>↕</span>
|
|
13
|
-
* </li>
|
|
14
|
-
* {{/each}}
|
|
15
|
-
* </ol>
|
|
16
|
-
*/
|
|
4
|
+
* Modifier to to mark the handle of an item. If this is not supplied the item will be the handle
|
|
5
|
+
*
|
|
6
|
+
* @module drag-drop/draggable-group
|
|
7
|
+
* @example*
|
|
8
|
+
* <ol {{sortable-group onChange=this.update a11yAnnouncementConfig=this.myA11yConfig}}>
|
|
9
|
+
* {{#each model.items as |item|}}
|
|
10
|
+
* <li {{sortable-item model=item}}>
|
|
11
|
+
* {{item.name}}
|
|
12
|
+
* <span class="handle" {{sortable-handle}}>↕</span>
|
|
13
|
+
* </li>
|
|
14
|
+
* {{/each}}
|
|
15
|
+
* </ol>
|
|
16
|
+
*/
|
|
17
17
|
export default class SortableHandleModifier extends Modifier {
|
|
18
|
-
|
|
19
18
|
didInstall() {
|
|
20
19
|
// take the model and look up the registered element, the tell that element you are the handle
|
|
21
|
-
this.element.dataset.sortableHandle=true;
|
|
22
|
-
this.element.tabIndex =
|
|
23
|
-
this.element.setAttribute(
|
|
20
|
+
this.element.dataset.sortableHandle = true;
|
|
21
|
+
this.element.tabIndex = '0';
|
|
22
|
+
this.element.setAttribute('role', 'button');
|
|
24
23
|
}
|
|
25
|
-
|
|
26
24
|
}
|