├── .babelrc ├── .gitignore ├── preview.png ├── _config.yml ├── CONTRIBUTING.md ├── demo ├── index.html ├── ie11test.html ├── minimal-theme.html ├── externaldrag.html ├── keyboardcontrol.html └── dark-theme.html ├── tsconfig.json ├── package.json ├── LICENSE ├── dist ├── sl-vue-tree-minimal.css ├── sl-vue-tree-dark.css ├── sl-vue-tree.d.ts ├── sl-vue-tree.js └── sl-vue-tree.js.map ├── src ├── sl-vue-tree-minimal.css ├── sl-vue-tree-dark.css ├── sl-vue-tree.d.ts ├── sl-vue-tree.vue └── sl-vue-tree.js ├── webpack.config.js └── README.md /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["@babel/preset-env"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | node_modules/ 4 | yarn-error.log -------------------------------------------------------------------------------- /preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holiber/sl-vue-tree/HEAD/preview.png -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | title: sl-vue-tree 2 | description: Customizable draggable tree component for Vue.js 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | PRs are appreciated. 4 | 5 | to start watcher run: 6 | 7 | `npm run start` 8 | 9 | to build project run: 10 | 11 | `npm run build` 12 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sl-vue-tree 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "target": "es5", 5 | "lib": [ 6 | "dom", 7 | "es7", 8 | "es2017" 9 | ], 10 | "module": "es2015", 11 | "moduleResolution": "node", 12 | "isolatedModules": false, 13 | "experimentalDecorators": true, 14 | "noImplicitAny": false, 15 | "noImplicitThis": true, 16 | "removeComments": true, 17 | "suppressImplicitAnyIndexErrors": true, 18 | "allowSyntheticDefaultImports": true, 19 | 20 | "outDir": "./", 21 | "sourceMap": true, 22 | "allowJs": false, 23 | "strictNullChecks": false, 24 | "emitDecoratorMetadata": true, 25 | "baseUrl": "./src", 26 | "declaration": true 27 | }, 28 | "exclude": [ 29 | "node_modules" 30 | ], 31 | "include": [ 32 | "./src/**/*.ts" 33 | ] 34 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sl-vue-tree", 3 | "version": "1.8.5", 4 | "description": "draggable tree vue component", 5 | "browserslist": "> 0.25%, not dead", 6 | "main": "dist/sl-vue-tree.js", 7 | "types": "dist/sl-vue-tree.d.ts", 8 | "scripts": { 9 | "clear": "rimraf dist", 10 | "build": "npm run clear && webpack-cli --progress --mode production", 11 | "start": "npm run clear && webpack-cli --watch --progress --mode development", 12 | "test": "echo \"Error: no test specified\" && exit 1" 13 | }, 14 | "keywords": [ 15 | "vue", 16 | "tree", 17 | "draggable", 18 | "sortable" 19 | ], 20 | "author": "Holiber", 21 | "license": "MIT", 22 | "devDependencies": { 23 | "@babel/core": "^7.1.2", 24 | "@babel/preset-env": "^7.1.0", 25 | "babel-loader": "^8.0.4", 26 | "copy-webpack-plugin": "^5.1.1", 27 | "css-loader": "^3.4.2", 28 | "rimraf": "^2.6.2", 29 | "vue": "^2.5.16", 30 | "vue-loader": "^14.2.2", 31 | "vue-template-compiler": "^2.5.16", 32 | "webpack": "^4.42.0", 33 | "webpack-cli": "^3.1.2" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2018 General Workings, Inc. 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 13 | all 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 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /dist/sl-vue-tree-minimal.css: -------------------------------------------------------------------------------- 1 | .sl-vue-tree { 2 | position: relative; 3 | cursor: default; 4 | -webkit-touch-callout: none; /* iOS Safari */ 5 | -webkit-user-select: none; /* Safari */ 6 | -khtml-user-select: none; /* Konqueror HTML */ 7 | -moz-user-select: none; /* Firefox */ 8 | -ms-user-select: none; /* Internet Explorer/Edge */ 9 | user-select: none; 10 | } 11 | 12 | .sl-vue-tree-root > .sl-vue-tree-nodes-list { 13 | overflow: hidden; 14 | position: relative; 15 | padding-bottom: 4px; 16 | } 17 | 18 | .sl-vue-tree-selected > .sl-vue-tree-node-item { 19 | background-color: rgba(100, 100, 255, 0.5); 20 | } 21 | 22 | .sl-vue-tree-node-list { 23 | position: relative; 24 | display: flex; 25 | flex-direction: row; 26 | } 27 | 28 | .sl-vue-tree-node-item { 29 | position: relative; 30 | display: flex; 31 | flex-direction: row; 32 | } 33 | .sl-vue-tree-node-item.sl-vue-tree-cursor-inside { 34 | outline: 1px solid rgba(100, 100, 255, 0.5); 35 | } 36 | 37 | .sl-vue-tree-gap { 38 | width: 20px; 39 | min-height: 1px; 40 | 41 | } 42 | 43 | .sl-vue-tree-sidebar { 44 | margin-left: auto; 45 | } 46 | 47 | .sl-vue-tree-cursor { 48 | position: absolute; 49 | border: 1px solid rgba(100, 100, 255, 0.5); 50 | height: 1px; 51 | width: 100%; 52 | } 53 | 54 | .sl-vue-tree-drag-info { 55 | position: absolute; 56 | background-color: rgba(0,0,0,0.5); 57 | opacity: 0.5; 58 | margin-left: 20px; 59 | margin-bottom: 20px; 60 | padding: 5px 10px; 61 | } 62 | -------------------------------------------------------------------------------- /src/sl-vue-tree-minimal.css: -------------------------------------------------------------------------------- 1 | .sl-vue-tree { 2 | position: relative; 3 | cursor: default; 4 | -webkit-touch-callout: none; /* iOS Safari */ 5 | -webkit-user-select: none; /* Safari */ 6 | -khtml-user-select: none; /* Konqueror HTML */ 7 | -moz-user-select: none; /* Firefox */ 8 | -ms-user-select: none; /* Internet Explorer/Edge */ 9 | user-select: none; 10 | } 11 | 12 | .sl-vue-tree-root > .sl-vue-tree-nodes-list { 13 | overflow: hidden; 14 | position: relative; 15 | padding-bottom: 4px; 16 | } 17 | 18 | .sl-vue-tree-selected > .sl-vue-tree-node-item { 19 | background-color: rgba(100, 100, 255, 0.5); 20 | } 21 | 22 | .sl-vue-tree-node-list { 23 | position: relative; 24 | display: flex; 25 | flex-direction: row; 26 | } 27 | 28 | .sl-vue-tree-node-item { 29 | position: relative; 30 | display: flex; 31 | flex-direction: row; 32 | } 33 | .sl-vue-tree-node-item.sl-vue-tree-cursor-inside { 34 | outline: 1px solid rgba(100, 100, 255, 0.5); 35 | } 36 | 37 | .sl-vue-tree-gap { 38 | width: 20px; 39 | min-height: 1px; 40 | 41 | } 42 | 43 | .sl-vue-tree-sidebar { 44 | margin-left: auto; 45 | } 46 | 47 | .sl-vue-tree-cursor { 48 | position: absolute; 49 | border: 1px solid rgba(100, 100, 255, 0.5); 50 | height: 1px; 51 | width: 100%; 52 | } 53 | 54 | .sl-vue-tree-drag-info { 55 | position: absolute; 56 | background-color: rgba(0,0,0,0.5); 57 | opacity: 0.5; 58 | margin-left: 20px; 59 | margin-bottom: 20px; 60 | padding: 5px 10px; 61 | } 62 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 3 | 4 | module.exports = { 5 | entry: { 6 | 'SlVueTree': './src/sl-vue-tree.vue' 7 | }, 8 | output: { 9 | path: __dirname + '/dist', 10 | filename: 'sl-vue-tree.js', 11 | library: 'SlVueTree', 12 | libraryTarget: 'umd', 13 | libraryExport: 'default' 14 | }, 15 | 16 | devtool: 'sourcemap', 17 | 18 | 19 | resolve: { 20 | extensions: ['.js'], 21 | modules: [path.resolve(__dirname, 'src'), 'node_modules'] 22 | }, 23 | 24 | externals: { 25 | 'Vue': 'vue' 26 | }, 27 | 28 | module: { 29 | rules: [ 30 | { 31 | test: /\.vue$/, 32 | loader: 'vue-loader', 33 | options: { 34 | esModule: true, 35 | transformToRequire: { 36 | video: 'src', 37 | source: 'src' 38 | } 39 | } 40 | }, 41 | { 42 | test: /\.js$/, 43 | loader: 'babel-loader', 44 | exclude: /node_modules/ 45 | }, 46 | { 47 | test: /\.(png|jpe?g|gif|svg|mp4|ico|wav)(\?.*)?$/, 48 | loader: 'file-loader', 49 | options: { 50 | name: '[name]-[hash].[ext]', 51 | outputPath: 'media/', 52 | publicPath: 'bundles/media/' 53 | } 54 | }, 55 | // Handles custom fonts. Currently used for icons. 56 | { 57 | test: /\.woff$/, 58 | loader: 'file-loader', 59 | options: { 60 | name: '[name].[ext]', 61 | outputPath: 'fonts/', 62 | publicPath: 'bundles/fonts/' 63 | } 64 | } 65 | ] 66 | }, 67 | 68 | plugins: [ 69 | new CopyWebpackPlugin([ 70 | { from: 'src/*.css', to: '[name].css'}, 71 | { from: 'src/*.d.ts', to: '[name].ts'} 72 | ]) 73 | ] 74 | }; 75 | -------------------------------------------------------------------------------- /dist/sl-vue-tree-dark.css: -------------------------------------------------------------------------------- 1 | .sl-vue-tree { 2 | position: relative; 3 | cursor: default; 4 | -webkit-touch-callout: none; /* iOS Safari */ 5 | -webkit-user-select: none; /* Safari */ 6 | -khtml-user-select: none; /* Konqueror HTML */ 7 | -moz-user-select: none; /* Firefox */ 8 | -ms-user-select: none; /* Internet Explorer/Edge */ 9 | user-select: none; 10 | } 11 | 12 | .sl-vue-tree.sl-vue-tree-root { 13 | border: 1px solid rgb(9, 22, 29); 14 | background-color: rgb(9, 22, 29); 15 | color: rgba(255, 255, 255, 0.5); 16 | border-radius: 3px; 17 | } 18 | 19 | .sl-vue-tree-root > .sl-vue-tree-nodes-list { 20 | overflow: hidden; 21 | position: relative; 22 | padding-bottom: 4px; 23 | } 24 | 25 | .sl-vue-tree-selected > .sl-vue-tree-node-item { 26 | background-color: #13242d; 27 | color: white; 28 | } 29 | 30 | .sl-vue-tree-node-item:hover, 31 | .sl-vue-tree-node-item.sl-vue-tree-cursor-hover { 32 | color: white; 33 | } 34 | 35 | .sl-vue-tree-node-item { 36 | position: relative; 37 | display: flex; 38 | flex-direction: row; 39 | 40 | padding-left: 10px; 41 | padding-right: 10px; 42 | line-height: 28px; 43 | border: 1px solid transparent; 44 | } 45 | 46 | 47 | .sl-vue-tree-node-item.sl-vue-tree-cursor-inside { 48 | border: 1px solid rgba(255, 255, 255, 0.5); 49 | } 50 | 51 | .sl-vue-tree-gap { 52 | width: 25px; 53 | min-height: 1px; 54 | 55 | } 56 | 57 | .sl-vue-tree-toggle { 58 | display: inline-block; 59 | text-align: left; 60 | width: 20px; 61 | } 62 | 63 | .sl-vue-tree-sidebar { 64 | margin-left: auto; 65 | } 66 | 67 | .sl-vue-tree-cursor { 68 | position: absolute; 69 | border: 1px solid rgba(255, 255, 255, 0.5); 70 | height: 1px; 71 | width: 100%; 72 | } 73 | 74 | .sl-vue-tree-drag-info { 75 | position: absolute; 76 | background-color: rgba(0,0,0,0.5); 77 | opacity: 0.5; 78 | margin-left: 20px; 79 | padding: 5px 10px; 80 | } 81 | -------------------------------------------------------------------------------- /src/sl-vue-tree-dark.css: -------------------------------------------------------------------------------- 1 | .sl-vue-tree { 2 | position: relative; 3 | cursor: default; 4 | -webkit-touch-callout: none; /* iOS Safari */ 5 | -webkit-user-select: none; /* Safari */ 6 | -khtml-user-select: none; /* Konqueror HTML */ 7 | -moz-user-select: none; /* Firefox */ 8 | -ms-user-select: none; /* Internet Explorer/Edge */ 9 | user-select: none; 10 | } 11 | 12 | .sl-vue-tree.sl-vue-tree-root { 13 | border: 1px solid rgb(9, 22, 29); 14 | background-color: rgb(9, 22, 29); 15 | color: rgba(255, 255, 255, 0.5); 16 | border-radius: 3px; 17 | } 18 | 19 | .sl-vue-tree-root > .sl-vue-tree-nodes-list { 20 | overflow: hidden; 21 | position: relative; 22 | padding-bottom: 4px; 23 | } 24 | 25 | .sl-vue-tree-selected > .sl-vue-tree-node-item { 26 | background-color: #13242d; 27 | color: white; 28 | } 29 | 30 | .sl-vue-tree-node-item:hover, 31 | .sl-vue-tree-node-item.sl-vue-tree-cursor-hover { 32 | color: white; 33 | } 34 | 35 | .sl-vue-tree-node-item { 36 | position: relative; 37 | display: flex; 38 | flex-direction: row; 39 | 40 | padding-left: 10px; 41 | padding-right: 10px; 42 | line-height: 28px; 43 | border: 1px solid transparent; 44 | } 45 | 46 | 47 | .sl-vue-tree-node-item.sl-vue-tree-cursor-inside { 48 | border: 1px solid rgba(255, 255, 255, 0.5); 49 | } 50 | 51 | .sl-vue-tree-gap { 52 | width: 25px; 53 | min-height: 1px; 54 | 55 | } 56 | 57 | .sl-vue-tree-toggle { 58 | display: inline-block; 59 | text-align: left; 60 | width: 20px; 61 | } 62 | 63 | .sl-vue-tree-sidebar { 64 | margin-left: auto; 65 | } 66 | 67 | .sl-vue-tree-cursor { 68 | position: absolute; 69 | border: 1px solid rgba(255, 255, 255, 0.5); 70 | height: 1px; 71 | width: 100%; 72 | } 73 | 74 | .sl-vue-tree-drag-info { 75 | position: absolute; 76 | background-color: rgba(0,0,0,0.5); 77 | opacity: 0.5; 78 | margin-left: 20px; 79 | padding: 5px 10px; 80 | } 81 | -------------------------------------------------------------------------------- /dist/sl-vue-tree.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | export interface ISlTreeNodeModel { 3 | title: string; 4 | isLeaf?: boolean; 5 | children?: ISlTreeNodeModel[]; 6 | isExpanded?: boolean; 7 | isSelected?: boolean; 8 | isDraggable?: boolean; 9 | isSelectable?: boolean; 10 | data?: TDataType; 11 | } 12 | export interface ISlTreeNode extends ISlTreeNodeModel { 13 | isVisible?: boolean; 14 | isFirstChild: boolean; 15 | isLastChild: boolean; 16 | ind: number; 17 | level: number; 18 | path: number[]; 19 | pathStr: string; 20 | children: ISlTreeNode[]; 21 | } 22 | export interface ICursorPosition { 23 | node: ISlTreeNode; 24 | placement: 'before' | 'inside' | 'after'; 25 | } 26 | export interface IVueData { 27 | rootCursorPosition: ICursorPosition; 28 | rootDraggingNode: ISlTreeNode; 29 | } 30 | export default class SlVueTree extends Vue { 31 | value: ISlTreeNodeModel[]; 32 | edgeSize: number; 33 | allowMultiselect: boolean; 34 | showBranches: boolean; 35 | level: number; 36 | parentInd: number; 37 | allowToggleBranch: boolean; 38 | private rootCursorPosition; 39 | private rootDraggingNode; 40 | cursorPosition: ICursorPosition; 41 | draggingNode: ISlTreeNode; 42 | readonly nodes: ISlTreeNode[]; 43 | getNode(path: number[]): ISlTreeNode; 44 | getFirstNode(): ISlTreeNode; 45 | getLastNode(): ISlTreeNode; 46 | getNextNode(path: number[], filter?: (node: ISlTreeNode) => boolean): ISlTreeNode; 47 | getPrevNode(path: number[], filter?: (node: ISlTreeNode) => boolean): ISlTreeNode; 48 | updateNode(path: number[], patch: Partial>): void; 49 | getSelected(): ISlTreeNode[]; 50 | traverse(cb: (node: ISlTreeNode, nodeModel: ISlTreeNodeModel, siblings: ISlTreeNodeModel[]) => boolean | void, nodeModels?: ISlTreeNodeModel[], parentPath?: number[]): ISlTreeNode[] | boolean; 51 | getNodeEl(path: number[]): HTMLElement; 52 | select(path: number[], addToSelection?: boolean): ISlTreeNode; 53 | remove(paths: number[][]): void 54 | insert(cursorPosition: ICursorPosition, nodeModel:ISlTreeNodeModel): void 55 | } 56 | -------------------------------------------------------------------------------- /src/sl-vue-tree.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | export interface ISlTreeNodeModel { 3 | title: string; 4 | isLeaf?: boolean; 5 | children?: ISlTreeNodeModel[]; 6 | isExpanded?: boolean; 7 | isSelected?: boolean; 8 | isDraggable?: boolean; 9 | isSelectable?: boolean; 10 | data?: TDataType; 11 | } 12 | export interface ISlTreeNode extends ISlTreeNodeModel { 13 | isVisible?: boolean; 14 | isFirstChild: boolean; 15 | isLastChild: boolean; 16 | ind: number; 17 | level: number; 18 | path: number[]; 19 | pathStr: string; 20 | children: ISlTreeNode[]; 21 | } 22 | export interface ICursorPosition { 23 | node: ISlTreeNode; 24 | placement: 'before' | 'inside' | 'after'; 25 | } 26 | export interface IVueData { 27 | rootCursorPosition: ICursorPosition; 28 | rootDraggingNode: ISlTreeNode; 29 | } 30 | export default class SlVueTree extends Vue { 31 | value: ISlTreeNodeModel[]; 32 | edgeSize: number; 33 | allowMultiselect: boolean; 34 | showBranches: boolean; 35 | level: number; 36 | parentInd: number; 37 | allowToggleBranch: boolean; 38 | private rootCursorPosition; 39 | private rootDraggingNode; 40 | cursorPosition: ICursorPosition; 41 | draggingNode: ISlTreeNode; 42 | readonly nodes: ISlTreeNode[]; 43 | getNode(path: number[]): ISlTreeNode; 44 | getFirstNode(): ISlTreeNode; 45 | getLastNode(): ISlTreeNode; 46 | getNextNode(path: number[], filter?: (node: ISlTreeNode) => boolean): ISlTreeNode; 47 | getPrevNode(path: number[], filter?: (node: ISlTreeNode) => boolean): ISlTreeNode; 48 | updateNode(path: number[], patch: Partial>): void; 49 | getSelected(): ISlTreeNode[]; 50 | traverse(cb: (node: ISlTreeNode, nodeModel: ISlTreeNodeModel, siblings: ISlTreeNodeModel[]) => boolean | void, nodeModels?: ISlTreeNodeModel[], parentPath?: number[]): ISlTreeNode[] | boolean; 51 | getNodeEl(path: number[]): HTMLElement; 52 | select(path: number[], addToSelection?: boolean): ISlTreeNode; 53 | remove(paths: number[][]): void; 54 | insert(cursorPosition: ICursorPosition, nodeModel:ISlTreeNodeModel): void; 55 | } 56 | -------------------------------------------------------------------------------- /demo/ie11test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sl-vue-tree 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
16 | 17 |

Sl-vue-tree - IE11-friendly code

18 | 19 | 20 |
21 |
22 | 26 | 27 |
28 | 29 | 30 |
31 |
{{ JSON.stringify(nodes, null, 4)}}
32 |
33 | 34 |
35 | 36 | 37 |
38 | 39 | 70 | 71 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /demo/minimal-theme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sl-vue-tree 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |

Sl-vue-tree - minimal css

16 | 17 | Source code 18 | 19 | 20 |
21 |
22 | 23 |
24 | 25 |
26 |
{{ JSON.stringify(nodes, null, 4)}}
27 |
28 |
29 | 30 | 31 |
32 | 33 | 75 | 76 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /demo/externaldrag.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sl-vue-tree 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
15 | 16 |

Sl-vue-tree - drag external elements

17 | 18 | 19 |
20 |
21 | 26 | 27 | 35 | 36 | 37 | 43 | 44 | 45 | 46 | 47 |
48 |

49 | Drag Me! 50 |
51 | 52 |
53 |

54 | Drag Me! 55 |
56 | 57 |
58 |

59 | Drag Me! 60 |
61 | 62 |
63 | 64 | 65 |
66 |
{{ JSON.stringify(nodes, null, 4)}}
67 |
68 | 69 |
70 | 71 | 72 | 73 |
74 | 75 | 121 | 122 | 177 | 178 | 179 | 180 | -------------------------------------------------------------------------------- /demo/keyboardcontrol.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sl-vue-tree 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
15 | 16 |

Sl-vue-tree - Press Up and Down to move selection, Space and Enter to expand / collapse

17 | 18 | Source code 19 |

20 | 21 | 22 |
23 |
24 | 28 | 29 | 37 | 38 | 39 | 45 | 46 | 47 | 48 |
49 | 50 | 51 |
52 |
{{ JSON.stringify(nodes, null, 4)}}
53 |
54 | 55 |
56 | 57 | 58 |
59 | 60 | 130 | 131 | 176 | 177 | 178 | -------------------------------------------------------------------------------- /src/sl-vue-tree.vue: -------------------------------------------------------------------------------- 1 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /demo/dark-theme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | sl-vue-tree 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |

Sl-vue-tree - custom dark theme and events handlers

16 | 17 | Source code 18 |

19 | 20 | 21 |
22 | Last event: {{ lastEvent }} 23 |
24 | 25 |
26 |
27 | 36 | 37 | 45 | 46 | 47 | 53 | 54 | 55 | 61 | 62 | 63 | 66 | 67 | 68 |
69 | 70 | 71 |
72 |
{{ JSON.stringify(nodes, null, 4)}}
73 |
74 | 75 |
76 |
Remove
77 |
78 |
79 | 80 | 81 |
82 | 83 | 172 | 173 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sl-vue-tree 2 | 3 | Customizable draggable tree component for Vue.js. 4 | 5 | ![Preview](preview.png) 6 | 7 | [Demo](https://holiber.github.io/sl-vue-tree/demo/index) 8 | 9 | ## Installation 10 | 11 | ```bash 12 | npm i sl-vue-tree 13 | ``` 14 | 15 | # Vue3 Support 16 | Support for Vue3 coming soon. Check out [sl-vue-tree-next](https://github.com/kcsujeet/sl-vue-tree-next) while that is being shaped up. 17 | 18 | # Quick Start 19 | 20 | ```html 21 |
22 | 23 |
24 | 25 | 26 | 27 | 28 | 53 | ``` 54 | 55 | The `value` property is an array of `ISlTreeNodeModel` nodes: 56 | 57 | ```typescript 58 | interface ISlTreeNodeModel { 59 | title: string; 60 | isLeaf?: boolean; 61 | children?: ISlTreeNodeModel[]; 62 | isExpanded?: boolean; 63 | isSelected?: boolean; 64 | isDraggable?: boolean; 65 | isSelectable?: boolean; 66 | data?: TDataType; // any serializable user data 67 | } 68 | ``` 69 | 70 | For convenience, the component's events return `ISlTreeNode` objects. These are actually `ISlTreeNodeModel` instances with some computed properties: 71 | 72 | ```typescript 73 | interface ISlTreeNode extends ISlTreeNodeModel { 74 | isFirstChild: boolean; 75 | isLastChild: boolean; 76 | isVisible: boolean; // node is visible if all of its parents are expanded 77 | level: number; // nesting level 78 | ind: number; // index in the array of siblings 79 | path: number[]; // path to node as an array of indexes, e.g., [2, 0, 1] is the path to `Item4` in the example above 80 | pathStr: string; // serialized path to node 81 | children: ISlTreeNode[]; 82 | } 83 | ``` 84 | 85 | You can get the list of `ISlTreeNode` objects from the computed `slVueTree.nodes` property. 86 | 87 | # Props 88 | 89 | | Prop | Type | Default | Description | 90 | |------------------|--------------------|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 91 | | value | ISlTreeNodeModel[] | `[]` | An array of nodes to display. Each node is represented by the `ISlTreeNodeModel` interface. | 92 | | allowMultiselect | Boolean | `true` | Enables or disables the multiselect feature. | 93 | | allowToggleBranch | Boolean | `true` | Enables or disables the expand/collapse button. | 94 | | edgeSize | Number | `3` | Offset in pixels from the top and bottom of a folder-node element. While dragging, if the cursor is within this offset, the dragged node will be placed before or after the folder-node instead of inside it. | 95 | | scrollAreaHeight | Number | `70` | Offset in pixels from the top and bottom of the component element. While dragging, if the cursor is within this area, scrolling starts. | 96 | | maxScrollSpeed | Number | `20` | The maximum scroll speed. The scroll speed is relative to the cursor position. | 97 | | multiselectKey | String or String[] | `['ctrlKey', 'metaKey']` | The keys for enabling multiselect mode. Allowed values are `'ctrlKey'`, `'metaKey'`, `'altKey'`. | 98 | 99 | # Computed Properties 100 | 101 | | Property | Type | Description | 102 | |----------------|----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------| 103 | | nodes | ISlTreeNode[] | List of nodes with computed properties. See the `ISlTreeNode` interface. | 104 | | cursorPosition | ICursorPosition | Represents the current cursor position that describes the action to be applied to the dragged node on the `mouseup` event. See the `ICursorPosition` interface. | 105 | | selectionSize | Number | The count of selected nodes. | 106 | | dragSize | Number | The count of selected and draggable nodes. | 107 | | isDragging | Boolean | Indicates whether nodes are currently being dragged. | 108 | 109 | ```typescript 110 | interface ICursorPosition { 111 | node: ISlTreeNode; 112 | placement: 'before' | 'inside' | 'after'; 113 | } 114 | ``` 115 | 116 | # Events 117 | 118 | | Event | Callback Arguments | Description | 119 | |-----------------|------------------------------------------------------------------------------|------------------------------------------------------| 120 | | input | `nodes: ISlTreeNodeModel[]` | Triggered whenever the `value` property changes. | 121 | | select | `selectedNodes: ISlTreeNode[]`, `event: MouseEvent` | Triggered when a node is selected or deselected. | 122 | | toggle | `toggledNode: ISlTreeNode`, `event: MouseEvent` | Triggered when a node is expanded or collapsed. | 123 | | drop | `draggingNodes: ISlTreeNode[]`, `position: ICursorPosition`, `event: MouseEvent` | Triggered when dragged nodes are dropped. | 124 | | nodeclick | `node: ISlTreeNode`, `event: MouseEvent` | Handles the `click` event on a node. | 125 | | nodedblclick | `node: ISlTreeNode`, `event: MouseEvent` | Handles the `dblclick` event on a node. | 126 | | nodecontextmenu | `node: ISlTreeNode`, `event: MouseEvent` | Handles the `contextmenu` event on a node. | 127 | | externaldrop | `cursorPosition: ICursorPosition`, `event: MouseEvent` | Handles the `drop` event for external items. [Demo](https://holiber.github.io/sl-vue-tree/demo/externaldrag) | 128 | 129 | # Methods 130 | 131 | | Method | Description | 132 | |---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------| 133 | | getNode(path: number[]): ISlTreeNode | Finds a node by its path. | 134 | | traverse(callback: (node: ISlTreeNode, nodeModel: ISlTreeNodeModel, siblings: ISlTreeNodeModel[]) => boolean) | Traverses all nodes. Traversing stops if the callback returns `false`. | 135 | | updateNode(path: number[], patch: Partial) | Updates a node by its path. | 136 | | select(path: number[], addToSelection = false) | Selects a node by its path. | 137 | | getNodeEl(path: number[]): HTMLElement | Gets the node's HTMLElement by its path. | 138 | | getSelected(): ISlTreeNode[] | Gets the selected nodes. | 139 | | insert(position: ICursorPosition, nodeModel: ISlTreeNodeModel) | Inserts a node at the specified cursor position. | 140 | | remove(paths: number[][]) | Removes nodes by their paths, e.g., `.remove([[0,1], [0,2]])`. | 141 | | getFirstNode(): ISlTreeNode | Gets the first node in the tree. | 142 | | getLastNode(): ISlTreeNode | Gets the last node in the tree. | 143 | | getNextNode(path: number[], filter?: (node: ISlTreeNode) => boolean): ISlTreeNode | Gets the next node. You can skip nodes by using the `filter` function. | 144 | | getPrevNode(path: number[], filter?: (node: ISlTreeNode) => boolean): ISlTreeNode | Gets the previous node. You can skip nodes by using the `filter` function. | 145 | 146 | # Slots 147 | 148 | | Slot | Context | Description | 149 | |-------------|---------------|-----------------------------------------------------------------------------------------------| 150 | | title | ISlTreeNode | Slot for customizing the item title. | 151 | | toggle | ISlTreeNode | Slot for the expand/collapse button. | 152 | | sidebar | ISlTreeNode | Slot for sidebar content. | 153 | | draginfo | SlVueTree | Slot that follows the mouse cursor while dragging. By default, shows the count of dragging nodes. | 154 | | empty-node | ISlTreeNode | Slot for an optional message when a folder is open but empty. | 155 | 156 | 157 | # Examples 158 | 159 | ## Add a Folder or Item Icon via the `title` Slot 160 | 161 | ```html 162 | 163 | 170 | 171 | ``` 172 | 173 | ## Select All Nodes 174 | 175 | ```javascript 176 | slVueTree.traverse((node, nodeModel, path) => { 177 | Vue.set(nodeModel, 'isSelected', true); 178 | }); 179 | ``` 180 | 181 | ## Handle `keydown` and `keyup` Events via `getNextNode` and `getPrevNode` Methods 182 | 183 | [Demo](https://holiber.github.io/sl-vue-tree/demo/keyboardcontrol) 184 | 185 | 186 | # IE11 Support 187 | 188 | You must include a [babel-polyfill](https://babeljs.io/docs/en/babel-polyfill) for the component to work correctly in IE11. 189 | 190 | [See IE11 Example](https://holiber.github.io/sl-vue-tree/demo/ie11test.html) 191 | 192 | # Contributing 193 | 194 | [See CONTRIBUTING.md](CONTRIBUTING.md) 195 | 196 | # Changelog 197 | 198 | ## v1.8.5 199 | 200 | - Fixed TypeScript definitions. See [#77](https://github.com/holiber/sl-vue-tree/pull/77). 201 | 202 | ## v1.8.4 203 | 204 | - Added `insert` method. See [#39](https://github.com/holiber/sl-vue-tree/pull/39). 205 | 206 | ## v1.8.3 207 | 208 | - Enabled the ability to disable or enable the expand/collapse button. See [#33](https://github.com/holiber/sl-vue-tree/pull/33). 209 | 210 | ## v1.8.1 211 | 212 | - Added IE11 support. See [#17](https://github.com/holiber/sl-vue-tree/issues/17). 213 | 214 | ## v1.8.0 215 | 216 | - Added `empty-node` slot. 217 | 218 | ## v1.7.1 219 | 220 | - Added `multiselectKey` property. 221 | 222 | ## v1.7.0 223 | 224 | - Added `isSelectable` and `isDraggable` flags. 225 | 226 | ## v1.6.0 227 | 228 | - Added `getNextNode` and `getPrevNode` methods. See [#6](https://github.com/holiber/sl-vue-tree/issues/6). 229 | 230 | ## v1.5.1 231 | 232 | - Improved dropping at the bottom of the tree. See [#5](https://github.com/holiber/sl-vue-tree/issues/5). 233 | 234 | ## v1.5.0 235 | 236 | - Added `SlVueTree.select` method. 237 | - Fixed `SlVueTree.@nodeclick` event. 238 | -------------------------------------------------------------------------------- /dist/sl-vue-tree.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.SlVueTree=t():e.SlVueTree=t()}(window,(function(){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var i=t[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,n),i.l=!0,i.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var i in e)n.d(r,i,function(t){return e[t]}.bind(null,i));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";function r(e){return function(e){if(Array.isArray(e)){for(var t=0,n=new Array(e.length);t0;)e.push(t);return e},isRoot:function(){return!this.level},selectionSize:function(){return this.getSelected().length},dragSize:function(){return this.getDraggable().length}},methods:{setCursorPosition:function(e){this.isRoot?this.rootCursorPosition=e:this.getParent().setCursorPosition(e)},getNodes:function(e){var t=this,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];return e.map((function(i,o){var s=n.concat(o);return t.getNode(s,i,e,r)}))},getNode:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:null,i=e.slice(-1)[0];if(n=n||this.getNodeSiblings(this.currentValue,e),t=t||n&&n[i]||null,null==r&&(r=this.isVisible(e)),!t)return null;var o=null==t.isExpanded||!!t.isExpanded,s=null==t.isDraggable||!!t.isDraggable,l=null==t.isSelectable||!!t.isSelectable,a={title:t.title,isLeaf:!!t.isLeaf,children:t.children?this.getNodes(t.children,e,o):[],isSelected:!!t.isSelected,isExpanded:o,isVisible:r,isDraggable:s,isSelectable:l,data:void 0!==t.data?t.data:{},path:e,pathStr:JSON.stringify(e),level:e.length,ind:i,isFirstChild:0==i,isLastChild:i===n.length-1};return a},isVisible:function(e){if(e.length<2)return!0;for(var t=this.currentValue,n=0;n1&&void 0!==arguments[1]&&arguments[1],r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:null,i=Array.isArray(this.multiselectKey)?this.multiselectKey:[this.multiselectKey],o=r&&!!i.find((function(e){return r[e]}));n=(o||n)&&this.allowMultiselect;var s=this.getNode(e);if(!s)return null;var l=this.copy(this.currentValue),a=this.allowMultiselect&&r&&r.shiftKey&&this.lastSelectedNode,u=[],c=!1;return this.traverse((function(e,r){a?(e.pathStr!==s.pathStr&&e.pathStr!==t.lastSelectedNode.pathStr||(r.isSelected=e.isSelectable,c=!c),c&&(r.isSelected=e.isSelectable)):e.pathStr===s.pathStr?r.isSelected=e.isSelectable:n||r.isSelected&&(r.isSelected=!1),r.isSelected&&u.push(e)}),l),this.lastSelectedNode=s,this.emitInput(l),this.emitSelect(u,r),s},onMousemoveHandler:function(e){if(this.isRoot){if(!this.preventDrag){var t=this.isDragging,n=this.isDragging||this.mouseIsDown&&(this.lastMousePos.x!==e.clientX||this.lastMousePos.y!==e.clientY),r=!1===t&&!0===n;if(this.lastMousePos={x:e.clientX,y:e.clientY},n){var i=this.getRoot().$el,o=i.getBoundingClientRect(),s=this.$refs.dragInfo,l=e.clientY-o.top+i.scrollTop-(0|s.style.marginBottom),a=e.clientX-o.left;s.style.top=l+"px",s.style.left=a+"px";var u=this.getCursorPositionFromCoords(e.clientX,e.clientY),c=u.node,d=u.placement;if(r&&!c.isSelected&&this.select(c.path,!1,e),this.getDraggable().length){this.isDragging=n,this.setCursorPosition({node:c,placement:d});var h=o.bottom-this.scrollAreaHeight,f=(e.clientY-h)/(o.bottom-h),g=o.top+this.scrollAreaHeight,p=(g-e.clientY)/(g-o.top);f>0?this.startScroll(f):p>0?this.startScroll(-p):this.stopScroll()}else this.preventDrag=!0}}}else this.getRoot().onMousemoveHandler(e)},getCursorPositionFromCoords:function(e,t){var n,r,i=document.elementFromPoint(e,t),o=i.getAttribute("path")?i:this.getClosetElementWithPath(i);if(o){if(!o)return;n=this.getNode(JSON.parse(o.getAttribute("path")));var s=o.offsetHeight,l=this.edgeSize,a=t-o.getBoundingClientRect().top;r=n.isLeaf?a>=s/2?"after":"before":a<=l?"before":a>=s-l?"after":"inside"}else{var u=this.getRoot().$el.getBoundingClientRect();t>u.top+u.height/2?(r="after",n=this.getLastNode()):(r="before",n=this.getFirstNode())}return{node:n,placement:r}},getClosetElementWithPath:function(e){return e?e.getAttribute("path")?e:this.getClosetElementWithPath(e.parentElement):null},onMouseleaveHandler:function(e){if(this.isRoot&&this.isDragging){var t=this.getRoot().$el.getBoundingClientRect();e.clientY>=t.bottom?this.setCursorPosition({node:this.nodes.slice(-1)[0],placement:"after"}):e.clientY1&&void 0!==arguments[1]?arguments[1]:null,r=null;return this.traverse((function(i){if(!(t.comparePaths(i.path,e)<1))return!n||n(i)?(r=i,!1):void 0})),r},getPrevNode:function(e,t){var n=this,r=[];this.traverse((function(t){if(n.comparePaths(t.path,e)>=0)return!1;r.push(t)}));for(var i=r.length;i--;){var o=r[i];if(!t||t(o))return o}return null},comparePaths:function(e,t){for(var n=0;nt[n])return 1;if(e[n]1&&void 0!==arguments[1]?arguments[1]:null;if(0===e.button)if(this.isRoot)if(this.mouseIsDown=!1,this.isDragging||!t||this.preventDrag||this.select(t.path,!1,e),this.preventDrag=!1,this.cursorPosition){var n=this.getDraggable(),r=!0,i=!1,o=void 0;try{for(var s,l=n[Symbol.iterator]();!(r=(s=l.next()).done);r=!0){var a=s.value;if(a.pathStr==this.cursorPosition.node.pathStr)return void this.stopDrag();if(this.checkNodeIsParent(a,this.cursorPosition.node))return void this.stopDrag()}}catch(e){i=!0,o=e}finally{try{r||null==l.return||l.return()}finally{if(i)throw o}}var u=this.copy(this.currentValue),c=[],d=!0,h=!1,f=void 0;try{for(var g,p=n[Symbol.iterator]();!(d=(g=p.next()).done);d=!0){var v=g.value,m=this.getNodeSiblings(u,v.path),S=m[v.ind];c.push(S)}}catch(e){h=!0,f=e}finally{try{d||null==p.return||p.return()}finally{if(h)throw f}}var y=!1;if(this.emitBeforeDrop(n,this.cursorPosition,(function(){return y=!0})),y)this.stopDrag();else{for(var b=[],_=0;_1&&void 0!==arguments[1]?arguments[1]:null,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];t||(t=this.currentValue);for(var r=!1,i=[],o=0;o [] 8 | }, 9 | edgeSize: { 10 | type: Number, 11 | default: 3 12 | }, 13 | showBranches: { 14 | type: Boolean, 15 | default: false 16 | }, 17 | level: { 18 | type: Number, 19 | default: 0 20 | }, 21 | parentInd: { 22 | type: Number 23 | }, 24 | allowMultiselect: { 25 | type: Boolean, 26 | default: true 27 | }, 28 | allowToggleBranch: { 29 | type: Boolean, 30 | default: true 31 | }, 32 | multiselectKey: { 33 | type: [String, Array], 34 | default: function () { 35 | return ['ctrlKey', 'metaKey'] 36 | }, 37 | validator: function (value) { 38 | let allowedKeys = ['ctrlKey', 'metaKey', 'altKey']; 39 | let multiselectKeys = Array.isArray(value) ? value : [value]; 40 | multiselectKeys = multiselectKeys.filter(keyName => allowedKeys.indexOf(keyName ) !== -1); 41 | return !!multiselectKeys.length; 42 | } 43 | }, 44 | scrollAreaHeight: { 45 | type: Number, 46 | default: 70 47 | }, 48 | maxScrollSpeed: { 49 | type: Number, 50 | default: 20 51 | } 52 | }, 53 | 54 | data() { 55 | return { 56 | rootCursorPosition: null, 57 | scrollIntervalId: 0, 58 | scrollSpeed: 0, 59 | lastSelectedNode: null, 60 | mouseIsDown: false, 61 | isDragging: false, 62 | lastMousePos: {x: 0, y: 0}, 63 | preventDrag: false, 64 | currentValue: this.value 65 | }; 66 | }, 67 | 68 | mounted() { 69 | if (this.isRoot) { 70 | document.addEventListener('mouseup', this.onDocumentMouseupHandler); 71 | } 72 | }, 73 | 74 | beforeDestroy() { 75 | document.removeEventListener('mouseup', this.onDocumentMouseupHandler); 76 | }, 77 | 78 | watch: { 79 | value: function (newValue) { 80 | this.currentValue = newValue; 81 | } 82 | }, 83 | 84 | computed: { 85 | cursorPosition() { 86 | if (this.isRoot) return this.rootCursorPosition; 87 | return this.getParent().cursorPosition; 88 | }, 89 | 90 | depth() { 91 | return this.gaps.length 92 | }, 93 | 94 | nodes() { 95 | if (this.isRoot) { 96 | const nodeModels = this.copy(this.currentValue); 97 | return this.getNodes(nodeModels); 98 | } 99 | 100 | return this.getParent().nodes[this.parentInd].children; 101 | }, 102 | /** 103 | * gaps is using for nodes indentation 104 | * @returns {number[]} 105 | */ 106 | gaps() { 107 | const gaps = []; 108 | let i = this.level - 1; 109 | if (!this.showBranches) i++; 110 | while (i-- > 0) gaps.push(i); 111 | return gaps; 112 | }, 113 | 114 | isRoot() { 115 | return !this.level 116 | }, 117 | 118 | selectionSize() { 119 | return this.getSelected().length; 120 | }, 121 | 122 | dragSize() { 123 | return this.getDraggable().length; 124 | } 125 | }, 126 | methods: { 127 | 128 | setCursorPosition(pos) { 129 | if (this.isRoot) { 130 | this.rootCursorPosition = pos; 131 | return; 132 | } 133 | this.getParent().setCursorPosition(pos); 134 | }, 135 | 136 | getNodes(nodeModels, parentPath = [], isVisible = true) { 137 | 138 | return nodeModels.map((nodeModel, ind) => { 139 | const nodePath = parentPath.concat(ind); 140 | return this.getNode(nodePath, nodeModel, nodeModels, isVisible); 141 | }) 142 | }, 143 | 144 | getNode( 145 | path, 146 | nodeModel = null, 147 | siblings = null, 148 | isVisible = null 149 | ) { 150 | const ind = path.slice(-1)[0]; 151 | 152 | // calculate nodeModel, siblings, isVisible fields if it is not passed as arguments 153 | siblings = siblings || this.getNodeSiblings(this.currentValue, path); 154 | nodeModel = nodeModel || (siblings && siblings[ind]) || null; 155 | 156 | if (isVisible == null) { 157 | isVisible = this.isVisible(path); 158 | } 159 | 160 | if (!nodeModel) return null; 161 | 162 | const isExpanded = nodeModel.isExpanded == void 0 ? true : !!nodeModel.isExpanded; 163 | const isDraggable = nodeModel.isDraggable == void 0 ? true : !!nodeModel.isDraggable; 164 | const isSelectable = nodeModel.isSelectable == void 0 ? true : !!nodeModel.isSelectable; 165 | 166 | const node = { 167 | 168 | // define the all ISlTreeNodeModel props 169 | title: nodeModel.title, 170 | isLeaf: !!nodeModel.isLeaf, 171 | children: nodeModel.children ? this.getNodes(nodeModel.children, path, isExpanded) : [], 172 | isSelected: !!nodeModel.isSelected, 173 | isExpanded, 174 | isVisible, 175 | isDraggable, 176 | isSelectable, 177 | data: nodeModel.data !== void 0 ? nodeModel.data : {}, 178 | 179 | // define the all ISlTreeNode computed props 180 | path: path, 181 | pathStr: JSON.stringify(path), 182 | level: path.length, 183 | ind, 184 | isFirstChild: ind == 0, 185 | isLastChild: ind === siblings.length - 1 186 | }; 187 | return node; 188 | }, 189 | 190 | isVisible(path) { 191 | if (path.length < 2) return true; 192 | let nodeModels = this.currentValue; 193 | 194 | for (let i = 0; i < path.length - 1; i++) { 195 | let ind = path[i]; 196 | let nodeModel = nodeModels[ind]; 197 | let isExpanded = nodeModel.isExpanded == void 0 ? true : !!nodeModel.isExpanded; 198 | if (!isExpanded) return false; 199 | nodeModels = nodeModel.children; 200 | } 201 | 202 | return true; 203 | }, 204 | 205 | emitInput(newValue) { 206 | this.currentValue = newValue; 207 | this.getRoot().$emit('input', newValue); 208 | }, 209 | 210 | emitSelect(selectedNodes, event) { 211 | this.getRoot().$emit('select', selectedNodes, event); 212 | }, 213 | 214 | emitBeforeDrop(draggingNodes, position, cancel) { 215 | this.getRoot().$emit('beforedrop', draggingNodes, position, cancel); 216 | }, 217 | 218 | emitDrop(draggingNodes, position, event) { 219 | this.getRoot().$emit('drop', draggingNodes, position, event); 220 | }, 221 | 222 | emitToggle(toggledNode, event) { 223 | this.getRoot().$emit('toggle', toggledNode, event); 224 | }, 225 | 226 | emitNodeClick(node, event) { 227 | this.getRoot().$emit('nodeclick', node, event); 228 | }, 229 | 230 | emitNodeDblclick(node, event) { 231 | this.getRoot().$emit('nodedblclick', node, event); 232 | }, 233 | 234 | emitNodeContextmenu(node, event) { 235 | this.getRoot().$emit('nodecontextmenu', node, event); 236 | }, 237 | 238 | onExternalDragoverHandler(node, event) { 239 | event.preventDefault(); 240 | const root = this.getRoot(); 241 | const cursorPosition = root.getCursorPositionFromCoords(event.clientX, event.clientY); 242 | root.setCursorPosition(cursorPosition); 243 | root.$emit('externaldragover', cursorPosition, event); 244 | }, 245 | 246 | onExternalDropHandler(node, event) { 247 | const root = this.getRoot(); 248 | const cursorPosition = root.getCursorPositionFromCoords(event.clientX, event.clientY); 249 | root.$emit('externaldrop', cursorPosition, event); 250 | this.setCursorPosition(null); 251 | }, 252 | 253 | select(path, addToSelection = false, event = null) { 254 | const multiselectKeys = Array.isArray(this.multiselectKey) ? 255 | this.multiselectKey: 256 | [this.multiselectKey]; 257 | const multiselectKeyIsPressed = event && !!multiselectKeys.find(key => event[key]); 258 | addToSelection = (multiselectKeyIsPressed || addToSelection) && this.allowMultiselect ; 259 | 260 | const selectedNode = this.getNode(path); 261 | if (!selectedNode) return null; 262 | const newNodes = this.copy(this.currentValue); 263 | const shiftSelectionMode = this.allowMultiselect && event && event.shiftKey && this.lastSelectedNode; 264 | const selectedNodes = []; 265 | let shiftSelectionStarted = false; 266 | 267 | this.traverse((node, nodeModel) => { 268 | 269 | 270 | if (shiftSelectionMode) { 271 | if (node.pathStr === selectedNode.pathStr || node.pathStr === this.lastSelectedNode.pathStr) { 272 | nodeModel.isSelected = node.isSelectable; 273 | shiftSelectionStarted = !shiftSelectionStarted; 274 | } 275 | if (shiftSelectionStarted) nodeModel.isSelected = node.isSelectable; 276 | } else if (node.pathStr === selectedNode.pathStr) { 277 | nodeModel.isSelected = node.isSelectable; 278 | } else if (!addToSelection) { 279 | if (nodeModel.isSelected) nodeModel.isSelected = false; 280 | } 281 | 282 | if (nodeModel.isSelected) selectedNodes.push(node); 283 | 284 | }, newNodes); 285 | 286 | 287 | this.lastSelectedNode = selectedNode; 288 | this.emitInput(newNodes); 289 | this.emitSelect(selectedNodes, event); 290 | return selectedNode; 291 | }, 292 | 293 | onMousemoveHandler(event) { 294 | if (!this.isRoot) { 295 | this.getRoot().onMousemoveHandler(event); 296 | return; 297 | } 298 | 299 | if (this.preventDrag) return; 300 | 301 | const initialDraggingState = this.isDragging; 302 | const isDragging = 303 | this.isDragging || ( 304 | this.mouseIsDown && 305 | (this.lastMousePos.x !== event.clientX || this.lastMousePos.y !== event.clientY) 306 | ); 307 | 308 | const isDragStarted = initialDraggingState === false && isDragging === true; 309 | 310 | this.lastMousePos = { 311 | x: event.clientX, 312 | y: event.clientY 313 | }; 314 | 315 | if (!isDragging) return; 316 | 317 | const $root = this.getRoot().$el; 318 | const rootRect = $root.getBoundingClientRect(); 319 | const $dragInfo = this.$refs.dragInfo; 320 | const dragInfoTop = (event.clientY - rootRect.top + $root.scrollTop - ($dragInfo.style.marginBottom | 0) ); 321 | const dragInfoLeft = (event.clientX - rootRect.left); 322 | 323 | $dragInfo.style.top = dragInfoTop + 'px'; 324 | $dragInfo.style.left = dragInfoLeft + 'px'; 325 | 326 | const cursorPosition = this.getCursorPositionFromCoords(event.clientX, event.clientY); 327 | const destNode = cursorPosition.node; 328 | const placement = cursorPosition.placement; 329 | 330 | if (isDragStarted && !destNode.isSelected) { 331 | this.select(destNode.path, false, event); 332 | } 333 | 334 | const draggableNodes = this.getDraggable(); 335 | if (!draggableNodes.length) { 336 | this.preventDrag = true; 337 | return; 338 | } 339 | 340 | this.isDragging = isDragging; 341 | 342 | this.setCursorPosition({ node: destNode, placement }); 343 | 344 | const scrollBottomLine = rootRect.bottom - this.scrollAreaHeight; 345 | const scrollDownSpeed = (event.clientY - scrollBottomLine) / (rootRect.bottom - scrollBottomLine); 346 | const scrollTopLine = rootRect.top + this.scrollAreaHeight; 347 | const scrollTopSpeed = (scrollTopLine - event.clientY) / (scrollTopLine - rootRect.top); 348 | 349 | if (scrollDownSpeed > 0) { 350 | this.startScroll(scrollDownSpeed); 351 | } else if (scrollTopSpeed > 0) { 352 | this.startScroll(-scrollTopSpeed) 353 | } else { 354 | this.stopScroll(); 355 | } 356 | }, 357 | 358 | getCursorPositionFromCoords(x, y) { 359 | const $target = document.elementFromPoint(x, y); 360 | const $nodeItem = $target.getAttribute('path') ? $target : this.getClosetElementWithPath($target); 361 | let destNode; 362 | let placement; 363 | 364 | if ($nodeItem) { 365 | 366 | if (!$nodeItem) return; 367 | 368 | destNode = this.getNode(JSON.parse($nodeItem.getAttribute('path'))); 369 | 370 | const nodeHeight = $nodeItem.offsetHeight; 371 | const edgeSize = this.edgeSize; 372 | const offsetY = y - $nodeItem.getBoundingClientRect().top; 373 | 374 | 375 | if (destNode.isLeaf) { 376 | placement = offsetY >= nodeHeight / 2 ? 'after' : 'before'; 377 | } else { 378 | if (offsetY <= edgeSize) { 379 | placement = 'before'; 380 | } else if (offsetY >= nodeHeight - edgeSize) { 381 | placement = 'after'; 382 | } else { 383 | placement = 'inside'; 384 | } 385 | } 386 | } else { 387 | const $root = this.getRoot().$el; 388 | const rootRect = $root.getBoundingClientRect(); 389 | if (y > rootRect.top + (rootRect.height / 2)) { 390 | placement = 'after'; 391 | destNode = this.getLastNode(); 392 | } else { 393 | placement = 'before'; 394 | destNode = this.getFirstNode(); 395 | } 396 | } 397 | 398 | return { node: destNode, placement }; 399 | }, 400 | 401 | getClosetElementWithPath($el) { 402 | if (!$el) return null; 403 | if ($el.getAttribute('path')) return $el; 404 | return this.getClosetElementWithPath($el.parentElement); 405 | }, 406 | 407 | onMouseleaveHandler(event) { 408 | if (!this.isRoot || !this.isDragging) return; 409 | const $root = this.getRoot().$el; 410 | const rootRect = $root.getBoundingClientRect(); 411 | if (event.clientY >= rootRect.bottom) { 412 | this.setCursorPosition({ node: this.nodes.slice(-1)[0], placement: 'after' }); 413 | } else if (event.clientY < rootRect.top) { 414 | this.setCursorPosition({ node: this.getFirstNode(), placement: 'before'}); 415 | } 416 | }, 417 | 418 | getNodeEl(path) { 419 | this.getRoot().$el.querySelector(`[path="${JSON.stringify(path)}"]`); 420 | }, 421 | 422 | getLastNode() { 423 | let lastNode = null; 424 | this.traverse((node) => { 425 | lastNode = node; 426 | }); 427 | return lastNode; 428 | }, 429 | 430 | getFirstNode() { 431 | return this.getNode([0]); 432 | }, 433 | 434 | getNextNode(path, filter = null) { 435 | 436 | let resultNode = null; 437 | 438 | this.traverse((node) => { 439 | if (this.comparePaths(node.path, path) < 1) return; 440 | 441 | if (!filter || filter(node)) { 442 | resultNode = node; 443 | return false; // stop traverse 444 | } 445 | 446 | }); 447 | 448 | return resultNode; 449 | }, 450 | 451 | getPrevNode(path, filter) { 452 | let prevNodes = []; 453 | 454 | this.traverse((node) => { 455 | if (this.comparePaths(node.path, path) >= 0) { 456 | return false; 457 | } 458 | prevNodes.push(node); 459 | }); 460 | 461 | let i = prevNodes.length; 462 | while (i--) { 463 | const node = prevNodes[i]; 464 | if (!filter || filter(node)) return node; 465 | } 466 | 467 | return null; 468 | }, 469 | 470 | /** 471 | * returns 1 if path1 > path2 472 | * returns -1 if path1 < path2 473 | * returns 0 if path1 == path2 474 | * 475 | * examples 476 | * 477 | * [1, 2, 3] < [1, 2, 4] 478 | * [1, 1, 3] < [1, 2, 3] 479 | * [1, 2, 3] > [1, 2, 0] 480 | * [1, 2, 3] > [1, 1, 3] 481 | * [1, 2] < [1, 2, 0] 482 | * 483 | */ 484 | comparePaths(path1, path2) { 485 | for (let i = 0; i < path1.length; i++) { 486 | if (path2[i] == void 0) return 1; 487 | if (path1[i] > path2[i]) return 1; 488 | if (path1[i] < path2[i]) return -1; 489 | } 490 | return path2[path1.length] == void 0 ? 0 : -1; 491 | }, 492 | 493 | onNodeMousedownHandler(event, node) { 494 | // handle only left mouse button 495 | if (event.button !== 0) return; 496 | 497 | if (!this.isRoot) { 498 | this.getRoot().onNodeMousedownHandler(event, node); 499 | return; 500 | } 501 | this.mouseIsDown = true; 502 | }, 503 | 504 | 505 | startScroll(speed) { 506 | const $root = this.getRoot().$el; 507 | if (this.scrollSpeed === speed) { 508 | return; 509 | } else if (this.scrollIntervalId) { 510 | this.stopScroll(); 511 | } 512 | 513 | this.scrollSpeed = speed; 514 | this.scrollIntervalId = setInterval(() => { 515 | $root.scrollTop += this.maxScrollSpeed * speed; 516 | }, 20); 517 | }, 518 | 519 | stopScroll() { 520 | clearInterval(this.scrollIntervalId); 521 | this.scrollIntervalId = 0; 522 | this.scrollSpeed = 0; 523 | }, 524 | 525 | onDocumentMouseupHandler(event) { 526 | if (this.isDragging) this.onNodeMouseupHandler(event); 527 | }, 528 | 529 | onNodeMouseupHandler(event, targetNode = null) { 530 | 531 | // handle only left mouse button 532 | if (event.button !== 0) return; 533 | 534 | if (!this.isRoot) { 535 | this.getRoot().onNodeMouseupHandler(event, targetNode); 536 | return; 537 | } 538 | 539 | this.mouseIsDown = false; 540 | 541 | if (!this.isDragging && targetNode && !this.preventDrag) { 542 | this.select(targetNode.path, false, event); 543 | } 544 | 545 | this.preventDrag = false; 546 | 547 | if (!this.cursorPosition) { 548 | this.stopDrag(); 549 | return; 550 | }; 551 | 552 | 553 | const draggingNodes = this.getDraggable(); 554 | 555 | // check that nodes is possible to insert 556 | for (let draggingNode of draggingNodes) { 557 | if (draggingNode.pathStr == this.cursorPosition.node.pathStr) { 558 | this.stopDrag(); 559 | return; 560 | } 561 | 562 | if (this.checkNodeIsParent(draggingNode, this.cursorPosition.node)) { 563 | this.stopDrag(); 564 | return; 565 | } 566 | } 567 | 568 | const newNodes = this.copy(this.currentValue); 569 | const nodeModelsSubjectToInsert = []; 570 | 571 | // find dragging model to delete 572 | for (let draggingNode of draggingNodes) { 573 | const sourceSiblings = this.getNodeSiblings(newNodes, draggingNode.path); 574 | const draggingNodeModel = sourceSiblings[draggingNode.ind]; 575 | nodeModelsSubjectToInsert.push(draggingNodeModel); 576 | } 577 | 578 | // allow the drop to be cancelled 579 | let cancelled = false; 580 | this.emitBeforeDrop(draggingNodes, this.cursorPosition, () => cancelled = true); 581 | 582 | if (cancelled) { 583 | this.stopDrag(); 584 | return; 585 | } 586 | 587 | const nodeModelsToInsert = []; 588 | 589 | // mark dragging model to delete 590 | for (let draggingNodeModel of nodeModelsSubjectToInsert) { 591 | nodeModelsToInsert.push(this.copy(draggingNodeModel)); 592 | draggingNodeModel['_markToDelete'] = true; 593 | } 594 | 595 | // insert dragging nodes to the new place 596 | this.insertModels(this.cursorPosition, nodeModelsToInsert, newNodes); 597 | 598 | 599 | // delete dragging node from the old place 600 | this.traverseModels((nodeModel, siblings, ind) => { 601 | if (!nodeModel._markToDelete) return; 602 | siblings.splice(ind, 1); 603 | }, newNodes); 604 | 605 | 606 | this.lastSelectedNode = null; 607 | this.emitInput(newNodes); 608 | this.emitDrop(draggingNodes, this.cursorPosition, event); 609 | this.stopDrag(); 610 | }, 611 | 612 | 613 | onToggleHandler(event, node) { 614 | if (!this.allowToggleBranch) return; 615 | 616 | this.updateNode(node.path, { isExpanded: !node.isExpanded }); 617 | this.emitToggle(node, event); 618 | event.stopPropagation(); 619 | }, 620 | 621 | stopDrag() { 622 | this.isDragging = false; 623 | this.mouseIsDown = false; 624 | this.setCursorPosition(null); 625 | this.stopScroll(); 626 | }, 627 | 628 | 629 | getParent() { 630 | return this.$parent; 631 | }, 632 | 633 | getRoot() { 634 | if (this.isRoot) return this; 635 | return this.getParent().getRoot(); 636 | }, 637 | 638 | getNodeSiblings(nodes, path) { 639 | if (path.length === 1) return nodes; 640 | return this.getNodeSiblings(nodes[path[0]].children, path.slice(1)); 641 | }, 642 | 643 | 644 | updateNode(path, patch) { 645 | if (!this.isRoot) { 646 | this.getParent().updateNode(path, patch); 647 | return; 648 | } 649 | 650 | const pathStr = JSON.stringify(path); 651 | const newNodes = this.copy(this.currentValue); 652 | this.traverse((node, nodeModel) => { 653 | if (node.pathStr !== pathStr) return; 654 | Object.assign(nodeModel, patch); 655 | }, newNodes); 656 | 657 | this.emitInput(newNodes); 658 | }, 659 | 660 | getSelected() { 661 | const selectedNodes = []; 662 | this.traverse((node) => { 663 | if (node.isSelected) selectedNodes.push(node); 664 | }); 665 | return selectedNodes; 666 | }, 667 | 668 | getDraggable() { 669 | const selectedNodes = []; 670 | this.traverse((node) => { 671 | if (node.isSelected && node.isDraggable) selectedNodes.push(node); 672 | }); 673 | return selectedNodes; 674 | }, 675 | 676 | 677 | traverse( 678 | cb, 679 | nodeModels = null, 680 | parentPath = [] 681 | ) { 682 | if (!nodeModels) nodeModels = this.currentValue; 683 | 684 | let shouldStop = false; 685 | 686 | const nodes = []; 687 | 688 | for (let nodeInd = 0; nodeInd < nodeModels.length; nodeInd++) { 689 | const nodeModel = nodeModels[nodeInd]; 690 | const itemPath = parentPath.concat(nodeInd); 691 | const node = this.getNode(itemPath, nodeModel, nodeModels); 692 | shouldStop = cb(node, nodeModel, nodeModels) === false; 693 | nodes.push(node); 694 | 695 | if (shouldStop) break; 696 | 697 | if (nodeModel.children) { 698 | shouldStop = this.traverse(cb, nodeModel.children, itemPath) === false; 699 | if (shouldStop) break; 700 | } 701 | } 702 | 703 | return !shouldStop ? nodes : false; 704 | }, 705 | 706 | traverseModels(cb, nodeModels) { 707 | let i = nodeModels.length; 708 | while (i--) { 709 | const nodeModel = nodeModels[i]; 710 | if (nodeModel.children) this.traverseModels(cb, nodeModel.children); 711 | cb(nodeModel, nodeModels, i); 712 | } 713 | return nodeModels; 714 | }, 715 | 716 | remove(paths) { 717 | const pathsStr = paths.map(path => JSON.stringify(path)); 718 | const newNodes = this.copy(this.currentValue); 719 | this.traverse( (node, nodeModel, siblings) => { 720 | for (const pathStr of pathsStr) { 721 | if (node.pathStr === pathStr) nodeModel._markToDelete = true; 722 | } 723 | }, newNodes); 724 | 725 | this.traverseModels((nodeModel, siblings, ind) => { 726 | if (!nodeModel._markToDelete) return; 727 | siblings.splice(ind, 1); 728 | }, newNodes); 729 | 730 | this.emitInput(newNodes); 731 | }, 732 | 733 | insertModels(cursorPosition, nodeModels, newNodes) { 734 | const destNode = cursorPosition.node; 735 | const destSiblings = this.getNodeSiblings(newNodes, destNode.path); 736 | const destNodeModel = destSiblings[destNode.ind]; 737 | 738 | if (cursorPosition.placement === 'inside') { 739 | destNodeModel.children = destNodeModel.children || []; 740 | destNodeModel.children.unshift(...nodeModels); 741 | } else { 742 | const insertInd = cursorPosition.placement === 'before' ? 743 | destNode.ind : 744 | destNode.ind + 1; 745 | 746 | destSiblings.splice(insertInd, 0, ...nodeModels); 747 | } 748 | }, 749 | 750 | insert(cursorPosition, nodeModel) { 751 | const nodeModels = Array.isArray(nodeModel) ? nodeModel : [nodeModel]; 752 | const newNodes = this.copy(this.currentValue); 753 | 754 | this.insertModels(cursorPosition, nodeModels, newNodes); 755 | 756 | this.emitInput(newNodes); 757 | }, 758 | 759 | checkNodeIsParent(sourceNode, destNode) { 760 | const destPath = destNode.path; 761 | return JSON.stringify(destPath.slice(0, sourceNode.path.length)) == sourceNode.pathStr; 762 | }, 763 | 764 | copy(entity) { 765 | return JSON.parse(JSON.stringify(entity)); 766 | } 767 | 768 | } 769 | }; 770 | -------------------------------------------------------------------------------- /dist/sl-vue-tree.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://SlVueTree/webpack/universalModuleDefinition","webpack://SlVueTree/webpack/bootstrap","webpack://SlVueTree/./src/sl-vue-tree.js","webpack://SlVueTree/./src/sl-vue-tree.vue?2ddf","webpack://SlVueTree/./src/sl-vue-tree.vue","webpack://SlVueTree/./node_modules/vue-loader/lib/runtime/component-normalizer.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","props","type","Array","default","edgeSize","Number","showBranches","Boolean","level","parentInd","allowMultiselect","allowToggleBranch","multiselectKey","String","validator","allowedKeys","multiselectKeys","isArray","filter","keyName","indexOf","length","scrollAreaHeight","maxScrollSpeed","data","rootCursorPosition","scrollIntervalId","scrollSpeed","lastSelectedNode","mouseIsDown","isDragging","lastMousePos","x","y","preventDrag","currentValue","this","mounted","isRoot","document","addEventListener","onDocumentMouseupHandler","beforeDestroy","removeEventListener","watch","newValue","computed","cursorPosition","getParent","depth","gaps","nodes","nodeModels","copy","getNodes","children","push","selectionSize","getSelected","dragSize","getDraggable","methods","setCursorPosition","pos","parentPath","isVisible","map","nodeModel","ind","nodePath","concat","getNode","path","siblings","slice","getNodeSiblings","isExpanded","isDraggable","isSelectable","node","title","isLeaf","isSelected","pathStr","JSON","stringify","isFirstChild","isLastChild","emitInput","getRoot","$emit","emitSelect","selectedNodes","event","emitBeforeDrop","draggingNodes","position","cancel","emitDrop","emitToggle","toggledNode","emitNodeClick","emitNodeDblclick","emitNodeContextmenu","onExternalDragoverHandler","preventDefault","getCursorPositionFromCoords","clientX","clientY","onExternalDropHandler","select","addToSelection","multiselectKeyIsPressed","find","selectedNode","newNodes","shiftSelectionMode","shiftKey","shiftSelectionStarted","traverse","onMousemoveHandler","initialDraggingState","isDragStarted","$root","$el","rootRect","getBoundingClientRect","$dragInfo","$refs","dragInfo","dragInfoTop","top","scrollTop","style","marginBottom","dragInfoLeft","left","destNode","placement","scrollBottomLine","bottom","scrollDownSpeed","scrollTopLine","scrollTopSpeed","startScroll","stopScroll","$target","elementFromPoint","$nodeItem","getAttribute","getClosetElementWithPath","parse","nodeHeight","offsetHeight","offsetY","height","getLastNode","getFirstNode","parentElement","onMouseleaveHandler","getNodeEl","querySelector","lastNode","getNextNode","resultNode","comparePaths","getPrevNode","prevNodes","path1","path2","onNodeMousedownHandler","button","speed","setInterval","clearInterval","onNodeMouseupHandler","targetNode","draggingNode","stopDrag","checkNodeIsParent","nodeModelsSubjectToInsert","sourceSiblings","draggingNodeModel","cancelled","nodeModelsToInsert","insertModels","traverseModels","_markToDelete","splice","onToggleHandler","updateNode","stopPropagation","$parent","patch","assign","cb","shouldStop","nodeInd","itemPath","remove","paths","pathsStr","destSiblings","destNodeModel","unshift","insertInd","insert","sourceNode","destPath","entity","render","_vm","_h","$createElement","_c","_self","staticClass","class","on","mousemove","mouseleave","dragend","$event","onDragendHandler","ref","_l","visibility","dragover","_v","attrs","mousedown","mouseup","contextmenu","dblclick","click","drop","gapInd","_t","_e","_s","fromCharCode","scopedSlots","_u","fn","directives","rawName","expression","_withStripped","Component","scriptExports","staticRenderFns","functionalTemplate","injectStyles","scopeId","moduleIdentifier","shadowMode","hook","options","_compiled","functional","_scopeId","context","$vnode","ssrContext","parent","__VUE_SSR_CONTEXT__","_registeredComponents","add","_ssrRegister","$options","shadowRoot","_injectStyles","originalRender","h","existing","beforeCreate","normalizeComponent","__file"],"mappings":"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","file":"sl-vue-tree.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"SlVueTree\"] = factory();\n\telse\n\t\troot[\"SlVueTree\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","\nexport default {\n name: 'sl-vue-tree',\n props: {\n value: {\n type: Array,\n default: () => []\n },\n edgeSize: {\n type: Number,\n default: 3\n },\n showBranches: {\n type: Boolean,\n default: false\n },\n level: {\n type: Number,\n default: 0\n },\n parentInd: {\n type: Number\n },\n allowMultiselect: {\n type: Boolean,\n default: true\n },\n allowToggleBranch: {\n type: Boolean,\n default: true\n },\n multiselectKey: {\n type: [String, Array],\n default: function () {\n return ['ctrlKey', 'metaKey']\n },\n validator: function (value) {\n let allowedKeys = ['ctrlKey', 'metaKey', 'altKey'];\n let multiselectKeys = Array.isArray(value) ? value : [value];\n multiselectKeys = multiselectKeys.filter(keyName => allowedKeys.indexOf(keyName ) !== -1);\n return !!multiselectKeys.length;\n }\n },\n scrollAreaHeight: {\n type: Number,\n default: 70\n },\n maxScrollSpeed: {\n type: Number,\n default: 20\n }\n },\n\n data() {\n return {\n rootCursorPosition: null,\n scrollIntervalId: 0,\n scrollSpeed: 0,\n lastSelectedNode: null,\n mouseIsDown: false,\n isDragging: false,\n lastMousePos: {x: 0, y: 0},\n preventDrag: false,\n currentValue: this.value\n };\n },\n\n mounted() {\n if (this.isRoot) {\n document.addEventListener('mouseup', this.onDocumentMouseupHandler);\n }\n },\n\n beforeDestroy() {\n document.removeEventListener('mouseup', this.onDocumentMouseupHandler);\n },\n\n watch: {\n value: function (newValue) {\n this.currentValue = newValue;\n }\n },\n\n computed: {\n cursorPosition() {\n if (this.isRoot) return this.rootCursorPosition;\n return this.getParent().cursorPosition;\n },\n\n depth() {\n return this.gaps.length\n },\n\n nodes() {\n if (this.isRoot) {\n const nodeModels = this.copy(this.currentValue);\n return this.getNodes(nodeModels);\n }\n\n return this.getParent().nodes[this.parentInd].children;\n },\n /**\n * gaps is using for nodes indentation\n * @returns {number[]}\n */\n gaps() {\n const gaps = [];\n let i = this.level - 1;\n if (!this.showBranches) i++;\n while (i-- > 0) gaps.push(i);\n return gaps;\n },\n\n isRoot() {\n return !this.level\n },\n\n selectionSize() {\n return this.getSelected().length;\n },\n\n dragSize() {\n return this.getDraggable().length;\n }\n },\n methods: {\n\n setCursorPosition(pos) {\n if (this.isRoot) {\n this.rootCursorPosition = pos;\n return;\n }\n this.getParent().setCursorPosition(pos);\n },\n\n getNodes(nodeModels, parentPath = [], isVisible = true) {\n\n return nodeModels.map((nodeModel, ind) => {\n const nodePath = parentPath.concat(ind);\n return this.getNode(nodePath, nodeModel, nodeModels, isVisible);\n })\n },\n\n getNode(\n path,\n nodeModel = null,\n siblings = null,\n isVisible = null\n ) {\n const ind = path.slice(-1)[0];\n\n // calculate nodeModel, siblings, isVisible fields if it is not passed as arguments\n siblings = siblings || this.getNodeSiblings(this.currentValue, path);\n nodeModel = nodeModel || (siblings && siblings[ind]) || null;\n\n if (isVisible == null) {\n isVisible = this.isVisible(path);\n }\n\n if (!nodeModel) return null;\n\n const isExpanded = nodeModel.isExpanded == void 0 ? true : !!nodeModel.isExpanded;\n const isDraggable = nodeModel.isDraggable == void 0 ? true : !!nodeModel.isDraggable;\n const isSelectable = nodeModel.isSelectable == void 0 ? true : !!nodeModel.isSelectable;\n\n const node = {\n\n // define the all ISlTreeNodeModel props\n title: nodeModel.title,\n isLeaf: !!nodeModel.isLeaf,\n children: nodeModel.children ? this.getNodes(nodeModel.children, path, isExpanded) : [],\n isSelected: !!nodeModel.isSelected,\n isExpanded,\n isVisible,\n isDraggable,\n isSelectable,\n data: nodeModel.data !== void 0 ? nodeModel.data : {},\n\n // define the all ISlTreeNode computed props\n path: path,\n pathStr: JSON.stringify(path),\n level: path.length,\n ind,\n isFirstChild: ind == 0,\n isLastChild: ind === siblings.length - 1\n };\n return node;\n },\n\n isVisible(path) {\n if (path.length < 2) return true;\n let nodeModels = this.currentValue;\n\n for (let i = 0; i < path.length - 1; i++) {\n let ind = path[i];\n let nodeModel = nodeModels[ind];\n let isExpanded = nodeModel.isExpanded == void 0 ? true : !!nodeModel.isExpanded;\n if (!isExpanded) return false;\n nodeModels = nodeModel.children;\n }\n\n return true;\n },\n\n emitInput(newValue) {\n this.currentValue = newValue;\n this.getRoot().$emit('input', newValue);\n },\n\n emitSelect(selectedNodes, event) {\n this.getRoot().$emit('select', selectedNodes, event);\n },\n\n emitBeforeDrop(draggingNodes, position, cancel) {\n this.getRoot().$emit('beforedrop', draggingNodes, position, cancel);\n },\n\n emitDrop(draggingNodes, position, event) {\n this.getRoot().$emit('drop', draggingNodes, position, event);\n },\n\n emitToggle(toggledNode, event) {\n this.getRoot().$emit('toggle', toggledNode, event);\n },\n\n emitNodeClick(node, event) {\n this.getRoot().$emit('nodeclick', node, event);\n },\n\n emitNodeDblclick(node, event) {\n this.getRoot().$emit('nodedblclick', node, event);\n },\n\n emitNodeContextmenu(node, event) {\n this.getRoot().$emit('nodecontextmenu', node, event);\n },\n\n onExternalDragoverHandler(node, event) {\n event.preventDefault();\n const root = this.getRoot();\n const cursorPosition = root.getCursorPositionFromCoords(event.clientX, event.clientY);\n root.setCursorPosition(cursorPosition);\n root.$emit('externaldragover', cursorPosition, event);\n },\n\n onExternalDropHandler(node, event) {\n const root = this.getRoot();\n const cursorPosition = root.getCursorPositionFromCoords(event.clientX, event.clientY);\n root.$emit('externaldrop', cursorPosition, event);\n this.setCursorPosition(null);\n },\n\n select(path, addToSelection = false, event = null) {\n const multiselectKeys = Array.isArray(this.multiselectKey) ?\n this.multiselectKey:\n [this.multiselectKey];\n const multiselectKeyIsPressed = event && !!multiselectKeys.find(key => event[key]);\n addToSelection = (multiselectKeyIsPressed || addToSelection) && this.allowMultiselect ;\n\n const selectedNode = this.getNode(path);\n if (!selectedNode) return null;\n const newNodes = this.copy(this.currentValue);\n const shiftSelectionMode = this.allowMultiselect && event && event.shiftKey && this.lastSelectedNode;\n const selectedNodes = [];\n let shiftSelectionStarted = false;\n\n this.traverse((node, nodeModel) => {\n\n\n if (shiftSelectionMode) {\n if (node.pathStr === selectedNode.pathStr || node.pathStr === this.lastSelectedNode.pathStr) {\n nodeModel.isSelected = node.isSelectable;\n shiftSelectionStarted = !shiftSelectionStarted;\n }\n if (shiftSelectionStarted) nodeModel.isSelected = node.isSelectable;\n } else if (node.pathStr === selectedNode.pathStr) {\n nodeModel.isSelected = node.isSelectable;\n } else if (!addToSelection) {\n if (nodeModel.isSelected) nodeModel.isSelected = false;\n }\n\n if (nodeModel.isSelected) selectedNodes.push(node);\n\n }, newNodes);\n\n\n this.lastSelectedNode = selectedNode;\n this.emitInput(newNodes);\n this.emitSelect(selectedNodes, event);\n return selectedNode;\n },\n\n onMousemoveHandler(event) {\n if (!this.isRoot) {\n this.getRoot().onMousemoveHandler(event);\n return;\n }\n\n if (this.preventDrag) return;\n\n const initialDraggingState = this.isDragging;\n const isDragging =\n this.isDragging || (\n this.mouseIsDown &&\n (this.lastMousePos.x !== event.clientX || this.lastMousePos.y !== event.clientY)\n );\n\n const isDragStarted = initialDraggingState === false && isDragging === true;\n\n this.lastMousePos = {\n x: event.clientX,\n y: event.clientY\n };\n\n if (!isDragging) return;\n\n const $root = this.getRoot().$el;\n const rootRect = $root.getBoundingClientRect();\n const $dragInfo = this.$refs.dragInfo;\n const dragInfoTop = (event.clientY - rootRect.top + $root.scrollTop - ($dragInfo.style.marginBottom | 0) );\n const dragInfoLeft = (event.clientX - rootRect.left);\n\n $dragInfo.style.top = dragInfoTop + 'px';\n $dragInfo.style.left = dragInfoLeft + 'px';\n\n const cursorPosition = this.getCursorPositionFromCoords(event.clientX, event.clientY);\n const destNode = cursorPosition.node;\n const placement = cursorPosition.placement;\n\n if (isDragStarted && !destNode.isSelected) {\n this.select(destNode.path, false, event);\n }\n\n const draggableNodes = this.getDraggable();\n if (!draggableNodes.length) {\n this.preventDrag = true;\n return;\n }\n\n this.isDragging = isDragging;\n\n this.setCursorPosition({ node: destNode, placement });\n\n const scrollBottomLine = rootRect.bottom - this.scrollAreaHeight;\n const scrollDownSpeed = (event.clientY - scrollBottomLine) / (rootRect.bottom - scrollBottomLine);\n const scrollTopLine = rootRect.top + this.scrollAreaHeight;\n const scrollTopSpeed = (scrollTopLine - event.clientY) / (scrollTopLine - rootRect.top);\n\n if (scrollDownSpeed > 0) {\n this.startScroll(scrollDownSpeed);\n } else if (scrollTopSpeed > 0) {\n this.startScroll(-scrollTopSpeed)\n } else {\n this.stopScroll();\n }\n },\n\n getCursorPositionFromCoords(x, y) {\n const $target = document.elementFromPoint(x, y);\n const $nodeItem = $target.getAttribute('path') ? $target : this.getClosetElementWithPath($target);\n let destNode;\n let placement;\n\n if ($nodeItem) {\n\n if (!$nodeItem) return;\n\n destNode = this.getNode(JSON.parse($nodeItem.getAttribute('path')));\n\n const nodeHeight = $nodeItem.offsetHeight;\n const edgeSize = this.edgeSize;\n const offsetY = y - $nodeItem.getBoundingClientRect().top;\n\n\n if (destNode.isLeaf) {\n placement = offsetY >= nodeHeight / 2 ? 'after' : 'before';\n } else {\n if (offsetY <= edgeSize) {\n placement = 'before';\n } else if (offsetY >= nodeHeight - edgeSize) {\n placement = 'after';\n } else {\n placement = 'inside';\n }\n }\n } else {\n const $root = this.getRoot().$el;\n const rootRect = $root.getBoundingClientRect();\n if (y > rootRect.top + (rootRect.height / 2)) {\n placement = 'after';\n destNode = this.getLastNode();\n } else {\n placement = 'before';\n destNode = this.getFirstNode();\n }\n }\n\n return { node: destNode, placement };\n },\n\n getClosetElementWithPath($el) {\n if (!$el) return null;\n if ($el.getAttribute('path')) return $el;\n return this.getClosetElementWithPath($el.parentElement);\n },\n\n onMouseleaveHandler(event) {\n if (!this.isRoot || !this.isDragging) return;\n const $root = this.getRoot().$el;\n const rootRect = $root.getBoundingClientRect();\n if (event.clientY >= rootRect.bottom) {\n this.setCursorPosition({ node: this.nodes.slice(-1)[0], placement: 'after' });\n } else if (event.clientY < rootRect.top) {\n this.setCursorPosition({ node: this.getFirstNode(), placement: 'before'});\n }\n },\n\n getNodeEl(path) {\n this.getRoot().$el.querySelector(`[path=\"${JSON.stringify(path)}\"]`);\n },\n\n getLastNode() {\n let lastNode = null;\n this.traverse((node) => {\n lastNode = node;\n });\n return lastNode;\n },\n\n getFirstNode() {\n return this.getNode([0]);\n },\n\n getNextNode(path, filter = null) {\n\n let resultNode = null;\n\n this.traverse((node) => {\n if (this.comparePaths(node.path, path) < 1) return;\n\n if (!filter || filter(node)) {\n resultNode = node;\n return false; // stop traverse\n }\n\n });\n\n return resultNode;\n },\n\n getPrevNode(path, filter) {\n let prevNodes = [];\n\n this.traverse((node) => {\n if (this.comparePaths(node.path, path) >= 0) {\n return false;\n }\n prevNodes.push(node);\n });\n\n let i = prevNodes.length;\n while (i--) {\n const node = prevNodes[i];\n if (!filter || filter(node)) return node;\n }\n\n return null;\n },\n\n /**\n * returns 1 if path1 > path2\n * returns -1 if path1 < path2\n * returns 0 if path1 == path2\n *\n * examples\n *\n * [1, 2, 3] < [1, 2, 4]\n * [1, 1, 3] < [1, 2, 3]\n * [1, 2, 3] > [1, 2, 0]\n * [1, 2, 3] > [1, 1, 3]\n * [1, 2] < [1, 2, 0]\n *\n */\n comparePaths(path1, path2) {\n for (let i = 0; i < path1.length; i++) {\n if (path2[i] == void 0) return 1;\n if (path1[i] > path2[i]) return 1;\n if (path1[i] < path2[i]) return -1;\n }\n return path2[path1.length] == void 0 ? 0 : -1;\n },\n\n onNodeMousedownHandler(event, node) {\n // handle only left mouse button\n if (event.button !== 0) return;\n\n if (!this.isRoot) {\n this.getRoot().onNodeMousedownHandler(event, node);\n return;\n }\n this.mouseIsDown = true;\n },\n\n\n startScroll(speed) {\n const $root = this.getRoot().$el;\n if (this.scrollSpeed === speed) {\n return;\n } else if (this.scrollIntervalId) {\n this.stopScroll();\n }\n\n this.scrollSpeed = speed;\n this.scrollIntervalId = setInterval(() => {\n $root.scrollTop += this.maxScrollSpeed * speed;\n }, 20);\n },\n\n stopScroll() {\n clearInterval(this.scrollIntervalId);\n this.scrollIntervalId = 0;\n this.scrollSpeed = 0;\n },\n\n onDocumentMouseupHandler(event) {\n if (this.isDragging) this.onNodeMouseupHandler(event);\n },\n\n onNodeMouseupHandler(event, targetNode = null) {\n\n // handle only left mouse button\n if (event.button !== 0) return;\n\n if (!this.isRoot) {\n this.getRoot().onNodeMouseupHandler(event, targetNode);\n return;\n }\n\n this.mouseIsDown = false;\n\n if (!this.isDragging && targetNode && !this.preventDrag) {\n this.select(targetNode.path, false, event);\n }\n\n this.preventDrag = false;\n\n if (!this.cursorPosition) {\n this.stopDrag();\n return;\n };\n\n\n const draggingNodes = this.getDraggable();\n\n // check that nodes is possible to insert\n for (let draggingNode of draggingNodes) {\n if (draggingNode.pathStr == this.cursorPosition.node.pathStr) {\n this.stopDrag();\n return;\n }\n\n if (this.checkNodeIsParent(draggingNode, this.cursorPosition.node)) {\n this.stopDrag();\n return;\n }\n }\n\n const newNodes = this.copy(this.currentValue);\n const nodeModelsSubjectToInsert = [];\n\n // find dragging model to delete\n for (let draggingNode of draggingNodes) {\n const sourceSiblings = this.getNodeSiblings(newNodes, draggingNode.path);\n const draggingNodeModel = sourceSiblings[draggingNode.ind];\n nodeModelsSubjectToInsert.push(draggingNodeModel);\n }\n\n // allow the drop to be cancelled\n let cancelled = false;\n this.emitBeforeDrop(draggingNodes, this.cursorPosition, () => cancelled = true);\n\n if (cancelled) {\n this.stopDrag();\n return;\n }\n\n const nodeModelsToInsert = [];\n\n // mark dragging model to delete\n for (let draggingNodeModel of nodeModelsSubjectToInsert) {\n nodeModelsToInsert.push(this.copy(draggingNodeModel));\n draggingNodeModel['_markToDelete'] = true;\n }\n\n // insert dragging nodes to the new place\n this.insertModels(this.cursorPosition, nodeModelsToInsert, newNodes);\n\n\n // delete dragging node from the old place\n this.traverseModels((nodeModel, siblings, ind) => {\n if (!nodeModel._markToDelete) return;\n siblings.splice(ind, 1);\n }, newNodes);\n\n\n this.lastSelectedNode = null;\n this.emitInput(newNodes);\n this.emitDrop(draggingNodes, this.cursorPosition, event);\n this.stopDrag();\n },\n\n\n onToggleHandler(event, node) {\n if (!this.allowToggleBranch) return;\n\n this.updateNode(node.path, { isExpanded: !node.isExpanded });\n this.emitToggle(node, event);\n event.stopPropagation();\n },\n\n stopDrag() {\n this.isDragging = false;\n this.mouseIsDown = false;\n this.setCursorPosition(null);\n this.stopScroll();\n },\n\n\n getParent() {\n return this.$parent;\n },\n\n getRoot() {\n if (this.isRoot) return this;\n return this.getParent().getRoot();\n },\n\n getNodeSiblings(nodes, path) {\n if (path.length === 1) return nodes;\n return this.getNodeSiblings(nodes[path[0]].children, path.slice(1));\n },\n\n\n updateNode(path, patch) {\n if (!this.isRoot) {\n this.getParent().updateNode(path, patch);\n return;\n }\n\n const pathStr = JSON.stringify(path);\n const newNodes = this.copy(this.currentValue);\n this.traverse((node, nodeModel) => {\n if (node.pathStr !== pathStr) return;\n Object.assign(nodeModel, patch);\n }, newNodes);\n\n this.emitInput(newNodes);\n },\n\n getSelected() {\n const selectedNodes = [];\n this.traverse((node) => {\n if (node.isSelected) selectedNodes.push(node);\n });\n return selectedNodes;\n },\n\n getDraggable() {\n const selectedNodes = [];\n this.traverse((node) => {\n if (node.isSelected && node.isDraggable) selectedNodes.push(node);\n });\n return selectedNodes;\n },\n\n\n traverse(\n cb,\n nodeModels = null,\n parentPath = []\n ) {\n if (!nodeModels) nodeModels = this.currentValue;\n\n let shouldStop = false;\n\n const nodes = [];\n\n for (let nodeInd = 0; nodeInd < nodeModels.length; nodeInd++) {\n const nodeModel = nodeModels[nodeInd];\n const itemPath = parentPath.concat(nodeInd);\n const node = this.getNode(itemPath, nodeModel, nodeModels);\n shouldStop = cb(node, nodeModel, nodeModels) === false;\n nodes.push(node);\n\n if (shouldStop) break;\n\n if (nodeModel.children) {\n shouldStop = this.traverse(cb, nodeModel.children, itemPath) === false;\n if (shouldStop) break;\n }\n }\n\n return !shouldStop ? nodes : false;\n },\n\n traverseModels(cb, nodeModels) {\n let i = nodeModels.length;\n while (i--) {\n const nodeModel = nodeModels[i];\n if (nodeModel.children) this.traverseModels(cb, nodeModel.children);\n cb(nodeModel, nodeModels, i);\n }\n return nodeModels;\n },\n\n remove(paths) {\n const pathsStr = paths.map(path => JSON.stringify(path));\n const newNodes = this.copy(this.currentValue);\n this.traverse( (node, nodeModel, siblings) => {\n for (const pathStr of pathsStr) {\n if (node.pathStr === pathStr) nodeModel._markToDelete = true;\n }\n }, newNodes);\n\n this.traverseModels((nodeModel, siblings, ind) => {\n if (!nodeModel._markToDelete) return;\n siblings.splice(ind, 1);\n }, newNodes);\n\n this.emitInput(newNodes);\n },\n\n insertModels(cursorPosition, nodeModels, newNodes) {\n const destNode = cursorPosition.node;\n const destSiblings = this.getNodeSiblings(newNodes, destNode.path);\n const destNodeModel = destSiblings[destNode.ind];\n\n if (cursorPosition.placement === 'inside') {\n destNodeModel.children = destNodeModel.children || [];\n destNodeModel.children.unshift(...nodeModels);\n } else {\n const insertInd = cursorPosition.placement === 'before' ?\n destNode.ind :\n destNode.ind + 1;\n\n destSiblings.splice(insertInd, 0, ...nodeModels);\n }\n },\n\n insert(cursorPosition, nodeModel) {\n const nodeModels = Array.isArray(nodeModel) ? nodeModel : [nodeModel];\n const newNodes = this.copy(this.currentValue);\n\n this.insertModels(cursorPosition, nodeModels, newNodes);\n\n this.emitInput(newNodes);\n },\n\n checkNodeIsParent(sourceNode, destNode) {\n const destPath = destNode.path;\n return JSON.stringify(destPath.slice(0, sourceNode.path.length)) == sourceNode.pathStr;\n },\n\n copy(entity) {\n return JSON.parse(JSON.stringify(entity));\n }\n\n }\n};\n","var render = function() {\n var _vm = this\n var _h = _vm.$createElement\n var _c = _vm._self._c || _h\n return _c(\n \"div\",\n {\n staticClass: \"sl-vue-tree\",\n class: { \"sl-vue-tree-root\": _vm.isRoot },\n on: {\n mousemove: _vm.onMousemoveHandler,\n mouseleave: _vm.onMouseleaveHandler,\n dragend: function($event) {\n _vm.onDragendHandler(null, $event)\n }\n }\n },\n [\n _c(\n \"div\",\n { ref: \"nodes\", staticClass: \"sl-vue-tree-nodes-list\" },\n [\n _vm._l(_vm.nodes, function(node, nodeInd) {\n return _c(\n \"div\",\n {\n staticClass: \"sl-vue-tree-node\",\n class: { \"sl-vue-tree-selected\": node.isSelected }\n },\n [\n _c(\"div\", {\n staticClass: \"sl-vue-tree-cursor sl-vue-tree-cursor_before\",\n style: {\n visibility:\n _vm.cursorPosition &&\n _vm.cursorPosition.node.pathStr === node.pathStr &&\n _vm.cursorPosition.placement === \"before\"\n ? \"visible\"\n : \"hidden\",\n \"--depth\": _vm.depth\n },\n on: {\n dragover: function($event) {\n $event.preventDefault()\n }\n }\n }),\n _vm._v(\" \"),\n _c(\n \"div\",\n {\n staticClass: \"sl-vue-tree-node-item\",\n class: {\n \"sl-vue-tree-cursor-hover\":\n _vm.cursorPosition &&\n _vm.cursorPosition.node.pathStr === node.pathStr,\n\n \"sl-vue-tree-cursor-inside\":\n _vm.cursorPosition &&\n _vm.cursorPosition.placement === \"inside\" &&\n _vm.cursorPosition.node.pathStr === node.pathStr,\n \"sl-vue-tree-node-is-leaf\": node.isLeaf,\n \"sl-vue-tree-node-is-folder\": !node.isLeaf\n },\n attrs: { path: node.pathStr },\n on: {\n mousedown: function($event) {\n _vm.onNodeMousedownHandler($event, node)\n },\n mouseup: function($event) {\n _vm.onNodeMouseupHandler($event, node)\n },\n contextmenu: function($event) {\n _vm.emitNodeContextmenu(node, $event)\n },\n dblclick: function($event) {\n _vm.emitNodeDblclick(node, $event)\n },\n click: function($event) {\n _vm.emitNodeClick(node, $event)\n },\n dragover: function($event) {\n _vm.onExternalDragoverHandler(node, $event)\n },\n drop: function($event) {\n _vm.onExternalDropHandler(node, $event)\n }\n }\n },\n [\n _vm._l(_vm.gaps, function(gapInd) {\n return _c(\"div\", { staticClass: \"sl-vue-tree-gap\" })\n }),\n _vm._v(\" \"),\n _vm.level && _vm.showBranches\n ? _c(\n \"div\",\n { staticClass: \"sl-vue-tree-branch\" },\n [\n _vm._t(\n \"branch\",\n [\n !node.isLastChild\n ? _c(\"span\", [\n _vm._v(\n \"\\n \" +\n _vm._s(String.fromCharCode(0x251c)) +\n _vm._s(String.fromCharCode(0x2500)) +\n \" \\n \"\n )\n ])\n : _vm._e(),\n _vm._v(\" \"),\n node.isLastChild\n ? _c(\"span\", [\n _vm._v(\n \"\\n \" +\n _vm._s(String.fromCharCode(0x2514)) +\n _vm._s(String.fromCharCode(0x2500)) +\n \" \\n \"\n )\n ])\n : _vm._e()\n ],\n { node: node }\n )\n ],\n 2\n )\n : _vm._e(),\n _vm._v(\" \"),\n _c(\n \"div\",\n { staticClass: \"sl-vue-tree-title\" },\n [\n !node.isLeaf\n ? _c(\n \"span\",\n {\n staticClass: \"sl-vue-tree-toggle\",\n on: {\n click: function($event) {\n _vm.onToggleHandler($event, node)\n }\n }\n },\n [\n _vm._t(\n \"toggle\",\n [\n _c(\"span\", [\n _vm._v(\n \"\\n \" +\n _vm._s(\n !node.isLeaf\n ? node.isExpanded\n ? \"-\"\n : \"+\"\n : \"\"\n ) +\n \"\\n \"\n )\n ])\n ],\n { node: node }\n )\n ],\n 2\n )\n : _vm._e(),\n _vm._v(\" \"),\n _vm._t(\"title\", [_vm._v(_vm._s(node.title))], {\n node: node\n }),\n _vm._v(\" \"),\n !node.isLeaf &&\n node.children.length == 0 &&\n node.isExpanded\n ? _vm._t(\"empty-node\", null, { node: node })\n : _vm._e()\n ],\n 2\n ),\n _vm._v(\" \"),\n _c(\n \"div\",\n { staticClass: \"sl-vue-tree-sidebar\" },\n [_vm._t(\"sidebar\", null, { node: node })],\n 2\n )\n ],\n 2\n ),\n _vm._v(\" \"),\n node.children && node.children.length && node.isExpanded\n ? _c(\"sl-vue-tree\", {\n attrs: {\n value: node.children,\n level: node.level,\n parentInd: nodeInd,\n allowMultiselect: _vm.allowMultiselect,\n allowToggleBranch: _vm.allowToggleBranch,\n edgeSize: _vm.edgeSize,\n showBranches: _vm.showBranches\n },\n on: {\n dragover: function($event) {\n $event.preventDefault()\n }\n },\n scopedSlots: _vm._u([\n {\n key: \"title\",\n fn: function(ref) {\n var node = ref.node\n return [\n _vm._t(\"title\", [_vm._v(_vm._s(node.title))], {\n node: node\n })\n ]\n }\n },\n {\n key: \"toggle\",\n fn: function(ref) {\n var node = ref.node\n return [\n _vm._t(\n \"toggle\",\n [\n _c(\"span\", [\n _vm._v(\n \"\\n \" +\n _vm._s(\n !node.isLeaf\n ? node.isExpanded\n ? \"-\"\n : \"+\"\n : \"\"\n ) +\n \"\\n \"\n )\n ])\n ],\n { node: node }\n )\n ]\n }\n },\n {\n key: \"sidebar\",\n fn: function(ref) {\n var node = ref.node\n return [_vm._t(\"sidebar\", null, { node: node })]\n }\n },\n {\n key: \"empty-node\",\n fn: function(ref) {\n var node = ref.node\n return [\n !node.isLeaf &&\n node.children.length == 0 &&\n node.isExpanded\n ? _vm._t(\"empty-node\", null, { node: node })\n : _vm._e()\n ]\n }\n }\n ])\n })\n : _vm._e(),\n _vm._v(\" \"),\n _c(\"div\", {\n staticClass: \"sl-vue-tree-cursor sl-vue-tree-cursor_after\",\n style: {\n visibility:\n _vm.cursorPosition &&\n _vm.cursorPosition.node.pathStr === node.pathStr &&\n _vm.cursorPosition.placement === \"after\"\n ? \"visible\"\n : \"hidden\",\n \"--depth\": _vm.depth\n },\n on: {\n dragover: function($event) {\n $event.preventDefault()\n }\n }\n })\n ],\n 1\n )\n }),\n _vm._v(\" \"),\n _vm.isRoot\n ? _c(\n \"div\",\n {\n directives: [\n {\n name: \"show\",\n rawName: \"v-show\",\n value: _vm.isDragging,\n expression: \"isDragging\"\n }\n ],\n ref: \"dragInfo\",\n staticClass: \"sl-vue-tree-drag-info\"\n },\n [\n _vm._t(\"draginfo\", [\n _vm._v(\n \"\\n Items: \" +\n _vm._s(_vm.selectionSize) +\n \"\\n \"\n )\n ])\n ],\n 2\n )\n : _vm._e()\n ],\n 2\n )\n ]\n )\n}\nvar staticRenderFns = []\nrender._withStripped = true\nexport { render, staticRenderFns }\nif (module.hot) {\n module.hot.accept()\n if (module.hot.data) {\n require(\"vue-hot-reload-api\") .rerender(\"data-v-539decb0\", { render: render, staticRenderFns: staticRenderFns })\n }\n}","var disposed = false\n/* script */\nexport * from \"!!babel-loader!./sl-vue-tree.js\"\nimport __vue_script__ from \"!!babel-loader!./sl-vue-tree.js\"/* template */\nimport {render as __vue_render__, staticRenderFns as __vue_static_render_fns__} from \"!!../node_modules/vue-loader/lib/template-compiler/index?{\\\"id\\\":\\\"data-v-539decb0\\\",\\\"hasScoped\\\":false,\\\"optionsId\\\":\\\"0\\\",\\\"buble\\\":{\\\"transforms\\\":{}}}!../node_modules/vue-loader/lib/selector?type=template&index=0!./sl-vue-tree.vue\"\n/* template functional */\nvar __vue_template_functional__ = false\n/* styles */\nvar __vue_styles__ = null\n/* scopeId */\nvar __vue_scopeId__ = null\n/* moduleIdentifier (server only) */\nvar __vue_module_identifier__ = null\nimport normalizeComponent from \"!../node_modules/vue-loader/lib/runtime/component-normalizer\"\nvar Component = normalizeComponent(\n __vue_script__,\n __vue_render__,\n __vue_static_render_fns__,\n __vue_template_functional__,\n __vue_styles__,\n __vue_scopeId__,\n __vue_module_identifier__\n)\nComponent.options.__file = \"src/sl-vue-tree.vue\"\n\n/* hot reload */\nif (module.hot) {(function () {\n var hotAPI = require(\"vue-hot-reload-api\")\n hotAPI.install(require(\"vue\"), false)\n if (!hotAPI.compatible) return\n module.hot.accept()\n if (!module.hot.data) {\n hotAPI.createRecord(\"data-v-539decb0\", Component.options)\n } else {\n hotAPI.reload(\"data-v-539decb0\", Component.options)\n }\n module.hot.dispose(function (data) {\n disposed = true\n })\n})()}\n\nexport default Component.exports\n","/* globals __VUE_SSR_CONTEXT__ */\n\n// IMPORTANT: Do NOT use ES2015 features in this file (except for modules).\n// This module is a runtime utility for cleaner component module output and will\n// be included in the final webpack user bundle.\n\nexport default function normalizeComponent (\n scriptExports,\n render,\n staticRenderFns,\n functionalTemplate,\n injectStyles,\n scopeId,\n moduleIdentifier, /* server only */\n shadowMode /* vue-cli only */\n) {\n scriptExports = scriptExports || {}\n\n // ES6 modules interop\n var type = typeof scriptExports.default\n if (type === 'object' || type === 'function') {\n scriptExports = scriptExports.default\n }\n\n // Vue.extend constructor export interop\n var options = typeof scriptExports === 'function'\n ? scriptExports.options\n : scriptExports\n\n // render functions\n if (render) {\n options.render = render\n options.staticRenderFns = staticRenderFns\n options._compiled = true\n }\n\n // functional template\n if (functionalTemplate) {\n options.functional = true\n }\n\n // scopedId\n if (scopeId) {\n options._scopeId = scopeId\n }\n\n var hook\n if (moduleIdentifier) { // server build\n hook = function (context) {\n // 2.3 injection\n context =\n context || // cached call\n (this.$vnode && this.$vnode.ssrContext) || // stateful\n (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext) // functional\n // 2.2 with runInNewContext: true\n if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {\n context = __VUE_SSR_CONTEXT__\n }\n // inject component styles\n if (injectStyles) {\n injectStyles.call(this, context)\n }\n // register component module identifier for async chunk inferrence\n if (context && context._registeredComponents) {\n context._registeredComponents.add(moduleIdentifier)\n }\n }\n // used by ssr in case component is cached and beforeCreate\n // never gets called\n options._ssrRegister = hook\n } else if (injectStyles) {\n hook = shadowMode\n ? function () { injectStyles.call(this, this.$root.$options.shadowRoot) }\n : injectStyles\n }\n\n if (hook) {\n if (options.functional) {\n // for template-only hot-reload because in that case the render fn doesn't\n // go through the normalizer\n options._injectStyles = hook\n // register for functioal component in vue file\n var originalRender = options.render\n options.render = function renderWithStyleInjection (h, context) {\n hook.call(context)\n return originalRender(h, context)\n }\n } else {\n // inject component registration as beforeCreate hook\n var existing = options.beforeCreate\n options.beforeCreate = existing\n ? [].concat(existing, hook)\n : [hook]\n }\n }\n\n return {\n exports: scriptExports,\n options: options\n }\n}\n"],"sourceRoot":""} --------------------------------------------------------------------------------