| | |
| | | <template> |
| | | <li |
| | | role="treeitem" |
| | | :class="classes" |
| | | :draggable="draggable" |
| | | @dragstart.stop="onItemDragStart($event, _self, _self.model)" |
| | | @dragend.stop.prevent="onItemDragEnd($event, _self, _self.model)" |
| | | @dragover.stop.prevent="isDragEnter = true" |
| | | @dragenter.stop.prevent="isDragEnter = true" |
| | | @dragleave.stop.prevent="isDragEnter = false" |
| | | @drop.stop.prevent="handleItemDrop($event, _self, _self.model)" |
| | | > |
| | | <div role="presentation" :class="wholeRowClasses" v-if="isWholeRow"> </div> |
| | | <i class="tree-icon tree-ocl" role="presentation" @click="handleItemToggle"></i> |
| | | <div :class="anchorClasses" v-on="events"> |
| | | <i |
| | | class="tree-icon tree-checkbox" |
| | | role="presentation" |
| | | v-show="isShowCheckBox" |
| | | @click.stop="handleCheckbox($event)" |
| | | ></i> |
| | | <slot :vm="this" :model="model"> |
| | | <i :class="themeIconClasses" role="presentation" v-if="!model.loading"></i> |
| | | <span v-html="model[textFieldName]"></span> |
| | | </slot> |
| | | </div> |
| | | <ul role="group" ref="group" class="tree-children" v-if="isFolder" :style="groupStyle"> |
| | | <tree-item |
| | | v-for="(child, index) in model[childrenFieldName]" |
| | | :key="index" |
| | | :data="child" |
| | | :text-field-name="textFieldName" |
| | | :value-field-name="valueFieldName" |
| | | :children-field-name="childrenFieldName" |
| | | :item-events="itemEvents" |
| | | :whole-row="wholeRow" |
| | | :show-checkbox="showCheckbox" |
| | | :allow-transition="allowTransition" |
| | | :height="height" |
| | | :parent-item="model[childrenFieldName]" |
| | | :draggable="draggable" |
| | | :drag-over-background-color="dragOverBackgroundColor" |
| | | :on-item-click="onItemClick" |
| | | :on-item-toggle="onItemToggle" |
| | | :on-item-drag-start="onItemDragStart" |
| | | :on-item-drag-end="onItemDragEnd" |
| | | :on-item-drop="onItemDrop" |
| | | :on-checkbox-click="onCheckboxClick" |
| | | :klass=" |
| | | index === model[childrenFieldName].length - 1 ? 'tree-last' : '' |
| | | " |
| | | > |
| | | <template slot-scope="_"> |
| | | <slot :vm="_.vm" :model="_.model"> |
| | | <i :class="_.vm.themeIconClasses" role="presentation" v-if="!model.loading"></i> |
| | | <span v-html="_.model[textFieldName]"></span> |
| | | </slot> |
| | | </template> |
| | | </tree-item> |
| | | </ul> |
| | | </li> |
| | | </template> |
| | | |
| | | <script> |
| | | /* eslint-disable */ |
| | | export default { |
| | | name: "TreeItem", |
| | | props: { |
| | | data: { type: Object, required: true }, |
| | | textFieldName: { type: String }, |
| | | valueFieldName: { type: String }, |
| | | childrenFieldName: { type: String }, |
| | | itemEvents: { type: Object }, |
| | | wholeRow: { type: Boolean, default: false }, |
| | | showCheckbox: { type: Boolean, default: false }, |
| | | allowTransition: { type: Boolean, default: false }, |
| | | height: { type: Number, default: 24 }, |
| | | parentItem: { type: Array }, |
| | | draggable: { type: Boolean, default: false }, |
| | | dragOverBackgroundColor: { type: String }, |
| | | onItemClick: { |
| | | type: Function, |
| | | default: () => false |
| | | }, |
| | | onItemToggle: { |
| | | type: Function, |
| | | default: () => false |
| | | }, |
| | | onItemDragStart: { |
| | | type: Function, |
| | | default: () => false |
| | | }, |
| | | onItemDragEnd: { |
| | | type: Function, |
| | | default: () => false |
| | | }, |
| | | onItemDrop: { |
| | | type: Function, |
| | | default: () => false |
| | | }, |
| | | onCheckboxClick: { |
| | | type: Function, |
| | | default: () => false |
| | | }, |
| | | klass: String |
| | | }, |
| | | data() { |
| | | return { |
| | | isHover: false, |
| | | isDragEnter: false, |
| | | model: this.data, |
| | | maxHeight: 0, |
| | | events: {} |
| | | }; |
| | | }, |
| | | watch: { |
| | | isDragEnter(newValue) { |
| | | if (newValue) { |
| | | this.$el.style.backgroundColor = this.dragOverBackgroundColor; |
| | | } else { |
| | | this.$el.style.backgroundColor = "inherit"; |
| | | } |
| | | }, |
| | | data(newValue) { |
| | | this.model = newValue; |
| | | }, |
| | | "model.opened": { |
| | | handler: function(val, oldVal) { |
| | | this.onItemToggle(this, this.model); |
| | | this.handleGroupMaxHeight(); |
| | | }, |
| | | deep: true |
| | | } |
| | | }, |
| | | computed: { |
| | | isShowCheckBox() { |
| | | return this.showCheckbox && (this.isHover || this.model.selected); |
| | | }, |
| | | isFolder() { |
| | | return ( |
| | | this.model[this.childrenFieldName] && |
| | | this.model[this.childrenFieldName].length |
| | | ); |
| | | }, |
| | | classes() { |
| | | return [ |
| | | { "tree-node": true }, |
| | | { "tree-open": this.model.opened }, |
| | | { "tree-closed": !this.model.opened }, |
| | | { "tree-leaf": !this.isFolder }, |
| | | { "tree-loading": !!this.model.loading }, |
| | | { "tree-drag-enter": this.isDragEnter }, |
| | | { [this.klass]: !!this.klass } |
| | | ]; |
| | | }, |
| | | anchorClasses() { |
| | | return [ |
| | | { "tree-anchor": true }, |
| | | { "tree-disabled": this.model.disabled }, |
| | | { "tree-selected": this.model.selected }, |
| | | { "tree-hovered": this.isHover } |
| | | ]; |
| | | }, |
| | | wholeRowClasses() { |
| | | return [ |
| | | { "tree-wholerow": true }, |
| | | { "tree-wholerow-clicked": this.model.selected }, |
| | | { "tree-wholerow-hovered": this.isHover } |
| | | ]; |
| | | }, |
| | | themeIconClasses() { |
| | | return [ |
| | | { "tree-icon": true }, |
| | | { "tree-themeicon": true }, |
| | | { [this.model.icon]: !!this.model.icon }, |
| | | { "tree-themeicon-custom": !!this.model.icon } |
| | | ]; |
| | | }, |
| | | isWholeRow() { |
| | | if (this.wholeRow) { |
| | | if ( |
| | | this.$parent.model === undefined || |
| | | this.$parent.model.opened === true |
| | | ) { |
| | | return true; |
| | | } |
| | | } |
| | | |
| | | return false; |
| | | }, |
| | | groupStyle() { |
| | | return { |
| | | position: this.model.opened ? "" : "relative", |
| | | "max-height": !!this.allowTransition ? this.maxHeight + "px" : "", |
| | | "transition-duration": this.allowTransition |
| | | ? Math.ceil(this.model[this.childrenFieldName].length / 100) * 300 + |
| | | "ms" |
| | | : "", |
| | | "transition-property": !!this.allowTransition ? "max-height" : "", |
| | | display: this.allowTransition |
| | | ? "block" |
| | | : this.model.opened |
| | | ? "block" |
| | | : "none" |
| | | }; |
| | | } |
| | | }, |
| | | methods: { |
| | | handleItemToggle(e) { |
| | | if (this.isFolder) { |
| | | this.model.opened = !this.model.opened; |
| | | this.onItemToggle(this, this.model); |
| | | } |
| | | }, |
| | | handleGroupMaxHeight() { |
| | | if (this.allowTransition) { |
| | | let length = 0; |
| | | let childHeight = 0; |
| | | if (this.model.opened) { |
| | | length = this.$children.length; |
| | | for (let children of this.$children) { |
| | | childHeight += children.maxHeight; |
| | | } |
| | | } |
| | | this.maxHeight = length * this.height + childHeight; |
| | | if (this.$parent.$options._componentTag === "tree-item") { |
| | | this.$parent.handleGroupMaxHeight(); |
| | | } |
| | | } |
| | | }, |
| | | handleItemClick(e) { |
| | | if (this.model.disabled) return; |
| | | this.model.selected = !this.model.selected; |
| | | this.onItemClick(this, this.model, e); |
| | | }, |
| | | handleItemMouseOver() { |
| | | this.isHover = true; |
| | | }, |
| | | handleItemMouseOut() { |
| | | this.isHover = false; |
| | | }, |
| | | handleItemDrop(e, oriNode, oriItem) { |
| | | this.$el.style.backgroundColor = "inherit"; |
| | | this.onItemDrop(e, oriNode, oriItem); |
| | | }, |
| | | handleCheckbox(e) { |
| | | if (this.model.disabled) return; |
| | | this.model.selected = !this.model.selected; |
| | | this.onCheckboxClick(this, this.model, e); |
| | | } |
| | | }, |
| | | created() { |
| | | const self = this; |
| | | const events = { |
| | | click: this.handleItemClick, |
| | | mouseover: this.handleItemMouseOver, |
| | | mouseout: this.handleItemMouseOut |
| | | }; |
| | | for (let itemEvent in this.itemEvents) { |
| | | let itemEventCallback = this.itemEvents[itemEvent]; |
| | | if (events.hasOwnProperty(itemEvent)) { |
| | | let eventCallback = events[itemEvent]; |
| | | events[itemEvent] = function(event) { |
| | | eventCallback(self, self.model, event); |
| | | itemEventCallback(self, self.model, event); |
| | | }; |
| | | } else { |
| | | events[itemEvent] = function(event) { |
| | | itemEventCallback(self, self.model, event); |
| | | }; |
| | | } |
| | | } |
| | | this.events = events; |
| | | }, |
| | | mounted() { |
| | | this.handleGroupMaxHeight(); |
| | | } |
| | | }; |
| | | </script> |
| | | <template>
|
| | | <li
|
| | | role="treeitem"
|
| | | :class="classes"
|
| | | :draggable="draggable"
|
| | | @dragstart.stop="onItemDragStart($event, _self, _self.model)"
|
| | | @dragend.stop.prevent="onItemDragEnd($event, _self, _self.model)"
|
| | | @dragover.stop.prevent="isDragEnter = true"
|
| | | @dragenter.stop.prevent="isDragEnter = true"
|
| | | @dragleave.stop.prevent="isDragEnter = false"
|
| | | @drop.stop.prevent="handleItemDrop($event, _self, _self.model)"
|
| | | >
|
| | | <div role="presentation" :class="wholeRowClasses" v-if="isWholeRow">
|
| | |
|
| | | </div>
|
| | | <i
|
| | | class="tree-icon tree-ocl"
|
| | | role="presentation"
|
| | | @click="handleItemToggle"
|
| | | ></i>
|
| | | <div :class="anchorClasses" v-on="events">
|
| | | <i
|
| | | class="tree-icon tree-checkbox"
|
| | | role="presentation"
|
| | | v-show="isShowCheckBox"
|
| | | @click.stop="handleCheckbox($event)"
|
| | | ></i>
|
| | | <slot :vm="this" :model="model">
|
| | | <i
|
| | | :class="themeIconClasses"
|
| | | role="presentation"
|
| | | v-if="!model.loading"
|
| | | ></i>
|
| | | <span v-html="model[textFieldName]"></span>
|
| | | </slot>
|
| | | </div>
|
| | | <ul
|
| | | role="group"
|
| | | ref="group"
|
| | | class="tree-children"
|
| | | v-if="isFolder"
|
| | | :style="groupStyle"
|
| | | >
|
| | | <tree-item
|
| | | v-for="(child, index) in model[childrenFieldName]"
|
| | | :key="index"
|
| | | :data="child"
|
| | | :text-field-name="textFieldName"
|
| | | :value-field-name="valueFieldName"
|
| | | :children-field-name="childrenFieldName"
|
| | | :item-events="itemEvents"
|
| | | :whole-row="wholeRow"
|
| | | :show-checkbox="showCheckbox"
|
| | | :allow-transition="allowTransition"
|
| | | :height="height"
|
| | | :parent-item="model[childrenFieldName]"
|
| | | :draggable="draggable"
|
| | | :drag-over-background-color="dragOverBackgroundColor"
|
| | | :on-item-click="onItemClick"
|
| | | :on-item-toggle="onItemToggle"
|
| | | :on-item-drag-start="onItemDragStart"
|
| | | :on-item-drag-end="onItemDragEnd"
|
| | | :on-item-drop="onItemDrop"
|
| | | :on-checkbox-click="onCheckboxClick"
|
| | | :klass="
|
| | | index === model[childrenFieldName].length - 1 ? 'tree-last' : ''
|
| | | "
|
| | | >
|
| | | <template slot-scope="_">
|
| | | <slot :vm="_.vm" :model="_.model">
|
| | | <i
|
| | | :class="_.vm.themeIconClasses"
|
| | | role="presentation"
|
| | | v-if="!model.loading"
|
| | | ></i>
|
| | | <span v-html="_.model[textFieldName]"></span>
|
| | | </slot>
|
| | | </template>
|
| | | </tree-item>
|
| | | </ul>
|
| | | </li>
|
| | | </template>
|
| | |
|
| | | <script>
|
| | | /* eslint-disable */
|
| | | export default {
|
| | | name: "TreeItem",
|
| | | props: {
|
| | | data: { type: Object, required: true },
|
| | | textFieldName: { type: String },
|
| | | valueFieldName: { type: String },
|
| | | childrenFieldName: { type: String },
|
| | | itemEvents: { type: Object },
|
| | | wholeRow: { type: Boolean, default: false },
|
| | | showCheckbox: { type: Boolean, default: false },
|
| | | allowTransition: { type: Boolean, default: false },
|
| | | height: { type: Number, default: 24 },
|
| | | parentItem: { type: Array },
|
| | | draggable: { type: Boolean, default: false },
|
| | | dragOverBackgroundColor: { type: String },
|
| | | onItemClick: {
|
| | | type: Function,
|
| | | default: () => false,
|
| | | },
|
| | | onItemToggle: {
|
| | | type: Function,
|
| | | default: () => false,
|
| | | },
|
| | | onItemDragStart: {
|
| | | type: Function,
|
| | | default: () => false,
|
| | | },
|
| | | onItemDragEnd: {
|
| | | type: Function,
|
| | | default: () => false,
|
| | | },
|
| | | onItemDrop: {
|
| | | type: Function,
|
| | | default: () => false,
|
| | | },
|
| | | onCheckboxClick: {
|
| | | type: Function,
|
| | | default: () => false,
|
| | | },
|
| | | klass: String,
|
| | | },
|
| | | data() {
|
| | | return {
|
| | | isHover: false,
|
| | | isDragEnter: false,
|
| | | model: this.data,
|
| | | maxHeight: 0,
|
| | | events: {},
|
| | | };
|
| | | },
|
| | | watch: {
|
| | | isDragEnter(newValue) {
|
| | | if (newValue) {
|
| | | this.$el.style.backgroundColor = this.dragOverBackgroundColor;
|
| | | } else {
|
| | | this.$el.style.backgroundColor = "inherit";
|
| | | }
|
| | | },
|
| | | data(newValue) {
|
| | | this.model = newValue;
|
| | | },
|
| | | "model.opened": {
|
| | | handler: function (val, oldVal) {
|
| | | this.onItemToggle(this, this.model);
|
| | | this.handleGroupMaxHeight();
|
| | | },
|
| | | deep: true,
|
| | | },
|
| | | },
|
| | | computed: {
|
| | | isShowCheckBox() {
|
| | | return this.showCheckbox && (this.isHover || this.model.selected);
|
| | | },
|
| | | isFolder() {
|
| | | return (
|
| | | this.model[this.childrenFieldName] &&
|
| | | this.model[this.childrenFieldName].length
|
| | | );
|
| | | },
|
| | | classes() {
|
| | | return [
|
| | | { "tree-node": true },
|
| | | { "tree-open": this.model.opened },
|
| | | { "tree-closed": !this.model.opened },
|
| | | { "tree-leaf": !this.isFolder },
|
| | | { "tree-loading": !!this.model.loading },
|
| | | { "tree-drag-enter": this.isDragEnter },
|
| | | { [this.klass]: !!this.klass },
|
| | | ];
|
| | | },
|
| | | anchorClasses() {
|
| | | return [
|
| | | { "tree-anchor": true },
|
| | | { "tree-disabled": this.model.disabled },
|
| | | { "tree-selected": this.model.selected },
|
| | | { "tree-hovered": this.isHover },
|
| | | ];
|
| | | },
|
| | | wholeRowClasses() {
|
| | | return [
|
| | | { "tree-wholerow": true },
|
| | | { "tree-wholerow-clicked": this.model.selected },
|
| | | { "tree-wholerow-hovered": this.isHover },
|
| | | ];
|
| | | },
|
| | | themeIconClasses() {
|
| | | return [
|
| | | { "tree-icon": true },
|
| | | { "tree-themeicon": true },
|
| | | { [this.model.icon]: !!this.model.icon },
|
| | | { "tree-themeicon-custom": !!this.model.icon },
|
| | | ];
|
| | | },
|
| | | isWholeRow() {
|
| | | if (this.wholeRow) {
|
| | | if (
|
| | | this.$parent.model === undefined ||
|
| | | this.$parent.model.opened === true
|
| | | ) {
|
| | | return true;
|
| | | }
|
| | | }
|
| | |
|
| | | return false;
|
| | | },
|
| | | groupStyle() {
|
| | | return {
|
| | | position: this.model.opened ? "" : "relative",
|
| | | "max-height": !!this.allowTransition ? this.maxHeight + "px" : "",
|
| | | "transition-duration": this.allowTransition
|
| | | ? Math.ceil(this.model[this.childrenFieldName].length / 100) * 300 +
|
| | | "ms"
|
| | | : "",
|
| | | "transition-property": !!this.allowTransition ? "max-height" : "",
|
| | | display: this.allowTransition
|
| | | ? "block"
|
| | | : this.model.opened
|
| | | ? "block"
|
| | | : "none",
|
| | | };
|
| | | },
|
| | | },
|
| | | methods: {
|
| | | handleItemToggle(e) {
|
| | | if (this.isFolder) {
|
| | | this.model.opened = !this.model.opened;
|
| | | this.onItemToggle(this, this.model);
|
| | | }
|
| | | },
|
| | | handleGroupMaxHeight() {
|
| | | if (this.allowTransition) {
|
| | | let length = 0;
|
| | | let childHeight = 0;
|
| | | if (this.model.opened) {
|
| | | length = this.$children.length;
|
| | | for (let children of this.$children) {
|
| | | childHeight += children.maxHeight;
|
| | | }
|
| | | }
|
| | | this.maxHeight = length * this.height + childHeight;
|
| | | if (this.$parent.$options._componentTag === "tree-item") {
|
| | | this.$parent.handleGroupMaxHeight();
|
| | | }
|
| | | }
|
| | | },
|
| | | handleItemClick(e) {
|
| | | if (this.model.disabled) return;
|
| | | this.model.selected = !this.model.selected;
|
| | | this.onItemClick(this, this.model, e);
|
| | | },
|
| | | handleItemMouseOver() {
|
| | | this.isHover = true;
|
| | | },
|
| | | handleItemMouseOut() {
|
| | | this.isHover = false;
|
| | | },
|
| | | handleItemDrop(e, oriNode, oriItem) {
|
| | | this.$el.style.backgroundColor = "inherit";
|
| | | this.onItemDrop(e, oriNode, oriItem);
|
| | | },
|
| | | handleCheckbox(e) {
|
| | | if (this.model.disabled) return;
|
| | | this.model.selected = !this.model.selected;
|
| | | this.onCheckboxClick(this, this.model, e);
|
| | | },
|
| | | },
|
| | | created() {
|
| | | const self = this;
|
| | | const events = {
|
| | | click: this.handleItemClick,
|
| | | mouseover: this.handleItemMouseOver,
|
| | | mouseout: this.handleItemMouseOut,
|
| | | };
|
| | | for (let itemEvent in this.itemEvents) {
|
| | | let itemEventCallback = this.itemEvents[itemEvent];
|
| | | if (events.hasOwnProperty(itemEvent)) {
|
| | | let eventCallback = events[itemEvent];
|
| | | events[itemEvent] = function (event) {
|
| | | eventCallback(self, self.model, event);
|
| | | itemEventCallback(self, self.model, event);
|
| | | };
|
| | | } else {
|
| | | events[itemEvent] = function (event) {
|
| | | itemEventCallback(self, self.model, event);
|
| | | };
|
| | | }
|
| | | }
|
| | | this.events = events;
|
| | | },
|
| | | mounted() {
|
| | | this.handleGroupMaxHeight();
|
| | | },
|
| | | };
|
| | | </script>
|