npm package: @jambonn/vue-nested-draggable
Description: Vue draggable tree view component
Author: Jambon
Latest version: 0.1.1

# vue-nested-draggable
> This is a nested draggable component. This component does not have css, you need to add your style refer to demo. The demo style is less, not difficult.
> This component doesn't render node. It exposes a node rendering slot. Please refer to the demo for rendering.

**[Full examples](https://jambonn.github.io/vue-nested-draggable/)**

# Touch
Support touch(single point).

## Indexes
- [Installation](#installation)
- [Usage](#usage)
    * [Global](#global)
    * [Local](#local)
    * [Data](#data)
    * [Template](#template)
- [Configuration](#configuration)
    * [Props](#props)
    * [Hooks](#hooks)
    * [Tree properties](#properties)
    * [draggableHelperInfo: {event, options, store}](#draggable_helper_info)
    * [Events](#events)
    * [Methods](#methods)
    * [node properties](#node_properties)
    * [node deep properties example](#node_deep_properties_example)
- [Other](#other)
    * [Demo css](#demo_css)
- [Development](#compiles-and-hot-reloads-for-development)
- [License](#license)

## Installation

``` bash
npm install @jambonn/vue-nested-draggable
```

or if you prefer yarn

``` bash
yarn add @jambonn/vue-nested-draggable
```

## Usage

### Global

You may install Vue Nested Draggable globally:

``` js
import Vue from 'vue';
import VueNestedDraggable from '@jambonn/vue-nested-draggable';

Vue.component('draggable-tree', VueNestedDraggable.DraggableTree);
```
This will make **&lt;draggable-tree&gt;** available to all components within your Vue app.

### Local

Include the carousel directly into your component using import:

``` js
import { DraggableTree } from '@jambonn/vue-nested-draggable';

export default {
  ...
  components: {
    DraggableTree
  }
  ...
};
```

### Data
```js
data: [
  {text: 'node 1'},
  {text: 'node 2'},
  {text: 'node 3 undraggable', draggable: false},
  {text: 'node 4'},
  {text: 'node 4 undroppable', droppable: false},
  {text: 'node 5', children: [
    {text: 'node 1'},
    {text: 'node 2', children: [
      {text: 'node 3'},
      {text: 'node 4'},
    ]},
    {text: 'node 2 undroppable', droppable: false, children: [
      {text: 'node 3'},
      {text: 'node 4'},
    ]},
    {text: 'node 2', children: [
      {text: 'node 3'},
      {text: 'node 4 undroppable', droppable: false},
    ]},
    {text: 'node 3'},
    {text: 'node 4'},
    {text: 'node 3'},
    {text: 'node 4'},
    {text: 'node 3'},
    {text: 'node 4'},
    {text: 'node 3'},
    {text: 'node 4'},
  ]},
]
```

### Template
```template
<draggable-tree :data="data" draggable="draggable" crosstree="crossTree">
    <div slot-scope="{data, store, vm}">
        <template v-if="!data.isDragPlaceHolder">
            <b v-if="data.children &amp;&amp; data.children.length" @click="store.toggleOpen(data)">
                {{data.open ? &apos;-&apos; : &apos;+&apos;}}&nbsp;
            </b>
            <span>{{data.text}}</span>
        </template>
    </div>
</tree>
```

## Configuration

### Props
```js
// base tree
data: {}, // type Array
indent: {default: 16},
activatedClass: {default: 'active'},
openedClass: {default: 'open'}
space: {default: 10}, // space between node, unit px
// draggable tree
preventSelect: {default: true}, // if to prevent drag handler text be selected when drag, excluding input and textarea
getTriggerEl: {type: Function}, // get the el trigger drag, default is node self. arguments(nodeVm)
draggable: {}, // is the tree draggable, default false
droppable: {default: true}, // is the tree droppable, default true
crossTree: {}, // can a node of the tree be dragged into other tree, or receive other tree node
```
### Hooks
```js
ondragstart: {type: Function}, // hook. return false to prevent drag. arguments(node, draggableHelperInfo)
ondragend: {type: Function}, // hook. return false to prevent drop. arguments(node, draggableHelperInfo)
```
### draggableHelperInfo
{event, options, store}

### Properties
```js
// base
rootData, // generated by tree
// draggable
dplh, // drag placeholder. globally unique.
trees, // array, all trees in the app. globally unique.
```

### Events
```js
// store is the tree vm
drag(node), // on drag start.
drop(node, targetTree, oldTree), // after drop.
change(node, targetTree, oldTree), // after drop, only when the node position changed
nodeOpenChanged(node) // on a node is closed or open
```

### Methods
```js
pure(node, withChildren, after)
/*
pure
return a node data without runtime properties.(!: property which starts with '_' will be removed)
withChildren: optional. after: Function, optional
the code about after(t is computed node data):
if (after) {
  return after(t, node) || t
}
return t
*/
getNodeById(id)
getActivated()
getOpened()
activeNode(node, inactiveOld)
toggleActive(node, inactiveOld)
openNode(node, closeOld)
toggleOpen(node, closeOld)
// follow methods are easy, so I paste their soure code
getPureData(after) { return this.pure(this.rootData, true, after).children } // after: Function, optional
deleteNode(node) { return hp.arrayRemove(node.parent.children, node) }
// add node: like array. eg: node.children.push(newNodeData)
// update node: just assign to the node properties directly
isNodeDraggable(node)
isNodeDroppable(node)
```

### Node properties
```js
// base
_id
_vm
parent
children: [],
open,
active: false,
style: {},
class: '',
innerStyle: {},
innerClass: '',
innerBackStyle: {},
innerBackClass: {},
// draggable
draggable // default true. Please check 'draggable & droppable' below
droppable // default true. Please check 'draggable & droppable' below
isDragPlaceHolder
```

#### Node deep properties example
```js
node._vm // vm
node._vm.level // 节点层级, 只读
node._vm.store // tree
node.parent._vm // parent node vm
node._vm.store
```

#### Node max level
```template
<draggable-tree :data="data" draggable="draggable" crosstree="crossTree" @drag="ondrag">
    <div slot-scope="{data, store, vm}">
        <template v-if="!data.isDragPlaceHolder">
            <b v-if="data.children &amp;&amp; data.children.length" @click="store.toggleOpen(data)">
                {{data.open ? &apos;-&apos; : &apos;+&apos;}}&nbsp;
            </b>
            <span>{{data.text}}</span>
        </template>
    </div>
</tree>
```
``` js
import { DraggableTree, depthFirstSearch } from '@jambonn/vue-nested-draggable';

export default {
  ...
    components: {
        DraggableTree
    },
    methods: {
        ondrag(node) {
          const maxLevel = 2
          let nodeLevels = 1
          depthFirstSearch(node, childNode => {
            if (childNode._vm.level > nodeLevels) {
              nodeLevels = childNode._vm.level
            }
          })
          nodeLevels = nodeLevels - node._vm.level + 1
          const childNodeMaxLevel = maxLevel - nodeLevels
          depthFirstSearch(this.originalData, childNode => {
            if (childNode === node) {
              return 'skip children'
            }
            if (!childNode._vm) {
              console.log(childNode)
            }
            this.$set(
              childNode,
              'droppable',
              childNode._vm.level <= childNodeMaxLevel,
            )
          })
        },
    },
  ...
};
```


# Other

### Demo css
```css
.he-tree{
  border: 1px solid #ccc;
  padding: 20px;
  width: 300px;
}
.tree-node-inner{
  padding: 5px;
  border: 1px solid #ccc;
  cursor: pointer;
}
.draggable-placeholder-inner{
  border: 1px dashed #0088F8;
  box-sizing: border-box;
  background: rgba(0, 136, 249, 0.09);
  color: #0088f9;
  text-align: center;
  padding: 0;
  display: flex;
  align-items: center;
}
```

## Project setup
```
yarn install
```

### Compiles and hot-reloads for development
```
yarn serve
```

### Compiles and minifies for production
```
yarn build
```

### Lints and fixes files
```
yarn lint
```

### License
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details.