Odoo18-Base/addons/web_hierarchy/static/src/hierarchy_renderer.js
2025-01-06 10:57:38 +07:00

147 lines
5.2 KiB
JavaScript

/** @odoo-module */
import { Component, useRef, onPatched } from "@odoo/owl";
import { _t } from "@web/core/l10n/translation";
import { useBus, useService } from "@web/core/utils/hooks";
import { scrollTo } from "@web/core/utils/scrolling";
import { HierarchyCard } from "./hierarchy_card";
import { useHierarchyNodeDraggable } from "./hierarchy_node_draggable";
export class HierarchyRenderer extends Component {
static components = {
HierarchyCard,
};
static props = {
model: Object,
openRecord: Function,
archInfo: Object,
templates: Object,
};
static template = "web_hierarchy.HierarchyRenderer";
setup() {
this.rendererRef = useRef("renderer");
this.notification = useService("notification");
if (this.canDragAndDropRecord) {
useHierarchyNodeDraggable({
ref: this.rendererRef,
enable: this.draggable,
elements: ".o_hierarchy_node_container",
handle: ".o_hierarchy_node",
rows: ".o_hierarchy_row",
ignore: "button",
onDragStart: ({ addClass, element }) => {
addClass(element, "o_hierarchy_dragged");
addClass(element.querySelector(".o_hierarchy_node"), "shadow");
},
onDragEnd: ({ removeClass, element, row, hierarchyRow }) => {
removeClass(element, "o_hierarchy_dragged");
if (row) {
removeClass(row, "o_hierarchy_hover");
}
if (hierarchyRow) {
removeClass(hierarchyRow, "o_hierarchy_hover");
}
},
onDrop: (params) => {
this.nodeDrop(params);
},
onElementEnter: ({ addClass, element }) => {
addClass(element, "o_hierarchy_hover");
},
onElementLeave: ({ removeClass, element }) => {
removeClass(element, "o_hierarchy_hover");
},
onRowEnter: ({ addClass, row }) => {
addClass(row, "o_hierarchy_hover");
},
onRowLeave: ({ removeClass, row }) => {
removeClass(row, "o_hierarchy_hover");
},
});
}
this.scrollTarget = "none";
useBus(this.props.model.bus, "hierarchyScrollTarget", (ev) => {
this.scrollTarget = ev.detail?.scrollTarget || "none";
});
onPatched(this.onPatched);
}
onPatched() {
if (this.scrollTarget === "none") {
return;
}
const row =
this.scrollTarget === "bottom"
? this.rendererRef.el.querySelector(":scope .o_hierarchy_row:last-child")
: this.rendererRef.el
.querySelector(
`:scope .o_hierarchy_node[data-node-id="${this.scrollTarget}"]`
)
?.closest(".o_hierarchy_row");
this.scrollTarget = "none";
if (!row) {
return;
}
scrollTo(row, { behavior: "smooth" });
}
get canDragAndDropRecord() {
return this.draggable && !this.env.isSmall;
}
get draggable() {
return this.props.archInfo.draggable;
}
get rows() {
const rootNodes = this.props.model.root.rootNodes.filter((n) => !n.hidden);
const rows = [{ nodes: rootNodes }];
const processNode = (node) => {
if (!node.isLeaf) {
const subNodes = node.nodes.filter((n) => !n.hidden);
rows.push({ parentNode: node, nodes: subNodes });
for (const subNode of subNodes) {
processNode(subNode);
}
}
};
for (const node of this.props.model.root.rootNodes) {
processNode(node);
}
return rows;
}
async nodeDrop({ element, row, nextRow, newParentNode }) {
let parentNodeId, parentResId;
if (newParentNode) {
parentNodeId = newParentNode.dataset.nodeId;
} else if (nextRow?.dataset.rowId !== row.dataset.rowId) {
parentNodeId = nextRow.dataset.parentNodeId;
if (!parentNodeId) {
const nodes = this.rows[nextRow.dataset.rowId].nodes || [];
if (nodes) {
parentNodeId = nodes[0].parentNode?.id;
if (!parentNodeId) {
parentResId = nodes[0].parentResId;
if (!nodes.every((node) => node.parentResId === parentResId)) {
this.notification.add(
_t("Impossible to update the parent node of the dragged node because no parent has been found."),
{
type: "danger",
}
);
return;
}
}
}
}
}
await this.props.model.updateParentNode(element.dataset.nodeId, { parentResId, parentNodeId });
}
}