├── .circleci └── config.yml ├── .github ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug-report.md │ ├── documentation-report.md │ ├── feature-request.md │ └── support-request.md └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── THIRD_PARTY_LICENSES ├── angular.json ├── atc-logo.png ├── doc ├── assets │ ├── css │ │ ├── main.css │ │ └── main.css.map │ ├── images │ │ ├── icons.png │ │ ├── icons@2x.png │ │ ├── widgets.png │ │ └── widgets@2x.png │ └── js │ │ ├── main.js │ │ ├── modernizr.js │ │ └── search.js ├── globals.html ├── index.html ├── interfaces │ ├── _api_.iallowdragfn.html │ ├── _api_.iallowdropfn.html │ ├── _api_.inodeheightfn.html │ ├── _api_.itreemodel.html │ ├── _api_.itreenode.html │ ├── _api_.itreenodedrag.html │ ├── _api_.itreeoptions.html │ └── _api_.itreestate.html └── modules │ └── _api_.html ├── e2e ├── async.testcafe.js ├── basic.testcafe.js ├── checkboxes.testcafe.js ├── drag.testcafe.js ├── dragover-styling.testcafe.js ├── empty.testcafe.js ├── fields.testcafe.js ├── filter.testcafe.js ├── helpers │ └── tree.driver.js ├── template.testcafe.js └── tsconfig.json ├── karma.conf.js ├── package-lock.json ├── package.json ├── projects ├── angular-tree-component │ ├── karma.conf.js │ ├── ng-package.json │ ├── package.json │ ├── src │ │ ├── lib │ │ │ ├── angular-tree-component.css │ │ │ ├── angular-tree-component.module.ts │ │ │ ├── components │ │ │ │ ├── loading.component.ts │ │ │ │ ├── tree-node-checkbox.component.ts │ │ │ │ ├── tree-node-children.component.ts │ │ │ │ ├── tree-node-collection.component.ts │ │ │ │ ├── tree-node-content.component.ts │ │ │ │ ├── tree-node-drop-slot.component.ts │ │ │ │ ├── tree-node-expander.component.ts │ │ │ │ ├── tree-node-wrapper.component.ts │ │ │ │ ├── tree-node.component.ts │ │ │ │ ├── tree-viewport.component.ts │ │ │ │ └── tree.component.ts │ │ │ ├── constants │ │ │ │ ├── events.ts │ │ │ │ └── keys.ts │ │ │ ├── defs │ │ │ │ └── api.ts │ │ │ ├── deprecated.ts │ │ │ ├── directives │ │ │ │ ├── tree-animate-open.directive.ts │ │ │ │ ├── tree-drag.directive.ts │ │ │ │ └── tree-drop.directive.ts │ │ │ ├── mobx-angular │ │ │ │ ├── mobx-proxy.ts │ │ │ │ └── tree-mobx-autorun.directive.ts │ │ │ └── models │ │ │ │ ├── tree-dragged-element.model.ts │ │ │ │ ├── tree-node.model.ts │ │ │ │ ├── tree-options.model.ts │ │ │ │ ├── tree-virtual-scroll.model.ts │ │ │ │ └── tree.model.ts │ │ ├── public-api.ts │ │ └── test.ts │ ├── tsconfig.lib.json │ ├── tsconfig.spec.json │ └── tslint.json ├── docs-app │ ├── .browserslistrc │ ├── karma.conf.js │ ├── src │ │ ├── app │ │ │ ├── app-routing.module.ts │ │ │ ├── app.component.html │ │ │ ├── app.component.scss │ │ │ ├── app.component.spec.ts │ │ │ ├── app.component.ts │ │ │ ├── app.module.ts │ │ │ ├── custom-elements │ │ │ │ ├── code │ │ │ │ │ ├── code-example.component.ts │ │ │ │ │ ├── code-example.module.ts │ │ │ │ │ ├── code-tabs.component.ts │ │ │ │ │ ├── code-tabs.module.ts │ │ │ │ │ ├── code.component.ts │ │ │ │ │ ├── code.module.ts │ │ │ │ │ └── pretty-printer.service.ts │ │ │ │ ├── custom-elements.module.ts │ │ │ │ ├── element-registry.ts │ │ │ │ ├── elements-loader.ts │ │ │ │ └── lazy-custom-element.component.ts │ │ │ ├── examples │ │ │ │ ├── basic-usage │ │ │ │ │ ├── basic-tree │ │ │ │ │ │ ├── basic-tree.component.html │ │ │ │ │ │ ├── basic-tree.component.scss │ │ │ │ │ │ ├── basic-tree.component.spec.ts │ │ │ │ │ │ └── basic-tree.component.ts │ │ │ │ │ ├── basic-usage.component.html │ │ │ │ │ ├── basic-usage.component.scss │ │ │ │ │ ├── basic-usage.component.spec.ts │ │ │ │ │ └── basic-usage.component.ts │ │ │ │ ├── columns-example │ │ │ │ │ ├── columns-example.component.html │ │ │ │ │ ├── columns-example.component.scss │ │ │ │ │ ├── columns-example.component.spec.ts │ │ │ │ │ ├── columns-example.component.ts │ │ │ │ │ └── columns │ │ │ │ │ │ ├── columns.component.html │ │ │ │ │ │ ├── columns.component.scss │ │ │ │ │ │ ├── columns.component.spec.ts │ │ │ │ │ │ └── columns.component.ts │ │ │ │ ├── crud-example │ │ │ │ │ ├── crud-example.component.html │ │ │ │ │ ├── crud-example.component.scss │ │ │ │ │ ├── crud-example.component.spec.ts │ │ │ │ │ ├── crud-example.component.ts │ │ │ │ │ └── crud │ │ │ │ │ │ ├── crud.component.html │ │ │ │ │ │ ├── crud.component.scss │ │ │ │ │ │ ├── crud.component.spec.ts │ │ │ │ │ │ └── crud.component.ts │ │ │ │ ├── examples.module.ts │ │ │ │ └── load-more-example │ │ │ │ │ ├── load-more-example.component.html │ │ │ │ │ ├── load-more-example.component.scss │ │ │ │ │ ├── load-more-example.component.spec.ts │ │ │ │ │ ├── load-more-example.component.ts │ │ │ │ │ └── load-more │ │ │ │ │ ├── load-more.component.html │ │ │ │ │ ├── load-more.component.scss │ │ │ │ │ ├── load-more.component.spec.ts │ │ │ │ │ └── load-more.component.ts │ │ │ ├── fundamentals │ │ │ │ ├── actions │ │ │ │ │ ├── actions-demo │ │ │ │ │ │ ├── actions-demo.component.html │ │ │ │ │ │ ├── actions-demo.component.scss │ │ │ │ │ │ ├── actions-demo.component.spec.ts │ │ │ │ │ │ └── actions-demo.component.ts │ │ │ │ │ ├── actions.component.html │ │ │ │ │ ├── actions.component.scss │ │ │ │ │ ├── actions.component.spec.ts │ │ │ │ │ └── actions.component.ts │ │ │ │ ├── api │ │ │ │ │ ├── api-demo │ │ │ │ │ │ ├── api-demo.component.html │ │ │ │ │ │ ├── api-demo.component.scss │ │ │ │ │ │ ├── api-demo.component.spec.ts │ │ │ │ │ │ └── api-demo.component.ts │ │ │ │ │ ├── api.component.html │ │ │ │ │ ├── api.component.scss │ │ │ │ │ ├── api.component.spec.ts │ │ │ │ │ └── api.component.ts │ │ │ │ ├── events │ │ │ │ │ ├── events.component.html │ │ │ │ │ ├── events.component.scss │ │ │ │ │ ├── events.component.spec.ts │ │ │ │ │ └── events.component.ts │ │ │ │ ├── focus │ │ │ │ │ ├── focus.component.html │ │ │ │ │ ├── focus.component.scss │ │ │ │ │ ├── focus.component.spec.ts │ │ │ │ │ └── focus.component.ts │ │ │ │ ├── fundamentals.module.ts │ │ │ │ ├── issues │ │ │ │ │ ├── issues.component.html │ │ │ │ │ ├── issues.component.scss │ │ │ │ │ ├── issues.component.spec.ts │ │ │ │ │ └── issues.component.ts │ │ │ │ ├── nodes │ │ │ │ │ ├── nodes.component.html │ │ │ │ │ ├── nodes.component.scss │ │ │ │ │ ├── nodes.component.spec.ts │ │ │ │ │ └── nodes.component.ts │ │ │ │ ├── options │ │ │ │ │ ├── options.component.html │ │ │ │ │ ├── options.component.scss │ │ │ │ │ ├── options.component.spec.ts │ │ │ │ │ └── options.component.ts │ │ │ │ ├── state-binding │ │ │ │ │ ├── state-binding-demo │ │ │ │ │ │ ├── state-binding-demo.component.html │ │ │ │ │ │ ├── state-binding-demo.component.scss │ │ │ │ │ │ ├── state-binding-demo.component.spec.ts │ │ │ │ │ │ └── state-binding-demo.component.ts │ │ │ │ │ ├── state-binding.component.html │ │ │ │ │ ├── state-binding.component.scss │ │ │ │ │ ├── state-binding.component.spec.ts │ │ │ │ │ └── state-binding.component.ts │ │ │ │ ├── styling │ │ │ │ │ ├── styling.component.html │ │ │ │ │ ├── styling.component.scss │ │ │ │ │ ├── styling.component.spec.ts │ │ │ │ │ └── styling.component.ts │ │ │ │ └── templates │ │ │ │ │ ├── templates-demo │ │ │ │ │ ├── templates-demo.component.html │ │ │ │ │ ├── templates-demo.component.scss │ │ │ │ │ ├── templates-demo.component.spec.ts │ │ │ │ │ └── templates-demo.component.ts │ │ │ │ │ ├── templates.component.html │ │ │ │ │ ├── templates.component.scss │ │ │ │ │ ├── templates.component.spec.ts │ │ │ │ │ └── templates.component.ts │ │ │ ├── getting-started │ │ │ │ ├── getting-started.component.html │ │ │ │ ├── getting-started.component.scss │ │ │ │ ├── getting-started.component.spec.ts │ │ │ │ └── getting-started.component.ts │ │ │ ├── guides │ │ │ │ ├── async-guide │ │ │ │ │ ├── async-guide.component.html │ │ │ │ │ ├── async-guide.component.scss │ │ │ │ │ ├── async-guide.component.spec.ts │ │ │ │ │ ├── async-guide.component.ts │ │ │ │ │ └── async │ │ │ │ │ │ ├── async.component.html │ │ │ │ │ │ ├── async.component.scss │ │ │ │ │ │ ├── async.component.spec.ts │ │ │ │ │ │ └── async.component.ts │ │ │ │ ├── auto-scroll-guide │ │ │ │ │ ├── auto-scroll-guide.component.html │ │ │ │ │ ├── auto-scroll-guide.component.scss │ │ │ │ │ ├── auto-scroll-guide.component.spec.ts │ │ │ │ │ ├── auto-scroll-guide.component.ts │ │ │ │ │ └── auto-scroll │ │ │ │ │ │ ├── auto-scroll.component.html │ │ │ │ │ │ ├── auto-scroll.component.scss │ │ │ │ │ │ ├── auto-scroll.component.spec.ts │ │ │ │ │ │ └── auto-scroll.component.ts │ │ │ │ ├── checkboxes-guide │ │ │ │ │ ├── checkboxes-guide.component.html │ │ │ │ │ ├── checkboxes-guide.component.scss │ │ │ │ │ ├── checkboxes-guide.component.spec.ts │ │ │ │ │ ├── checkboxes-guide.component.ts │ │ │ │ │ └── checkboxes │ │ │ │ │ │ ├── checkboxes.component.html │ │ │ │ │ │ ├── checkboxes.component.scss │ │ │ │ │ │ ├── checkboxes.component.spec.ts │ │ │ │ │ │ └── checkboxes.component.ts │ │ │ │ ├── custom-fields-guide │ │ │ │ │ ├── custom-fields-guide.component.html │ │ │ │ │ ├── custom-fields-guide.component.scss │ │ │ │ │ ├── custom-fields-guide.component.spec.ts │ │ │ │ │ └── custom-fields-guide.component.ts │ │ │ │ ├── drag-drop-guide │ │ │ │ │ ├── drag-drop-guide.component.html │ │ │ │ │ ├── drag-drop-guide.component.scss │ │ │ │ │ ├── drag-drop-guide.component.spec.ts │ │ │ │ │ ├── drag-drop-guide.component.ts │ │ │ │ │ └── drag-drop │ │ │ │ │ │ ├── drag-drop.component.html │ │ │ │ │ │ ├── drag-drop.component.scss │ │ │ │ │ │ ├── drag-drop.component.spec.ts │ │ │ │ │ │ └── drag-drop.component.ts │ │ │ │ ├── expanding-guide │ │ │ │ │ ├── expanding-guide.component.html │ │ │ │ │ ├── expanding-guide.component.scss │ │ │ │ │ ├── expanding-guide.component.spec.ts │ │ │ │ │ └── expanding-guide.component.ts │ │ │ │ ├── filter-guide │ │ │ │ │ ├── filter-guide.component.html │ │ │ │ │ ├── filter-guide.component.scss │ │ │ │ │ ├── filter-guide.component.spec.ts │ │ │ │ │ ├── filter-guide.component.ts │ │ │ │ │ └── filter │ │ │ │ │ │ ├── filter.component.html │ │ │ │ │ │ ├── filter.component.scss │ │ │ │ │ │ ├── filter.component.spec.ts │ │ │ │ │ │ └── filter.component.ts │ │ │ │ ├── guides.module.ts │ │ │ │ ├── large-tree-guide │ │ │ │ │ ├── large-tree-guide.component.html │ │ │ │ │ ├── large-tree-guide.component.scss │ │ │ │ │ ├── large-tree-guide.component.spec.ts │ │ │ │ │ ├── large-tree-guide.component.ts │ │ │ │ │ └── large-tree │ │ │ │ │ │ ├── large-tree.component.html │ │ │ │ │ │ ├── large-tree.component.scss │ │ │ │ │ │ ├── large-tree.component.spec.ts │ │ │ │ │ │ └── large-tree.component.ts │ │ │ │ ├── redux-guide │ │ │ │ │ ├── redux-guide.component.html │ │ │ │ │ ├── redux-guide.component.scss │ │ │ │ │ ├── redux-guide.component.spec.ts │ │ │ │ │ └── redux-guide.component.ts │ │ │ │ ├── rtl-guide │ │ │ │ │ ├── rtl-guide.component.html │ │ │ │ │ ├── rtl-guide.component.scss │ │ │ │ │ ├── rtl-guide.component.spec.ts │ │ │ │ │ ├── rtl-guide.component.ts │ │ │ │ │ └── rtl │ │ │ │ │ │ ├── rtl.component.html │ │ │ │ │ │ ├── rtl.component.scss │ │ │ │ │ │ ├── rtl.component.spec.ts │ │ │ │ │ │ └── rtl.component.ts │ │ │ │ └── update-guide │ │ │ │ │ ├── update-guide.component.html │ │ │ │ │ ├── update-guide.component.scss │ │ │ │ │ ├── update-guide.component.spec.ts │ │ │ │ │ └── update-guide.component.ts │ │ │ ├── layout │ │ │ │ ├── footer │ │ │ │ │ ├── footer.component.html │ │ │ │ │ ├── footer.component.scss │ │ │ │ │ ├── footer.component.spec.ts │ │ │ │ │ └── footer.component.ts │ │ │ │ ├── layout.module.ts │ │ │ │ └── nav-item │ │ │ │ │ ├── nav-item.component.html │ │ │ │ │ ├── nav-item.component.scss │ │ │ │ │ ├── nav-item.component.spec.ts │ │ │ │ │ └── nav-item.component.ts │ │ │ ├── navigation │ │ │ │ ├── navigation.model.ts │ │ │ │ ├── navigation.service.spec.ts │ │ │ │ └── navigation.service.ts │ │ │ └── shared │ │ │ │ ├── copier.service.ts │ │ │ │ ├── logger.service.ts │ │ │ │ └── shared.module.ts │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ ├── github-icon.svg │ │ │ ├── js │ │ │ │ └── prettify.js │ │ │ ├── styling │ │ │ │ ├── 0bd50e1-treecss.png │ │ │ │ ├── 28d7625-Screen_Shot_2016-11-29_at_12.11.01_PM.png │ │ │ │ └── f50955b-Screen_Shot_2016-11-29_at_12.11.52_PM.png │ │ │ └── tree-logo.svg │ │ ├── environments │ │ │ ├── environment.prod.ts │ │ │ └── environment.ts │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── index.html │ │ ├── main.ts │ │ ├── polyfills.ts │ │ ├── styles.scss │ │ ├── styles │ │ │ ├── _alert.scss │ │ │ ├── _code.scss │ │ │ ├── _constants.scss │ │ │ ├── _images.scss │ │ │ ├── _mixins.scss │ │ │ ├── _scrollbar.scss │ │ │ ├── _typography.scss │ │ │ └── angular-tree-component.css │ │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json └── example-app │ ├── .browserslistrc │ ├── .gitignore │ ├── angular.json │ ├── karma.conf.js │ ├── src │ ├── angular-tree-component.css │ ├── app │ │ ├── actions │ │ │ ├── actions.component.css │ │ │ ├── actions.component.html │ │ │ ├── actions.component.spec.ts │ │ │ └── actions.component.ts │ │ ├── api │ │ │ ├── api.component.css │ │ │ ├── api.component.html │ │ │ ├── api.component.spec.ts │ │ │ └── api.component.ts │ │ ├── app-routing.module.ts │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── async │ │ │ └── async.component.ts │ │ ├── basictree │ │ │ └── basictree.component.ts │ │ ├── checkboxes │ │ │ └── checkboxes.component.ts │ │ ├── contextmenu │ │ │ ├── contextmenu.component.html │ │ │ ├── contextmenu.component.spec.ts │ │ │ └── contextmenu.component.ts │ │ ├── drag │ │ │ └── drag.component.ts │ │ ├── dragover-styling │ │ │ ├── dragover-styling-full-tree.component.ts │ │ │ └── dragover-styling.component.ts │ │ ├── empty │ │ │ └── empty.component.ts │ │ ├── fields │ │ │ └── fields.component.ts │ │ ├── filter │ │ │ └── filter.component.ts │ │ ├── fulltree │ │ │ └── fulltree.component.ts │ │ ├── rtl │ │ │ └── rtl-tree.component.ts │ │ ├── save-restore │ │ │ └── save-restore.component.ts │ │ ├── scrollcontainer │ │ │ └── scrollcontainer.component.ts │ │ ├── templates │ │ │ └── templates.component.ts │ │ └── virtualscroll │ │ │ ├── virtualscroll.component.css │ │ │ ├── virtualscroll.component.html │ │ │ ├── virtualscroll.component.spec.ts │ │ │ └── virtualscroll.component.ts │ ├── assets │ │ └── .gitkeep │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.build.html │ ├── index.dev.html │ ├── index.html │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ └── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.es5.app.json │ ├── tsconfig.spec.json │ └── tslint.json ├── protractor.conf.js ├── rollup.config.js ├── tsconfig.json ├── tslint.json └── typedoc.json /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Javascript Node CircleCI 2.0 configuration file 2 | # 3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details 4 | # 5 | version: 2 6 | jobs: 7 | build: 8 | docker: 9 | # specify the version you desire here 10 | - image: circleci/node:8.9-browsers 11 | 12 | # Specify service dependencies here if necessary 13 | # CircleCI maintains a library of pre-built images 14 | # documented at https://circleci.com/docs/2.0/circleci-images/ 15 | # - image: circleci/mongo:3.4.4 16 | 17 | working_directory: ~/repo 18 | 19 | steps: 20 | - checkout 21 | 22 | # Download and cache dependencies 23 | - restore_cache: 24 | keys: 25 | - v1-dependencies-{{ checksum "package.json" }} 26 | # fallback to using the latest cache if no exact match is found 27 | - v1-dependencies- 28 | 29 | - run: npm install 30 | - run: npm run test:setup 31 | 32 | - save_cache: 33 | paths: 34 | - node_modules 35 | key: v1-dependencies-{{ checksum "package.json" }} 36 | 37 | # run tests! 38 | # - run: npm run test 39 | - run: npm run test:ci:local 40 | 41 | - store_test_results: 42 | path: /tmp/test-results 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## I'm submitting a... 2 | 3 | 4 |
5 | [ ] Regression (a behavior that used to work and stopped working in a new release)
6 | [ ] Bug report
7 | [ ] Feature request
8 | [ ] Documentation issue or request
9 |
10 |
11 | ## What is the current behavior?
12 |
13 |
14 |
15 | ## Expected behavior:
16 |
17 |
18 |
19 | ## Minimal reproduction of the problem with instructions:
20 |
21 |
25 |
26 | ## Version of affected browser(s),operating system(s), npm, node and angular-tree-component:
27 |
28 | ## Other information:
29 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: Report a bug or regression in functionality
4 | ---
5 |
6 |
7 |
8 | ## Minimal reproduction of the bug/regression with instructions:
9 |
10 |
11 |
12 |
13 |
14 | ## Expected behavior:
15 |
16 |
17 |
18 | ## Versions of Angular Tree Component, Angular, Node, affected browser(s) and operating system(s):
19 |
20 | ## Other information:
21 |
22 | ## I would be willing to submit a PR to fix this issue
23 |
24 | [ ] Yes (Assistance will be provided if you need help to submit a pull request)
25 | [ ] No
26 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Documentation Report
3 | about: Report missing or inaccurate documentation
4 | ---
5 |
6 |
7 |
8 | ## Other information:
9 |
10 | ## I would be willing to submit a PR for the docs :heart:
11 |
12 | [ ] Yes (Assistance will be provided if you need help to submit a pull request)
13 | [ ] No
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Submit a Request For Consideration
4 | ---
5 |
6 |
7 |
8 | ## Describe any alternatives/workarounds you're currently using
9 |
10 | ## Other information:
11 |
12 | ## If accepted, I would be willing to submit a PR for this feature
13 |
14 | [ ] Yes (Assistance will be provided if you need help to submit a pull request)
15 | [ ] No
16 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/support-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Support Request
3 | about: I need general help
4 | ---
5 |
6 | ## Support Requests should not be opened as issues and should be handled in the following ways:
7 |
8 | ### On [StackOverflow](https://stackoverflow.com/questions/tagged/angular-tree-component) using the `angular-tree-component` tag
9 |
10 | ### In our slack support channel at https://angular-tree-component.herokuapp.com/
11 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## PR Checklist
2 | Please check if your PR fulfills the following requirements:
3 |
4 | - [ ] The commit message follows our guidelines: https://github.com/CirclonGroup/angular-tree-component/blob/master/CONTRIBUTING.md#commit-message-guidelines
5 | - [ ] Tests for the changes have been added (for bug fixes / features)
6 |
7 | ## PR Type
8 | What kind of change does this PR introduce?
9 |
10 |
11 |
12 | ```
13 | [ ] Bugfix
14 | [ ] Feature
15 | [ ] Code style update (formatting, local variables)
16 | [ ] Refactoring (no functional changes, no api changes)
17 | [ ] Build related changes
18 | [ ] CI related changes
19 | [ ] Documentation content changes
20 | [ ] Other... Please describe:
21 | ```
22 |
23 | ## What is the current behavior?
24 |
25 |
26 | Closes #
27 |
28 | ## What is the new behavior?
29 |
30 | ## Does this PR introduce a breaking change?
31 |
32 | ```
33 | [ ] Yes
34 | [ ] No
35 | ```
36 |
37 |
38 |
39 | ## Other information
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 |
5 | # Runtime data
6 | pids
7 | *.pid
8 | *.seed
9 |
10 | # Directory for instrumented libs generated by jscoverage/JSCover
11 | lib-cov
12 |
13 | # Coverage directory used by tools like istanbul
14 | coverage
15 |
16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
17 | .grunt
18 |
19 | # Compiled binary addons (http://nodejs.org/api/addons.html)
20 | build/Release
21 |
22 | # Users Environment Variables
23 | .lock-wscript
24 |
25 | # OS generated files #
26 | .DS_Store
27 | ehthumbs.db
28 | Icon?
29 | Thumbs.db
30 |
31 | # Node Files #
32 | /node_modules
33 | /bower_components
34 | /projects/**/node_modules
35 | npm-debug.log
36 |
37 | # Coverage #
38 | /coverage/
39 | /xunit/
40 |
41 | # Typing #
42 | /src/typings/tsd/
43 | /typings/
44 | /tsd_typings/
45 |
46 | # Dist #
47 | /public/__build__/
48 | /src/*/__build__/
49 | /__build__/**
50 | /public/dist/
51 | /src/*/dist/
52 | .webpack.json
53 | /projects/**/package-lock.json
54 |
55 | # Doc #
56 |
57 | # IDE #
58 | .vscode/*
59 | .idea/
60 | *.swp
61 |
62 | /dist
63 |
64 | compiled
65 |
66 | testScreenshots
67 | testResults
68 | e2eResults
69 |
70 | e2e/dist
71 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | dist
2 | doc
3 | typings
4 | node_modules
5 | example
6 | *webpack*conf*.js
7 | *karma*.js
8 | *.ts
9 | !*.d.ts
10 | testScreenshots
11 | testResults
12 | e2eResults
13 | e2e
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | dist: trusty
2 | sudo: required
3 |
4 | addons:
5 | firefox: latest
6 | apt:
7 | sources:
8 | - google-chrome
9 | packages:
10 | - google-chrome-stable fluxbox
11 |
12 | language: node_js
13 | node_js:
14 | - "8.9.0"
15 |
16 | before_install:
17 | - "export DISPLAY=:99.0"
18 | - "sh -e /etc/init.d/xvfb start"
19 | - sleep 3
20 | - fluxbox >/dev/null 2>&1 &
21 |
22 | before_script:
23 | - npm run test:setup
24 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020 Circlon Group
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/THIRD_PARTY_LICENSES:
--------------------------------------------------------------------------------
1 | * https://github.com/ayamflow/virtual-scroll/
2 | // The MIT License (MIT)
3 |
4 | // Copyright (c) 2014 Florian Morel
5 |
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 |
13 | // The above copyright notice and this permission notice shall be included in all
14 | // copies or substantial portions of the Software.
15 |
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | // SOFTWARE.
23 |
--------------------------------------------------------------------------------
/atc-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CirclonGroup/angular-tree-component/19b58abe33dcbddbcba80c80ed26babfb7d43a16/atc-logo.png
--------------------------------------------------------------------------------
/doc/assets/images/icons.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CirclonGroup/angular-tree-component/19b58abe33dcbddbcba80c80ed26babfb7d43a16/doc/assets/images/icons.png
--------------------------------------------------------------------------------
/doc/assets/images/icons@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CirclonGroup/angular-tree-component/19b58abe33dcbddbcba80c80ed26babfb7d43a16/doc/assets/images/icons@2x.png
--------------------------------------------------------------------------------
/doc/assets/images/widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CirclonGroup/angular-tree-component/19b58abe33dcbddbcba80c80ed26babfb7d43a16/doc/assets/images/widgets.png
--------------------------------------------------------------------------------
/doc/assets/images/widgets@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/CirclonGroup/angular-tree-component/19b58abe33dcbddbcba80c80ed26babfb7d43a16/doc/assets/images/widgets@2x.png
--------------------------------------------------------------------------------
/e2e/async.testcafe.js:
--------------------------------------------------------------------------------
1 | import { Selector } from 'testcafe';
2 | import { TreeDriver } from './helpers/tree.driver';
3 |
4 | fixture `Async`
5 | .page `http://localhost:4200/#/async`
6 | .beforeEach( async t => {
7 | t.ctx.tree = new TreeDriver('tree-root');
8 | t.ctx.root2 = t.ctx.tree.getNode('root2');
9 | });
10 |
11 | test('should show the tree', async t => {
12 | await t.expect(t.ctx.tree.isPresent()).ok();
13 | });
14 |
15 | test('should have 3 nodes', async t => {
16 | await t.expect(t.ctx.tree.getNodes().count).eql(3);
17 | });
18 |
19 | test('should not show loading before expanding', async t => {
20 | await t.expect(t.ctx.root2.getLoading().exists).notOk();
21 | });
22 |
23 | // TODO: find out why fails on saucelabs
24 | test.skip('should show loading', async t => {
25 | await t.ctx.root2.clickExpander(t)
26 | .expect(t.ctx.root2.getLoading().exists).ok();
27 | });
28 |
29 | test('should show children and then loading disappears', async t => {
30 | await t.ctx.root2.clickExpander(t)
31 | .expect(t.ctx.root2.getNode('child1').isPresent()).ok()
32 | .expect(t.ctx.root2.getLoading().exists).notOk();
33 | });
34 |
35 | test('should show not show loading the second time we expand the node', async t => {
36 | await t.ctx.root2.clickExpander(t)
37 | .expect(t.ctx.root2.getNode('child1').isPresent()).ok();
38 |
39 | await t.ctx.root2.clickExpander(t);
40 | await t.ctx.root2.clickExpander(t)
41 | .expect(t.ctx.root2.getLoading().exists).notOk();
42 | });
43 |
--------------------------------------------------------------------------------
/e2e/drag.testcafe.js:
--------------------------------------------------------------------------------
1 | const { TreeDriver } = require('./helpers/tree.driver');
2 |
3 | fixture `Drag and Drop`
4 | .page `http://localhost:4200/#/drag`
5 | .beforeEach( async t => {
6 | t.ctx.tree = new TreeDriver('tree-root');
7 | t.ctx.root1 = t.ctx.tree.getNode('root1');
8 | t.ctx.child1 = t.ctx.root1.getNode('child1');
9 | t.ctx.root2 = t.ctx.tree.getNode('root2');
10 | t.ctx.child21 = t.ctx.root2.getNode('child2.1');
11 | });
12 |
13 | test('should show the tree', async t => {
14 | await t.expect(t.ctx.tree.isPresent()).ok();
15 | });
16 |
17 | test('should have expected children', async t => {
18 | await t.expect(t.ctx.root1.getNodes().count).eql(2)
19 | .expect(t.ctx.root2.getNodes().count).eql(2)
20 | .expect(t.ctx.child21.getNodes().count).eql(0);
21 | });
22 |
23 | test('should allow to drag leaf', async t => {
24 | await t.ctx.child1.dragToNode(t, t.ctx.child21);
25 | await t.ctx.child21.clickExpander(t)
26 | .expect(t.ctx.root1.getNodes().count).eql(1)
27 | .expect(t.ctx.child21.getNodes().count).eql(1);
28 | });
29 |
30 | // TODO: find out why fails on saucelabs
31 | test.skip('should allow to drag to drop slot', async t => {
32 | await t.ctx.child1.dragToDropSlot(t, t.ctx.child21)
33 | .expect(t.ctx.root1.getNodes().count).eql(1)
34 | .expect(t.ctx.root2.getNodes().count).eql(3);
35 | });
36 |
--------------------------------------------------------------------------------
/e2e/dragover-styling.testcafe.js:
--------------------------------------------------------------------------------
1 | const { TreeDriver } = require('./helpers/tree.driver');
2 |
3 | fixture `Drag and Drop Styling`
4 | .page `http://localhost:4200/#/dragover-styling`
5 | .beforeEach( async t => {
6 | t.ctx.tree = new TreeDriver('tree-root');
7 | t.ctx.root1 = t.ctx.tree.getNode('root1');
8 | t.ctx.child1 = t.ctx.root1.getNode('child1');
9 | t.ctx.root2 = t.ctx.tree.getNode('root2');
10 | t.ctx.child21 = t.ctx.root2.getNode('child2.1');
11 | });
12 |
13 | test('should show the tree', async t => {
14 | await t.expect(t.ctx.tree.isPresent()).ok();
15 | });
16 |
17 | test('should have expected children', async t => {
18 | await t.expect(t.ctx.root1.getNodes().count).eql(2)
19 | .expect(t.ctx.root2.getNodes().count).eql(2)
20 | .expect(t.ctx.child21.getNodes().count).eql(0);
21 | });
22 |
23 | test('should allow to drag leaf', async t => {
24 | await t.ctx.child1.dragToNode(t, t.ctx.child21);
25 | await t.ctx.child21.clickExpander(t)
26 | .expect(t.ctx.root1.getNodes().count).eql(1)
27 | .expect(t.ctx.child21.getNodes().count).eql(1);
28 | });
29 |
30 | // TODO: find out why fails on saucelabs
31 | test.skip('should allow to drag to drop slot', async t => {
32 | await t.ctx.child1.dragToDropSlot(t, t.ctx.child21)
33 | .expect(t.ctx.root1.getNodes().count).eql(1)
34 | .expect(t.ctx.root2.getNodes().count).eql(3);
35 | });
36 |
--------------------------------------------------------------------------------
/e2e/empty.testcafe.js:
--------------------------------------------------------------------------------
1 | import { Selector } from 'testcafe';
2 | import { TreeDriver } from './helpers/tree.driver';
3 |
4 | const testEmptyTree = (treeId) => {
5 | fixture `Empty`
6 | .page `http://localhost:4200/#/empty`
7 | .beforeEach( async t => {
8 | t.ctx.tree = new TreeDriver(treeId);
9 | });
10 |
11 | test('should show the tree', async t => {
12 | await t.expect(t.ctx.tree.isPresent()).ok();
13 | });
14 |
15 | test('should have 0 nodes', async t => {
16 | await t.expect(t.ctx.tree.getNodes().count).eql(0);
17 | });
18 |
19 | test('should load nodes into the tree', async t => {
20 | await t.click(Selector('button'));
21 | await t.expect(t.ctx.tree.getNodes().count).eql(1);
22 | });
23 | };
24 |
25 | testEmptyTree('#tree1');
26 | testEmptyTree('#tree2');
27 |
--------------------------------------------------------------------------------
/e2e/fields.testcafe.js:
--------------------------------------------------------------------------------
1 | import { Selector } from 'testcafe';
2 | import { TreeDriver } from './helpers/tree.driver';
3 |
4 | fixture `Fields`
5 | .page `http://localhost:4200/#/fields`
6 | .beforeEach( async t => {
7 | t.ctx.tree = new TreeDriver('#tree1');
8 | });
9 |
10 |
11 | test('should show the tree', async t => {
12 | await t.expect(t.ctx.tree.isPresent()).ok();
13 | });
14 |
15 | test('should have 2 nodes', async t => {
16 | await t.expect(t.ctx.tree.getNodes().count).eql(2);
17 | });
18 |
19 | test('should display the custom display field', async t => {
20 | const root1 = t.ctx.tree.getNode('root1');
21 |
22 | await t.expect(root1.isPresent()).ok();
23 | });
24 |
25 | test('should use the nodeClass option', async t => {
26 | const root1Title = t.ctx.tree.selector.find('.root1Class').withText('root1');
27 |
28 | await t.expect(root1Title.exists).ok();
29 | });
30 |
--------------------------------------------------------------------------------
/e2e/template.testcafe.js:
--------------------------------------------------------------------------------
1 | import { Selector } from 'testcafe';
2 | import { TreeDriver } from './helpers/tree.driver';
3 |
4 | ['#tree1', '#tree2', '#tree3'].forEach((treeId) => {
5 | fixture `Templates ${treeId}`
6 | .page `http://localhost:4200/#/templates`
7 | .beforeEach( async t => {
8 | t.ctx.tree = new TreeDriver('#tree1');
9 | t.ctx.tree = new TreeDriver(treeId);
10 | });
11 |
12 | test('should show the tree', async t => {
13 | await t.expect(t.ctx.tree.isPresent()).ok();
14 | });
15 |
16 | test('should have 2 nodes', async t => {
17 | await t.expect(t.ctx.tree.getNodes().count).eql(2);
18 | });
19 |
20 | test('should use the template and pass it a node var', async t => {
21 | const root1Title = t.ctx.tree.selector.find('.root1Class').withText('root1');
22 |
23 | await t.expect(root1Title.exists).ok();
24 | });
25 |
26 | test('should use the template and pass it an index var', async t => {
27 | const root1Index = t.ctx.tree.selector.find('.root1ClassIndex').withText('0');
28 |
29 | await t.expect(root1Index.exists).ok();
30 | });
31 | });
32 | fixture `Templates loading component`
33 | .page `http://localhost:4200/#/templates`
34 | .beforeEach(async t => {
35 | t.ctx.tree = new TreeDriver('#tree1');
36 | t.ctx.root2 = t.ctx.tree.getNodeByIndex(1);
37 | });
38 |
39 | test('should show the loading template', async t => {
40 | await t.ctx.root2.clickExpander(t);
41 | const loadingComponent = t.ctx.tree.selector.find('.root2ClassLoading').withText('Loading root2...');
42 |
43 | await t.expect(loadingComponent.exists).ok();
44 | });
45 |
--------------------------------------------------------------------------------
/e2e/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es6",
4 | "moduleResolution": "node",
5 | "sourceMap": false,
6 | "declaration": false,
7 | "noImplicitAny": false,
8 | "outDir": "dist",
9 | "noEmitOnError": true
10 | },
11 | "include": [
12 | "**/*.ts"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | const { join } = require('path');
5 | const { constants } = require('karma');
6 |
7 | module.exports = () => {
8 | return {
9 | basePath: '',
10 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
11 | plugins: [
12 | require('karma-jasmine'),
13 | require('karma-chrome-launcher'),
14 | require('karma-jasmine-html-reporter'),
15 | require('karma-coverage-istanbul-reporter'),
16 | require('@angular-devkit/build-angular/plugins/karma'),
17 | require('@angular-devkit/build-angular/plugins/karma'),
18 | ],
19 | client: {
20 | clearContext: false, // leave Jasmine Spec Runner output visible in browser
21 | jasmine: {
22 | random: true
23 | }
24 | },
25 | coverageIstanbulReporter: {
26 | dir: join(__dirname, 'coverage'),
27 | reports: ['text-summary', 'html', 'lcovonly'],
28 | fixWebpackSourcePaths: true,
29 | thresholds: {
30 | emitWarning: false, // <- this is important to make karma fail
31 | global: {
32 | statements: 0,
33 | lines: 0,
34 | branches: 0,
35 | functions: 0
36 | }
37 | }
38 | },
39 | angularCli: {
40 | environment: 'dev'
41 | },
42 | reporters: ['progress', 'kjhtml', 'coverage-istanbul'],
43 | port: 9876,
44 | browserNoActivityTimeout: 1000000,
45 | colors: true,
46 | logLevel: constants.LOG_INFO,
47 | autoWatch: true,
48 | browsers: ['Chrome'],
49 | singleRun: false
50 | };
51 | };
52 |
--------------------------------------------------------------------------------
/projects/angular-tree-component/karma.conf.js:
--------------------------------------------------------------------------------
1 | // Karma configuration file, see link for more information
2 | // https://karma-runner.github.io/1.0/config/configuration-file.html
3 |
4 | module.exports = function (config) {
5 | config.set({
6 | basePath: '',
7 | frameworks: ['jasmine', '@angular-devkit/build-angular'],
8 | plugins: [
9 | require('karma-jasmine'),
10 | require('karma-chrome-launcher'),
11 | require('karma-jasmine-html-reporter'),
12 | require('karma-coverage-istanbul-reporter'),
13 | require('@angular-devkit/build-angular/plugins/karma')
14 | ],
15 | client: {
16 | clearContext: false // leave Jasmine Spec Runner output visible in browser
17 | },
18 | coverageIstanbulReporter: {
19 | dir: require('path').join(__dirname, '../../coverage/angular-tree-component'),
20 | reports: ['html', 'lcovonly', 'text-summary'],
21 | fixWebpackSourcePaths: true
22 | },
23 | reporters: ['progress', 'kjhtml'],
24 | port: 9876,
25 | colors: true,
26 | logLevel: config.LOG_INFO,
27 | autoWatch: true,
28 | browsers: ['Chrome'],
29 | singleRun: false,
30 | restartOnFileChange: true
31 | });
32 | };
33 |
--------------------------------------------------------------------------------
/projects/angular-tree-component/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/angular-tree-component",
4 | "assets": ["src/lib/angular-tree-component.css"],
5 | "lib": {
6 | "entryFile": "src/public-api.ts",
7 | "umdModuleIds": {
8 | "mobx": "mobx",
9 | "lodash-es": "lodash-es"
10 | }
11 | },
12 | "whitelistedNonPeerDependencies": ["core-js", "lodash-es", "mobx"]
13 | }
14 |
--------------------------------------------------------------------------------
/projects/angular-tree-component/src/lib/components/loading.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Input, TemplateRef, ViewEncapsulation } from '@angular/core';
2 | import { TreeNode } from '../models/tree-node.model';
3 |
4 | @Component({
5 | encapsulation: ViewEncapsulation.None,
6 | selector: 'tree-loading-component',
7 | template: `
8 | loading...
9 |