Skip to content

Commit

Permalink
[MIG 16.0] owl_tutorial_views
Browse files Browse the repository at this point in the history
- Migration to new view definition
  • Loading branch information
PhilDL committed Nov 23, 2022
1 parent 5cf4384 commit 546b280
Show file tree
Hide file tree
Showing 12 changed files with 378 additions and 324 deletions.
4 changes: 2 additions & 2 deletions owl_tutorial_views/README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Coding Dodo - Odoo 15 Tutorial Creating an OWL View from scratch
# Coding Dodo - Odoo 16 Tutorial Creating an OWL View from scratch

This addon was originally created in [Odoo JavaScript 101 - Part 2: Creating an OWL View from scratch](https://codingdodo.com/odoo-javascript-tutorial-101-part-2-creating-an-owl-view/).

This branch is the companion piece of the [Article about migrating that view to Odoo 15.](https://codingdodo.com/odoo-15-owl-view-migration-guide)
This branch is the companion piece of the an upcoming article on how to upgrade to Odoo 16.

### Author

Expand Down
4 changes: 2 additions & 2 deletions owl_tutorial_views/README.rst
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@

Coding Dodo - Odoo 15 Tutorial Creating an OWL View from scratch
Coding Dodo - Odoo 16 Tutorial Creating an OWL View from scratch
================================================================

This addon was originally created in `Odoo JavaScript 101 - Part 2: Creating an OWL View from scratch <https://codingdodo.com/odoo-javascript-tutorial-101-part-2-creating-an-owl-view/>`_.

This branch is the companion piece of the `Article about migrating that view to Odoo 15. <https://codingdodo.com/odoo-15-owl-view-migration-guide>`_
This branch is the companion piece of the an upcoming article on how to upgrade to Odoo 16.

Author
^^^^^^
Expand Down
13 changes: 7 additions & 6 deletions owl_tutorial_views/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,24 @@
"author": "Coding Dodo",
"website": "https://codingdodo.com",
"category": "Tools",
"version": "15.0.1",
"version": "16.0.1",
"depends": ["base", "web", "mail", "product"],
"data": [
"views/product_views.xml",
],
"assets": {
"web.assets_qweb": [
"/owl_tutorial_views/static/src/components/tree_item/TreeItem.xml",
"/owl_tutorial_views/static/src/xml/owl_tree_view.xml",
],
"web.assets_backend": [
"/owl_tutorial_views/static/src/components/tree_item/tree_item.scss",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_view.scss",
"/owl_tutorial_views/static/src/components/tree_item/TreeItem.js",
"/owl_tutorial_views/static/src/components/tree_item/TreeItem.xml",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_arch_parser.js",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_view.js",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_controller.js",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_controller.xml",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_view.scss",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_model.js",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_renderer.js",
"/owl_tutorial_views/static/src/owl_tree_view/owl_tree_renderer.xml",
],
},
}
110 changes: 59 additions & 51 deletions owl_tutorial_views/static/src/components/tree_item/TreeItem.js
Original file line number Diff line number Diff line change
@@ -1,64 +1,72 @@
/** @odoo-module **/
const { Component } = owl;
const { useState } = owl.hooks;
import {Component, useState} from "@odoo/owl";

export class TreeItem extends Component {
/**
* @override
*/
constructor(...args) {
super(...args);
this.state = useState({
isDraggedOn: false,
});
}

toggleChildren() {
if (this.props.item.child_id.length > 0) {
this.trigger("tree_item_clicked", { data: this.props.item });
/**
* @override
*/
constructor(...args) {
super(...args);
this.state = useState({
isDraggedOn: false,
});
}
}

onDragstart(event) {
event.dataTransfer.setData("TreeItem", JSON.stringify(this.props.item));
}
toggleChildren() {
if (this.props.item.child_id.length > 0) {
this.props.onTreeItemClicked(this.props.item);
}
}

onDragover() {}
onDragstart(event) {
event.dataTransfer.setData("TreeItem", JSON.stringify(this.props.item));
}

onDragenter() {
Object.assign(this.state, { isDraggedOn: true });
}
onDragover() {}

onDragleave() {
Object.assign(this.state, { isDraggedOn: false });
}
onDragenter() {
Object.assign(this.state, {isDraggedOn: true});
}

onDrop(event) {
Object.assign(this.state, { isDraggedOn: false });
let droppedItem = JSON.parse(event.dataTransfer.getData("TreeItem"));
if (
droppedItem.id == this.props.item.id ||
droppedItem.parent_id[0] == this.props.item.id
) {
console.log("Drop inside itself or same parent has no effect");
return;
onDragleave() {
Object.assign(this.state, {isDraggedOn: false});
}
if (this.props.item.parent_path.startsWith(droppedItem.parent_path)) {
console.log("Oops, drop inside child item is forbidden.");
return;

onDrop(event) {
Object.assign(this.state, {isDraggedOn: false});
let droppedItem = JSON.parse(event.dataTransfer.getData("TreeItem"));
if (droppedItem.id == this.props.item.id || droppedItem.parent_id[0] == this.props.item.id) {
console.log("Drop inside itself or same parent has no effect");
return;
}
if (this.props.item.parent_path.startsWith(droppedItem.parent_path)) {
console.log("Oops, drop inside child item is forbidden.");
return;
}
this.props.onChangeItemTree({
itemMoved: droppedItem,
newParent: this.props.item,
});
}
this.trigger("change_item_tree", {
itemMoved: droppedItem,
newParent: this.props.item,
});
}
}

Object.assign(TreeItem, {
components: { TreeItem },
props: {
item: {},
countField: "",
},
template: "owl_tutorial_views.TreeItem",
});
TreeItem.components = {TreeItem};
TreeItem.props = {
countField: {
type: String,
optional: true,
},
onTreeItemClicked: {
type: Function,
optional: true,
},
onChangeItemTree: {
type: Function,
optional: true,
},
item: {
type: Object,
optional: true,
},
};
TreeItem.template = "owl_tutorial_views.TreeItem";
36 changes: 18 additions & 18 deletions owl_tutorial_views/static/src/components/tree_item/TreeItem.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,37 @@

<t t-name="owl_tutorial_views.TreeItem" owl="1">
<div class="tree-item-wrapper">
<div
draggable="true"
t-on-dragstart="onDragstart"
t-on-drop.stop.prevent="onDrop"
t-on-dragover.prevent="onDragover"
t-on-dragenter.prevent="onDragenter"
t-on-dragleave.prevent="onDragleave"
<div
draggable="true"
t-on-dragstart="onDragstart"
t-on-drop.stop.prevent="onDrop"
t-on-dragover.prevent="onDragover"
t-on-dragenter.prevent="onDragenter"
t-on-dragleave.prevent="onDragleave"
t-attf-class="list-group-item list-group-item-action d-flex justify-content-between align-items-center owl-tree-item {{ state.isDraggedOn ? 'list-group-item-warning': '' }}"
>
<a href="#" t-on-click.stop.prevent="toggleChildren" t-if="props.item.child_id.length > 0">
<t t-esc="props.item.display_name"/>
<i t-attf-class="pl-2 fa {{ props.item.childrenVisible ? 'fa-caret-down': 'fa-caret-right'}}" ></i>
<t t-esc="props.item.display_name" />
<i t-attf-class="ps-2 fa {{ props.item.childrenVisible ? 'fa-caret-down': 'fa-caret-right'}}"></i>
</a>
<span t-else="">
<t t-esc="props.item.display_name"/>
</span>
<span
t-if="props.countField !== '' and props.item.hasOwnProperty(props.countField)"
class="badge badge-primary badge-pill"
t-esc="props.item[props.countField]">
<t t-esc="props.item.display_name" />
</span>
<span
t-if="props.countField !== '' and props.item.hasOwnProperty(props.countField)"
class="badge badge-primary badge-pill"
t-esc="props.item[props.countField]"></span>
</div>
<t t-if="props.item.child_id.length > 0">
<div class="d-flex pl-4 py-1 flex-row treeview" t-if="props.item.children and props.item.children.length > 0 and props.item.childrenVisible">
<div class="d-flex ps-4 py-1 flex-row treeview" t-if="props.item.children and props.item.children.length > 0 and props.item.childrenVisible">
<div class="list-group">
<t t-foreach="props.item.children" t-as="child_item" t-key="child_item.id">
<TreeItem item="child_item"/>
<TreeItem item="child_item" onTreeItemClicked="props.onTreeItemClicked"
onChangeItemTree="props.onChangeItemTree" countField="props.countField" />
</t>
</div>
</div>
</t>
</div>
</t>
</templates>
</templates>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/** @odoo-module */

/**
*
*
* @typedef {Object} ArchInfo
* @property {string} arch
* @property {string} countField
*/

import {XMLParser} from "@web/core/utils/xml";

export class OWLTreeArchParser extends XMLParser {
parse(arch) {
const xmlDoc = this.parseXML(arch);
const countField = xmlDoc.getAttribute("count_field");
/** @type { ArchInfo} */
return {
arch,
countField,
};
}
}
65 changes: 65 additions & 0 deletions owl_tutorial_views/static/src/owl_tree_view/owl_tree_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/** @odoo-module **/
/** @typedef {import("./owl_tree_model").OWLTreeModel} OWLTreeModel */
import {Component, useState, onWillStart, onWillUpdateProps} from "@odoo/owl";
import {Layout} from "@web/search/layout";
import {useService} from "@web/core/utils/hooks";

export class OWLTreeController extends Component {
/**
* Standard setup function of OWL Component, here we parse the XML
* template to get the options and instantiate the Model.
**/
setup() {
this.orm = useService("orm");
this.rpc = useService("rpc");
/** @type OWLTreeModel */
this.model = useState(
new this.props.Model(
this.orm,
this.props.resModel,
this.props.fields,
this.props.archInfo,
this.props.domain,
this.props.context,
this.rpc
)
);
const {arch, templateDocs} = this.props.archInfo;

onWillStart(async () => {
await this.model.load();
});

onWillUpdateProps(async (nextProps) => {
if (JSON.stringify(nextProps.domain) !== JSON.stringify(this.props.domain)) {
this.model.domain = nextProps.domain;
await this.model.load();
}
});
}

/**
*/
async _onTreeItemClicked(treeItem) {
if (treeItem.children === undefined) {
await this.model.expandChildrenOf(treeItem.id, treeItem.parent_path);
} else {
this.model.toggleChildrenVisibleForItem(treeItem);
}
}

/**
*/
async _onChangeItemTree({itemMoved, newParent}) {
await this.model.changeParent(itemMoved.id, newParent.id);

// Refresh old parent
let oldParent = await this.model.refreshNode(itemMoved.parent_id[0]);
await this.model.expandChildrenOf(oldParent.id, oldParent.parent_path);

// Refresh new parent
await this.model.expandChildrenOf(newParent.id, newParent.parent_path);
}
}
OWLTreeController.components = {Layout};
OWLTreeController.template = "owl_tutorial_views.View";
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates xml:space="preserve">
<t t-name="owl_tutorial_views.View" owl="1">
<Layout display="props.display" className="'h-100 overflow-auto'">
<t
t-component="props.Renderer"
countField="props.archInfo.countField"
onTreeItemClicked="_onTreeItemClicked.bind(this)" onChangeItemTree="_onChangeItemTree.bind(this)"
items="model.data"
/>
</Layout>
</t>
</templates>
Loading

0 comments on commit 546b280

Please sign in to comment.