|
| 1 | +/** @odoo-module alias=owl_tutorial_views.OWLTreeModel default=0 **/ |
| 2 | +import {Model} from "@web/views/helpers/model"; |
| 3 | +import {KeepLast} from "@web/core/utils/concurrency"; |
| 4 | + |
| 5 | +export default class OWLTreeModel extends Model { |
| 6 | + setup(params, {orm}) { |
| 7 | + this.modelName = params.resModel; |
| 8 | + this.orm = orm; |
| 9 | + this.keepLast = new KeepLast(); |
| 10 | + } |
| 11 | + |
| 12 | + /** |
| 13 | + * Make an RPC 'write' method call to update the parent_id of |
| 14 | + * an existing record. |
| 15 | + * |
| 16 | + * @param {integer} id ID Of the item we want to update |
| 17 | + * @param {integer} parent_id The parent item ID |
| 18 | + */ |
| 19 | + async changeParent(id, parent_id) { |
| 20 | + await this.orm.write(this.modelName, [id], {parent_id: parent_id}); |
| 21 | + this.notify(); |
| 22 | + } |
| 23 | + |
| 24 | + /** |
| 25 | + * Refresh a node get fresh data from the server for a given item. |
| 26 | + * A search_read is executed via RPC Call and then the item is modified |
| 27 | + * in place in the hierarchical tree structure. |
| 28 | + * |
| 29 | + * @param {integer} id ID Of the item we want to refresh |
| 30 | + */ |
| 31 | + async refreshNode(id) { |
| 32 | + var self = this; |
| 33 | + var result = null; |
| 34 | + const itemUpdated = await this.orm.read(this.modelName, [id], []); |
| 35 | + |
| 36 | + const path = itemUpdated[0].parent_path; |
| 37 | + let target_node = self.__target_parent_node_with_path( |
| 38 | + path.split("/").filter((i) => i), |
| 39 | + self.data |
| 40 | + ); |
| 41 | + target_node = itemUpdated[0]; |
| 42 | + result = itemUpdated[0]; |
| 43 | + this.notify(); |
| 44 | + return result; |
| 45 | + } |
| 46 | + |
| 47 | + /** |
| 48 | + * Make an RPC call to get the child of the target itm then navigates |
| 49 | + * the nodes to the target the item and assign its "children" property |
| 50 | + * to the result of the RPC call. |
| 51 | + * |
| 52 | + * @param {integer} parentId Category we will "open/expand" |
| 53 | + * @param {String} path The parent_path represents the parents ids like "1/3/32/123/" |
| 54 | + */ |
| 55 | + async expandChildrenOf(parentId, path) { |
| 56 | + var self = this; |
| 57 | + const children = await this.orm.searchRead(this.modelName, [["parent_id", "=", parentId]]); |
| 58 | + var target_node = self.__target_parent_node_with_path( |
| 59 | + path.split("/").filter((i) => i), |
| 60 | + self.data |
| 61 | + ); |
| 62 | + target_node.children = children; |
| 63 | + target_node.child_id = children.map((i) => i.id); |
| 64 | + target_node.childrenVisible = true; |
| 65 | + this.notify(); |
| 66 | + } |
| 67 | + |
| 68 | + async toggleChildrenVisibleForItem(item) { |
| 69 | + var target_node = this.__target_parent_node_with_path( |
| 70 | + item.parent_path.split("/").filter((i) => i), |
| 71 | + this.data |
| 72 | + ); |
| 73 | + target_node.childrenVisible = !target_node.childrenVisible; |
| 74 | + this.notify(); |
| 75 | + } |
| 76 | + |
| 77 | + async _recursivelyOpenParents(item) { |
| 78 | + if (item.parent_id) { |
| 79 | + const parent = await this.orm.read(this.modelName, [item.parent_id[0]], []); |
| 80 | + const directParent = parent[0]; |
| 81 | + directParent.children = [item]; |
| 82 | + directParent.childrenVisible = true; |
| 83 | + return await this._recursivelyOpenParents(directParent); |
| 84 | + } |
| 85 | + return [item]; |
| 86 | + } |
| 87 | + /** |
| 88 | + * Search for the Node corresponding to the given path. |
| 89 | + * Paths are present in the property `parent_path` of any nested item they are |
| 90 | + * in the form "1/3/32/123/" we have to split the string to manipulate an Array. |
| 91 | + * Each item in the Array will correspond to an item ID in the tree, each one |
| 92 | + * level deeper than the last. |
| 93 | + * |
| 94 | + * @private |
| 95 | + * @param {Array} path for example ["1", "3", "32", "123"] |
| 96 | + * @param {Array} items the items to search in |
| 97 | + * @param {integer} n The current index of deep inside the tree |
| 98 | + * @returns {Object|undefined} the tree Node corresponding to the path |
| 99 | + **/ |
| 100 | + __target_parent_node_with_path(path, items, n = 0) { |
| 101 | + for (const item of items) { |
| 102 | + if (item.id == parseInt(path[n])) { |
| 103 | + if (n < path.length - 1) { |
| 104 | + return this.__target_parent_node_with_path(path, item.children, n + 1); |
| 105 | + } |
| 106 | + return item; |
| 107 | + } |
| 108 | + } |
| 109 | + return undefined; |
| 110 | + } |
| 111 | + |
| 112 | + async load(params) { |
| 113 | + let isSearch = false; |
| 114 | + let domain = [["parent_id", "=", false]]; |
| 115 | + if (params.domain && params.domain.length > 0) { |
| 116 | + isSearch = true; |
| 117 | + domain = params.domain; |
| 118 | + } |
| 119 | + const result = await this.keepLast.add(this.orm.searchRead(this.modelName, domain, [])); |
| 120 | + if (isSearch) { |
| 121 | + for (const item of result) { |
| 122 | + this.data = await this._recursivelyOpenParents(item); |
| 123 | + } |
| 124 | + } else { |
| 125 | + this.data = result; |
| 126 | + } |
| 127 | + this.notify(); |
| 128 | + } |
| 129 | +} |
| 130 | +OWLTreeModel.services = ["orm"]; |
0 commit comments