tree.mjs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. import { CdkTreeNode, CdkTreeNodeDef, CdkNestedTreeNode, CDK_TREE_NODE_OUTLET_NODE, CdkTreeNodePadding, CdkTreeNodeOutlet, CdkTree, CdkTreeNodeToggle, CdkTreeModule } from '@angular/cdk/tree';
  2. import * as i0 from '@angular/core';
  3. import { inject, HostAttributeToken, numberAttribute, booleanAttribute, Directive, Input, ViewContainerRef, Component, ViewEncapsulation, ChangeDetectionStrategy, ViewChild, NgModule } from '@angular/core';
  4. import { M as MatCommonModule } from './common-module-WayjW0Pb.mjs';
  5. import { DataSource } from '@angular/cdk/collections';
  6. import { BehaviorSubject, merge } from 'rxjs';
  7. import { take, map } from 'rxjs/operators';
  8. import '@angular/cdk/a11y';
  9. import '@angular/cdk/bidi';
  10. /**
  11. * Determinte if argument TreeKeyManager is the NoopTreeKeyManager. This function is safe to use with SSR.
  12. */
  13. function isNoopTreeKeyManager(keyManager) {
  14. return !!keyManager._isNoopTreeKeyManager;
  15. }
  16. /**
  17. * Wrapper for the CdkTree node with Material design styles.
  18. */
  19. class MatTreeNode extends CdkTreeNode {
  20. /**
  21. * The tabindex of the tree node.
  22. *
  23. * @deprecated By default MatTreeNode manages focus using TreeKeyManager instead of tabIndex.
  24. * Recommend to avoid setting tabIndex directly to prevent TreeKeyManager form getting into
  25. * an unexpected state. Tabindex to be removed in a future version.
  26. * @breaking-change 21.0.0 Remove this attribute.
  27. */
  28. get tabIndexInputBinding() {
  29. return this._tabIndexInputBinding;
  30. }
  31. set tabIndexInputBinding(value) {
  32. // If the specified tabIndex value is null or undefined, fall back to the default value.
  33. this._tabIndexInputBinding = value;
  34. }
  35. _tabIndexInputBinding;
  36. /**
  37. * The default tabindex of the tree node.
  38. *
  39. * @deprecated By default MatTreeNode manages focus using TreeKeyManager instead of tabIndex.
  40. * Recommend to avoid setting tabIndex directly to prevent TreeKeyManager form getting into
  41. * an unexpected state. Tabindex to be removed in a future version.
  42. * @breaking-change 21.0.0 Remove this attribute.
  43. */
  44. defaultTabIndex = 0;
  45. _getTabindexAttribute() {
  46. if (isNoopTreeKeyManager(this._tree._keyManager)) {
  47. return this.tabIndexInputBinding;
  48. }
  49. return this._tabindex;
  50. }
  51. /**
  52. * Whether the component is disabled.
  53. *
  54. * @deprecated This is an alias for `isDisabled`.
  55. * @breaking-change 21.0.0 Remove this input
  56. */
  57. get disabled() {
  58. return this.isDisabled;
  59. }
  60. set disabled(value) {
  61. this.isDisabled = value;
  62. }
  63. constructor() {
  64. super();
  65. const tabIndex = inject(new HostAttributeToken('tabindex'), { optional: true });
  66. this.tabIndexInputBinding = Number(tabIndex) || this.defaultTabIndex;
  67. }
  68. // This is a workaround for https://github.com/angular/angular/issues/23091
  69. // In aot mode, the lifecycle hooks from parent class are not called.
  70. ngOnInit() {
  71. super.ngOnInit();
  72. }
  73. ngOnDestroy() {
  74. super.ngOnDestroy();
  75. }
  76. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNode, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  77. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.6", type: MatTreeNode, isStandalone: true, selector: "mat-tree-node", inputs: { tabIndexInputBinding: ["tabIndex", "tabIndexInputBinding", (value) => (value == null ? 0 : numberAttribute(value))], disabled: ["disabled", "disabled", booleanAttribute] }, outputs: { activation: "activation", expandedChange: "expandedChange" }, host: { listeners: { "click": "_focusItem()" }, properties: { "attr.aria-expanded": "_getAriaExpanded()", "attr.aria-level": "level + 1", "attr.aria-posinset": "_getPositionInSet()", "attr.aria-setsize": "_getSetSize()", "tabindex": "_getTabindexAttribute()" }, classAttribute: "mat-tree-node" }, providers: [{ provide: CdkTreeNode, useExisting: MatTreeNode }], exportAs: ["matTreeNode"], usesInheritance: true, ngImport: i0 });
  78. }
  79. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNode, decorators: [{
  80. type: Directive,
  81. args: [{
  82. selector: 'mat-tree-node',
  83. exportAs: 'matTreeNode',
  84. outputs: ['activation', 'expandedChange'],
  85. providers: [{ provide: CdkTreeNode, useExisting: MatTreeNode }],
  86. host: {
  87. 'class': 'mat-tree-node',
  88. '[attr.aria-expanded]': '_getAriaExpanded()',
  89. '[attr.aria-level]': 'level + 1',
  90. '[attr.aria-posinset]': '_getPositionInSet()',
  91. '[attr.aria-setsize]': '_getSetSize()',
  92. '(click)': '_focusItem()',
  93. '[tabindex]': '_getTabindexAttribute()',
  94. },
  95. }]
  96. }], ctorParameters: () => [], propDecorators: { tabIndexInputBinding: [{
  97. type: Input,
  98. args: [{
  99. transform: (value) => (value == null ? 0 : numberAttribute(value)),
  100. alias: 'tabIndex',
  101. }]
  102. }], disabled: [{
  103. type: Input,
  104. args: [{ transform: booleanAttribute }]
  105. }] } });
  106. /**
  107. * Wrapper for the CdkTree node definition with Material design styles.
  108. * Captures the node's template and a when predicate that describes when this node should be used.
  109. */
  110. class MatTreeNodeDef extends CdkTreeNodeDef {
  111. data;
  112. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNodeDef, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  113. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: MatTreeNodeDef, isStandalone: true, selector: "[matTreeNodeDef]", inputs: { when: ["matTreeNodeDefWhen", "when"], data: ["matTreeNode", "data"] }, providers: [{ provide: CdkTreeNodeDef, useExisting: MatTreeNodeDef }], usesInheritance: true, ngImport: i0 });
  114. }
  115. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNodeDef, decorators: [{
  116. type: Directive,
  117. args: [{
  118. selector: '[matTreeNodeDef]',
  119. inputs: [{ name: 'when', alias: 'matTreeNodeDefWhen' }],
  120. providers: [{ provide: CdkTreeNodeDef, useExisting: MatTreeNodeDef }],
  121. }]
  122. }], propDecorators: { data: [{
  123. type: Input,
  124. args: ['matTreeNode']
  125. }] } });
  126. /**
  127. * Wrapper for the CdkTree nested node with Material design styles.
  128. */
  129. class MatNestedTreeNode extends CdkNestedTreeNode {
  130. node;
  131. /**
  132. * Whether the node is disabled.
  133. *
  134. * @deprecated This is an alias for `isDisabled`.
  135. * @breaking-change 21.0.0 Remove this input
  136. */
  137. get disabled() {
  138. return this.isDisabled;
  139. }
  140. set disabled(value) {
  141. this.isDisabled = value;
  142. }
  143. /** Tabindex of the node. */
  144. get tabIndex() {
  145. return this.isDisabled ? -1 : this._tabIndex;
  146. }
  147. set tabIndex(value) {
  148. // If the specified tabIndex value is null or undefined, fall back to the default value.
  149. this._tabIndex = value;
  150. }
  151. _tabIndex;
  152. // This is a workaround for https://github.com/angular/angular/issues/19145
  153. // In aot mode, the lifecycle hooks from parent class are not called.
  154. // TODO(tinayuangao): Remove when the angular issue #19145 is fixed
  155. ngOnInit() {
  156. super.ngOnInit();
  157. }
  158. ngAfterContentInit() {
  159. super.ngAfterContentInit();
  160. }
  161. ngOnDestroy() {
  162. super.ngOnDestroy();
  163. }
  164. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatNestedTreeNode, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  165. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.6", type: MatNestedTreeNode, isStandalone: true, selector: "mat-nested-tree-node", inputs: { node: ["matNestedTreeNode", "node"], disabled: ["disabled", "disabled", booleanAttribute], tabIndex: ["tabIndex", "tabIndex", (value) => (value == null ? 0 : numberAttribute(value))] }, outputs: { activation: "activation", expandedChange: "expandedChange" }, host: { classAttribute: "mat-nested-tree-node" }, providers: [
  166. { provide: CdkNestedTreeNode, useExisting: MatNestedTreeNode },
  167. { provide: CdkTreeNode, useExisting: MatNestedTreeNode },
  168. { provide: CDK_TREE_NODE_OUTLET_NODE, useExisting: MatNestedTreeNode },
  169. ], exportAs: ["matNestedTreeNode"], usesInheritance: true, ngImport: i0 });
  170. }
  171. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatNestedTreeNode, decorators: [{
  172. type: Directive,
  173. args: [{
  174. selector: 'mat-nested-tree-node',
  175. exportAs: 'matNestedTreeNode',
  176. outputs: ['activation', 'expandedChange'],
  177. providers: [
  178. { provide: CdkNestedTreeNode, useExisting: MatNestedTreeNode },
  179. { provide: CdkTreeNode, useExisting: MatNestedTreeNode },
  180. { provide: CDK_TREE_NODE_OUTLET_NODE, useExisting: MatNestedTreeNode },
  181. ],
  182. host: {
  183. 'class': 'mat-nested-tree-node',
  184. },
  185. }]
  186. }], propDecorators: { node: [{
  187. type: Input,
  188. args: ['matNestedTreeNode']
  189. }], disabled: [{
  190. type: Input,
  191. args: [{ transform: booleanAttribute }]
  192. }], tabIndex: [{
  193. type: Input,
  194. args: [{
  195. transform: (value) => (value == null ? 0 : numberAttribute(value)),
  196. }]
  197. }] } });
  198. /**
  199. * Wrapper for the CdkTree padding with Material design styles.
  200. */
  201. class MatTreeNodePadding extends CdkTreeNodePadding {
  202. /** The level of depth of the tree node. The padding will be `level * indent` pixels. */
  203. get level() {
  204. return this._level;
  205. }
  206. set level(value) {
  207. this._setLevelInput(value);
  208. }
  209. /** The indent for each level. Default number 40px from material design menu sub-menu spec. */
  210. get indent() {
  211. return this._indent;
  212. }
  213. set indent(indent) {
  214. this._setIndentInput(indent);
  215. }
  216. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNodePadding, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  217. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "19.2.6", type: MatTreeNodePadding, isStandalone: true, selector: "[matTreeNodePadding]", inputs: { level: ["matTreeNodePadding", "level", numberAttribute], indent: ["matTreeNodePaddingIndent", "indent"] }, providers: [{ provide: CdkTreeNodePadding, useExisting: MatTreeNodePadding }], usesInheritance: true, ngImport: i0 });
  218. }
  219. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNodePadding, decorators: [{
  220. type: Directive,
  221. args: [{
  222. selector: '[matTreeNodePadding]',
  223. providers: [{ provide: CdkTreeNodePadding, useExisting: MatTreeNodePadding }],
  224. }]
  225. }], propDecorators: { level: [{
  226. type: Input,
  227. args: [{ alias: 'matTreeNodePadding', transform: numberAttribute }]
  228. }], indent: [{
  229. type: Input,
  230. args: ['matTreeNodePaddingIndent']
  231. }] } });
  232. /**
  233. * Outlet for nested CdkNode. Put `[matTreeNodeOutlet]` on a tag to place children dataNodes
  234. * inside the outlet.
  235. */
  236. class MatTreeNodeOutlet {
  237. viewContainer = inject(ViewContainerRef);
  238. _node = inject(CDK_TREE_NODE_OUTLET_NODE, { optional: true });
  239. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNodeOutlet, deps: [], target: i0.ɵɵFactoryTarget.Directive });
  240. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: MatTreeNodeOutlet, isStandalone: true, selector: "[matTreeNodeOutlet]", providers: [
  241. {
  242. provide: CdkTreeNodeOutlet,
  243. useExisting: MatTreeNodeOutlet,
  244. },
  245. ], ngImport: i0 });
  246. }
  247. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNodeOutlet, decorators: [{
  248. type: Directive,
  249. args: [{
  250. selector: '[matTreeNodeOutlet]',
  251. providers: [
  252. {
  253. provide: CdkTreeNodeOutlet,
  254. useExisting: MatTreeNodeOutlet,
  255. },
  256. ],
  257. }]
  258. }] });
  259. /**
  260. * Wrapper for the CdkTable with Material design styles.
  261. */
  262. class MatTree extends CdkTree {
  263. // Outlets within the tree's template where the dataNodes will be inserted.
  264. // We need an initializer here to avoid a TS error. The value will be set in `ngAfterViewInit`.
  265. _nodeOutlet = undefined;
  266. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTree, deps: null, target: i0.ɵɵFactoryTarget.Component });
  267. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.6", type: MatTree, isStandalone: true, selector: "mat-tree", host: { classAttribute: "mat-tree" }, providers: [{ provide: CdkTree, useExisting: MatTree }], viewQueries: [{ propertyName: "_nodeOutlet", first: true, predicate: MatTreeNodeOutlet, descendants: true, static: true }], exportAs: ["matTree"], usesInheritance: true, ngImport: i0, template: `<ng-container matTreeNodeOutlet></ng-container>`, isInline: true, styles: [".mat-tree{display:block;background-color:var(--mat-tree-container-background-color, var(--mat-sys-surface))}.mat-tree-node,.mat-nested-tree-node{color:var(--mat-tree-node-text-color, var(--mat-sys-on-surface));font-family:var(--mat-tree-node-text-font, var(--mat-sys-body-large-font));font-size:var(--mat-tree-node-text-size, var(--mat-sys-body-large-size));font-weight:var(--mat-tree-node-text-weight, var(--mat-sys-body-large-weight))}.mat-tree-node{display:flex;align-items:center;flex:1;word-wrap:break-word;min-height:var(--mat-tree-node-min-height, 48px)}.mat-nested-tree-node{border-bottom-width:0}\n"], dependencies: [{ kind: "directive", type: MatTreeNodeOutlet, selector: "[matTreeNodeOutlet]" }], changeDetection: i0.ChangeDetectionStrategy.Default, encapsulation: i0.ViewEncapsulation.None });
  268. }
  269. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTree, decorators: [{
  270. type: Component,
  271. args: [{ selector: 'mat-tree', exportAs: 'matTree', template: `<ng-container matTreeNodeOutlet></ng-container>`, host: {
  272. 'class': 'mat-tree',
  273. }, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.Default, providers: [{ provide: CdkTree, useExisting: MatTree }], imports: [MatTreeNodeOutlet], styles: [".mat-tree{display:block;background-color:var(--mat-tree-container-background-color, var(--mat-sys-surface))}.mat-tree-node,.mat-nested-tree-node{color:var(--mat-tree-node-text-color, var(--mat-sys-on-surface));font-family:var(--mat-tree-node-text-font, var(--mat-sys-body-large-font));font-size:var(--mat-tree-node-text-size, var(--mat-sys-body-large-size));font-weight:var(--mat-tree-node-text-weight, var(--mat-sys-body-large-weight))}.mat-tree-node{display:flex;align-items:center;flex:1;word-wrap:break-word;min-height:var(--mat-tree-node-min-height, 48px)}.mat-nested-tree-node{border-bottom-width:0}\n"] }]
  274. }], propDecorators: { _nodeOutlet: [{
  275. type: ViewChild,
  276. args: [MatTreeNodeOutlet, { static: true }]
  277. }] } });
  278. /**
  279. * Wrapper for the CdkTree's toggle with Material design styles.
  280. */
  281. class MatTreeNodeToggle extends CdkTreeNodeToggle {
  282. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNodeToggle, deps: null, target: i0.ɵɵFactoryTarget.Directive });
  283. static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.6", type: MatTreeNodeToggle, isStandalone: true, selector: "[matTreeNodeToggle]", inputs: { recursive: ["matTreeNodeToggleRecursive", "recursive"] }, providers: [{ provide: CdkTreeNodeToggle, useExisting: MatTreeNodeToggle }], usesInheritance: true, ngImport: i0 });
  284. }
  285. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeNodeToggle, decorators: [{
  286. type: Directive,
  287. args: [{
  288. selector: '[matTreeNodeToggle]',
  289. providers: [{ provide: CdkTreeNodeToggle, useExisting: MatTreeNodeToggle }],
  290. inputs: [{ name: 'recursive', alias: 'matTreeNodeToggleRecursive' }],
  291. }]
  292. }] });
  293. const MAT_TREE_DIRECTIVES = [
  294. MatNestedTreeNode,
  295. MatTreeNodeDef,
  296. MatTreeNodePadding,
  297. MatTreeNodeToggle,
  298. MatTree,
  299. MatTreeNode,
  300. MatTreeNodeOutlet,
  301. ];
  302. class MatTreeModule {
  303. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  304. static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.6", ngImport: i0, type: MatTreeModule, imports: [CdkTreeModule, MatCommonModule, MatNestedTreeNode,
  305. MatTreeNodeDef,
  306. MatTreeNodePadding,
  307. MatTreeNodeToggle,
  308. MatTree,
  309. MatTreeNode,
  310. MatTreeNodeOutlet], exports: [MatCommonModule, MatNestedTreeNode,
  311. MatTreeNodeDef,
  312. MatTreeNodePadding,
  313. MatTreeNodeToggle,
  314. MatTree,
  315. MatTreeNode,
  316. MatTreeNodeOutlet] });
  317. static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeModule, imports: [CdkTreeModule, MatCommonModule, MatCommonModule] });
  318. }
  319. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.6", ngImport: i0, type: MatTreeModule, decorators: [{
  320. type: NgModule,
  321. args: [{
  322. imports: [CdkTreeModule, MatCommonModule, ...MAT_TREE_DIRECTIVES],
  323. exports: [MatCommonModule, MAT_TREE_DIRECTIVES],
  324. }]
  325. }] });
  326. /**
  327. * Tree flattener to convert a normal type of node to node with children & level information.
  328. * Transform nested nodes of type `T` to flattened nodes of type `F`.
  329. *
  330. * For example, the input data of type `T` is nested, and contains its children data:
  331. * SomeNode: {
  332. * key: 'Fruits',
  333. * children: [
  334. * NodeOne: {
  335. * key: 'Apple',
  336. * },
  337. * NodeTwo: {
  338. * key: 'Pear',
  339. * }
  340. * ]
  341. * }
  342. * After flattener flatten the tree, the structure will become
  343. * SomeNode: {
  344. * key: 'Fruits',
  345. * expandable: true,
  346. * level: 1
  347. * },
  348. * NodeOne: {
  349. * key: 'Apple',
  350. * expandable: false,
  351. * level: 2
  352. * },
  353. * NodeTwo: {
  354. * key: 'Pear',
  355. * expandable: false,
  356. * level: 2
  357. * }
  358. * and the output flattened type is `F` with additional information.
  359. *
  360. * @deprecated Use MatTree#childrenAccessor and MatTreeNode#isExpandable
  361. * instead. To be removed in a future version.
  362. * @breaking-change 21.0.0
  363. */
  364. class MatTreeFlattener {
  365. transformFunction;
  366. getLevel;
  367. isExpandable;
  368. getChildren;
  369. constructor(transformFunction, getLevel, isExpandable, getChildren) {
  370. this.transformFunction = transformFunction;
  371. this.getLevel = getLevel;
  372. this.isExpandable = isExpandable;
  373. this.getChildren = getChildren;
  374. }
  375. _flattenNode(node, level, resultNodes, parentMap) {
  376. const flatNode = this.transformFunction(node, level);
  377. resultNodes.push(flatNode);
  378. if (this.isExpandable(flatNode)) {
  379. const childrenNodes = this.getChildren(node);
  380. if (childrenNodes) {
  381. if (Array.isArray(childrenNodes)) {
  382. this._flattenChildren(childrenNodes, level, resultNodes, parentMap);
  383. }
  384. else {
  385. childrenNodes.pipe(take(1)).subscribe(children => {
  386. this._flattenChildren(children, level, resultNodes, parentMap);
  387. });
  388. }
  389. }
  390. }
  391. return resultNodes;
  392. }
  393. _flattenChildren(children, level, resultNodes, parentMap) {
  394. children.forEach((child, index) => {
  395. let childParentMap = parentMap.slice();
  396. childParentMap.push(index != children.length - 1);
  397. this._flattenNode(child, level + 1, resultNodes, childParentMap);
  398. });
  399. }
  400. /**
  401. * Flatten a list of node type T to flattened version of node F.
  402. * Please note that type T may be nested, and the length of `structuredData` may be different
  403. * from that of returned list `F[]`.
  404. */
  405. flattenNodes(structuredData) {
  406. let resultNodes = [];
  407. structuredData.forEach(node => this._flattenNode(node, 0, resultNodes, []));
  408. return resultNodes;
  409. }
  410. /**
  411. * Expand flattened node with current expansion status.
  412. * The returned list may have different length.
  413. */
  414. expandFlattenedNodes(nodes, treeControl) {
  415. let results = [];
  416. let currentExpand = [];
  417. currentExpand[0] = true;
  418. nodes.forEach(node => {
  419. let expand = true;
  420. for (let i = 0; i <= this.getLevel(node); i++) {
  421. expand = expand && currentExpand[i];
  422. }
  423. if (expand) {
  424. results.push(node);
  425. }
  426. if (this.isExpandable(node)) {
  427. currentExpand[this.getLevel(node) + 1] = treeControl.isExpanded(node);
  428. }
  429. });
  430. return results;
  431. }
  432. }
  433. /**
  434. * Data source for flat tree.
  435. * The data source need to handle expansion/collapsion of the tree node and change the data feed
  436. * to `MatTree`.
  437. * The nested tree nodes of type `T` are flattened through `MatTreeFlattener`, and converted
  438. * to type `F` for `MatTree` to consume.
  439. *
  440. * @deprecated Use one of levelAccessor or childrenAccessor instead. To be removed in a future
  441. * version.
  442. * @breaking-change 21.0.0
  443. */
  444. class MatTreeFlatDataSource extends DataSource {
  445. _treeControl;
  446. _treeFlattener;
  447. _flattenedData = new BehaviorSubject([]);
  448. _expandedData = new BehaviorSubject([]);
  449. get data() {
  450. return this._data.value;
  451. }
  452. set data(value) {
  453. this._data.next(value);
  454. this._flattenedData.next(this._treeFlattener.flattenNodes(this.data));
  455. this._treeControl.dataNodes = this._flattenedData.value;
  456. }
  457. _data = new BehaviorSubject([]);
  458. constructor(_treeControl, _treeFlattener, initialData) {
  459. super();
  460. this._treeControl = _treeControl;
  461. this._treeFlattener = _treeFlattener;
  462. if (initialData) {
  463. // Assign the data through the constructor to ensure that all of the logic is executed.
  464. this.data = initialData;
  465. }
  466. }
  467. connect(collectionViewer) {
  468. return merge(collectionViewer.viewChange, this._treeControl.expansionModel.changed, this._flattenedData).pipe(map(() => {
  469. this._expandedData.next(this._treeFlattener.expandFlattenedNodes(this._flattenedData.value, this._treeControl));
  470. return this._expandedData.value;
  471. }));
  472. }
  473. disconnect() {
  474. // no op
  475. }
  476. }
  477. /**
  478. * Data source for nested tree.
  479. *
  480. * The data source for nested tree doesn't have to consider node flattener, or the way to expand
  481. * or collapse. The expansion/collapsion will be handled by TreeControl and each non-leaf node.
  482. */
  483. class MatTreeNestedDataSource extends DataSource {
  484. /**
  485. * Data for the nested tree
  486. */
  487. get data() {
  488. return this._data.value;
  489. }
  490. set data(value) {
  491. this._data.next(value);
  492. }
  493. _data = new BehaviorSubject([]);
  494. connect(collectionViewer) {
  495. return merge(...[collectionViewer.viewChange, this._data]).pipe(map(() => this.data));
  496. }
  497. disconnect() {
  498. // no op
  499. }
  500. }
  501. export { MatNestedTreeNode, MatTree, MatTreeFlatDataSource, MatTreeFlattener, MatTreeModule, MatTreeNestedDataSource, MatTreeNode, MatTreeNodeDef, MatTreeNodeOutlet, MatTreeNodePadding, MatTreeNodeToggle };
  502. //# sourceMappingURL=tree.mjs.map