@brightspace-ui/core 1.210.0 → 1.213.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/README.md +11 -6
- package/components/dropdown/dropdown-content-mixin.js +3 -4
- package/components/dropdown/dropdown-menu.js +1 -3
- package/components/dropdown/dropdown-opener-mixin.js +1 -1
- package/components/filter/filter.js +36 -12
- package/components/list/demo/{list-demo-drag-and-drop-usage.js → list-drag-and-drop-position.js} +3 -2
- package/components/list/demo/list-drag-and-drop.html +12 -19
- package/components/list/demo/list-drag-and-drop.js +171 -0
- package/components/list/list-item-checkbox-mixin.js +4 -10
- package/components/list/list-item-drag-drop-mixin.js +205 -47
- package/components/list/list-item-drag-handle.js +18 -7
- package/components/list/list-item-generic-layout.js +12 -1
- package/components/list/list-item-mixin.js +51 -3
- package/components/list/list.js +30 -12
- package/components/menu/menu-item-mixin.js +3 -1
- package/components/menu/menu-item-styles.js +5 -4
- package/components/menu/menu.js +2 -1
- package/controllers/subscriber/README.md +177 -0
- package/controllers/subscriber/subscriberControllers.js +180 -0
- package/custom-elements.json +121 -35
- package/package.json +6 -4
- package/tools/perf-test-helper.js +0 -45
|
@@ -1,23 +1,27 @@
|
|
|
1
1
|
import { css, html } from 'lit-element/lit-element.js';
|
|
2
|
+
import { findComposedAncestor, isComposedAncestor } from '../../helpers/dom.js';
|
|
2
3
|
import { announce } from '../../helpers/announce.js';
|
|
3
4
|
import { classMap } from 'lit-html/directives/class-map.js';
|
|
4
5
|
import { dragActions } from './list-item-drag-handle.js';
|
|
5
|
-
import { findComposedAncestor } from '../../helpers/dom.js';
|
|
6
6
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
7
7
|
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
|
8
8
|
import { nothing } from 'lit-html';
|
|
9
|
+
import { SelectionInfo } from '../selection/selection-mixin.js';
|
|
9
10
|
|
|
10
|
-
export const
|
|
11
|
+
export const moveLocations = Object.freeze({
|
|
11
12
|
above: 1,
|
|
12
13
|
below: 2,
|
|
13
14
|
first: 3,
|
|
14
15
|
last: 4,
|
|
15
16
|
shiftDown: 5,
|
|
16
17
|
shiftUp: 6,
|
|
18
|
+
nest: 7,
|
|
17
19
|
void: 0
|
|
18
20
|
});
|
|
19
21
|
|
|
20
|
-
const
|
|
22
|
+
export const dropLocation = moveLocations; // backwards compatibility
|
|
23
|
+
|
|
24
|
+
const dropTargetLeaveDelay = 1000; // ms
|
|
21
25
|
const touchHoldDuration = 400; // length of time user needs to hold down touch before dragging occurs
|
|
22
26
|
const scrollSensitivity = 150; // pixels between top/bottom of viewport to scroll for mobile
|
|
23
27
|
|
|
@@ -38,20 +42,16 @@ const isDragSupported = () => {
|
|
|
38
42
|
};
|
|
39
43
|
|
|
40
44
|
class DragState {
|
|
41
|
-
constructor(
|
|
42
|
-
this.
|
|
45
|
+
constructor(dragTargets) {
|
|
46
|
+
this._dragTargets = dragTargets;
|
|
43
47
|
this._activeDropTarget = null;
|
|
44
48
|
this._dropTargets = new Map();
|
|
45
49
|
this._dropLocation = dropLocation.void;
|
|
46
50
|
this._time = 0;
|
|
47
51
|
}
|
|
48
52
|
|
|
49
|
-
get
|
|
50
|
-
return this.
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
get dragTargetKey() {
|
|
54
|
-
return this._dragTarget && this._dragTarget.key;
|
|
53
|
+
get dragTargets() {
|
|
54
|
+
return this._dragTargets;
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
get dropLocation() {
|
|
@@ -117,9 +117,9 @@ class DragState {
|
|
|
117
117
|
|
|
118
118
|
let dragState = null;
|
|
119
119
|
|
|
120
|
-
function createDragState(
|
|
120
|
+
function createDragState(targets) {
|
|
121
121
|
clearDragState();
|
|
122
|
-
dragState = new DragState(
|
|
122
|
+
dragState = new DragState(targets ? targets : []);
|
|
123
123
|
return dragState;
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -263,6 +263,11 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
263
263
|
* @type {string}
|
|
264
264
|
*/
|
|
265
265
|
dragHandleText: { type: String, attribute: 'drag-handle-text' },
|
|
266
|
+
/**
|
|
267
|
+
* **Drag & drop:** Whether the items can be dropped as nested children
|
|
268
|
+
* @type {boolean}
|
|
269
|
+
*/
|
|
270
|
+
dropNested: { type: Boolean, attribute: 'drop-nested' },
|
|
266
271
|
/**
|
|
267
272
|
* **Drag & drop:** Text to drag and drop
|
|
268
273
|
* @type {string}
|
|
@@ -274,7 +279,7 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
274
279
|
*/
|
|
275
280
|
key: { type: String, reflect: true },
|
|
276
281
|
_draggingOver: { type: Boolean },
|
|
277
|
-
_dropLocation: { type: Number },
|
|
282
|
+
_dropLocation: { type: Number, reflect: true, attribute: '_drop-location' },
|
|
278
283
|
_focusingDragHandle: { type: Boolean },
|
|
279
284
|
_hovering: { type: Boolean },
|
|
280
285
|
_keyboardActive: { type: Boolean },
|
|
@@ -293,6 +298,7 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
293
298
|
}
|
|
294
299
|
.d2l-list-item-drag-bottom-marker,
|
|
295
300
|
.d2l-list-item-drag-top-marker {
|
|
301
|
+
pointer-events: none;
|
|
296
302
|
position: absolute;
|
|
297
303
|
width: 100%;
|
|
298
304
|
z-index: 1;
|
|
@@ -311,16 +317,16 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
311
317
|
display: grid;
|
|
312
318
|
grid-template-columns: 100%;
|
|
313
319
|
grid-template-rows: 1rem 1fr 1fr 1rem;
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
z-index: 100;
|
|
320
|
+
}
|
|
321
|
+
:host([_drop-location="7"]) d2l-list-item-generic-layout {
|
|
322
|
+
border-radius: 6px;
|
|
323
|
+
outline: 2px solid var(--d2l-color-celestine);
|
|
319
324
|
}
|
|
320
325
|
@media only screen and (hover: hover), only screen and (pointer: fine) {
|
|
321
326
|
d2l-list-item-drag-handle {
|
|
322
327
|
opacity: 0;
|
|
323
328
|
}
|
|
329
|
+
:host([selected]) d2l-list-item-drag-handle,
|
|
324
330
|
d2l-list-item-drag-handle.d2l-hovering,
|
|
325
331
|
d2l-list-item-drag-handle.d2l-focusing {
|
|
326
332
|
opacity: 1;
|
|
@@ -335,8 +341,10 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
335
341
|
constructor() {
|
|
336
342
|
super();
|
|
337
343
|
this._itemDragId = getUniqueId();
|
|
344
|
+
this.draggable = false;
|
|
338
345
|
/** @ignore */
|
|
339
346
|
this.dragging = false;
|
|
347
|
+
this.dropNested = false;
|
|
340
348
|
}
|
|
341
349
|
|
|
342
350
|
connectedCallback() {
|
|
@@ -351,6 +359,10 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
351
359
|
super.firstUpdated(changedProperties);
|
|
352
360
|
}
|
|
353
361
|
|
|
362
|
+
activateDragHandle() {
|
|
363
|
+
this.shadowRoot.querySelector(`#${this._itemDragId}`).activateKeyboardMode();
|
|
364
|
+
}
|
|
365
|
+
|
|
354
366
|
_annoucePositionChange(dragTargetKey, dropTargetKey, dropLocation) {
|
|
355
367
|
/** Dispatched when a draggable list item's position changes in the list. See [Event Details: d2l-list-item-position-change](#event-details%3A-d2l-list-item-position-change). */
|
|
356
368
|
this.dispatchEvent(new CustomEvent('d2l-list-item-position-change', {
|
|
@@ -359,6 +371,84 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
359
371
|
}));
|
|
360
372
|
}
|
|
361
373
|
|
|
374
|
+
_dispatchListItemsMove(sourceItems, targetItem, moveLocation, keyboardActive) {
|
|
375
|
+
if (!keyboardActive) keyboardActive = false;
|
|
376
|
+
const rootList = this._getRootList();
|
|
377
|
+
rootList.dispatchEvent(new CustomEvent('d2l-list-items-move', {
|
|
378
|
+
detail: {
|
|
379
|
+
keyboardActive: keyboardActive,
|
|
380
|
+
sourceItems: sourceItems,
|
|
381
|
+
target: {
|
|
382
|
+
item: targetItem,
|
|
383
|
+
location: moveLocation
|
|
384
|
+
}
|
|
385
|
+
},
|
|
386
|
+
bubbles: true
|
|
387
|
+
}));
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
_dispatchMoveListItemFirst(moveToRoot) {
|
|
391
|
+
const list = (moveToRoot ? this._getRootList() : findComposedAncestor(this, node => node.tagName === 'D2L-LIST'));
|
|
392
|
+
const items = list.getItems();
|
|
393
|
+
this._dispatchListItemsMove([this], items[0], moveLocations.above, true);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
_dispatchMoveListItemLast(moveToRoot) {
|
|
397
|
+
const list = (moveToRoot ? this._getRootList() : findComposedAncestor(this, node => node.tagName === 'D2L-LIST'));
|
|
398
|
+
const items = list.getItems();
|
|
399
|
+
this._dispatchListItemsMove([this], items[items.length - 1], moveLocations.below, true);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
_dispatchMoveListItemNest() {
|
|
403
|
+
const listItem = this._getPreviousListItemSibling();
|
|
404
|
+
if (listItem) {
|
|
405
|
+
this._dispatchListItemsMove([this], listItem, moveLocations.nest, true);
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
_dispatchMoveListItemNext() {
|
|
410
|
+
const listItem = this._getNextListItemSibling();
|
|
411
|
+
if (listItem) {
|
|
412
|
+
const nestedList = listItem._getNestedList();
|
|
413
|
+
const items = (nestedList ? nestedList.getItems() : []);
|
|
414
|
+
if (items.length > 0) {
|
|
415
|
+
this._dispatchListItemsMove([this], items[0], moveLocations.above, true);
|
|
416
|
+
} else {
|
|
417
|
+
this._dispatchListItemsMove([this], listItem, moveLocations.below, true);
|
|
418
|
+
}
|
|
419
|
+
} else {
|
|
420
|
+
const parentListItem = this._getParentListItem();
|
|
421
|
+
if (parentListItem) {
|
|
422
|
+
this._dispatchListItemsMove([this], parentListItem, moveLocations.below, true);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
_dispatchMoveListItemPrevious() {
|
|
428
|
+
const listItem = this._getPreviousListItemSibling();
|
|
429
|
+
if (listItem) {
|
|
430
|
+
const nestedList = listItem._getNestedList();
|
|
431
|
+
const items = (nestedList ? nestedList.getItems() : []);
|
|
432
|
+
if (items.length > 0) {
|
|
433
|
+
this._dispatchListItemsMove([this], items[items.length - 1], moveLocations.below, true);
|
|
434
|
+
} else {
|
|
435
|
+
this._dispatchListItemsMove([this], listItem, moveLocations.above, true);
|
|
436
|
+
}
|
|
437
|
+
} else {
|
|
438
|
+
const parentListItem = this._getParentListItem();
|
|
439
|
+
if (parentListItem) {
|
|
440
|
+
this._dispatchListItemsMove([this], parentListItem, moveLocations.above, true);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
_dispatchMoveListItemUnnest() {
|
|
446
|
+
const listItem = this._getParentListItem();
|
|
447
|
+
if (listItem) {
|
|
448
|
+
this._dispatchListItemsMove([this], listItem, moveLocations.below, true);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
362
452
|
_findListItemFromCoordinates(x, y) {
|
|
363
453
|
const listNode = findComposedAncestor(this.parentNode, (node) => node && node.tagName === 'D2L-LIST');
|
|
364
454
|
return listNode.shadowRoot.elementFromPoint(x, y);
|
|
@@ -380,11 +470,27 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
380
470
|
}
|
|
381
471
|
|
|
382
472
|
_onDragEnd(e) {
|
|
473
|
+
|
|
383
474
|
const dragState = getDragState();
|
|
384
475
|
this.dragging = false;
|
|
385
|
-
|
|
386
|
-
|
|
476
|
+
|
|
477
|
+
// check the dropEffect in case the user cancelled by Escape while dragging ('none' set by browser)
|
|
478
|
+
if (e.dataTransfer.dropEffect !== 'none' && dragState.shouldDrop(e.timeStamp)) {
|
|
479
|
+
|
|
480
|
+
const dropTargetList = findComposedAncestor(dragState.dropTarget, node => node.tagName === 'D2L-LIST');
|
|
481
|
+
const shouldDispatchPositionChange = !dragState.dragTargets.find(dragTarget => {
|
|
482
|
+
const dragTargetList = findComposedAncestor(dragTarget, node => node.tagName === 'D2L-LIST');
|
|
483
|
+
return dragTargetList !== dropTargetList;
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
if (shouldDispatchPositionChange && dragState.dragTargets.length === 1) {
|
|
487
|
+
this._annoucePositionChange(dragState.dragTargets[0].key, dragState.dropTargetKey, dragState.dropLocation);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
this._dispatchListItemsMove(dragState.dragTargets, dragState.dropTarget, dragState.dropLocation, false);
|
|
491
|
+
|
|
387
492
|
}
|
|
493
|
+
|
|
388
494
|
clearDragState();
|
|
389
495
|
}
|
|
390
496
|
|
|
@@ -399,15 +505,31 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
399
505
|
break;
|
|
400
506
|
case dragActions.up:
|
|
401
507
|
this._annoucePositionChange(this.key, null, dropLocation.shiftUp);
|
|
508
|
+
this._dispatchMoveListItemPrevious();
|
|
402
509
|
break;
|
|
403
510
|
case dragActions.down:
|
|
404
511
|
this._annoucePositionChange(this.key, null, dropLocation.shiftDown);
|
|
512
|
+
this._dispatchMoveListItemNext();
|
|
513
|
+
break;
|
|
514
|
+
case dragActions.nest:
|
|
515
|
+
this._dispatchMoveListItemNest();
|
|
516
|
+
break;
|
|
517
|
+
case dragActions.unnest:
|
|
518
|
+
this._dispatchMoveListItemUnnest();
|
|
405
519
|
break;
|
|
406
520
|
case dragActions.first:
|
|
407
521
|
this._annoucePositionChange(this.key, null, dropLocation.first);
|
|
522
|
+
this._dispatchMoveListItemFirst();
|
|
523
|
+
break;
|
|
524
|
+
case dragActions.rootFirst:
|
|
525
|
+
this._dispatchMoveListItemFirst(true);
|
|
408
526
|
break;
|
|
409
527
|
case dragActions.last:
|
|
410
528
|
this._annoucePositionChange(this.key, null, dropLocation.last);
|
|
529
|
+
this._dispatchMoveListItemLast();
|
|
530
|
+
break;
|
|
531
|
+
case dragActions.rootLast:
|
|
532
|
+
this._dispatchMoveListItemLast(true);
|
|
411
533
|
break;
|
|
412
534
|
default:
|
|
413
535
|
break;
|
|
@@ -427,13 +549,32 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
427
549
|
e.dataTransfer.setData('text/plain', `${this.dropText}`);
|
|
428
550
|
}
|
|
429
551
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
}
|
|
552
|
+
const nodeImage = this.shadowRoot.querySelector('.d2l-list-item-drag-image') || this;
|
|
553
|
+
e.dataTransfer.setDragImage(nodeImage, 50, 50);
|
|
554
|
+
|
|
555
|
+
const rootList = this._getRootList(this);
|
|
435
556
|
|
|
436
|
-
|
|
557
|
+
// getSelectionInfo(false) is fast so we can quickly check the state
|
|
558
|
+
if (!rootList.dragMultiple || rootList.getSelectionInfo(false).state === SelectionInfo.states.none) {
|
|
559
|
+
createDragState([this]);
|
|
560
|
+
} else {
|
|
561
|
+
|
|
562
|
+
// get the seelcted items, but do not include selected items of selected items
|
|
563
|
+
const getDragTargets = list => {
|
|
564
|
+
let dragTargets = [];
|
|
565
|
+
list.getItems().forEach(item => {
|
|
566
|
+
if (item.selected || item === this) {
|
|
567
|
+
dragTargets.push(item);
|
|
568
|
+
} else if (item._selectionProvider) {
|
|
569
|
+
dragTargets = [...dragTargets, ...getDragTargets(item._selectionProvider)];
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
return dragTargets;
|
|
573
|
+
};
|
|
574
|
+
const dragTargets = getDragTargets(rootList);
|
|
575
|
+
|
|
576
|
+
createDragState(dragTargets);
|
|
577
|
+
}
|
|
437
578
|
|
|
438
579
|
setTimeout(() => {
|
|
439
580
|
this.dragging = true;
|
|
@@ -461,35 +602,47 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
461
602
|
dragState.setActiveDropTarget(this, dragState.dropLocation);
|
|
462
603
|
}
|
|
463
604
|
|
|
464
|
-
|
|
605
|
+
_onDropTargetBottomDragEnter(e) {
|
|
465
606
|
e.dataTransfer.dropEffect = 'move';
|
|
466
607
|
const dragState = getDragState();
|
|
467
608
|
dragState.setActiveDropTarget(this, dropLocation.below);
|
|
468
609
|
this._inBottomArea = true;
|
|
469
610
|
}
|
|
470
611
|
|
|
471
|
-
_onDropTargetDragEnter(e) {
|
|
472
|
-
e.dataTransfer.dropEffect = 'move';
|
|
473
|
-
const dragState = getDragState();
|
|
474
|
-
dragState.setActiveDropTarget(this, dropLocation.above);
|
|
475
|
-
this._inTopArea = true;
|
|
476
|
-
}
|
|
477
|
-
|
|
478
612
|
_onDropTargetLowerDragEnter(e) {
|
|
479
613
|
e.dataTransfer.dropEffect = 'move';
|
|
480
|
-
if (this.
|
|
481
|
-
const dragState = getDragState();
|
|
482
|
-
dragState.setActiveDropTarget(this, dropLocation.above);
|
|
614
|
+
if (this.dropNested) {
|
|
483
615
|
this._inBottomArea = false;
|
|
616
|
+
const dragState = getDragState();
|
|
617
|
+
dragState.setActiveDropTarget(this, moveLocations.nest);
|
|
618
|
+
} else {
|
|
619
|
+
if (this._inBottomArea) {
|
|
620
|
+
const dragState = getDragState();
|
|
621
|
+
dragState.setActiveDropTarget(this, dropLocation.above);
|
|
622
|
+
this._inBottomArea = false;
|
|
623
|
+
}
|
|
484
624
|
}
|
|
485
625
|
}
|
|
486
626
|
|
|
627
|
+
_onDropTargetTopDragEnter(e) {
|
|
628
|
+
e.dataTransfer.dropEffect = 'move';
|
|
629
|
+
const dragState = getDragState();
|
|
630
|
+
dragState.setActiveDropTarget(this, dropLocation.above);
|
|
631
|
+
this._inTopArea = true;
|
|
632
|
+
}
|
|
633
|
+
|
|
487
634
|
_onDropTargetUpperDragEnter(e) {
|
|
488
635
|
e.dataTransfer.dropEffect = 'move';
|
|
489
|
-
if (this.
|
|
490
|
-
const dragState = getDragState();
|
|
491
|
-
dragState.setActiveDropTarget(this, dropLocation.below);
|
|
636
|
+
if (this.dropNested) {
|
|
492
637
|
this._inTopArea = false;
|
|
638
|
+
const dragState = getDragState();
|
|
639
|
+
dragState.setActiveDropTarget(this, moveLocations.nest);
|
|
640
|
+
} else {
|
|
641
|
+
if (this._inTopArea) {
|
|
642
|
+
const dragState = getDragState();
|
|
643
|
+
dragState.setActiveDropTarget(this, dropLocation.below);
|
|
644
|
+
this._inTopArea = false;
|
|
645
|
+
}
|
|
493
646
|
}
|
|
494
647
|
}
|
|
495
648
|
|
|
@@ -504,9 +657,14 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
504
657
|
|
|
505
658
|
_onHostDragEnter(e) {
|
|
506
659
|
const dragState = getDragState();
|
|
507
|
-
if (this === dragState.dragTarget)
|
|
508
|
-
|
|
509
|
-
|
|
660
|
+
if (this === dragState.dragTarget) return;
|
|
661
|
+
|
|
662
|
+
// check if any of the drag targets are ancestors of the drop target
|
|
663
|
+
const invalidDropTarget = dragState.dragTargets.find(dragTarget => {
|
|
664
|
+
return isComposedAncestor(dragTarget, this);
|
|
665
|
+
});
|
|
666
|
+
if (invalidDropTarget) return;
|
|
667
|
+
|
|
510
668
|
dragState.addDropTarget(this);
|
|
511
669
|
this._draggingOver = true;
|
|
512
670
|
e.dataTransfer.dropEffect = 'move';
|
|
@@ -635,11 +793,11 @@ export const ListItemDragDropMixin = superclass => class extends superclass {
|
|
|
635
793
|
_renderDropTarget(templateMethod) {
|
|
636
794
|
templateMethod = templateMethod || (DropTarget => DropTarget);
|
|
637
795
|
return this.draggable && this._draggingOver ? templateMethod(html`
|
|
638
|
-
<div class="d2l-list-item-drag-drop-grid" @drop="${this._onDrop}" @dragover="${this._onDragOver}">
|
|
639
|
-
<div @dragenter="${this.
|
|
796
|
+
<div class="d2l-list-item-drag-drop-grid" slot="drop-target" @drop="${this._onDrop}" @dragover="${this._onDragOver}">
|
|
797
|
+
<div @dragenter="${this._onDropTargetTopDragEnter}"></div>
|
|
640
798
|
<div @dragenter="${this._onDropTargetUpperDragEnter}"></div>
|
|
641
799
|
<div @dragenter="${this._onDropTargetLowerDragEnter}"></div>
|
|
642
|
-
<div @dragenter="${this.
|
|
800
|
+
<div @dragenter="${this._onDropTargetBottomDragEnter}"></div>
|
|
643
801
|
</div>
|
|
644
802
|
`) : nothing;
|
|
645
803
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
1
|
import '../button/button-icon.js';
|
|
3
2
|
import '../icons/icon.js';
|
|
4
3
|
import { css, html, LitElement } from 'lit-element/lit-element.js';
|
|
@@ -6,6 +5,7 @@ import { buttonStyles } from '../button/button-styles.js';
|
|
|
6
5
|
import { findComposedAncestor } from '../../helpers/dom.js';
|
|
7
6
|
import { getFirstFocusableDescendant } from '../../helpers/focus.js';
|
|
8
7
|
import { LocalizeCoreElement } from '../../lang/localize-core-element.js';
|
|
8
|
+
import { RtlMixin } from '../../mixins/rtl-mixin.js';
|
|
9
9
|
|
|
10
10
|
const keyCodes = Object.freeze({
|
|
11
11
|
DOWN: 40,
|
|
@@ -26,16 +26,20 @@ export const dragActions = Object.freeze({
|
|
|
26
26
|
down: 'down',
|
|
27
27
|
first: 'first',
|
|
28
28
|
last: 'last',
|
|
29
|
+
nest: 'nest',
|
|
29
30
|
nextElement: 'next-element',
|
|
30
31
|
previousElement: 'previous-element',
|
|
32
|
+
rootFirst: 'rootFirst',
|
|
33
|
+
rootLast: 'rootLast',
|
|
31
34
|
save: 'keyboard-deactivate-save',
|
|
35
|
+
unnest: 'unnest',
|
|
32
36
|
up: 'up'
|
|
33
37
|
});
|
|
34
38
|
|
|
35
39
|
/**
|
|
36
40
|
* @fires d2l-list-item-drag-handle-action - Dispatched when an action performed on the drag handle
|
|
37
41
|
*/
|
|
38
|
-
class ListItemDragHandle extends LocalizeCoreElement(LitElement) {
|
|
42
|
+
class ListItemDragHandle extends LocalizeCoreElement(RtlMixin(LitElement)) {
|
|
39
43
|
|
|
40
44
|
static get properties() {
|
|
41
45
|
return {
|
|
@@ -176,11 +180,11 @@ class ListItemDragHandle extends LocalizeCoreElement(LitElement) {
|
|
|
176
180
|
break;
|
|
177
181
|
case keyCodes.HOME:
|
|
178
182
|
this._movingElement = true;
|
|
179
|
-
action = dragActions.first;
|
|
183
|
+
action = (e.ctrlKey ? dragActions.rootFirst : dragActions.first);
|
|
180
184
|
break;
|
|
181
185
|
case keyCodes.END:
|
|
182
186
|
this._movingElement = true;
|
|
183
|
-
action = dragActions.last;
|
|
187
|
+
action = (e.ctrlKey ? dragActions.rootLast : dragActions.last);
|
|
184
188
|
break;
|
|
185
189
|
case keyCodes.TAB:
|
|
186
190
|
action = e.shiftKey ? dragActions.previousElement : dragActions.nextElement;
|
|
@@ -189,9 +193,16 @@ class ListItemDragHandle extends LocalizeCoreElement(LitElement) {
|
|
|
189
193
|
action = dragActions.cancel;
|
|
190
194
|
this.updateComplete.then(() => this._keyboardActive = false);
|
|
191
195
|
break;
|
|
196
|
+
case keyCodes.RIGHT:
|
|
197
|
+
this._movingElement = true;
|
|
198
|
+
action = (this.dir === 'rtl' ? dragActions.unnest : dragActions.nest);
|
|
199
|
+
break;
|
|
200
|
+
case keyCodes.LEFT:
|
|
201
|
+
this._movingElement = true;
|
|
202
|
+
action = (this.dir === 'rtl' ? dragActions.nest : dragActions.unnest) ;
|
|
203
|
+
break;
|
|
192
204
|
case keyCodes.ENTER:
|
|
193
205
|
case keyCodes.SPACE:
|
|
194
|
-
case keyCodes.RIGHT:
|
|
195
206
|
action = dragActions.save;
|
|
196
207
|
this.updateComplete.then(() => this._keyboardActive = false);
|
|
197
208
|
break;
|
|
@@ -221,7 +232,7 @@ class ListItemDragHandle extends LocalizeCoreElement(LitElement) {
|
|
|
221
232
|
}
|
|
222
233
|
|
|
223
234
|
_onInactiveKeyboard(e) {
|
|
224
|
-
if (e.type === 'click' || e.keyCode === keyCodes.ENTER || e.keyCode === keyCodes.SPACE
|
|
235
|
+
if (e.type === 'click' || e.keyCode === keyCodes.ENTER || e.keyCode === keyCodes.SPACE) {
|
|
225
236
|
this._dispatchAction(dragActions.active);
|
|
226
237
|
this._keyboardActive = true;
|
|
227
238
|
e.preventDefault();
|
|
@@ -229,7 +240,7 @@ class ListItemDragHandle extends LocalizeCoreElement(LitElement) {
|
|
|
229
240
|
}
|
|
230
241
|
|
|
231
242
|
_onInactiveKeyDown(e) {
|
|
232
|
-
if (e.type === 'click' || e.keyCode === keyCodes.ENTER || e.keyCode === keyCodes.SPACE
|
|
243
|
+
if (e.type === 'click' || e.keyCode === keyCodes.ENTER || e.keyCode === keyCodes.SPACE) {
|
|
233
244
|
e.preventDefault();
|
|
234
245
|
}
|
|
235
246
|
}
|
|
@@ -67,6 +67,17 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
|
67
67
|
grid-column: content-start / end;
|
|
68
68
|
grid-row: nested-start / nested-end;
|
|
69
69
|
}
|
|
70
|
+
:host(.d2l-dragging-over) ::slotted([slot="nested"]) {
|
|
71
|
+
z-index: 6;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
::slotted([slot="drop-target"]) {
|
|
75
|
+
height: 100%;
|
|
76
|
+
position: absolute;
|
|
77
|
+
top: 0;
|
|
78
|
+
width: 100%;
|
|
79
|
+
z-index: 5;
|
|
80
|
+
}
|
|
70
81
|
|
|
71
82
|
::slotted([slot="outside-control"]),
|
|
72
83
|
::slotted([slot="control"]),
|
|
@@ -115,7 +126,6 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
|
115
126
|
grid-column: content-start / end;
|
|
116
127
|
z-index: 3;
|
|
117
128
|
}
|
|
118
|
-
|
|
119
129
|
`;
|
|
120
130
|
}
|
|
121
131
|
|
|
@@ -148,6 +158,7 @@ class ListItemGenericLayout extends RtlMixin(LitElement) {
|
|
|
148
158
|
|
|
149
159
|
render() {
|
|
150
160
|
return html`
|
|
161
|
+
<slot name="drop-target"></slot>
|
|
151
162
|
<slot name="content-action" class="d2l-cell" data-cell-num="5"></slot>
|
|
152
163
|
<slot name="outside-control-action" class="d2l-cell" data-cell-num="1"></slot>
|
|
153
164
|
<slot name="outside-control" class="d2l-cell" data-cell-num="2"></slot>
|
|
@@ -2,6 +2,7 @@ import '../colors/colors.js';
|
|
|
2
2
|
import './list-item-generic-layout.js';
|
|
3
3
|
import './list-item-placement-marker.js';
|
|
4
4
|
import { css, html } from 'lit-element/lit-element.js';
|
|
5
|
+
import { findComposedAncestor, getComposedParent } from '../../helpers/dom.js';
|
|
5
6
|
import { classMap } from 'lit-html/directives/class-map.js';
|
|
6
7
|
import { getFirstFocusableDescendant } from '../../helpers/focus.js';
|
|
7
8
|
import { getUniqueId } from '../../helpers/uniqueId.js';
|
|
@@ -301,6 +302,52 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
301
302
|
});
|
|
302
303
|
}
|
|
303
304
|
|
|
305
|
+
_getNestedList() {
|
|
306
|
+
const nestedSlot = this.shadowRoot.querySelector('slot[name="nested"]');
|
|
307
|
+
let nestedNodes = nestedSlot.assignedNodes();
|
|
308
|
+
if (nestedNodes.length === 0) {
|
|
309
|
+
nestedNodes = [...nestedSlot.childNodes];
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
return nestedNodes.find(node => (node.nodeType === Node.ELEMENT_NODE && node.tagName === 'D2L-LIST'));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
_getNextListItemSibling() {
|
|
316
|
+
let nextElement = this.nextElementSibling;
|
|
317
|
+
while (nextElement) {
|
|
318
|
+
if (this._isListItem(nextElement)) return nextElement;
|
|
319
|
+
nextElement = nextElement.nextElementSibling;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
_getParentListItem() {
|
|
324
|
+
const parentListItem = findComposedAncestor(this.parentNode, node => this._isListItem(node));
|
|
325
|
+
return parentListItem;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
_getPreviousListItemSibling() {
|
|
329
|
+
let previousElement = this.previousElementSibling;
|
|
330
|
+
while (previousElement) {
|
|
331
|
+
if (this._isListItem(previousElement)) return previousElement;
|
|
332
|
+
previousElement = previousElement.previousElementSibling;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
_getRootList(node) {
|
|
337
|
+
if (!node) node = this;
|
|
338
|
+
let rootList;
|
|
339
|
+
while (node) {
|
|
340
|
+
if (node.tagName === 'D2L-LIST') rootList = node;
|
|
341
|
+
node = getComposedParent(node);
|
|
342
|
+
}
|
|
343
|
+
return rootList;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
_isListItem(node) {
|
|
347
|
+
if (!node) node = this;
|
|
348
|
+
return node.role === 'rowgroup' || node.role === 'listitem';
|
|
349
|
+
}
|
|
350
|
+
|
|
304
351
|
_onFocusIn() {
|
|
305
352
|
this._focusing = true;
|
|
306
353
|
}
|
|
@@ -341,18 +388,18 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
341
388
|
'd2l-list-item-content-extend-separators': this._extendSeparators,
|
|
342
389
|
'd2l-focusing': this._focusing,
|
|
343
390
|
'd2l-hovering': this._hovering,
|
|
391
|
+
'd2l-dragging-over': this._draggingOver
|
|
344
392
|
};
|
|
345
393
|
const contentClasses = {
|
|
346
394
|
'd2l-list-item-content': true,
|
|
347
395
|
'd2l-hovering': this._hoveringPrimaryAction,
|
|
348
|
-
'd2l-focusing': this._focusingPrimaryAction
|
|
396
|
+
'd2l-focusing': this._focusingPrimaryAction
|
|
349
397
|
};
|
|
350
398
|
|
|
351
399
|
const primaryAction = this._renderPrimaryAction ? this._renderPrimaryAction(this._contentId) : null;
|
|
352
400
|
|
|
353
401
|
return html`
|
|
354
402
|
${this._renderTopPlacementMarker(html`<d2l-list-item-placement-marker></d2l-list-item-placement-marker>`)}
|
|
355
|
-
${this._renderDropTarget()}
|
|
356
403
|
<div class="d2l-list-item-drag-image">
|
|
357
404
|
<d2l-list-item-generic-layout
|
|
358
405
|
@focusin="${this._onFocusIn}"
|
|
@@ -361,6 +408,7 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
361
408
|
data-breakpoint="${this._breakpoint}"
|
|
362
409
|
data-separators="${ifDefined(this._separators)}"
|
|
363
410
|
?grid-active="${this.role === 'rowgroup'}">
|
|
411
|
+
${this._renderDropTarget()}
|
|
364
412
|
${this._renderDragHandle(this._renderOutsideControl)}
|
|
365
413
|
${this._renderDragTarget(this._renderOutsideControlAction)}
|
|
366
414
|
${this.selectable ? html`
|
|
@@ -391,7 +439,7 @@ export const ListItemMixin = superclass => class extends ListItemDragDropMixin(L
|
|
|
391
439
|
<slot name="actions" class="d2l-list-item-actions">${actions}</slot>
|
|
392
440
|
</div>
|
|
393
441
|
<div slot="nested" @d2l-selection-provider-connected="${this._onSelectionProviderConnected}">
|
|
394
|
-
<slot name="nested">${nested}</slot>
|
|
442
|
+
<slot name="nested" @slotchange="${this._onNestedSlotChange}">${nested}</slot>
|
|
395
443
|
</div>
|
|
396
444
|
</d2l-list-item-generic-layout>
|
|
397
445
|
<div class="d2l-list-item-active-border"></div>
|