diff --git a/README.md b/README.md index aa24cdd..bac5654 100644 --- a/README.md +++ b/README.md @@ -250,6 +250,7 @@ shortcuts: { | selectMode | Boolean | `false` | If set to `true`, a _toggle_ mode is activated similar to the `toggleSingleItem` shortcut. Useful for mobile. | | custom | Boolean | `false` | If set to `true`, all default styles for selected items will not be applied. | | selectWithShortcut | Boolean | `false` | If set to `true`, items can only be selected when single clicking and applying a keyboard shortcut | +| additive | Boolean | `false` | If set to `true`, will add items to selection when clicking and dragging. | Here's an example of all inputs in action: @@ -261,7 +262,8 @@ Here's an example of all inputs in action: [disableDrag]="true" [selectMode]="true" [custom]="true" - [selectWithShortcut]="false"> + [selectWithShortcut]="false" + [additive]="true"> ... ``` diff --git a/cypress/integration/clicking.spec.ts b/cypress/integration/clicking.spec.ts index 472b82a..62a287b 100644 --- a/cypress/integration/clicking.spec.ts +++ b/cypress/integration/clicking.spec.ts @@ -3,6 +3,7 @@ import { DEFAULT_CONFIG } from '../../projects/ngx-drag-to-select/src/lib/config import { disableRangeSelection, disableSelectOnDrag, + enableAdditive, enableSelectWithShortcut, getDesktopExample, toggleItem @@ -233,4 +234,38 @@ describe('Clicking', () => { }); }); }); + + describe('Select with Additive', () => { + beforeEach(() => { + enableAdditive(); + }); + + it('should add item to selection if clicked', () => { + getDesktopExample().within(() => { + cy.getSelectItem(0) + .dispatch('mousedown', { button: 0 }) + .dispatch('mouseup') + .getSelectItem(1) + .dispatch('mousedown', { button: 0 }) + .dispatch('mouseup') + .shouldSelect([1, 2]); + }); + }); + + it('should remove the item if clicked', () => { + getDesktopExample().within(() => { + cy.getSelectItem(0) + .dispatch('mousedown', { button: 0 }) + .dispatch('mouseup') + .getSelectItem(1) + .dispatch('mousedown', { button: 0 }) + .dispatch('mouseup') + .shouldSelect([1, 2]) + .getSelectItem(0) + .dispatch('mousedown', { button: 0 }) + .dispatch('mouseup') + .shouldSelect([2]); + }); + }); + }); }); diff --git a/cypress/integration/dragging.spec.ts b/cypress/integration/dragging.spec.ts index 70f1b45..2875d95 100644 --- a/cypress/integration/dragging.spec.ts +++ b/cypress/integration/dragging.spec.ts @@ -4,6 +4,7 @@ import { disableSelection, disableSelectOnDrag, enableSelectMode, + enableAdditive, getDesktopExample, shouldBeInvisible, shouldBeVisible, @@ -372,6 +373,31 @@ describe('Dragging', () => { }); }); + describe('Additive', () => { + beforeEach(() => { + enableAdditive(); + }); + + it('should extend selection after mouseup', () => { + getDesktopExample().within(() => { + cy.getSelectItem(0) + .dispatch('mousedown', { button: 0 }) + .getSelectItem(5) + .dispatch('mousemove') + .dispatch('mouseup') + .shouldSelect([1, 2, 5, 6]) + .getSelectItem(2) + .dispatch('mousedown', { button: 0 }) + .getSelectItem(7) + .dispatch('mousemove') + .dispatch('mouseup') + .shouldSelect([1, 2, 3, 4, 5, 6, 7, 8]) + .get(`.${SELECTED_CLASS}`) + .should('have.length', 8); + }); + }); + }); + describe('Shortcuts', () => { it('should toggle single items', () => { getDesktopExample().within(() => { diff --git a/cypress/support/utils.ts b/cypress/support/utils.ts index 1b7ee73..a0e6c5b 100644 --- a/cypress/support/utils.ts +++ b/cypress/support/utils.ts @@ -68,6 +68,10 @@ export const enableSelectWithShortcut = () => { return cy.get('[data-cy="selectWithShortcut"]').click(); }; +export const enableAdditive = () => { + return cy.get('[data-cy="additive"]').click(); +}; + export const selectAll = () => { return getSelectAllButton().click(); }; diff --git a/projects/ngx-drag-to-select/src/lib/select-container.component.ts b/projects/ngx-drag-to-select/src/lib/select-container.component.ts index 7f8ee81..43de814 100644 --- a/projects/ngx-drag-to-select/src/lib/select-container.component.ts +++ b/projects/ngx-drag-to-select/src/lib/select-container.component.ts @@ -103,6 +103,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After @Input() disableRangeSelection = false; @Input() selectMode = false; @Input() selectWithShortcut = false; + @Input() additive = false; @Input() @HostBinding('class.dts-custom') @@ -466,7 +467,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After const itemRect = item.getBoundingClientRect(); const withinBoundingBox = inBoundingBox(mousePoint, itemRect); - if (this.shortcuts.extendedSelectionShortcut(event) && this.disableRangeSelection) { + if (this.shortcuts.extendedSelectionShortcut(event) && this.disableRangeSelection /* || this.additive*/) { return; } @@ -482,25 +483,27 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After (withinBoundingBox && !this.shortcuts.toggleSingleItem(event) && !this.selectMode && + !this.additive && !this.selectWithShortcut) || (this.shortcuts.extendedSelectionShortcut(event) && item.selected && !this._lastRangeSelection.get(item)) || withinRange || (withinBoundingBox && this.shortcuts.toggleSingleItem(event) && !item.selected) || (!withinBoundingBox && this.shortcuts.toggleSingleItem(event) && item.selected) || - (withinBoundingBox && !item.selected && this.selectMode) || - (!withinBoundingBox && item.selected && this.selectMode); + (withinBoundingBox && !item.selected && (this.selectMode || this.additive)) || + (!withinBoundingBox && item.selected && (this.selectMode || this.additive)); const shouldRemove = (!withinBoundingBox && !this.shortcuts.toggleSingleItem(event) && !this.selectMode && + !this.additive && !this.shortcuts.extendedSelectionShortcut(event) && !this.selectWithShortcut) || (this.shortcuts.extendedSelectionShortcut(event) && currentIndex > -1) || (!withinBoundingBox && this.shortcuts.toggleSingleItem(event) && !item.selected) || (withinBoundingBox && this.shortcuts.toggleSingleItem(event) && item.selected) || - (!withinBoundingBox && !item.selected && this.selectMode) || - (withinBoundingBox && item.selected && this.selectMode); + (!withinBoundingBox && !item.selected && (this.selectMode || this.additive)) || + (withinBoundingBox && item.selected && (this.selectMode || this.additive)); if (shouldAdd) { this._selectItem(item); @@ -546,11 +549,14 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After private _normalSelectionMode(selectBox: BoundingBox, item: SelectItemDirective, event: Event) { const inSelection = boxIntersects(selectBox, item.getBoundingClientRect()); - const shouldAdd = inSelection && !item.selected && !this.shortcuts.removeFromSelection(event); + const shouldAdd = + (inSelection && !item.selected && !this.shortcuts.removeFromSelection(event)) || + (this.additive && ((inSelection && !item.selected) || (!inSelection && item.selected))); const shouldRemove = (!inSelection && item.selected && !this.shortcuts.addToSelection(event)) || - (inSelection && item.selected && this.shortcuts.removeFromSelection(event)); + (inSelection && item.selected && this.shortcuts.removeFromSelection(event)) || + (this.additive && !inSelection && !item.selected); if (shouldAdd) { this._selectItem(item); @@ -562,7 +568,7 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After private _extendedSelectionMode(selectBox, item: SelectItemDirective, event: Event) { const inSelection = boxIntersects(selectBox, item.getBoundingClientRect()); - const shoudlAdd = + const shouldAdd = (inSelection && !item.selected && !this.shortcuts.removeFromSelection(event) && !this._tmpItems.has(item)) || (inSelection && item.selected && this.shortcuts.removeFromSelection(event) && !this._tmpItems.has(item)); @@ -570,12 +576,12 @@ export class SelectContainerComponent implements AfterViewInit, OnDestroy, After (!inSelection && item.selected && this.shortcuts.addToSelection(event) && this._tmpItems.has(item)) || (!inSelection && !item.selected && this.shortcuts.removeFromSelection(event) && this._tmpItems.has(item)); - if (shoudlAdd) { + if (shouldAdd) { item.selected ? item._deselect() : item._select(); const action = this.shortcuts.removeFromSelection(event) ? Action.Delete - : this.shortcuts.addToSelection(event) + : this.shortcuts.addToSelection(event) || this.additive ? Action.Add : Action.None; diff --git a/src/app/app.component.html b/src/app/app.component.html index 70c95fe..9f46247 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -26,6 +26,7 @@