From 05d661f14e3c97d27387221fd449f224bf755c51 Mon Sep 17 00:00:00 2001 From: Gregg Rapoza Date: Wed, 13 Mar 2019 10:50:44 -0400 Subject: [PATCH] Adds node deletion Closes #16 --- docs/index.md | 8 +++- package.json | 2 +- src/components/TreeView.vue | 13 ++++- src/components/TreeViewNode.vue | 69 +++++++++++++++++++++----- tests/data/node-generator.js | 5 +- tests/local/basic.html | 46 ++++++++++++++++++ tests/local/basic.js | 85 +++++++++++++++++++++++++++++++++ tests/local/demo.css | 15 ++++++ tests/local/radioBasic.html | 48 +++++++++++++++++++ tests/local/radioBasic.js | 64 +++++++++++++++++++++++++ tests/unit/TreeViewNode.spec.js | 47 +++++++++++++++++- yarn.lock | 5 -- 12 files changed, 384 insertions(+), 23 deletions(-) create mode 100644 tests/local/basic.html create mode 100644 tests/local/basic.js create mode 100644 tests/local/demo.css create mode 100644 tests/local/radioBasic.html create mode 100644 tests/local/radioBasic.js diff --git a/docs/index.md b/docs/index.md index 74d275ea..6da1cf05 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,7 +18,7 @@ Planned: - Node selection ([#5](https://github.com/grapoza/vue-tree/issues/5)) - Async loading ([#13](https://github.com/grapoza/vue-tree/issues/13)) -- Adding/deleting nodes ([#24](https://github.com/grapoza/vue-tree/issues/24), [#16](https://github.com/grapoza/vue-tree/issues/16)) +- Adding nodes ([#24](https://github.com/grapoza/vue-tree/issues/24)) - Icons ([#22](https://github.com/grapoza/vue-tree/issues/22)) - Searching ([#4](https://github.com/grapoza/vue-tree/issues/4)) - Drag n' Drop ([#6](https://github.com/grapoza/vue-tree/issues/6)) @@ -153,6 +153,7 @@ The properties below can be specified for each node. | label | String | The text to show in the treeview | - | Yes | | expandable | Boolean | True to show a toggle for expanding nodes' subnode lists | `true` | | | selectable | Boolean | True to allow the node to be selected* | `false` | | +| deletable | Boolean | True to allow the node to be deleted | `false` | | | input | Object | Contains data specific to the node's `input` element | `null` | | | input.type | String | The type of input; valid values are `checkbox` or `radio` | - | Yes** | | input.name | String | The name attribute of the input; used with `radio` type | `'unspecifiedRadioName'` | | @@ -207,6 +208,7 @@ If specified, the `modelDefaults` property of the treeview will be merged with n |:----------------------------|:--------------------------------------------------------|:-----------------------------------------------------------------------| | treeViewNodeClick | Emitted when a node is clicked | `target` The model of the target node
`event` The original event | | treeViewNodeDblclick | Emitted when a node is double clicked | `target` The model of the target node
`event` The original event | +| treeViewNodeDelete | Emitted when a node is deleted | `target` The model of the target node
`event` The original event | | treeViewNodeCheckboxChange | Emitted when a node's checkbox emits a change event | `target` The model of the target node
`event` The original event | | treeViewNodeRadioChange | Emitted when a node's radio button emits a change event | `target` The model of the target node
`event` The original event | | treeViewNodeExpandedChange | Emitted when a node is expanded or collapsed | `target` The model of the target node
`event` The original event | @@ -229,6 +231,8 @@ The display of the treeview can be customized via CSS using the following classe | `tree-view-node-self-checkbox` | The checkbox | | `tree-view-node-self-radio` | The radio button | | `tree-view-node-self-text` | The text for a non-input node | +| `tree-view-node-self-delete` | The delete button | +| `tree-view-node-self-delete-icon` | The `` element containing the delete icon | | `tree-view-node-children` | The list of child nodes | ## Customizing TreeViewNode Markup @@ -251,4 +255,6 @@ A customizations object may have the following properties: | classes.treeViewNodeSelfCheckbox | String | Classes to add to the checkbox | Add | | classes.treeViewNodeSelfRadio | String | Classes to add to the radio button | Add | | classes.treeViewNodeSelfText | String | Classes to add to the text for a non-input node | Add | +| classes.treeViewNodeSelfDelete | String | Classes to add to the delete button | Add | +| classes.treeViewNodeSelfDeleteIcon | String | Classes to add to the `` element containing the delete icon | Add | | classes.treeViewNodeChildren | String | Classes to add to the list of child nodes | Add | diff --git a/package.json b/package.json index 66cc31f8..417ba80e 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "description": "Yet another Vue treeview component.", "author": "Gregg Rapoza ", "license": "MIT", - "version": "0.5.0", + "version": "0.6.0", "browser": "index.js", "repository": { "url": "https://github.com/grapoza/vue-tree", diff --git a/src/components/TreeView.vue b/src/components/TreeView.vue index f0c0dd56..a8d515dc 100644 --- a/src/components/TreeView.vue +++ b/src/components/TreeView.vue @@ -12,7 +12,8 @@ @treeViewNodeDblclick="(t, e)=>$emit('treeViewNodeDblclick', t, e)" @treeViewNodeCheckboxChange="(t, e)=>$emit('treeViewNodeCheckboxChange', t, e)" @treeViewNodeRadioChange="(t, e)=>$emit('treeViewNodeRadioChange', t, e)" - @treeViewNodeExpandedChange="(t, e)=>$emit('treeViewNodeExpandedChange', t, e)"> + @treeViewNodeExpandedChange="(t, e)=>$emit('treeViewNodeExpandedChange', t, e)" + @treeViewNodeDelete="(t, e)=>$_treeViewNode_handleChildDeletion(t, e)"> @@ -84,6 +85,16 @@ } return checked; + }, + $_treeViewNode_handleChildDeletion(node, event) { + // Remove the node from the array of children if this is an immediate child. + // Note that only the node that was deleted fires these, not any subnode. + let targetIndex = this.model.indexOf(node); + if (targetIndex > -1) { + this.model.splice(targetIndex, 1); + } + + this.$emit('treeViewNodeDelete', node, event); } } }; diff --git a/src/components/TreeViewNode.vue b/src/components/TreeViewNode.vue index 0c9f158f..33300b09 100644 --- a/src/components/TreeViewNode.vue +++ b/src/components/TreeViewNode.vue @@ -61,6 +61,17 @@ :class="customClasses.treeViewNodeSelfText"> {{ model.label }} + + + @@ -81,7 +92,8 @@ @treeViewNodeDblclick="(t, e)=>$emit('treeViewNodeDblclick', t, e)" @treeViewNodeCheckboxChange="(t, e)=>$emit('treeViewNodeCheckboxChange', t, e)" @treeViewNodeRadioChange="(t, e)=>$emit('treeViewNodeRadioChange', t, e)" - @treeViewNodeExpandedChange="(t, e)=>$emit('treeViewNodeExpandedChange', t, e)"> + @treeViewNodeExpandedChange="(t, e)=>$emit('treeViewNodeExpandedChange', t, e)" + @treeViewNodeDelete="(t, e)=>$_treeViewNode_handleChildDeletion(t, e)"> @@ -171,14 +183,15 @@ if (!Array.isArray(this.model.children)) { this.$set(this.model, 'children', []); } - - // Set basic node options if (typeof this.model.expandable !== 'boolean') { this.$set(this.model, 'expandable', true); } if (typeof this.model.selectable !== 'boolean') { this.$set(this.model, 'selectable', false); } + if (typeof this.model.deletable !== 'boolean') { + this.$set(this.model, 'deletable', false); + } this.$_treeViewNode_normalizeNodeInputData(); this.$_treeViewNode_normalizeNodeStateData(); @@ -258,22 +271,38 @@ this.$emit('treeViewNodeExpandedChange', this.model, event); }, $_treeViewNode_onClick(event) { - // Don't fire this if the target is the input or expander, which have their own events - if (!event.target.matches("input, .tree-view-node-self-expander")) { + // Don't fire this if the target is an element which has its own events + if (!event.target.matches("input, .tree-view-node-self-expander, .tree-view-node-self-delete")) { this.$emit('treeViewNodeClick', this.model, event); } }, $_treeViewNode_onDblclick(event) { - // Don't fire this if the target is the input or expander, which have their own events - if (!event.target.matches("input, .tree-view-node-self-expander")) { + // Don't fire this if the target is an element which has its own events + if (!event.target.matches("input, .tree-view-node-self-expander, .tree-view-node-self-delete")) { this.$emit('treeViewNodeDblclick', this.model, event); } + }, + $_treeViewNode_onDelete(event) { + this.$emit('treeViewNodeDelete', this.model, event); + }, + $_treeViewNode_handleChildDeletion(node, event) { + // Remove the node from the array of children if this is an immediate child. + // Note that only the node that was deleted fires these, not any subnode. + let targetIndex = this.model.children.indexOf(node); + if (targetIndex > -1) { + this.model.children.splice(targetIndex, 1); + } + + this.$emit('treeViewNodeDelete', node, event); } }, };