Skip to content

Commit

Permalink
feat(tree-select): component tree-select (#92)
Browse files Browse the repository at this point in the history
* prepared code

* fixes and refactoring in tree

* fixes and refactoring in select

* added tree-select component

* save

* now tree is rendering in select (WIP)

* added styles + restored padding and toggling in mc-tree-option

* save

* partially realized navigation

* added mc-tree-select-option

* navigation had been fixed

* selectionModel + initialisation selected options

* added autoSelect (true by default)

* added multiselect

* partially fixed errors on build

* fixed build

* one more fix for build task

* fix after review

* fixed tests

* errors and constants moved in core (maybe should make common)

* refactoring

* refactoring

* cdkTreeNodeToggle replaced on mcTreeNodeToggle

* added tests

* еще немного фиксов в тестах

* small fix

* WIP save

* save

* added some tests (not all)

* save

* added latest tests

* tslint fix

* tree-option moved from tree-selection

* made a few fixes for tree-selection and tree-select

* fixed tests
  • Loading branch information
lskramarov authored Mar 5, 2019
1 parent cb5362b commit dc52656
Show file tree
Hide file tree
Showing 78 changed files with 8,284 additions and 1,392 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@
"server-dev:toggle": "npm run server-dev -- --env.component toggle",
"server-dev:theme-picker": "npm run server-dev -- --env.component theme-picker",
"server-dev:tree": "npm run server-dev -- --env.component tree",
"server-dev:tree-select": "npm run server-dev -- --env.component tree-select",
"server-dev:typography": "npm run server-dev -- --env.component typography",
"server-dev:tooltip": "npm run server-dev -- --env.component tooltip",
"server-dev:timepicker": "npm run server-dev -- --env.component timepicker"
Expand Down
6 changes: 3 additions & 3 deletions src/cdk/a11y/key-manager/activedescendant-key-manager.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@

import { ListKeyManager, IListKeyManagerOption } from './list-key-manager';
import { ListKeyManager, ListKeyManagerOption } from './list-key-manager';


/**
* This is the interface for highlightable items (used by the ActiveDescendantKeyManager).
* Each item must know how to style itself as active or inactive and whether or not it is
* currently disabled.
*/
export interface IHighlightable extends IListKeyManagerOption {
export interface Highlightable extends ListKeyManagerOption {
// Applies the styles for an active item to this item.
setActiveStyles(): void;

// Applies the styles for an inactive item to this item.
setInactiveStyles(): void;
}

export class ActiveDescendantKeyManager<T> extends ListKeyManager<IHighlightable & T> {
export class ActiveDescendantKeyManager<T> extends ListKeyManager<Highlightable & T> {

/**
* Sets the active item to the item at the specified index and adds the
Expand Down
4 changes: 2 additions & 2 deletions src/cdk/a11y/key-manager/focus-key-manager.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { FocusOrigin } from '../focus-monitor/focus-monitor';

import { ListKeyManager, IListKeyManagerOption } from './list-key-manager';
import { ListKeyManager, ListKeyManagerOption } from './list-key-manager';


/**
* This is the interface for focusable items (used by the FocusKeyManager).
* Each item must know how to focus itself, whether or not it is currently disabled
* and be able to supply it's label.
*/
export interface IFocusableOption extends IListKeyManagerOption {
export interface IFocusableOption extends ListKeyManagerOption {
// Focuses the `FocusableOption`. */
focus(origin?: FocusOrigin): void;
}
Expand Down
6 changes: 4 additions & 2 deletions src/cdk/a11y/key-manager/list-key-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {


// This interface is for items that can be passed to a ListKeyManager.
export interface IListKeyManagerOption {
export interface ListKeyManagerOption {
// Whether the option is disabled.
disabled?: boolean;

Expand All @@ -30,7 +30,7 @@ export interface IListKeyManagerOption {
* This class manages keyboard events for selectable lists. If you pass it a query list
* of items, it will set the active item correctly when arrow events occur.
*/
export class ListKeyManager<T extends IListKeyManagerOption> {
export class ListKeyManager<T extends ListKeyManagerOption> {
/**
* Stream that emits any time the TAB key is pressed, so components can react
* when focus is shifted off of the list.
Expand Down Expand Up @@ -61,7 +61,9 @@ export class ListKeyManager<T extends IListKeyManagerOption> {

constructor(private _items: QueryList<T>) {
if (_items instanceof QueryList) {

_items.changes.subscribe((newItems: QueryList<T>) => {

if (this._activeItem) {
const itemArray = newItems.toArray();
const newIndex = itemArray.indexOf(this._activeItem);
Expand Down
96 changes: 51 additions & 45 deletions src/cdk/collections/selection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,6 @@ import { Subject } from 'rxjs';
*/
export class SelectionModel<T> {

/** Selected values. */
get selected(): T[] {
if (!this._selected) {
this._selected = Array.from(this._selection.values());
}

return this._selected;
}

/** Event emitted when the value has changed. */
changed: Subject<SelectionChange<T>> = new Subject();

Expand All @@ -25,79 +16,94 @@ export class SelectionModel<T> {
*/
onChange: Subject<SelectionChange<T>> = this.changed;
/** Currently-selected values. */
private _selection = new Set<T>();
selection = new Set<T>();

/** Keeps track of the deselected options that haven't been emitted by the change event. */
private _deselectedToEmit: T[] = [];
private deselectedToEmit: T[] = [];

/** Keeps track of the selected options that haven't been emitted by the change event. */
private _selectedToEmit: T[] = [];
private selectedToEmit: T[] = [];

get selected(): T[] {
if (!this._selected) {
this._selected = Array.from(this.selection.values());
}

return this._selected;
}

/** Cache for the array value of the selected items. */
private _selected: T[] | null;

constructor(
private _multiple = false,
initiallySelectedValues?: T[],
private _emitChanges = true) {

private _emitChanges: boolean = true
) {
if (initiallySelectedValues && initiallySelectedValues.length) {
if (_multiple) {
initiallySelectedValues.forEach((value) => this._markSelected(value));
initiallySelectedValues.forEach((value) => this.markSelected(value));
} else {
this._markSelected(initiallySelectedValues[0]);
this.markSelected(initiallySelectedValues[0]);
}

// Clear the array in order to avoid firing the change event for preselected values.
this._selectedToEmit.length = 0;
this.selectedToEmit.length = 0;
}
}

/**
* Selects a value or an array of values.
*/
select(...values: T[]): void {
this._verifyValueAssignment(values);
values.forEach((value) => this._markSelected(value));
this._emitChangeEvent();
this.verifyValueAssignment(values);

values.forEach((value) => this.markSelected(value));

this.emitChangeEvent();
}

/**
* Deselects a value or an array of values.
*/
deselect(...values: T[]): void {
this._verifyValueAssignment(values);
values.forEach((value) => this._unmarkSelected(value));
this._emitChangeEvent();
this.verifyValueAssignment(values);

values.forEach((value) => this.unmarkSelected(value));

this.emitChangeEvent();
}

/**
* Toggles a value between selected and deselected.
*/
toggle(value: T): void {
this.isSelected(value) ? this.deselect(value) : this.select(value);
if (this.isSelected(value)) {
this.deselect(value);
} else {
this.select(value);
}
}

/**
* Clears all of the selected values.
*/
clear(): void {
this._unmarkAll();
this._emitChangeEvent();
this.unmarkAll();
this.emitChangeEvent();
}

/**
* Determines whether a value is selected.
*/
isSelected(value: T): boolean {
return this._selection.has(value);
return this.selection.has(value);
}

/**
* Determines whether the model does not have a value.
*/
isEmpty(): boolean {
return this._selection.size === 0;
return this.selection.size === 0;
}

/**
Expand All @@ -124,60 +130,60 @@ export class SelectionModel<T> {
}

/** Emits a change event and clears the records of selected and deselected values. */
private _emitChangeEvent() {
private emitChangeEvent() {
// Clear the selected values so they can be re-cached.
this._selected = null;

if (this._selectedToEmit.length || this._deselectedToEmit.length) {
if (this.selectedToEmit.length || this.deselectedToEmit.length) {
this.changed.next({
source: this,
added: this._selectedToEmit,
removed: this._deselectedToEmit
added: this.selectedToEmit,
removed: this.deselectedToEmit
});

this._deselectedToEmit = [];
this._selectedToEmit = [];
this.deselectedToEmit = [];
this.selectedToEmit = [];
}
}

/** Selects a value. */
private _markSelected(value: T) {
private markSelected(value: T) {
if (!this.isSelected(value)) {
if (!this._multiple) {
this._unmarkAll();
this.unmarkAll();
}

this._selection.add(value);
this.selection.add(value);

if (this._emitChanges) {
this._selectedToEmit.push(value);
this.selectedToEmit.push(value);
}
}
}

/** Deselects a value. */
private _unmarkSelected(value: T) {
private unmarkSelected(value: T) {
if (this.isSelected(value)) {
this._selection.delete(value);
this.selection.delete(value);

if (this._emitChanges) {
this._deselectedToEmit.push(value);
this.deselectedToEmit.push(value);
}
}
}

/** Clears out the selected values. */
private _unmarkAll() {
private unmarkAll() {
if (!this.isEmpty()) {
this._selection.forEach((value) => this._unmarkSelected(value));
this.selection.forEach((value) => this.unmarkSelected(value));
}
}

/**
* Verifies the value assignment and throws an error if the specified value array is
* including multiple values while the selection model is not supporting multiple values.
*/
private _verifyValueAssignment(values: T[]) {
private verifyValueAssignment(values: T[]) {
if (values.length > 1 && !this._multiple) {
throw getMultipleValuesInSingleSelectionError();
}
Expand Down
4 changes: 2 additions & 2 deletions src/cdk/overlay/overlay-directives.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ describe('Overlay directives', () => {

const backdrop =
overlayContainerElement.querySelector('.cdk-overlay-backdrop') as HTMLElement;
expect(backdrop.classList).toContain('mat-test-class');
expect(backdrop.classList).toContain('mc-test-class');
});

it('should set the offsetX', () => {
Expand Down Expand Up @@ -380,7 +380,7 @@ describe('Overlay directives', () => {
[cdkConnectedOverlayFlexibleDimensions]="flexibleDimensions"
[cdkConnectedOverlayGrowAfterOpen]="growAfterOpen"
[cdkConnectedOverlayPush]="push"
cdkConnectedOverlayBackdropClass="mat-test-class"
cdkConnectedOverlayBackdropClass="mc-test-class"
(backdropClick)="backdropClickHandler($event)"
[cdkConnectedOverlayOffsetX]="offsetX"
[cdkConnectedOverlayOffsetY]="offsetY"
Expand Down
3 changes: 2 additions & 1 deletion src/cdk/overlay/overlay-directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ export class CdkConnectedOverlay implements OnDestroy, OnChanges {
templateRef: TemplateRef<any>,
viewContainerRef: ViewContainerRef,
@Inject(CDK_CONNECTED_OVERLAY_SCROLL_STRATEGY) private _scrollStrategy,
@Optional() private _dir: Directionality) {
@Optional() private _dir: Directionality
) {
this._templatePortal = new TemplatePortal(templateRef, viewContainerRef);
}

Expand Down
4 changes: 2 additions & 2 deletions src/cdk/overlay/overlay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ export class Overlay {
private _injector: Injector,
private _ngZone: NgZone,
@Inject(DOCUMENT) private _document: any,
private _directionality: Directionality) {
}
private _directionality: Directionality
) {}

/**
* Creates an overlay.
Expand Down
2 changes: 1 addition & 1 deletion src/cdk/testing/dispatch-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export function dispatchFakeEvent(node: Node | Window, type: string, canBubble?:
export function dispatchKeyboardEvent(node: Node, type: string, keyCode: number, target?: Element,
shiftKey = false, ctrlKey = false, altKey = false):
KeyboardEvent {
const event = createKeyboardEvent(type, keyCode, target, undefined, shiftKey, ctrlKey, altKey);
const event = createKeyboardEvent(type, keyCode, target, undefined, shiftKey, ctrlKey, altKey);

return dispatchEvent(node, event) as KeyboardEvent;
}
Expand Down
2 changes: 2 additions & 0 deletions src/cdk/tree/control/base-tree-control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { ITreeControl } from './tree-control';


/** Base tree control. It has basic toggle/expand/collapse operations on a single data node. */
// todo здесь явно ошибка проектирования, абстрактный класс реализует функционал
/* tslint:disable-next-line:naming-convention */
export abstract class BaseTreeControl<T> implements ITreeControl<T> {

/** Saved data node for `expandAll` action. */
Expand Down
Loading

0 comments on commit dc52656

Please sign in to comment.