Vulture/VApp/node_modules/vuetify/lib/components/VTreeview/VTreeview.mjs

350 lines
12 KiB
JavaScript

// @ts-nocheck
/* eslint-disable */
// Styles
import "./VTreeview.css";
// Types
// Components
import VTreeviewNode, { VTreeviewNodeProps } from "./VTreeviewNode.mjs"; // Mixins
import Themeable from "../../mixins/themeable.mjs";
import { provide as RegistrableProvide } from "../../mixins/registrable.mjs"; // Utils
import { arrayDiff, deepEqual, getObjectValueByPath } from "../../util/helpers.mjs";
import mixins from "../../util/mixins.mjs";
import { consoleWarn } from "../../util/console.mjs";
import { filterTreeItems, filterTreeItem } from "./util/filterTreeItems.mjs";
export default mixins(RegistrableProvide('treeview'), Themeable
/* @vue/component */).extend({
name: 'v-treeview',
provide() {
return {
treeview: this
};
},
props: {
active: {
type: Array,
default: () => []
},
dense: Boolean,
disabled: Boolean,
filter: Function,
hoverable: Boolean,
items: {
type: Array,
default: () => []
},
multipleActive: Boolean,
open: {
type: Array,
default: () => []
},
openAll: Boolean,
returnObject: {
type: Boolean,
default: false // TODO: Should be true in next major
},
search: String,
value: {
type: Array,
default: () => []
},
...VTreeviewNodeProps
},
data: () => ({
level: -1,
activeCache: new Set(),
nodes: {},
openCache: new Set(),
selectedCache: new Set()
}),
computed: {
excludedItems() {
const excluded = new Set();
if (!this.search) return excluded;
for (let i = 0; i < this.items.length; i++) {
filterTreeItems(this.filter || filterTreeItem, this.items[i], this.search, this.itemKey, this.itemText, this.itemChildren, excluded);
}
return excluded;
}
},
watch: {
items: {
handler() {
const oldKeys = Object.keys(this.nodes).map(k => getObjectValueByPath(this.nodes[k].item, this.itemKey));
const newKeys = this.getKeys(this.items);
const diff = arrayDiff(newKeys, oldKeys);
// We only want to do stuff if items have changed
if (!diff.length && newKeys.length < oldKeys.length) return;
// If nodes are removed we need to clear them from this.nodes
diff.forEach(k => delete this.nodes[k]);
const oldSelectedCache = [...this.selectedCache];
this.selectedCache = new Set();
this.activeCache = new Set();
this.openCache = new Set();
this.buildTree(this.items);
// Only emit selected if selection has changed
// as a result of items changing. This fixes a
// potential double emit when selecting a node
// with dynamic children
if (!deepEqual(oldSelectedCache, [...this.selectedCache])) this.emitSelected();
},
deep: true
},
active(value) {
this.handleNodeCacheWatcher(value, this.activeCache, this.updateActive, this.emitActive);
},
value(value) {
this.handleNodeCacheWatcher(value, this.selectedCache, this.updateSelected, this.emitSelected);
},
open(value) {
this.handleNodeCacheWatcher(value, this.openCache, this.updateOpen, this.emitOpen);
}
},
created() {
const getValue = key => this.returnObject ? getObjectValueByPath(key, this.itemKey) : key;
this.buildTree(this.items);
for (const value of this.value.map(getValue)) {
this.updateSelected(value, true, true);
}
for (const active of this.active.map(getValue)) {
this.updateActive(active, true);
}
},
mounted() {
// Save the developer from themselves
if (this.$slots.prepend || this.$slots.append) {
consoleWarn('The prepend and append slots require a slot-scope attribute', this);
}
if (this.openAll) {
this.updateAll(true);
} else {
this.open.forEach(key => this.updateOpen(this.returnObject ? getObjectValueByPath(key, this.itemKey) : key, true));
this.emitOpen();
}
},
methods: {
/** @public */
updateAll(value) {
Object.keys(this.nodes).forEach(key => this.updateOpen(getObjectValueByPath(this.nodes[key].item, this.itemKey), value));
this.emitOpen();
},
getKeys(items) {
let keys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
for (let i = 0; i < items.length; i++) {
const key = getObjectValueByPath(items[i], this.itemKey);
keys.push(key);
const children = getObjectValueByPath(items[i], this.itemChildren);
if (children) {
keys.push(...this.getKeys(children));
}
}
return keys;
},
buildTree(items) {
let parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
for (let i = 0; i < items.length; i++) {
const item = items[i];
const key = getObjectValueByPath(item, this.itemKey);
const children = getObjectValueByPath(item, this.itemChildren) ?? [];
const oldNode = this.nodes.hasOwnProperty(key) ? this.nodes[key] : {
isSelected: false,
isIndeterminate: false,
isActive: false,
isOpen: false,
vnode: null
};
const node = {
vnode: oldNode.vnode,
parent,
children: children.map(c => getObjectValueByPath(c, this.itemKey)),
item
};
this.buildTree(children, key);
// This fixed bug with dynamic children resetting selected parent state
if (this.selectionType !== 'independent' && parent !== null && !this.nodes.hasOwnProperty(key) && this.nodes.hasOwnProperty(parent)) {
node.isSelected = this.nodes[parent].isSelected;
} else {
node.isSelected = oldNode.isSelected;
node.isIndeterminate = oldNode.isIndeterminate;
}
node.isActive = oldNode.isActive;
node.isOpen = oldNode.isOpen;
this.nodes[key] = node;
if (children.length && this.selectionType !== 'independent') {
const {
isSelected,
isIndeterminate
} = this.calculateState(key, this.nodes);
node.isSelected = isSelected;
node.isIndeterminate = isIndeterminate;
}
// Don't forget to rebuild cache
if (this.nodes[key].isSelected && (this.selectionType === 'independent' || node.children.length === 0)) this.selectedCache.add(key);
if (this.nodes[key].isActive) this.activeCache.add(key);
if (this.nodes[key].isOpen) this.openCache.add(key);
this.updateVnodeState(key);
}
},
calculateState(node, state) {
const children = state[node].children;
const counts = children.reduce((counts, child) => {
counts[0] += +Boolean(state[child].isSelected);
counts[1] += +Boolean(state[child].isIndeterminate);
return counts;
}, [0, 0]);
const isSelected = !!children.length && counts[0] === children.length;
const isIndeterminate = !isSelected && (counts[0] > 0 || counts[1] > 0);
return {
isSelected,
isIndeterminate
};
},
emitOpen() {
this.emitNodeCache('update:open', this.openCache);
},
emitSelected() {
this.emitNodeCache('input', this.selectedCache);
},
emitActive() {
this.emitNodeCache('update:active', this.activeCache);
},
emitNodeCache(event, cache) {
this.$emit(event, this.returnObject ? [...cache].map(key => this.nodes[key].item) : [...cache]);
},
handleNodeCacheWatcher(value, cache, updateFn, emitFn) {
value = this.returnObject ? value.map(v => getObjectValueByPath(v, this.itemKey)) : value;
const old = [...cache];
if (deepEqual(old, value)) return;
old.forEach(key => updateFn(key, false));
value.forEach(key => updateFn(key, true));
emitFn();
},
getDescendants(key) {
let descendants = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
const children = this.nodes[key].children;
descendants.push(...children);
for (let i = 0; i < children.length; i++) {
descendants = this.getDescendants(children[i], descendants);
}
return descendants;
},
getParents(key) {
let parent = this.nodes[key].parent;
const parents = [];
while (parent !== null) {
parents.push(parent);
parent = this.nodes[parent].parent;
}
return parents;
},
register(node) {
const key = getObjectValueByPath(node.item, this.itemKey);
this.nodes[key].vnode = node;
this.updateVnodeState(key);
},
unregister(node) {
const key = getObjectValueByPath(node.item, this.itemKey);
if (this.nodes[key]) this.nodes[key].vnode = null;
},
isParent(key) {
return this.nodes[key].children && this.nodes[key].children.length;
},
updateActive(key, isActive) {
if (!this.nodes.hasOwnProperty(key)) return;
if (!this.multipleActive) {
this.activeCache.forEach(active => {
this.nodes[active].isActive = false;
this.updateVnodeState(active);
this.activeCache.delete(active);
});
}
const node = this.nodes[key];
if (!node) return;
if (isActive) this.activeCache.add(key);else this.activeCache.delete(key);
node.isActive = isActive;
this.updateVnodeState(key);
},
updateSelected(key, isSelected) {
let isForced = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
if (!this.nodes.hasOwnProperty(key)) return;
const changed = new Map();
if (this.selectionType !== 'independent') {
for (const descendant of this.getDescendants(key)) {
if (!getObjectValueByPath(this.nodes[descendant].item, this.itemDisabled) || isForced) {
this.nodes[descendant].isSelected = isSelected;
this.nodes[descendant].isIndeterminate = false;
changed.set(descendant, isSelected);
}
}
const calculated = this.calculateState(key, this.nodes);
this.nodes[key].isSelected = isSelected;
this.nodes[key].isIndeterminate = calculated.isIndeterminate;
changed.set(key, isSelected);
for (const parent of this.getParents(key)) {
const calculated = this.calculateState(parent, this.nodes);
this.nodes[parent].isSelected = calculated.isSelected;
this.nodes[parent].isIndeterminate = calculated.isIndeterminate;
changed.set(parent, calculated.isSelected);
}
} else {
this.nodes[key].isSelected = isSelected;
this.nodes[key].isIndeterminate = false;
changed.set(key, isSelected);
}
for (const [key, value] of changed.entries()) {
this.updateVnodeState(key);
if (this.selectionType === 'leaf' && this.isParent(key)) continue;
value === true ? this.selectedCache.add(key) : this.selectedCache.delete(key);
}
},
updateOpen(key, isOpen) {
if (!this.nodes.hasOwnProperty(key)) return;
const node = this.nodes[key];
const children = getObjectValueByPath(node.item, this.itemChildren);
if (children && !children.length && node.vnode && !node.vnode.hasLoaded) {
node.vnode.checkChildren().then(() => this.updateOpen(key, isOpen));
} else if (children && children.length) {
node.isOpen = isOpen;
node.isOpen ? this.openCache.add(key) : this.openCache.delete(key);
this.updateVnodeState(key);
}
},
updateVnodeState(key) {
const node = this.nodes[key];
if (node && node.vnode) {
node.vnode.isSelected = node.isSelected;
node.vnode.isIndeterminate = node.isIndeterminate;
node.vnode.isActive = node.isActive;
node.vnode.isOpen = node.isOpen;
}
},
isExcluded(key) {
return !!this.search && this.excludedItems.has(key);
}
},
render(h) {
const children = this.items.length ? this.items.filter(item => {
return !this.isExcluded(getObjectValueByPath(item, this.itemKey));
}).map(item => {
const genChild = VTreeviewNode.options.methods.genChild.bind(this);
return genChild(item, this.disabled || getObjectValueByPath(item, this.itemDisabled));
})
/* istanbul ignore next */ : this.$slots.default; // TODO: remove type annotation with TS 3.2
return h('div', {
staticClass: 'v-treeview',
class: {
'v-treeview--hoverable': this.hoverable,
'v-treeview--dense': this.dense,
...this.themeClasses
}
}, children);
}
});
//# sourceMappingURL=VTreeview.mjs.map