blob: 7fc86e1a28209dd369f40bdf4a52cd1e9e836806 [file] [log] [blame]
/**
* @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
*/
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/cdk/collections'), require('rxjs'), require('rxjs/operators'), require('@angular/core'), require('@angular/cdk/bidi'), require('@angular/cdk/coercion'), require('@angular/cdk/a11y'), require('@angular/common')) :
typeof define === 'function' && define.amd ? define('@angular/cdk/tree', ['exports', '@angular/cdk/collections', 'rxjs', 'rxjs/operators', '@angular/core', '@angular/cdk/bidi', '@angular/cdk/coercion', '@angular/cdk/a11y', '@angular/common'], factory) :
(factory((global.ng = global.ng || {}, global.ng.cdk = global.ng.cdk || {}, global.ng.cdk.tree = {}),global.ng.cdk.collections,global.rxjs,global.rxjs.operators,global.ng.core,global.ng.cdk.bidi,global.ng.cdk.coercion,global.ng.cdk.a11y,global.ng.common));
}(this, (function (exports,collections,rxjs,operators,core,bidi,coercion,a11y,common) { 'use strict';
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABLITY OR NON-INFRINGEMENT.
See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Base tree control. It has basic toggle/expand/collapse operations on a single data node.
* @abstract
* @template T
*/
var /**
* Base tree control. It has basic toggle/expand/collapse operations on a single data node.
* @abstract
* @template T
*/
BaseTreeControl = /** @class */ (function () {
function BaseTreeControl() {
/**
* A selection model with multi-selection to track expansion status.
*/
this.expansionModel = new collections.SelectionModel(true);
}
/** Toggles one single data node's expanded/collapsed state. */
/**
* Toggles one single data node's expanded/collapsed state.
* @param {?} dataNode
* @return {?}
*/
BaseTreeControl.prototype.toggle = /**
* Toggles one single data node's expanded/collapsed state.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
this.expansionModel.toggle(dataNode);
};
/** Expands one single data node. */
/**
* Expands one single data node.
* @param {?} dataNode
* @return {?}
*/
BaseTreeControl.prototype.expand = /**
* Expands one single data node.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
this.expansionModel.select(dataNode);
};
/** Collapses one single data node. */
/**
* Collapses one single data node.
* @param {?} dataNode
* @return {?}
*/
BaseTreeControl.prototype.collapse = /**
* Collapses one single data node.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
this.expansionModel.deselect(dataNode);
};
/** Whether a given data node is expanded or not. Returns true if the data node is expanded. */
/**
* Whether a given data node is expanded or not. Returns true if the data node is expanded.
* @param {?} dataNode
* @return {?}
*/
BaseTreeControl.prototype.isExpanded = /**
* Whether a given data node is expanded or not. Returns true if the data node is expanded.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
return this.expansionModel.isSelected(dataNode);
};
/** Toggles a subtree rooted at `node` recursively. */
/**
* Toggles a subtree rooted at `node` recursively.
* @param {?} dataNode
* @return {?}
*/
BaseTreeControl.prototype.toggleDescendants = /**
* Toggles a subtree rooted at `node` recursively.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
this.expansionModel.isSelected(dataNode)
? this.collapseDescendants(dataNode)
: this.expandDescendants(dataNode);
};
/** Collapse all dataNodes in the tree. */
/**
* Collapse all dataNodes in the tree.
* @return {?}
*/
BaseTreeControl.prototype.collapseAll = /**
* Collapse all dataNodes in the tree.
* @return {?}
*/
function () {
this.expansionModel.clear();
};
/** Expands a subtree rooted at given data node recursively. */
/**
* Expands a subtree rooted at given data node recursively.
* @param {?} dataNode
* @return {?}
*/
BaseTreeControl.prototype.expandDescendants = /**
* Expands a subtree rooted at given data node recursively.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
var _a;
/** @type {?} */
var toBeProcessed = [dataNode];
toBeProcessed.push.apply(toBeProcessed, this.getDescendants(dataNode));
(_a = this.expansionModel).select.apply(_a, toBeProcessed);
};
/** Collapses a subtree rooted at given data node recursively. */
/**
* Collapses a subtree rooted at given data node recursively.
* @param {?} dataNode
* @return {?}
*/
BaseTreeControl.prototype.collapseDescendants = /**
* Collapses a subtree rooted at given data node recursively.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
var _a;
/** @type {?} */
var toBeProcessed = [dataNode];
toBeProcessed.push.apply(toBeProcessed, this.getDescendants(dataNode));
(_a = this.expansionModel).deselect.apply(_a, toBeProcessed);
};
return BaseTreeControl;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Flat tree control. Able to expand/collapse a subtree recursively for flattened tree.
* @template T
*/
var /**
* Flat tree control. Able to expand/collapse a subtree recursively for flattened tree.
* @template T
*/
FlatTreeControl = /** @class */ (function (_super) {
__extends(FlatTreeControl, _super);
/** Construct with flat tree data node functions getLevel and isExpandable. */
function FlatTreeControl(getLevel, isExpandable) {
var _this = _super.call(this) || this;
_this.getLevel = getLevel;
_this.isExpandable = isExpandable;
return _this;
}
/**
* Gets a list of the data node's subtree of descendent data nodes.
*
* To make this working, the `dataNodes` of the TreeControl must be flattened tree nodes
* with correct levels.
*/
/**
* Gets a list of the data node's subtree of descendent data nodes.
*
* To make this working, the `dataNodes` of the TreeControl must be flattened tree nodes
* with correct levels.
* @param {?} dataNode
* @return {?}
*/
FlatTreeControl.prototype.getDescendants = /**
* Gets a list of the data node's subtree of descendent data nodes.
*
* To make this working, the `dataNodes` of the TreeControl must be flattened tree nodes
* with correct levels.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
/** @type {?} */
var startIndex = this.dataNodes.indexOf(dataNode);
/** @type {?} */
var results = [];
// Goes through flattened tree nodes in the `dataNodes` array, and get all descendants.
// The level of descendants of a tree node must be greater than the level of the given
// tree node.
// If we reach a node whose level is equal to the level of the tree node, we hit a sibling.
// If we reach a node whose level is greater than the level of the tree node, we hit a
// sibling of an ancestor.
for (var i = startIndex + 1; i < this.dataNodes.length && this.getLevel(dataNode) < this.getLevel(this.dataNodes[i]); i++) {
results.push(this.dataNodes[i]);
}
return results;
};
/**
* Expands all data nodes in the tree.
*
* To make this working, the `dataNodes` variable of the TreeControl must be set to all flattened
* data nodes of the tree.
*/
/**
* Expands all data nodes in the tree.
*
* To make this working, the `dataNodes` variable of the TreeControl must be set to all flattened
* data nodes of the tree.
* @return {?}
*/
FlatTreeControl.prototype.expandAll = /**
* Expands all data nodes in the tree.
*
* To make this working, the `dataNodes` variable of the TreeControl must be set to all flattened
* data nodes of the tree.
* @return {?}
*/
function () {
var _a;
(_a = this.expansionModel).select.apply(_a, this.dataNodes);
};
return FlatTreeControl;
}(BaseTreeControl));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Nested tree control. Able to expand/collapse a subtree recursively for NestedNode type.
* @template T
*/
var /**
* Nested tree control. Able to expand/collapse a subtree recursively for NestedNode type.
* @template T
*/
NestedTreeControl = /** @class */ (function (_super) {
__extends(NestedTreeControl, _super);
/** Construct with nested tree function getChildren. */
function NestedTreeControl(getChildren) {
var _this = _super.call(this) || this;
_this.getChildren = getChildren;
return _this;
}
/**
* Expands all dataNodes in the tree.
*
* To make this working, the `dataNodes` variable of the TreeControl must be set to all root level
* data nodes of the tree.
*/
/**
* Expands all dataNodes in the tree.
*
* To make this working, the `dataNodes` variable of the TreeControl must be set to all root level
* data nodes of the tree.
* @return {?}
*/
NestedTreeControl.prototype.expandAll = /**
* Expands all dataNodes in the tree.
*
* To make this working, the `dataNodes` variable of the TreeControl must be set to all root level
* data nodes of the tree.
* @return {?}
*/
function () {
var _this = this;
var _a;
this.expansionModel.clear();
/** @type {?} */
var allNodes = this.dataNodes.reduce((/**
* @param {?} accumulator
* @param {?} dataNode
* @return {?}
*/
function (accumulator, dataNode) {
return accumulator.concat(_this.getDescendants(dataNode), [dataNode]);
}), []);
(_a = this.expansionModel).select.apply(_a, allNodes);
};
/** Gets a list of descendant dataNodes of a subtree rooted at given data node recursively. */
/**
* Gets a list of descendant dataNodes of a subtree rooted at given data node recursively.
* @param {?} dataNode
* @return {?}
*/
NestedTreeControl.prototype.getDescendants = /**
* Gets a list of descendant dataNodes of a subtree rooted at given data node recursively.
* @param {?} dataNode
* @return {?}
*/
function (dataNode) {
/** @type {?} */
var descendants = [];
this._getDescendants(descendants, dataNode);
// Remove the node itself
return descendants.splice(1);
};
/** A helper function to get descendants recursively. */
/**
* A helper function to get descendants recursively.
* @protected
* @param {?} descendants
* @param {?} dataNode
* @return {?}
*/
NestedTreeControl.prototype._getDescendants = /**
* A helper function to get descendants recursively.
* @protected
* @param {?} descendants
* @param {?} dataNode
* @return {?}
*/
function (descendants, dataNode) {
var _this = this;
descendants.push(dataNode);
/** @type {?} */
var childrenNodes = this.getChildren(dataNode);
if (Array.isArray(childrenNodes)) {
childrenNodes.forEach((/**
* @param {?} child
* @return {?}
*/
function (child) { return _this._getDescendants(descendants, child); }));
}
else if (childrenNodes instanceof rxjs.Observable) {
// TypeScript as of version 3.5 doesn't seem to treat `Boolean` like a function that
// returns a `boolean` specifically in the context of `filter`, so we manually clarify that.
childrenNodes.pipe(operators.take(1), operators.filter((/** @type {?} */ (Boolean))))
.subscribe((/**
* @param {?} children
* @return {?}
*/
function (children) {
for (var _i = 0, children_1 = children; _i < children_1.length; _i++) {
var child = children_1[_i];
_this._getDescendants(descendants, child);
}
}));
}
};
return NestedTreeControl;
}(BaseTreeControl));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Injection token used to provide a `CdkTreeNode` to its outlet.
* Used primarily to avoid circular imports.
* \@docs-private
* @type {?}
*/
var CDK_TREE_NODE_OUTLET_NODE = new core.InjectionToken('CDK_TREE_NODE_OUTLET_NODE');
/**
* Outlet for nested CdkNode. Put `[cdkTreeNodeOutlet]` on a tag to place children dataNodes
* inside the outlet.
*/
var CdkTreeNodeOutlet = /** @class */ (function () {
function CdkTreeNodeOutlet(viewContainer, _node) {
this.viewContainer = viewContainer;
this._node = _node;
}
CdkTreeNodeOutlet.decorators = [
{ type: core.Directive, args: [{
selector: '[cdkTreeNodeOutlet]'
},] },
];
/** @nocollapse */
CdkTreeNodeOutlet.ctorParameters = function () { return [
{ type: core.ViewContainerRef },
{ type: undefined, decorators: [{ type: core.Inject, args: [CDK_TREE_NODE_OUTLET_NODE,] }, { type: core.Optional }] }
]; };
return CdkTreeNodeOutlet;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Context provided to the tree node component.
* @template T
*/
var /**
* Context provided to the tree node component.
* @template T
*/
CdkTreeNodeOutletContext = /** @class */ (function () {
function CdkTreeNodeOutletContext(data) {
this.$implicit = data;
}
return CdkTreeNodeOutletContext;
}());
/**
* Data node definition for the CdkTree.
* Captures the node's template and a when predicate that describes when this node should be used.
* @template T
*/
var CdkTreeNodeDef = /** @class */ (function () {
/** @docs-private */
function CdkTreeNodeDef(template) {
this.template = template;
}
CdkTreeNodeDef.decorators = [
{ type: core.Directive, args: [{
selector: '[cdkTreeNodeDef]',
inputs: [
'when: cdkTreeNodeDefWhen'
],
},] },
];
/** @nocollapse */
CdkTreeNodeDef.ctorParameters = function () { return [
{ type: core.TemplateRef }
]; };
return CdkTreeNodeDef;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Returns an error to be thrown when there is no usable data.
* \@docs-private
* @return {?}
*/
function getTreeNoValidDataSourceError() {
return Error("A valid data source must be provided.");
}
/**
* Returns an error to be thrown when there are multiple nodes that are missing a when function.
* \@docs-private
* @return {?}
*/
function getTreeMultipleDefaultNodeDefsError() {
return Error("There can only be one default row without a when predicate function.");
}
/**
* Returns an error to be thrown when there are no matching node defs for a particular set of data.
* \@docs-private
* @return {?}
*/
function getTreeMissingMatchingNodeDefError() {
return Error("Could not find a matching node definition for the provided node data.");
}
/**
* Returns an error to be thrown when there are tree control.
* \@docs-private
* @return {?}
*/
function getTreeControlMissingError() {
return Error("Could not find a tree control for the tree.");
}
/**
* Returns an error to be thrown when tree control did not implement functions for flat/nested node.
* \@docs-private
* @return {?}
*/
function getTreeControlFunctionsMissingError() {
return Error("Could not find functions for nested/flat tree in tree control.");
}
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* CDK tree component that connects with a data source to retrieve data of type `T` and renders
* dataNodes with hierarchy. Updates the dataNodes when new data is provided by the data source.
* @template T
*/
var CdkTree = /** @class */ (function () {
function CdkTree(_differs, _changeDetectorRef) {
this._differs = _differs;
this._changeDetectorRef = _changeDetectorRef;
/**
* Subject that emits when the component has been destroyed.
*/
this._onDestroy = new rxjs.Subject();
/**
* Level of nodes
*/
this._levels = new Map();
// TODO(tinayuangao): Setup a listener for scrolling, emit the calculated view to viewChange.
// Remove the MAX_VALUE in viewChange
/**
* Stream containing the latest information on what rows are being displayed on screen.
* Can be used by the data source to as a heuristic of what data should be provided.
*/
this.viewChange = new rxjs.BehaviorSubject({ start: 0, end: Number.MAX_VALUE });
}
Object.defineProperty(CdkTree.prototype, "dataSource", {
/**
* Provides a stream containing the latest data array to render. Influenced by the tree's
* stream of view window (what dataNodes are currently on screen).
* Data source can be an observable of data array, or a data array to render.
*/
get: /**
* Provides a stream containing the latest data array to render. Influenced by the tree's
* stream of view window (what dataNodes are currently on screen).
* Data source can be an observable of data array, or a data array to render.
* @return {?}
*/
function () { return this._dataSource; },
set: /**
* @param {?} dataSource
* @return {?}
*/
function (dataSource) {
if (this._dataSource !== dataSource) {
this._switchDataSource(dataSource);
}
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
CdkTree.prototype.ngOnInit = /**
* @return {?}
*/
function () {
this._dataDiffer = this._differs.find([]).create(this.trackBy);
if (!this.treeControl) {
throw getTreeControlMissingError();
}
};
/**
* @return {?}
*/
CdkTree.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
this._nodeOutlet.viewContainer.clear();
this._onDestroy.next();
this._onDestroy.complete();
if (this._dataSource && typeof ((/** @type {?} */ (this._dataSource))).disconnect === 'function') {
((/** @type {?} */ (this.dataSource))).disconnect(this);
}
if (this._dataSubscription) {
this._dataSubscription.unsubscribe();
this._dataSubscription = null;
}
};
/**
* @return {?}
*/
CdkTree.prototype.ngAfterContentChecked = /**
* @return {?}
*/
function () {
/** @type {?} */
var defaultNodeDefs = this._nodeDefs.filter((/**
* @param {?} def
* @return {?}
*/
function (def) { return !def.when; }));
if (defaultNodeDefs.length > 1) {
throw getTreeMultipleDefaultNodeDefsError();
}
this._defaultNodeDef = defaultNodeDefs[0];
if (this.dataSource && this._nodeDefs && !this._dataSubscription) {
this._observeRenderChanges();
}
};
// TODO(tinayuangao): Work on keyboard traversal and actions, make sure it's working for RTL
// and nested trees.
/**
* Switch to the provided data source by resetting the data and unsubscribing from the current
* render change subscription if one exists. If the data source is null, interpret this by
* clearing the node outlet. Otherwise start listening for new data.
*/
// TODO(tinayuangao): Work on keyboard traversal and actions, make sure it's working for RTL
// and nested trees.
/**
* Switch to the provided data source by resetting the data and unsubscribing from the current
* render change subscription if one exists. If the data source is null, interpret this by
* clearing the node outlet. Otherwise start listening for new data.
* @private
* @param {?} dataSource
* @return {?}
*/
CdkTree.prototype._switchDataSource =
// TODO(tinayuangao): Work on keyboard traversal and actions, make sure it's working for RTL
// and nested trees.
/**
* Switch to the provided data source by resetting the data and unsubscribing from the current
* render change subscription if one exists. If the data source is null, interpret this by
* clearing the node outlet. Otherwise start listening for new data.
* @private
* @param {?} dataSource
* @return {?}
*/
function (dataSource) {
if (this._dataSource && typeof ((/** @type {?} */ (this._dataSource))).disconnect === 'function') {
((/** @type {?} */ (this.dataSource))).disconnect(this);
}
if (this._dataSubscription) {
this._dataSubscription.unsubscribe();
this._dataSubscription = null;
}
// Remove the all dataNodes if there is now no data source
if (!dataSource) {
this._nodeOutlet.viewContainer.clear();
}
this._dataSource = dataSource;
if (this._nodeDefs) {
this._observeRenderChanges();
}
};
/** Set up a subscription for the data provided by the data source. */
/**
* Set up a subscription for the data provided by the data source.
* @private
* @return {?}
*/
CdkTree.prototype._observeRenderChanges = /**
* Set up a subscription for the data provided by the data source.
* @private
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var dataStream;
if (collections.isDataSource(this._dataSource)) {
dataStream = this._dataSource.connect(this);
}
else if (this._dataSource instanceof rxjs.Observable) {
dataStream = this._dataSource;
}
else if (Array.isArray(this._dataSource)) {
dataStream = rxjs.of(this._dataSource);
}
if (dataStream) {
this._dataSubscription = dataStream.pipe(operators.takeUntil(this._onDestroy))
.subscribe((/**
* @param {?} data
* @return {?}
*/
function (data) { return _this.renderNodeChanges(data); }));
}
else {
throw getTreeNoValidDataSourceError();
}
};
/** Check for changes made in the data and render each change (node added/removed/moved). */
/**
* Check for changes made in the data and render each change (node added/removed/moved).
* @param {?} data
* @param {?=} dataDiffer
* @param {?=} viewContainer
* @param {?=} parentData
* @return {?}
*/
CdkTree.prototype.renderNodeChanges = /**
* Check for changes made in the data and render each change (node added/removed/moved).
* @param {?} data
* @param {?=} dataDiffer
* @param {?=} viewContainer
* @param {?=} parentData
* @return {?}
*/
function (data, dataDiffer, viewContainer, parentData) {
var _this = this;
if (dataDiffer === void 0) { dataDiffer = this._dataDiffer; }
if (viewContainer === void 0) { viewContainer = this._nodeOutlet.viewContainer; }
/** @type {?} */
var changes = dataDiffer.diff(data);
if (!changes) {
return;
}
changes.forEachOperation((/**
* @param {?} item
* @param {?} adjustedPreviousIndex
* @param {?} currentIndex
* @return {?}
*/
function (item, adjustedPreviousIndex, currentIndex) {
if (item.previousIndex == null) {
_this.insertNode(data[(/** @type {?} */ (currentIndex))], (/** @type {?} */ (currentIndex)), viewContainer, parentData);
}
else if (currentIndex == null) {
viewContainer.remove((/** @type {?} */ (adjustedPreviousIndex)));
_this._levels.delete(item.item);
}
else {
/** @type {?} */
var view = viewContainer.get((/** @type {?} */ (adjustedPreviousIndex)));
viewContainer.move((/** @type {?} */ (view)), currentIndex);
}
}));
this._changeDetectorRef.detectChanges();
};
/**
* Finds the matching node definition that should be used for this node data. If there is only
* one node definition, it is returned. Otherwise, find the node definition that has a when
* predicate that returns true with the data. If none return true, return the default node
* definition.
*/
/**
* Finds the matching node definition that should be used for this node data. If there is only
* one node definition, it is returned. Otherwise, find the node definition that has a when
* predicate that returns true with the data. If none return true, return the default node
* definition.
* @param {?} data
* @param {?} i
* @return {?}
*/
CdkTree.prototype._getNodeDef = /**
* Finds the matching node definition that should be used for this node data. If there is only
* one node definition, it is returned. Otherwise, find the node definition that has a when
* predicate that returns true with the data. If none return true, return the default node
* definition.
* @param {?} data
* @param {?} i
* @return {?}
*/
function (data, i) {
if (this._nodeDefs.length === 1) {
return this._nodeDefs.first;
}
/** @type {?} */
var nodeDef = this._nodeDefs.find((/**
* @param {?} def
* @return {?}
*/
function (def) { return def.when && def.when(i, data); })) || this._defaultNodeDef;
if (!nodeDef) {
throw getTreeMissingMatchingNodeDefError();
}
return nodeDef;
};
/**
* Create the embedded view for the data node template and place it in the correct index location
* within the data node view container.
*/
/**
* Create the embedded view for the data node template and place it in the correct index location
* within the data node view container.
* @param {?} nodeData
* @param {?} index
* @param {?=} viewContainer
* @param {?=} parentData
* @return {?}
*/
CdkTree.prototype.insertNode = /**
* Create the embedded view for the data node template and place it in the correct index location
* within the data node view container.
* @param {?} nodeData
* @param {?} index
* @param {?=} viewContainer
* @param {?=} parentData
* @return {?}
*/
function (nodeData, index, viewContainer, parentData) {
/** @type {?} */
var node = this._getNodeDef(nodeData, index);
// Node context that will be provided to created embedded view
/** @type {?} */
var context = new CdkTreeNodeOutletContext(nodeData);
// If the tree is flat tree, then use the `getLevel` function in flat tree control
// Otherwise, use the level of parent node.
if (this.treeControl.getLevel) {
context.level = this.treeControl.getLevel(nodeData);
}
else if (typeof parentData !== 'undefined' && this._levels.has(parentData)) {
context.level = (/** @type {?} */ (this._levels.get(parentData))) + 1;
}
else {
context.level = 0;
}
this._levels.set(nodeData, context.level);
// Use default tree nodeOutlet, or nested node's nodeOutlet
/** @type {?} */
var container = viewContainer ? viewContainer : this._nodeOutlet.viewContainer;
container.createEmbeddedView(node.template, context, index);
// Set the data to just created `CdkTreeNode`.
// The `CdkTreeNode` created from `createEmbeddedView` will be saved in static variable
// `mostRecentTreeNode`. We get it from static variable and pass the node data to it.
if (CdkTreeNode.mostRecentTreeNode) {
CdkTreeNode.mostRecentTreeNode.data = nodeData;
}
};
CdkTree.decorators = [
{ type: core.Component, args: [{selector: 'cdk-tree',
exportAs: 'cdkTree',
template: "<ng-container cdkTreeNodeOutlet></ng-container>",
host: {
'class': 'cdk-tree',
'role': 'tree',
},
encapsulation: core.ViewEncapsulation.None,
// The "OnPush" status for the `CdkTree` component is effectively a noop, so we are removing it.
// The view for `CdkTree` consists entirely of templates declared in other views. As they are
// declared elsewhere, they are checked when their declaration points are checked.
// tslint:disable-next-line:validate-decorators
changeDetection: core.ChangeDetectionStrategy.Default
},] },
];
/** @nocollapse */
CdkTree.ctorParameters = function () { return [
{ type: core.IterableDiffers },
{ type: core.ChangeDetectorRef }
]; };
CdkTree.propDecorators = {
dataSource: [{ type: core.Input }],
treeControl: [{ type: core.Input }],
trackBy: [{ type: core.Input }],
_nodeOutlet: [{ type: core.ViewChild, args: [CdkTreeNodeOutlet, { static: true },] }],
_nodeDefs: [{ type: core.ContentChildren, args: [CdkTreeNodeDef,] }]
};
return CdkTree;
}());
/**
* Tree node for CdkTree. It contains the data in the tree node.
* @template T
*/
var CdkTreeNode = /** @class */ (function () {
function CdkTreeNode(_elementRef, _tree) {
this._elementRef = _elementRef;
this._tree = _tree;
/**
* Subject that emits when the component has been destroyed.
*/
this._destroyed = new rxjs.Subject();
/**
* Emits when the node's data has changed.
*/
this._dataChanges = new rxjs.Subject();
/**
* The role of the node should be 'group' if it's an internal node,
* and 'treeitem' if it's a leaf node.
*/
this.role = 'treeitem';
CdkTreeNode.mostRecentTreeNode = (/** @type {?} */ (this));
}
Object.defineProperty(CdkTreeNode.prototype, "data", {
/** The tree node's data. */
get: /**
* The tree node's data.
* @return {?}
*/
function () { return this._data; },
set: /**
* @param {?} value
* @return {?}
*/
function (value) {
if (value !== this._data) {
this._data = value;
this._setRoleFromData();
this._dataChanges.next();
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(CdkTreeNode.prototype, "isExpanded", {
get: /**
* @return {?}
*/
function () {
return this._tree.treeControl.isExpanded(this._data);
},
enumerable: true,
configurable: true
});
Object.defineProperty(CdkTreeNode.prototype, "level", {
get: /**
* @return {?}
*/
function () {
return this._tree.treeControl.getLevel ? this._tree.treeControl.getLevel(this._data) : 0;
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
CdkTreeNode.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
// If this is the last tree node being destroyed,
// clear out the reference to avoid leaking memory.
if (CdkTreeNode.mostRecentTreeNode === this) {
CdkTreeNode.mostRecentTreeNode = null;
}
this._dataChanges.complete();
this._destroyed.next();
this._destroyed.complete();
};
/** Focuses the menu item. Implements for FocusableOption. */
/**
* Focuses the menu item. Implements for FocusableOption.
* @return {?}
*/
CdkTreeNode.prototype.focus = /**
* Focuses the menu item. Implements for FocusableOption.
* @return {?}
*/
function () {
this._elementRef.nativeElement.focus();
};
/**
* @protected
* @return {?}
*/
CdkTreeNode.prototype._setRoleFromData = /**
* @protected
* @return {?}
*/
function () {
var _this = this;
if (this._tree.treeControl.isExpandable) {
this.role = this._tree.treeControl.isExpandable(this._data) ? 'group' : 'treeitem';
}
else {
if (!this._tree.treeControl.getChildren) {
throw getTreeControlFunctionsMissingError();
}
/** @type {?} */
var childrenNodes = this._tree.treeControl.getChildren(this._data);
if (Array.isArray(childrenNodes)) {
this._setRoleFromChildren((/** @type {?} */ (childrenNodes)));
}
else if (childrenNodes instanceof rxjs.Observable) {
childrenNodes.pipe(operators.takeUntil(this._destroyed))
.subscribe((/**
* @param {?} children
* @return {?}
*/
function (children) { return _this._setRoleFromChildren(children); }));
}
}
};
/**
* @protected
* @param {?} children
* @return {?}
*/
CdkTreeNode.prototype._setRoleFromChildren = /**
* @protected
* @param {?} children
* @return {?}
*/
function (children) {
this.role = children && children.length ? 'group' : 'treeitem';
};
/**
* The most recently created `CdkTreeNode`. We save it in static variable so we can retrieve it
* in `CdkTree` and set the data to it.
*/
CdkTreeNode.mostRecentTreeNode = null;
CdkTreeNode.decorators = [
{ type: core.Directive, args: [{
selector: 'cdk-tree-node',
exportAs: 'cdkTreeNode',
host: {
'[attr.aria-expanded]': 'isExpanded',
'[attr.aria-level]': 'role === "treeitem" ? level : null',
'[attr.role]': 'role',
'class': 'cdk-tree-node',
},
},] },
];
/** @nocollapse */
CdkTreeNode.ctorParameters = function () { return [
{ type: core.ElementRef },
{ type: CdkTree }
]; };
CdkTreeNode.propDecorators = {
role: [{ type: core.Input }]
};
return CdkTreeNode;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Nested node is a child of `<cdk-tree>`. It works with nested tree.
* By using `cdk-nested-tree-node` component in tree node template, children of the parent node will
* be added in the `cdkTreeNodeOutlet` in tree node template.
* For example:
* ```html
* <cdk-nested-tree-node>
* {{node.name}}
* <ng-template cdkTreeNodeOutlet></ng-template>
* </cdk-nested-tree-node>
* ```
* The children of node will be automatically added to `cdkTreeNodeOutlet`, the result dom will be
* like this:
* ```html
* <cdk-nested-tree-node>
* {{node.name}}
* <cdk-nested-tree-node>{{child1.name}}</cdk-nested-tree-node>
* <cdk-nested-tree-node>{{child2.name}}</cdk-nested-tree-node>
* </cdk-nested-tree-node>
* ```
* @template T
*/
var CdkNestedTreeNode = /** @class */ (function (_super) {
__extends(CdkNestedTreeNode, _super);
function CdkNestedTreeNode(_elementRef, _tree, _differs) {
var _this = _super.call(this, _elementRef, _tree) || this;
_this._elementRef = _elementRef;
_this._tree = _tree;
_this._differs = _differs;
return _this;
}
/**
* @return {?}
*/
CdkNestedTreeNode.prototype.ngAfterContentInit = /**
* @return {?}
*/
function () {
var _this = this;
this._dataDiffer = this._differs.find([]).create(this._tree.trackBy);
if (!this._tree.treeControl.getChildren) {
throw getTreeControlFunctionsMissingError();
}
/** @type {?} */
var childrenNodes = this._tree.treeControl.getChildren(this.data);
if (Array.isArray(childrenNodes)) {
this.updateChildrenNodes((/** @type {?} */ (childrenNodes)));
}
else if (childrenNodes instanceof rxjs.Observable) {
childrenNodes.pipe(operators.takeUntil(this._destroyed))
.subscribe((/**
* @param {?} result
* @return {?}
*/
function (result) { return _this.updateChildrenNodes(result); }));
}
this.nodeOutlet.changes.pipe(operators.takeUntil(this._destroyed))
.subscribe((/**
* @return {?}
*/
function () { return _this.updateChildrenNodes(); }));
};
/**
* @return {?}
*/
CdkNestedTreeNode.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
this._clear();
_super.prototype.ngOnDestroy.call(this);
};
/** Add children dataNodes to the NodeOutlet */
/**
* Add children dataNodes to the NodeOutlet
* @protected
* @param {?=} children
* @return {?}
*/
CdkNestedTreeNode.prototype.updateChildrenNodes = /**
* Add children dataNodes to the NodeOutlet
* @protected
* @param {?=} children
* @return {?}
*/
function (children) {
/** @type {?} */
var outlet = this._getNodeOutlet();
if (children) {
this._children = children;
}
if (outlet && this._children) {
/** @type {?} */
var viewContainer = outlet.viewContainer;
this._tree.renderNodeChanges(this._children, this._dataDiffer, viewContainer, this._data);
}
else {
// Reset the data differ if there's no children nodes displayed
this._dataDiffer.diff([]);
}
};
/** Clear the children dataNodes. */
/**
* Clear the children dataNodes.
* @protected
* @return {?}
*/
CdkNestedTreeNode.prototype._clear = /**
* Clear the children dataNodes.
* @protected
* @return {?}
*/
function () {
/** @type {?} */
var outlet = this._getNodeOutlet();
if (outlet) {
outlet.viewContainer.clear();
this._dataDiffer.diff([]);
}
};
/** Gets the outlet for the current node. */
/**
* Gets the outlet for the current node.
* @private
* @return {?}
*/
CdkNestedTreeNode.prototype._getNodeOutlet = /**
* Gets the outlet for the current node.
* @private
* @return {?}
*/
function () {
var _this = this;
/** @type {?} */
var outlets = this.nodeOutlet;
if (outlets) {
// Note that since we use `descendants: true` on the query, we have to ensure
// that we don't pick up the outlet of a child node by accident.
return outlets.find((/**
* @param {?} outlet
* @return {?}
*/
function (outlet) { return !outlet._node || outlet._node === _this; }));
}
};
CdkNestedTreeNode.decorators = [
{ type: core.Directive, args: [{
selector: 'cdk-nested-tree-node',
exportAs: 'cdkNestedTreeNode',
host: {
'[attr.aria-expanded]': 'isExpanded',
'[attr.role]': 'role',
'class': 'cdk-tree-node cdk-nested-tree-node',
},
providers: [
{ provide: CdkTreeNode, useExisting: CdkNestedTreeNode },
{ provide: CDK_TREE_NODE_OUTLET_NODE, useExisting: CdkNestedTreeNode }
]
},] },
];
/** @nocollapse */
CdkNestedTreeNode.ctorParameters = function () { return [
{ type: core.ElementRef },
{ type: CdkTree },
{ type: core.IterableDiffers }
]; };
CdkNestedTreeNode.propDecorators = {
nodeOutlet: [{ type: core.ContentChildren, args: [CdkTreeNodeOutlet, {
// We need to use `descendants: true`, because Ivy will no longer match
// indirect descendants if it's left as false.
descendants: true
},] }]
};
return CdkNestedTreeNode;
}(CdkTreeNode));
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Regex used to split a string on its CSS units.
* @type {?}
*/
var cssUnitPattern = /([A-Za-z%]+)$/;
/**
* Indent for the children tree dataNodes.
* This directive will add left-padding to the node to show hierarchy.
* @template T
*/
var CdkTreeNodePadding = /** @class */ (function () {
function CdkTreeNodePadding(_treeNode, _tree, _renderer, _element, _dir) {
var _this = this;
this._treeNode = _treeNode;
this._tree = _tree;
this._renderer = _renderer;
this._element = _element;
this._dir = _dir;
/**
* Subject that emits when the component has been destroyed.
*/
this._destroyed = new rxjs.Subject();
/**
* CSS units used for the indentation value.
*/
this.indentUnits = 'px';
this._indent = 40;
this._setPadding();
if (_dir) {
_dir.change.pipe(operators.takeUntil(this._destroyed)).subscribe((/**
* @return {?}
*/
function () { return _this._setPadding(true); }));
}
// In Ivy the indentation binding might be set before the tree node's data has been added,
// which means that we'll miss the first render. We have to subscribe to changes in the
// data to ensure that everything is up to date.
_treeNode._dataChanges.subscribe((/**
* @return {?}
*/
function () { return _this._setPadding(); }));
}
Object.defineProperty(CdkTreeNodePadding.prototype, "level", {
/** The level of depth of the tree node. The padding will be `level * indent` pixels. */
get: /**
* The level of depth of the tree node. The padding will be `level * indent` pixels.
* @return {?}
*/
function () { return this._level; },
set: /**
* @param {?} value
* @return {?}
*/
function (value) {
this._level = coercion.coerceNumberProperty(value);
this._setPadding();
},
enumerable: true,
configurable: true
});
Object.defineProperty(CdkTreeNodePadding.prototype, "indent", {
/**
* The indent for each level. Can be a number or a CSS string.
* Default number 40px from material design menu sub-menu spec.
*/
get: /**
* The indent for each level. Can be a number or a CSS string.
* Default number 40px from material design menu sub-menu spec.
* @return {?}
*/
function () { return this._indent; },
set: /**
* @param {?} indent
* @return {?}
*/
function (indent) {
/** @type {?} */
var value = indent;
/** @type {?} */
var units = 'px';
if (typeof indent === 'string') {
/** @type {?} */
var parts = indent.split(cssUnitPattern);
value = parts[0];
units = parts[1] || units;
}
this.indentUnits = units;
this._indent = coercion.coerceNumberProperty(value);
this._setPadding();
},
enumerable: true,
configurable: true
});
/**
* @return {?}
*/
CdkTreeNodePadding.prototype.ngOnDestroy = /**
* @return {?}
*/
function () {
this._destroyed.next();
this._destroyed.complete();
};
/** The padding indent value for the tree node. Returns a string with px numbers if not null. */
/**
* The padding indent value for the tree node. Returns a string with px numbers if not null.
* @return {?}
*/
CdkTreeNodePadding.prototype._paddingIndent = /**
* The padding indent value for the tree node. Returns a string with px numbers if not null.
* @return {?}
*/
function () {
/** @type {?} */
var nodeLevel = (this._treeNode.data && this._tree.treeControl.getLevel)
? this._tree.treeControl.getLevel(this._treeNode.data)
: null;
/** @type {?} */
var level = this._level || nodeLevel;
return level ? "" + level * this._indent + this.indentUnits : null;
};
/**
* @param {?=} forceChange
* @return {?}
*/
CdkTreeNodePadding.prototype._setPadding = /**
* @param {?=} forceChange
* @return {?}
*/
function (forceChange) {
if (forceChange === void 0) { forceChange = false; }
/** @type {?} */
var padding = this._paddingIndent();
if (padding !== this._currentPadding || forceChange) {
/** @type {?} */
var element = this._element.nativeElement;
/** @type {?} */
var paddingProp = this._dir && this._dir.value === 'rtl' ? 'paddingRight' : 'paddingLeft';
/** @type {?} */
var resetProp = paddingProp === 'paddingLeft' ? 'paddingRight' : 'paddingLeft';
this._renderer.setStyle(element, paddingProp, padding);
this._renderer.setStyle(element, resetProp, null);
this._currentPadding = padding;
}
};
CdkTreeNodePadding.decorators = [
{ type: core.Directive, args: [{
selector: '[cdkTreeNodePadding]',
},] },
];
/** @nocollapse */
CdkTreeNodePadding.ctorParameters = function () { return [
{ type: CdkTreeNode },
{ type: CdkTree },
{ type: core.Renderer2 },
{ type: core.ElementRef },
{ type: bidi.Directionality, decorators: [{ type: core.Optional }] }
]; };
CdkTreeNodePadding.propDecorators = {
level: [{ type: core.Input, args: ['cdkTreeNodePadding',] }],
indent: [{ type: core.Input, args: ['cdkTreeNodePaddingIndent',] }]
};
return CdkTreeNodePadding;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/**
* Node toggle to expand/collapse the node.
* @template T
*/
var CdkTreeNodeToggle = /** @class */ (function () {
function CdkTreeNodeToggle(_tree, _treeNode) {
this._tree = _tree;
this._treeNode = _treeNode;
this._recursive = false;
}
Object.defineProperty(CdkTreeNodeToggle.prototype, "recursive", {
/** Whether expand/collapse the node recursively. */
get: /**
* Whether expand/collapse the node recursively.
* @return {?}
*/
function () { return this._recursive; },
set: /**
* @param {?} value
* @return {?}
*/
function (value) { this._recursive = coercion.coerceBooleanProperty(value); },
enumerable: true,
configurable: true
});
// We have to use a `HostListener` here in order to support both Ivy and ViewEngine.
// In Ivy the `host` bindings will be merged when this class is extended, whereas in
// ViewEngine they're overwritten.
// TODO(crisbeto): we move this back into `host` once Ivy is turned on by default.
// tslint:disable-next-line:no-host-decorator-in-concrete
// We have to use a `HostListener` here in order to support both Ivy and ViewEngine.
// In Ivy the `host` bindings will be merged when this class is extended, whereas in
// ViewEngine they're overwritten.
// TODO(crisbeto): we move this back into `host` once Ivy is turned on by default.
// tslint:disable-next-line:no-host-decorator-in-concrete
/**
* @param {?} event
* @return {?}
*/
CdkTreeNodeToggle.prototype._toggle =
// We have to use a `HostListener` here in order to support both Ivy and ViewEngine.
// In Ivy the `host` bindings will be merged when this class is extended, whereas in
// ViewEngine they're overwritten.
// TODO(crisbeto): we move this back into `host` once Ivy is turned on by default.
// tslint:disable-next-line:no-host-decorator-in-concrete
/**
* @param {?} event
* @return {?}
*/
function (event) {
this.recursive
? this._tree.treeControl.toggleDescendants(this._treeNode.data)
: this._tree.treeControl.toggle(this._treeNode.data);
event.stopPropagation();
};
CdkTreeNodeToggle.decorators = [
{ type: core.Directive, args: [{ selector: '[cdkTreeNodeToggle]' },] },
];
/** @nocollapse */
CdkTreeNodeToggle.ctorParameters = function () { return [
{ type: CdkTree },
{ type: CdkTreeNode }
]; };
CdkTreeNodeToggle.propDecorators = {
recursive: [{ type: core.Input, args: ['cdkTreeNodeToggleRecursive',] }],
_toggle: [{ type: core.HostListener, args: ['click', ['$event'],] }]
};
return CdkTreeNodeToggle;
}());
/**
* @fileoverview added by tsickle
* @suppress {checkTypes,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc
*/
/** @type {?} */
var EXPORTED_DECLARATIONS = [
CdkNestedTreeNode,
CdkTreeNodeDef,
CdkTreeNodePadding,
CdkTreeNodeToggle,
CdkTree,
CdkTreeNode,
CdkTreeNodeOutlet,
];
var CdkTreeModule = /** @class */ (function () {
function CdkTreeModule() {
}
CdkTreeModule.decorators = [
{ type: core.NgModule, args: [{
imports: [common.CommonModule],
exports: EXPORTED_DECLARATIONS,
declarations: EXPORTED_DECLARATIONS,
providers: [a11y.FocusMonitor, CdkTreeNodeDef]
},] },
];
return CdkTreeModule;
}());
exports.BaseTreeControl = BaseTreeControl;
exports.FlatTreeControl = FlatTreeControl;
exports.NestedTreeControl = NestedTreeControl;
exports.CdkNestedTreeNode = CdkNestedTreeNode;
exports.CdkTreeNodeOutletContext = CdkTreeNodeOutletContext;
exports.CdkTreeNodeDef = CdkTreeNodeDef;
exports.CdkTreeNodePadding = CdkTreeNodePadding;
exports.CDK_TREE_NODE_OUTLET_NODE = CDK_TREE_NODE_OUTLET_NODE;
exports.CdkTreeNodeOutlet = CdkTreeNodeOutlet;
exports.CdkTree = CdkTree;
exports.CdkTreeNode = CdkTreeNode;
exports.getTreeNoValidDataSourceError = getTreeNoValidDataSourceError;
exports.getTreeMultipleDefaultNodeDefsError = getTreeMultipleDefaultNodeDefsError;
exports.getTreeMissingMatchingNodeDefError = getTreeMissingMatchingNodeDefError;
exports.getTreeControlMissingError = getTreeControlMissingError;
exports.getTreeControlFunctionsMissingError = getTreeControlFunctionsMissingError;
exports.CdkTreeModule = CdkTreeModule;
exports.CdkTreeNodeToggle = CdkTreeNodeToggle;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=cdk-tree.umd.js.map