Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(drag-drop): add injection token for configuring the input defaults #17970

Merged
merged 1 commit into from
Jan 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions src/cdk/drag-drop/directives/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import {InjectionToken} from '@angular/core';
import {DragRefConfig, Point, DragRef} from '../drag-ref';

/** Possible values that can be used to configure the drag start delay. */
export type DragStartDelay = number | {touch: number, mouse: number};

/** Possible axis along which dragging can be locked. */
export type DragAxis = 'x' | 'y';

/** Function that can be used to constrain the position of a dragged element. */
export type DragConstrainPosition = (point: Point, dragRef: DragRef) => Point;

/** Possible orientations for a drop list. */
export type DropListOrientation = 'horizontal' | 'vertical';

/**
* Injection token that can be used to configure the
* behavior of the drag&drop-related components.
*/
export const CDK_DRAG_CONFIG = new InjectionToken<DragDropConfig>('CDK_DRAG_CONFIG');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CDK_DRAG_DEFAULT_OPTIONS for consistency?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be a breaking change since CDK_DRAG_CONFIG is already in master.


/**
* Object that can be used to configure the drag
* items and drop lists within a module or a component.
*/
export interface DragDropConfig extends Partial<DragRefConfig> {
lockAxis?: DragAxis;
dragStartDelay?: DragStartDelay;
constrainPosition?: DragConstrainPosition;
previewClass?: string | string[];
boundaryElement?: string;
rootElementSelector?: string;
draggingDisabled?: boolean;
sortingDisabled?: boolean;
listAutoScrollDisabled?: boolean;
listOrientation?: DropListOrientation;
}

/**
* @deprecated No longer being used. To be removed.
* @breaking-change 10.0.0
* @docs-private
*/
export function CDK_DRAG_CONFIG_FACTORY(): DragDropConfig {
return {dragStartThreshold: 5, pointerDirectionChangeThreshold: 5};
}
70 changes: 67 additions & 3 deletions src/cdk/drag-drop/directives/drag.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,12 @@ import {of as observableOf} from 'rxjs';

import {DragDropModule} from '../drag-drop-module';
import {CdkDragDrop, CdkDragEnter} from '../drag-events';
import {DragRefConfig, Point, DragRef} from '../drag-ref';
import {Point, DragRef} from '../drag-ref';
import {extendStyles} from '../drag-styling';
import {moveItemInArray} from '../drag-utils';

import {CDK_DRAG_CONFIG, CdkDrag} from './drag';
import {CdkDrag} from './drag';
import {CDK_DRAG_CONFIG, DragDropConfig} from './config';
import {CdkDragHandle} from './drag-handle';
import {CdkDropList} from './drop-list';
import {CdkDropListGroup} from './drop-list-group';
Expand All @@ -58,7 +59,7 @@ describe('CdkDrag', () => {
// have to deal with thresholds.
dragStartThreshold: dragDistance,
pointerDirectionChangeThreshold: 5
} as DragRefConfig
} as DragDropConfig
},
...providers
],
Expand Down Expand Up @@ -1160,6 +1161,32 @@ describe('CdkDrag', () => {
expect(touchmoveEvent.defaultPrevented).toBe(true);
}));

it('should be able to configure the drag input defaults through a provider', fakeAsync(() => {
const config: DragDropConfig = {
draggingDisabled: true,
dragStartDelay: 1337,
lockAxis: 'y',
constrainPosition: () => ({x: 1337, y: 42}),
previewClass: 'custom-preview-class',
boundaryElement: '.boundary',
rootElementSelector: '.root'
};

const fixture = createComponent(PlainStandaloneDraggable, [{
provide: CDK_DRAG_CONFIG,
useValue: config
}]);
fixture.detectChanges();
const drag = fixture.componentInstance.dragInstance;
expect(drag.disabled).toBe(true);
expect(drag.dragStartDelay).toBe(1337);
expect(drag.lockAxis).toBe('y');
expect(drag.constrainPosition).toBe(config.constrainPosition);
expect(drag.previewClass).toBe('custom-preview-class');
expect(drag.boundaryElement).toBe('.boundary');
expect(drag.rootElementSelector).toBe('.root');
}));

});

describe('draggable with a handle', () => {
Expand Down Expand Up @@ -3510,6 +3537,29 @@ describe('CdkDrag', () => {
expect(dragItems.map(drag => drag.element.nativeElement.textContent!.trim()))
.toEqual(['One', 'Two', 'Zero', 'Three']);
}));

it('should be able to configure the drop input defaults through a provider', fakeAsync(() => {
const config: DragDropConfig = {
draggingDisabled: true,
sortingDisabled: true,
listAutoScrollDisabled: true,
listOrientation: 'horizontal',
lockAxis: 'y'
};

const fixture = createComponent(PlainStandaloneDropList, [{
provide: CDK_DRAG_CONFIG,
useValue: config
}]);
fixture.detectChanges();
const list = fixture.componentInstance.dropList;
expect(list.disabled).toBe(true);
expect(list.sortingDisabled).toBe(true);
expect(list.autoScrollDisabled).toBe(true);
expect(list.orientation).toBe('horizontal');
expect(list.lockAxis).toBe('y');
}));

});

describe('in a connected drop container', () => {
Expand Down Expand Up @@ -5345,6 +5395,20 @@ class NestedDropZones {
items = ['Zero', 'One', 'Two', 'Three'];
}

@Component({
template: `<div cdkDrag></div>`
})
class PlainStandaloneDraggable {
@ViewChild(CdkDrag) dragInstance: CdkDrag;
}

@Component({
template: `<div cdkDropList></div>`
})
class PlainStandaloneDropList {
@ViewChild(CdkDropList) dropList: CdkDropList;
}

/**
* Drags an element to a position on the page using the mouse.
* @param fixture Fixture on which to run change detection.
Expand Down
66 changes: 49 additions & 17 deletions src/cdk/drag-drop/directives/drag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,27 +51,17 @@ import {CdkDragHandle} from './drag-handle';
import {CdkDragPlaceholder} from './drag-placeholder';
import {CdkDragPreview} from './drag-preview';
import {CDK_DRAG_PARENT} from '../drag-parent';
import {DragRef, DragRefConfig, Point} from '../drag-ref';
import {DragRef, Point} from '../drag-ref';
import {CdkDropListInternal as CdkDropList} from './drop-list';
import {DragDrop} from '../drag-drop';
import {CDK_DRAG_CONFIG, DragDropConfig, DragStartDelay, DragAxis} from './config';

/**
* Injection token that is used to provide a CdkDropList instance to CdkDrag.
* Used for avoiding circular imports.
*/
export const CDK_DROP_LIST = new InjectionToken<CdkDropList>('CDK_DROP_LIST');

/** Injection token that can be used to configure the behavior of `CdkDrag`. */
export const CDK_DRAG_CONFIG = new InjectionToken<DragRefConfig>('CDK_DRAG_CONFIG', {
providedIn: 'root',
factory: CDK_DRAG_CONFIG_FACTORY
});

/** @docs-private */
export function CDK_DRAG_CONFIG_FACTORY(): DragRefConfig {
return {dragStartThreshold: 5, pointerDirectionChangeThreshold: 5};
}

/** Element that can be moved inside a CdkDropList container. */
@Directive({
selector: '[cdkDrag]',
Expand Down Expand Up @@ -102,7 +92,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
@Input('cdkDragData') data: T;

/** Locks the position of the dragged element along the specified axis. */
@Input('cdkDragLockAxis') lockAxis: 'x' | 'y';
@Input('cdkDragLockAxis') lockAxis: DragAxis;

/**
* Selector that will be used to determine the root draggable element, starting from
Expand All @@ -123,7 +113,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
* Amount of milliseconds to wait after the user has put their
* pointer down before starting to drag the element.
*/
@Input('cdkDragStartDelay') dragStartDelay: number | {touch: number, mouse: number} = 0;
@Input('cdkDragStartDelay') dragStartDelay: DragStartDelay;

/**
* Sets the position of a `CdkDrag` that is outside of a drop container.
Expand All @@ -140,7 +130,7 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
this._disabled = coerceBooleanProperty(value);
this._dragRef.disabled = this._disabled;
}
private _disabled = false;
private _disabled: boolean;

/**
* Function that can be used to customize the logic of how the position of the drag item
Expand Down Expand Up @@ -200,11 +190,22 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
/** Droppable container that the draggable is a part of. */
@Inject(CDK_DROP_LIST) @Optional() @SkipSelf() public dropContainer: CdkDropList,
@Inject(DOCUMENT) private _document: any, private _ngZone: NgZone,
private _viewContainerRef: ViewContainerRef, @Inject(CDK_DRAG_CONFIG) config: DragRefConfig,
private _viewContainerRef: ViewContainerRef,
@Optional() @Inject(CDK_DRAG_CONFIG) config: DragDropConfig,
@Optional() private _dir: Directionality, dragDrop: DragDrop,
private _changeDetectorRef: ChangeDetectorRef) {
this._dragRef = dragDrop.createDrag(element, config);
this._dragRef = dragDrop.createDrag(element, {
dragStartThreshold: config && config.dragStartThreshold != null ?
config.dragStartThreshold : 5,
pointerDirectionChangeThreshold: config && config.pointerDirectionChangeThreshold != null ?
config.pointerDirectionChangeThreshold : 5
});
this._dragRef.data = this;

if (config) {
this._assignDefaults(config);
}

this._syncInputs(this._dragRef);
this._handleEvents(this._dragRef);
}
Expand Down Expand Up @@ -414,6 +415,37 @@ export class CdkDrag<T = any> implements AfterViewInit, OnChanges, OnDestroy {
});
}

/** Assigns the default input values based on a provided config object. */
private _assignDefaults(config: DragDropConfig) {
const {
lockAxis, dragStartDelay, constrainPosition, previewClass,
boundaryElement, draggingDisabled, rootElementSelector
} = config;

this.disabled = draggingDisabled == null ? false : draggingDisabled;
this.dragStartDelay = dragStartDelay || 0;

if (lockAxis) {
this.lockAxis = lockAxis;
}

if (constrainPosition) {
this.constrainPosition = constrainPosition;
}

if (previewClass) {
this.previewClass = previewClass;
}

if (boundaryElement) {
this.boundaryElement = boundaryElement;
}

if (rootElementSelector) {
this.rootElementSelector = rootElementSelector;
}
}

static ngAcceptInputType_disabled: BooleanInput;
}

Expand Down
36 changes: 30 additions & 6 deletions src/cdk/drag-drop/directives/drop-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
ChangeDetectorRef,
SkipSelf,
AfterContentInit,
Inject,
} from '@angular/core';
import {Directionality} from '@angular/cdk/bidi';
import {ScrollDispatcher} from '@angular/cdk/scrolling';
Expand All @@ -29,6 +30,7 @@ import {CdkDropListGroup} from './drop-list-group';
import {DropListRef} from '../drop-list-ref';
import {DragRef} from '../drag-ref';
import {DragDrop} from '../drag-drop';
import {DropListOrientation, DragAxis, DragDropConfig, CDK_DRAG_CONFIG} from './config';
import {Subject} from 'rxjs';
import {startWith, takeUntil} from 'rxjs/operators';

Expand Down Expand Up @@ -84,7 +86,7 @@ export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
@Input('cdkDropListData') data: T;

/** Direction in which the list is oriented. */
@Input('cdkDropListOrientation') orientation: 'horizontal' | 'vertical' = 'vertical';
@Input('cdkDropListOrientation') orientation: DropListOrientation;

/**
* Unique ID for the drop zone. Can be used as a reference
Expand All @@ -93,7 +95,7 @@ export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
@Input() id: string = `cdk-drop-list-${_uniqueIdCounter++}`;

/** Locks the position of the draggable elements inside the container along the specified axis. */
@Input('cdkDropListLockAxis') lockAxis: 'x' | 'y';
@Input('cdkDropListLockAxis') lockAxis: DragAxis;

/** Whether starting a dragging sequence from this container is disabled. */
@Input('cdkDropListDisabled')
Expand All @@ -107,11 +109,11 @@ export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
// the user in a disabled state, so we also need to sync it as it's being set.
this._dropListRef.disabled = this._disabled = coerceBooleanProperty(value);
}
private _disabled = false;
private _disabled: boolean;

/** Whether sorting within this drop list is disabled. */
@Input('cdkDropListSortingDisabled')
sortingDisabled: boolean = false;
sortingDisabled: boolean;

/**
* Function that is used to determine whether an item
Expand All @@ -122,7 +124,7 @@ export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {

/** Whether to auto-scroll the view when the user moves their pointer close to the edges. */
@Input('cdkDropListAutoScrollDisabled')
autoScrollDisabled: boolean = false;
autoScrollDisabled: boolean;

/** Emits when the user drops an item inside the container. */
@Output('cdkDropListDropped')
Expand Down Expand Up @@ -155,9 +157,15 @@ export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
* @deprecated _scrollDispatcher parameter to become required.
* @breaking-change 11.0.0
*/
private _scrollDispatcher?: ScrollDispatcher) {
private _scrollDispatcher?: ScrollDispatcher,
@Optional() @Inject(CDK_DRAG_CONFIG) config?: DragDropConfig) {
this._dropListRef = dragDrop.createDropList(element);
this._dropListRef.data = this;

if (config) {
this._assignDefaults(config);
}

this._dropListRef.enterPredicate = (drag: DragRef<CdkDrag>, drop: DropListRef<CdkDropList>) => {
return this.enterPredicate(drag.data, drop.data);
};
Expand Down Expand Up @@ -347,6 +355,22 @@ export class CdkDropList<T = any> implements AfterContentInit, OnDestroy {
});
}

/** Assigns the default input values based on a provided config object. */
private _assignDefaults(config: DragDropConfig) {
const {
lockAxis, draggingDisabled, sortingDisabled, listAutoScrollDisabled, listOrientation
} = config;

this.disabled = draggingDisabled == null ? false : draggingDisabled;
this.sortingDisabled = sortingDisabled == null ? false : sortingDisabled;
this.autoScrollDisabled = listAutoScrollDisabled == null ? false : listAutoScrollDisabled;
this.orientation = listOrientation || 'vertical';

if (lockAxis) {
this.lockAxis = lockAxis;
}
}

static ngAcceptInputType_disabled: BooleanInput;
static ngAcceptInputType_sortingDisabled: BooleanInput;
static ngAcceptInputType_autoScrollDisabled: BooleanInput;
Expand Down
Loading