[IMP] todo: make the name of a to-do editable from the breadcrumbs
In the module note, the name of a note was automatically computed based on the begining of its content. Fot the module todo, we want the name to be editable in the form view, while still keeping a clean interface for the form. This commit makes therefore the name of a to-do directly editable in the breadcrumbs. The behavior is a mix between the editable breadcrumb name in Spreadsheet and the classical edition behavior for a field in a form view, i.e: - When creating a new to-do, a placeholder for the name is set to _Untitled to-do_. A name must be entered before saving the record. - A name entered in the Breadcrumb will be saved either if the save button is pressed, either when the form view is quit. - The discard button allows to go back to the last saved name. The implementation relies, for its biggest part, on a new component inheriting _CharField_ that copies some functions from the component _SpreadsheetName_ used in Spreadsheet (see task-2621549) for the edition part and use the autoResize hook from discuss recently moved into the framework (see https://github.com/odoo/odoo/pull/117355). The rest of the implementation consists of overrides of _FormControlPanel_, _FormController_ and _formView_ to adapt the use of this input field in the context of a form view (>< Spreadsheet). task-3085077
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
'uninstall_hook': '_todo_uninstall',
|
||||
'assets': {
|
||||
'web.assets_backend': [
|
||||
'todo/static/src/components/**/*',
|
||||
'todo/static/src/scss/todo.scss',
|
||||
'todo/static/src/views/**/*',
|
||||
'todo/static/src/web/**/*',
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/** @odoo-module */
|
||||
|
||||
import { useState, onRendered, useRef } from "@odoo/owl";
|
||||
|
||||
import { _lt } from "@web/core/l10n/translation";
|
||||
import { CharField } from "@web/views/fields/char/char_field";
|
||||
import { useAutoresize } from "@web/core/utils/autoresize";
|
||||
|
||||
export class TodoEditableBreadcrumbName extends CharField {
|
||||
setup() {
|
||||
super.setup();
|
||||
this.placeholder = _lt("Untitled to-do");;
|
||||
this.input = useRef("input");
|
||||
|
||||
this.stateTodo = useState({
|
||||
isUntitled: true,
|
||||
});
|
||||
|
||||
onRendered(() => {
|
||||
this.stateTodo.isUntitled = this._isUntitled(this.props.record.data[this.props.name]);
|
||||
});
|
||||
useAutoresize(this.input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the name is empty or is the generic name
|
||||
* for untitled todos.
|
||||
* @param {string} name
|
||||
* @returns {boolean}
|
||||
*/
|
||||
_isUntitled(name) {
|
||||
name = name && name.trim();
|
||||
return !name || name === this.placeholder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {InputEvent} ev
|
||||
*/
|
||||
_onFocus(ev) {
|
||||
if (this._isUntitled(ev.target.value)) {
|
||||
ev.target.value = this.placeholder;
|
||||
ev.target.select();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {InputEvent} ev
|
||||
*/
|
||||
_onInput(ev) {
|
||||
const value = ev.target.value;
|
||||
this.stateTodo.isUntitled = this._isUntitled(value);
|
||||
}
|
||||
}
|
||||
|
||||
TodoEditableBreadcrumbName.template = 'todo.TodoEditableBreadcrumbName';
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
.o_todo_breadcrumb_name_input{
|
||||
width: 100%;
|
||||
text-overflow: clip;
|
||||
overflow: hidden;
|
||||
border: none;
|
||||
padding: 0px 5px 0px 2px;
|
||||
color: $o-brand-secondary;
|
||||
|
||||
&:focus {
|
||||
outline: 1px solid #ccc;
|
||||
outline-offset: -1px;
|
||||
color: $dark;
|
||||
}
|
||||
|
||||
&.o-todo-untitled {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
&.o-todo-untitled:focus {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
background-color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.o_todo_breadcrumb_name_input:hover {
|
||||
border-bottom: $input-border-width solid $o-brand-primary;
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="todo.TodoEditableBreadcrumbName" t-inherit="web.CharField" t-inherit-mode="primary" owl="1">
|
||||
<xpath expr="//input[hasclass('o_input')]" position="attributes">
|
||||
<attribute name="class">o_input o_todo_breadcrumb_name_input</attribute>
|
||||
<attribute name="t-on-focus">_onFocus</attribute>
|
||||
<attribute name="t-att-placeholder">placeholder</attribute>
|
||||
<attribute name="t-on-input">_onInput</attribute>
|
||||
<attribute name="t-att-class">stateTodo.isUntitled ? 'o-todo-untitled' : ''</attribute>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,7 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { ControlPanel } from "@web/search/control_panel/control_panel";
|
||||
|
||||
export class TodoFormControlPanel extends ControlPanel {
|
||||
static template = "todo.TodoFormControlPanel";
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="todo.TodoFormControlPanel" t-inherit="web.ControlPanel" t-inherit-mode="primary" owl="1">
|
||||
<xpath expr="//div/t/t[@t-slot='control-panel-breadcrumb']" position="replace">
|
||||
<t t-slot="control-panel-breadcrumb">
|
||||
<t t-call="todo.TodoBreadcrumbs"/>
|
||||
</t>
|
||||
</xpath>
|
||||
|
||||
</t>
|
||||
|
||||
<t t-name="todo.TodoBreadcrumbs" t-inherit="web.Breadcrumbs" t-inherit-mode="primary" owl="1">
|
||||
<xpath expr="//div[hasclass('o_last_breadcrumb_item')]//span" position="replace">
|
||||
<t t-slot="control-panel-todo-name" />
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,14 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { FormController } from "@web/views/form/form_controller";
|
||||
import { TodoEditableBreadcrumbName } from "@todo/components/todo_editable_breadcrumb_name/todo_editable_breadcrumb_name";
|
||||
|
||||
/**
|
||||
* The FormController is overridden to be able to manage the edition of the name of a to-do directly
|
||||
* in the breadcrumb.
|
||||
*/
|
||||
|
||||
export class TodoFormController extends FormController {}
|
||||
|
||||
Object.assign(TodoFormController.components, { TodoEditableBreadcrumbName });
|
||||
TodoFormController.template = 'todo.TodoFormView';
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="todo.TodoFormView" t-inherit="web.FormView" t-inherit-mode="primary" owl="1">
|
||||
|
||||
<xpath expr="//div[hasclass('o_form_view_container')]/Layout" position="inside">
|
||||
<t t-set-slot="control-panel-todo-name">
|
||||
<t t-set="record" t-value="model.root"/>
|
||||
<TodoEditableBreadcrumbName
|
||||
name="'name'"
|
||||
record="record"
|
||||
id="'name'"
|
||||
/>
|
||||
</t>
|
||||
</xpath>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1,14 @@
|
||||
/** @odoo-module **/
|
||||
|
||||
import { registry } from "@web/core/registry";
|
||||
import { formView } from "@web/views/form/form_view";
|
||||
import { TodoFormControlPanel } from "./todo_form_control_panel";
|
||||
import { TodoFormController } from "./todo_form_controller";
|
||||
|
||||
export const todoFormView = {
|
||||
...formView,
|
||||
ControlPanel: TodoFormControlPanel,
|
||||
Controller: TodoFormController,
|
||||
};
|
||||
|
||||
registry.category("views").add("todo_form", todoFormView);
|
||||
@@ -98,6 +98,7 @@
|
||||
<form string="To-do"
|
||||
class="o_todo_form_view"
|
||||
js_class="todo_form">
|
||||
<field name="name" invisible="1"/>
|
||||
<header>
|
||||
<div class="py-1 px-2 border rounded bg-view">
|
||||
<field name="tag_ids"
|
||||
|
||||
Reference in New Issue
Block a user