| <!-- |
| ~ Licensed to the Apache Software Foundation (ASF) under one or more |
| ~ contributor license agreements. See the NOTICE file distributed with |
| ~ this work for additional information regarding copyright ownership. |
| ~ The ASF licenses this file to You under the Apache License, Version 2.0 |
| ~ (the "License"); you may not use this file except in compliance with |
| ~ the License. You may obtain a copy of the License at |
| ~ |
| ~ http://www.apache.org/licenses/LICENSE-2.0 |
| ~ |
| ~ Unless required by applicable law or agreed to in writing, software |
| ~ distributed under the License is distributed on an "AS IS" BASIS, |
| ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ~ See the License for the specific language governing permissions and |
| ~ limitations under the License. |
| --> |
| |
| |
| <template> |
| <div |
| v-show="node.visible" |
| :class="nodeClasses" |
| :fsType="fsType" |
| class="we-tree-node" |
| > |
| <div |
| :title="node.data.path" |
| :style="contentStyle" |
| class="we-tree-node__content" |
| @contextmenu.prevent.stop="handleContextMenu" |
| @click.stop="handleClick" |
| @keyup.stop="handleKeyUp" |
| @dblclick.stop="handleDblClick"> |
| <span v-if="expanded" class="fi-folder-o"/> |
| <span v-else :style="'color: ' + supportIcon(node).color" :class="[ supportIcon(node).className, supportIcon(node).icon ]" /> |
| <template v-if="node.isEditState"> |
| <div |
| :class="{'is-error': !inputValid}" |
| class="we-tree-node__edit"> |
| <input |
| ref="edit" |
| :value="node.label" |
| type="text" |
| @click.stop |
| @keyup.stop |
| @blur="endNodeEdit" |
| @keyup.enter.stop.prevent="endNodeEdit"> |
| <div |
| v-if="errorMsg" |
| class="we-tree-node__error">{{ errorMsg }}</div> |
| </div> |
| </template> |
| <template v-else-if="node.data && node.data.isFn"> |
| <div class="we-tree-node__checkbox"> |
| <input |
| v-model="node.data.load" |
| :value="node.data.name" |
| :disabled="node.data.disabled || (node.data.type==='self' && node.data.shared)" |
| type="checkbox" |
| @change="hanlderCheck"> |
| <view-modal :node="node.data"> |
| <span |
| :title="node.data.name" |
| :class="{expired: node.data.expire}">{{ node.data.name }}</span> |
| </view-modal> |
| </div> |
| </template> |
| <template v-else> |
| <span class="we-tree-node__label">{{ node.label }}</span> |
| </template> |
| </div> |
| <div |
| v-show="expanded" |
| class="we-tree-node__children"> |
| <we-tree-node |
| v-for="(child, index) in node.computedNodes" |
| :key="getNodeKey(child, index)" |
| :node="child" |
| :fs-type="fsType" |
| :highlight-path="highlightPath" |
| :currentNode="currentNode"/> |
| </div> |
| </div> |
| </template> |
| <script> |
| import mixin from './mixin.js'; |
| import viewModal from './functionView'; |
| import SUPPORTED_LANG_MODES from '@/common/config/scriptis.js'; |
| export default { |
| name: 'WeTreeNode', |
| components: { |
| viewModal, |
| }, |
| mixins: [mixin], |
| props: { |
| node: { |
| type: Object, |
| default: () => {}, |
| }, |
| currentNode: { |
| type: Object, |
| defalut: {} |
| } |
| }, |
| data() { |
| return { |
| tree: null, |
| expanded: false, |
| inputValid: true, |
| errorMsg: null, |
| nameList: [], |
| SUPPORTED_LANG_MODES |
| }; |
| }, |
| computed: { |
| isHasFileOpen() { |
| if (!this.highlightPath) return false; |
| const highlightList = this.highlightPath.split('/'); |
| // One-to-one correspondence between directories, all parent levels need to be recursively matched(目录一一对应,需递归匹配所有父层级) |
| let flag = false; |
| const checkName = (node) => { |
| const name = node.data.name; |
| const needToHighLighted = highlightList[node._level - 1]; |
| if (name === needToHighLighted) { |
| if (node.parent) { |
| checkName(node.parent); |
| } else { |
| flag = true; |
| } |
| } |
| }; |
| checkName(this.node); |
| return flag; |
| }, |
| nodeClasses() { |
| return { |
| 'is-expanded': this.expanded, |
| 'is-current': this.tree.store.currentNode === this.node, |
| 'is-actived': this.isHasFileOpen, |
| }; |
| }, |
| contentStyle() { |
| return { |
| 'padding-left': this.node._level * this.tree.indent + 'px', |
| }; |
| }, |
| }, |
| watch: { |
| 'node.isEditState'(val) { |
| if (val) { |
| this.$nextTick(() => { |
| this.$refs.edit && this.$refs.edit.focus(); |
| // set selected area(设置选中区域) |
| // When the index is -1, it is a folder, and all will be selected by default(index为-1时,是文件夹,会默认选中全部) |
| if (this.node.label) { |
| const index = this.node.label.lastIndexOf('.'); |
| this.$refs.edit.setSelectionRange(0, index); |
| } |
| }); |
| } |
| }, |
| 'node.data.expanded'(val) { |
| this.expanded = val; |
| }, |
| 'currentNode.isEditState'(val) { |
| if (this.currentNode.data.path === this.node.data.path && val) { |
| this.node.changeEditState(val); |
| } |
| } |
| }, |
| created() { |
| const parent = this.$parent; |
| this.tree = parent.isTree ? parent : parent.tree; |
| this.initData(); |
| this.initWatch(); |
| }, |
| methods: { |
| initData() { |
| this.node.isDirNull = true; |
| let treeData = null; |
| treeData = this.tree.data[0].children; |
| if (treeData) { |
| treeData.forEach((e) => { |
| if (e.isLeaf) { |
| this.nameList.push(e.name); // todo |
| } |
| }); |
| } |
| // The root directory is opened by default during initialization(初始化的时候默认打开根目录) |
| if (this.isRootDefaultOpen) { |
| this.expanded = true; |
| } |
| }, |
| initWatch() { |
| const nodeProps = this.tree.nodeProps || {}; |
| const propName = nodeProps.children || 'children'; |
| this.$watch(`node.data.${propName}`, () => { |
| this.node.updateChildren(); |
| }); |
| }, |
| handleContextMenu(e) { |
| const tree = this.tree; |
| const store = tree.store; |
| store.setCurrentNode(this.node); |
| this.nameList = []; |
| const nodeData = this.node.data; |
| const childrenKey = tree.nodeProps.children || 'children'; |
| const that = this; |
| if (nodeData && nodeData.children && nodeData.children.length) { |
| nodeData.children.forEach((node) => { |
| if (node.isLeaf) { |
| this.nameList.push(node.name); |
| } |
| }); |
| } else if (tree && tree.loadDataFn && !nodeData.isLeaf) { |
| tree.loadDataFn(this.node, (data) => { |
| if (data) { |
| that.$set(that.node.data, childrenKey, data); |
| tree.store.filter(); |
| } |
| }); |
| } |
| this.tree.$emit('node-contextmenu', e, { |
| nodeData, |
| node: this.node, |
| nameList: this.nameList, |
| }); |
| }, |
| handleClick(e) { |
| const store = this.tree.store; |
| store.setCurrentNode(this.node); |
| if (!this.node.isLeaf) { |
| if (this.expanded) { |
| this.expanded = false; |
| } else { |
| this.handleExpand(); |
| } |
| } |
| this.tree.$emit('node-click', e, { |
| nodeData: this.node.data, |
| node: this.node, |
| }); |
| }, |
| handleExpand() { |
| const tree = this.tree; |
| const childrenKey = tree.nodeProps.children || 'children'; |
| const that = this; |
| const children = that.node.data[childrenKey] || []; |
| // If there is children data, do not request(如果有children数据就不去请求) |
| if (tree && tree.loadDataFn && !children.length) { |
| tree.loadDataFn(this.node, (data) => { |
| if (data) { |
| that.$set(that.node.data, childrenKey, data); |
| this.$nextTick(() => { |
| tree.store.filter(); |
| }); |
| } |
| this.expanded = true; |
| }); |
| } else { |
| that.$set(that.node.data, childrenKey, children); |
| this.expanded = true; |
| tree.store.filter(); |
| } |
| }, |
| handleKeyUp(e) { |
| this.tree.$emit('node-keyup', e, { |
| nodeData: this.node.data, |
| node: this.node, |
| }); |
| }, |
| handleDblClick(e) { |
| if (this.node.isEditState) { |
| this.endNodeEdit(); |
| } else { |
| this.tree.$emit('node-dblclick', e, { |
| nodeData: this.node.data, |
| node: this.node, |
| }); |
| } |
| }, |
| endNodeEdit() { |
| if (!this.node.isEditState) return; |
| const oldLabel = this.node.label; |
| const newLabel = this.$refs.edit.value; |
| if (oldLabel === newLabel) { |
| this.node.changeEditState(false); |
| this.changeInputValid(true); |
| this.errorMsg = ''; |
| return; |
| } |
| if (this.tree.nodeEditValid) { |
| this.errorMsg = this.tree.nodeEditValid({ |
| label: newLabel, |
| node: this.node.data, |
| }); |
| // If the script type is sql or hql, it supports script modification suffix, and the modified suffix is correct(如果脚本类型是sql或者是hql是支持脚本修改后缀的,且修改的后缀是正确的) |
| const reg = /\.(hql|sql)$/i; |
| const newResult = reg.test(newLabel); |
| const oldResult = reg.test(oldLabel); |
| if (oldResult) { |
| if (newResult) { |
| this.errorMsg = ''; |
| } else { |
| this.errorMsg = '请填写正确后缀名'; |
| } |
| } |
| |
| if (this.errorMsg) { |
| this.node.changeEditState(true); |
| this.changeInputValid(false); |
| return; |
| } else { |
| this.node.changeEditState(false); |
| this.changeInputValid(true); |
| this.errorMsg = ''; |
| } |
| } |
| if (this.tree.beforeChange) { |
| this.tree.beforeChange({ |
| label: newLabel, |
| node: this.node.data, |
| }, (isExist) => { |
| if (!isExist) { |
| this.node.changeEditState(true); |
| this.changeInputValid(true); |
| } else { |
| this.changeInputValid(true); |
| this.errorMsg = ''; |
| const evName = this.node.isNew ? 'node-create' : 'node-edit'; |
| this.node.isNew = false; |
| this.node.changeEditState(false); |
| this.node.label = newLabel; |
| this.errorMsg = ''; |
| this.tree.$emit(evName, evName, { |
| nodeData: this.node.data, |
| node: this.node, |
| oldLabel, |
| }); |
| } |
| }); |
| } |
| }, |
| changeInputValid(valid) { |
| this.inputValid = valid; |
| }, |
| getNodeKey(node, index) { |
| const nodeKey = this.tree.nodeKey; |
| let key = index; |
| if (!node.data) { |
| return key; |
| } |
| if (nodeKey) { |
| key = node.data[nodeKey]; |
| } else { |
| key = node.data.name + index; |
| } |
| return key; |
| }, |
| hanlderCheck(e) { |
| this.tree.$emit('node-check', e, { |
| nodeData: this.node.data, |
| node: this.node, |
| }); |
| }, |
| supportIcon(node) { |
| const supportModes = this.SUPPORTED_LANG_MODES; |
| const match = supportModes.find((item) => item.rule.test(this.node.label)); |
| if (node.isLeaf && match) { |
| return { |
| className: 'is-leaf', |
| icon: match.logo, |
| color: match.color |
| } |
| } else if (node.isLeaf && !match && !node.data.isFn) { |
| return { |
| className: 'is-leaf', |
| icon: 'fi-file' |
| } |
| } else if (!node.isLeaf) { |
| return { |
| icon: 'fi-folder' |
| } |
| } else if (node.data.isFn) { |
| return { |
| className: 'is-checkbox', |
| } |
| } |
| }, |
| }, |
| }; |
| </script> |