Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VTreeview.js 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
  2. var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
  3. function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
  4. // Styles
  5. import '../../../src/stylus/components/_treeview.styl';
  6. // Components
  7. import VTreeviewNode, { VTreeviewNodeProps } from './VTreeviewNode';
  8. // Mixins
  9. import Themeable from '../../mixins/themeable';
  10. import { provide as RegistrableProvide } from '../../mixins/registrable';
  11. // Utils
  12. import { arrayDiff, deepEqual, getObjectValueByPath } from '../../util/helpers';
  13. import mixins from '../../util/mixins';
  14. import { consoleWarn } from '../../util/console';
  15. import { filterTreeItems, filterTreeItem } from './util/filterTreeItems';
  16. export default mixins(RegistrableProvide('treeview'), Themeable
  17. /* @vue/component */
  18. ).extend({
  19. name: 'v-treeview',
  20. provide: function provide() {
  21. return { treeview: this };
  22. },
  23. props: _extends({
  24. active: {
  25. type: Array,
  26. default: function _default() {
  27. return [];
  28. }
  29. },
  30. items: {
  31. type: Array,
  32. default: function _default() {
  33. return [];
  34. }
  35. },
  36. hoverable: Boolean,
  37. multipleActive: Boolean,
  38. open: {
  39. type: Array,
  40. default: function _default() {
  41. return [];
  42. }
  43. },
  44. openAll: Boolean,
  45. returnObject: {
  46. type: Boolean,
  47. default: false // TODO: Should be true in next major
  48. },
  49. value: {
  50. type: Array,
  51. default: function _default() {
  52. return [];
  53. }
  54. },
  55. search: String,
  56. filter: Function
  57. }, VTreeviewNodeProps),
  58. data: function data() {
  59. return {
  60. nodes: {},
  61. selectedCache: new Set(),
  62. activeCache: new Set(),
  63. openCache: new Set()
  64. };
  65. },
  66. computed: {
  67. excludedItems: function excludedItems() {
  68. var excluded = new Set();
  69. if (!this.search) return excluded;
  70. for (var i = 0; i < this.items.length; i++) {
  71. filterTreeItems(this.filter || filterTreeItem, this.items[i], this.search, this.itemKey, this.itemText, this.itemChildren, excluded);
  72. }
  73. return excluded;
  74. }
  75. },
  76. watch: {
  77. items: {
  78. handler: function handler() {
  79. var _this = this;
  80. var oldKeys = Object.keys(this.nodes).map(function (k) {
  81. return getObjectValueByPath(_this.nodes[k].item, _this.itemKey);
  82. });
  83. var newKeys = this.getKeys(this.items);
  84. var diff = arrayDiff(newKeys, oldKeys);
  85. // We only want to do stuff if items have changed
  86. if (!diff.length && newKeys.length < oldKeys.length) return;
  87. // If nodes are removed we need to clear them from this.nodes
  88. diff.forEach(function (k) {
  89. return delete _this.nodes[k];
  90. });
  91. var oldSelectedCache = [].concat(_toConsumableArray(this.selectedCache));
  92. this.selectedCache = new Set();
  93. this.activeCache = new Set();
  94. this.openCache = new Set();
  95. this.buildTree(this.items);
  96. // Only emit selected if selection has changed
  97. // as a result of items changing. This fixes a
  98. // potential double emit when selecting a node
  99. // with dynamic children
  100. if (!deepEqual(oldSelectedCache, [].concat(_toConsumableArray(this.selectedCache)))) this.emitSelected();
  101. },
  102. deep: true
  103. },
  104. active: function active(value) {
  105. this.handleNodeCacheWatcher(value, this.activeCache, this.updateActive, this.emitActive);
  106. },
  107. value: function value(_value) {
  108. this.handleNodeCacheWatcher(_value, this.selectedCache, this.updateSelected, this.emitSelected);
  109. },
  110. open: function open(value) {
  111. this.handleNodeCacheWatcher(value, this.openCache, this.updateOpen, this.emitOpen);
  112. }
  113. },
  114. created: function created() {
  115. var _this2 = this;
  116. this.buildTree(this.items);
  117. this.value.forEach(function (key) {
  118. return _this2.updateSelected(key, true);
  119. });
  120. this.emitSelected();
  121. this.active.forEach(function (key) {
  122. return _this2.updateActive(key, true);
  123. });
  124. this.emitActive();
  125. },
  126. mounted: function mounted() {
  127. var _this3 = this;
  128. // Save the developer from themselves
  129. if (this.$slots.prepend || this.$slots.append) {
  130. consoleWarn('The prepend and append slots require a slot-scope attribute', this);
  131. }
  132. if (this.openAll) {
  133. this.updateAll(true);
  134. } else {
  135. this.open.forEach(function (key) {
  136. return _this3.updateOpen(key, true);
  137. });
  138. this.emitOpen();
  139. }
  140. },
  141. methods: {
  142. /** @public */
  143. updateAll: function updateAll(value) {
  144. var _this4 = this;
  145. Object.keys(this.nodes).forEach(function (key) {
  146. return _this4.updateOpen(getObjectValueByPath(_this4.nodes[key].item, _this4.itemKey), value);
  147. });
  148. this.emitOpen();
  149. },
  150. getKeys: function getKeys(items) {
  151. var keys = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  152. for (var i = 0; i < items.length; i++) {
  153. var key = getObjectValueByPath(items[i], this.itemKey);
  154. keys.push(key);
  155. var children = getObjectValueByPath(items[i], this.itemChildren);
  156. if (children) {
  157. keys.push.apply(keys, _toConsumableArray(this.getKeys(children)));
  158. }
  159. }
  160. return keys;
  161. },
  162. buildTree: function buildTree(items) {
  163. var _this5 = this;
  164. var parent = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  165. for (var i = 0; i < items.length; i++) {
  166. var item = items[i];
  167. var key = getObjectValueByPath(item, this.itemKey);
  168. var children = getObjectValueByPath(item, this.itemChildren, []);
  169. var oldNode = this.nodes.hasOwnProperty(key) ? this.nodes[key] : {
  170. isSelected: false, isIndeterminate: false, isActive: false, isOpen: false, vnode: null
  171. };
  172. var node = {
  173. vnode: oldNode.vnode,
  174. parent: parent,
  175. children: children.map(function (c) {
  176. return getObjectValueByPath(c, _this5.itemKey);
  177. }),
  178. item: item
  179. };
  180. this.buildTree(children, key);
  181. // This fixed bug with dynamic children resetting selected parent state
  182. if (!this.nodes.hasOwnProperty(key) && parent !== null && this.nodes.hasOwnProperty(parent)) {
  183. node.isSelected = this.nodes[parent].isSelected;
  184. node.isIndeterminate = this.nodes[parent].isIndeterminate;
  185. } else {
  186. node.isSelected = oldNode.isSelected;
  187. node.isIndeterminate = oldNode.isIndeterminate;
  188. }
  189. node.isActive = oldNode.isActive;
  190. node.isOpen = oldNode.isOpen;
  191. this.nodes[key] = !children.length ? node : this.calculateState(node, this.nodes);
  192. // Don't forget to rebuild cache
  193. if (this.nodes[key].isSelected) this.selectedCache.add(key);
  194. if (this.nodes[key].isActive) this.activeCache.add(key);
  195. if (this.nodes[key].isOpen) this.openCache.add(key);
  196. this.updateVnodeState(key);
  197. }
  198. },
  199. calculateState: function calculateState(node, state) {
  200. var counts = node.children.reduce(function (counts, child) {
  201. counts[0] += +Boolean(state[child].isSelected);
  202. counts[1] += +Boolean(state[child].isIndeterminate);
  203. return counts;
  204. }, [0, 0]);
  205. node.isSelected = !!node.children.length && counts[0] === node.children.length;
  206. node.isIndeterminate = !node.isSelected && (counts[0] > 0 || counts[1] > 0);
  207. return node;
  208. },
  209. emitOpen: function emitOpen() {
  210. this.emitNodeCache('update:open', this.openCache);
  211. },
  212. emitSelected: function emitSelected() {
  213. this.emitNodeCache('input', this.selectedCache);
  214. },
  215. emitActive: function emitActive() {
  216. this.emitNodeCache('update:active', this.activeCache);
  217. },
  218. emitNodeCache: function emitNodeCache(event, cache) {
  219. var _this6 = this;
  220. this.$emit(event, this.returnObject ? [].concat(_toConsumableArray(cache)).map(function (key) {
  221. return _this6.nodes[key].item;
  222. }) : [].concat(_toConsumableArray(cache)));
  223. },
  224. handleNodeCacheWatcher: function handleNodeCacheWatcher(value, cache, updateFn, emitFn) {
  225. var _this7 = this;
  226. value = this.returnObject ? value.map(function (v) {
  227. return getObjectValueByPath(v, _this7.itemKey);
  228. }) : value;
  229. var old = [].concat(_toConsumableArray(cache));
  230. if (deepEqual(old, value)) return;
  231. old.forEach(function (key) {
  232. return updateFn(key, false);
  233. });
  234. value.forEach(function (key) {
  235. return updateFn(key, true);
  236. });
  237. emitFn();
  238. },
  239. getDescendants: function getDescendants(key) {
  240. var _descendants;
  241. var descendants = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  242. var children = this.nodes[key].children;
  243. (_descendants = descendants).push.apply(_descendants, _toConsumableArray(children));
  244. for (var i = 0; i < children.length; i++) {
  245. descendants = this.getDescendants(children[i], descendants);
  246. }
  247. return descendants;
  248. },
  249. getParents: function getParents(key) {
  250. var parent = this.nodes[key].parent;
  251. var parents = [];
  252. while (parent !== null) {
  253. parents.push(parent);
  254. parent = this.nodes[parent].parent;
  255. }
  256. return parents;
  257. },
  258. register: function register(node) {
  259. var key = getObjectValueByPath(node.item, this.itemKey);
  260. this.nodes[key].vnode = node;
  261. this.updateVnodeState(key);
  262. },
  263. unregister: function unregister(node) {
  264. var key = getObjectValueByPath(node.item, this.itemKey);
  265. if (this.nodes[key]) this.nodes[key].vnode = null;
  266. },
  267. updateActive: function updateActive(key, isActive) {
  268. var _this8 = this;
  269. if (!this.nodes.hasOwnProperty(key)) return;
  270. if (!this.multipleActive) {
  271. this.activeCache.forEach(function (active) {
  272. _this8.nodes[active].isActive = false;
  273. _this8.updateVnodeState(active);
  274. _this8.activeCache.delete(active);
  275. });
  276. }
  277. var node = this.nodes[key];
  278. if (!node) return;
  279. if (isActive) this.activeCache.add(key);else this.activeCache.delete(key);
  280. node.isActive = isActive;
  281. this.updateVnodeState(key);
  282. },
  283. updateSelected: function updateSelected(key, isSelected) {
  284. var _this9 = this;
  285. if (!this.nodes.hasOwnProperty(key)) return;
  286. var changed = new Map();
  287. var descendants = [key].concat(_toConsumableArray(this.getDescendants(key)));
  288. descendants.forEach(function (descendant) {
  289. _this9.nodes[descendant].isSelected = isSelected;
  290. _this9.nodes[descendant].isIndeterminate = false;
  291. changed.set(descendant, isSelected);
  292. });
  293. var parents = this.getParents(key);
  294. parents.forEach(function (parent) {
  295. _this9.nodes[parent] = _this9.calculateState(_this9.nodes[parent], _this9.nodes);
  296. changed.set(parent, _this9.nodes[parent].isSelected);
  297. });
  298. var all = [key].concat(_toConsumableArray(descendants), _toConsumableArray(parents));
  299. all.forEach(this.updateVnodeState);
  300. var _iteratorNormalCompletion = true;
  301. var _didIteratorError = false;
  302. var _iteratorError = undefined;
  303. try {
  304. for (var _iterator = changed.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
  305. var _ref = _step.value;
  306. var _ref2 = _slicedToArray(_ref, 2);
  307. var _key = _ref2[0];
  308. var value = _ref2[1];
  309. value === true ? this.selectedCache.add(_key) : this.selectedCache.delete(_key);
  310. }
  311. } catch (err) {
  312. _didIteratorError = true;
  313. _iteratorError = err;
  314. } finally {
  315. try {
  316. if (!_iteratorNormalCompletion && _iterator.return) {
  317. _iterator.return();
  318. }
  319. } finally {
  320. if (_didIteratorError) {
  321. throw _iteratorError;
  322. }
  323. }
  324. }
  325. },
  326. updateOpen: function updateOpen(key, isOpen) {
  327. var _this10 = this;
  328. if (!this.nodes.hasOwnProperty(key)) return;
  329. var node = this.nodes[key];
  330. var children = getObjectValueByPath(node.item, this.itemChildren);
  331. if (children && !children.length && node.vnode && !node.vnode.hasLoaded) {
  332. node.vnode.checkChildren().then(function () {
  333. return _this10.updateOpen(key, isOpen);
  334. });
  335. } else if (children && children.length) {
  336. node.isOpen = isOpen;
  337. node.isOpen ? this.openCache.add(key) : this.openCache.delete(key);
  338. this.updateVnodeState(key);
  339. }
  340. },
  341. updateVnodeState: function updateVnodeState(key) {
  342. var node = this.nodes[key];
  343. if (node && node.vnode) {
  344. node.vnode.isSelected = node.isSelected;
  345. node.vnode.isIndeterminate = node.isIndeterminate;
  346. node.vnode.isActive = node.isActive;
  347. node.vnode.isOpen = node.isOpen;
  348. }
  349. },
  350. isExcluded: function isExcluded(key) {
  351. return !!this.search && this.excludedItems.has(key);
  352. }
  353. },
  354. render: function render(h) {
  355. var children = this.items.length ? this.items.map(VTreeviewNode.options.methods.genChild.bind(this))
  356. /* istanbul ignore next */
  357. : this.$slots.default; // TODO: remove type annotation with TS 3.2
  358. return h('div', {
  359. staticClass: 'v-treeview',
  360. class: _extends({
  361. 'v-treeview--hoverable': this.hoverable
  362. }, this.themeClasses)
  363. }, children);
  364. }
  365. });
  366. //# sourceMappingURL=VTreeview.js.map