[IMP] web: changes in name and signature for sign

This commit adapts the NameAndSignature component to allow usage in the sign
module by enabling customization of behavior when "auto" and "load" buttons are
clicked. It also replaces the top buttons for fa icons for a cleaner UI and
adds autofocus to the name input field.

task-3286974

Part-of: odoo/odoo#126296
This commit is contained in:
Leonardo Pavan Rocha
2023-07-20 11:49:17 +02:00
parent 0479b2b594
commit c4994c7d10
3 changed files with 54 additions and 55 deletions
@@ -3,7 +3,7 @@
import { isMobileOS } from "@web/core/browser/feature_detection";
import { Dropdown } from "@web/core/dropdown/dropdown";
import { DropdownItem } from "@web/core/dropdown/dropdown_item";
import { useService } from "@web/core/utils/hooks";
import { useService, useAutofocus } from "@web/core/utils/hooks";
import { pick } from "@web/core/utils/objects";
import { renderToString } from "@web/core/utils/render";
import { getDataURLFromFile } from "@web/core/utils/urls";
@@ -28,14 +28,15 @@ export class NameAndSignature extends Component {
});
this.signNameInputRef = useRef("signNameInput");
const signInputLoad = useRef("signInputLoad");
this.signInputLoad = useRef("signInputLoad");
useAutofocus({ refName: "signNameInput" });
useEffect(
(el) => {
if (el) {
el.click();
}
},
() => [signInputLoad.el]
() => [this.signInputLoad.el]
);
onWillStart(async () => {
@@ -137,6 +138,10 @@ export class NameAndSignature extends Component {
return this.$signatureField.jSignature(...arguments);
}
uploadFile() {
this.signInputLoad.el?.click();
}
/**
* Handles change on load file input: displays the loaded image if the
* format is correct, or displays an error otherwise.
@@ -170,6 +175,14 @@ export class NameAndSignature extends Component {
this.jSignature("reset");
}
onClickSignLoad() {
this.setMode("load");
}
onClickSignAuto() {
this.setMode("auto");
}
onInputSignName(ev) {
this.props.signature.name = ev.target.value;
if (!this.state.showSignatureArea && this.getCleanedName()) {
@@ -182,7 +195,7 @@ export class NameAndSignature extends Component {
}
onSelectFont(index) {
this.currentFont = this.fonts[index];
this.currentFont = index;
this.drawCurrentName();
}
@@ -53,7 +53,7 @@
<div class="card-header">
<div class="row g-0">
<div t-if="!props.noInputName or defaultName" class="col-auto">
<a role="button" href="#" t-on-click.prevent="() => this.setMode('auto')" t-attf-class="o_web_sign_auto_button me-2 btn btn-light {{ state.signMode === 'auto' ? 'active': '' }}">
<a role="button" href="#" t-on-click.prevent="onClickSignAuto" t-attf-class="o_web_sign_auto_button me-2 btn btn-light {{ state.signMode === 'auto' ? 'active': '' }}">
Auto
</a>
</div>
@@ -63,20 +63,14 @@
</a>
</div>
<div class="col-auto">
<a role="button" href="#" t-on-click.prevent="() => this.setMode('load')" t-attf-class="o_web_sign_load_button me-2 btn btn-light {{ state.signMode === 'load' ? 'active': '' }}">
<a role="button" href="#" t-on-click.prevent="onClickSignLoad" t-attf-class="o_web_sign_load_button me-2 btn btn-light {{ state.signMode === 'load' ? 'active': '' }}">
Load
</a>
</div>
<div t-if="state.signMode === 'draw'" t-attf-class="o_web_sign_draw_clear col-auto ms-auto">
<a role="button" href="#" t-on-click.prevent="onClickSignDrawClear" class="btn btn-link">
Clear
</a>
</div>
<Dropdown t-if="state.signMode === 'auto'" class="'o_web_sign_auto_select_style col-auto ms-auto'" togglerClass="'btn btn-link'">
<t t-set-slot="toggler">
Style
</t>
<div class="col-auto division ms-auto"></div>
<Dropdown t-if="state.signMode === 'auto'" class="'o_web_sign_auto_select_style col-auto'" togglerClass="'btn btn-link fa fa-font'">
<t t-foreach="fonts" t-as="font" t-key="font_index">
<DropdownItem onSelected="() => this.onSelectFont(font_index)">
<img class="img-fluid" t-att-src="getSVGTextFont(font)"/>
@@ -84,8 +78,14 @@
</t>
</Dropdown>
<div t-if="state.signMode === 'draw'" t-attf-class="o_web_sign_draw_clear col-auto">
<a role="button" href="#" t-on-click.prevent="onClickSignDrawClear" class="btn btn-link fa fa-trash"/>
</div>
<div t-if="state.signMode === 'load'" class="o_web_sign_load_file col-auto">
<input t-ref="signInputLoad" type="file" role="button" name="files[]" class="btn btn-link py-0" t-on-change="onChangeSignLoadInput"/>
<button type="button" id="loadFileXml" t-on-click="uploadFile"
class="btn btn-link fa fa-upload" />
<input t-ref="signInputLoad" type="file" role="button" name="files[]" class="d-none" t-on-change="onChangeSignLoadInput"/>
</div>
</div>
</div>
@@ -13,6 +13,16 @@ let env;
let target;
let props;
const getNameAndSignatureButtonNames = (target) => {
return [...target.querySelectorAll(".card-header .col-auto")].reduce((names, el) => {
const text = el.textContent.trim();
if (text) {
names.push(text);
}
return names;
}, []);
};
QUnit.module("Components", ({ beforeEach }) => {
beforeEach(async () => {
const mockRPC = async (route, args) => {
@@ -37,11 +47,11 @@ QUnit.module("Components", ({ beforeEach }) => {
const defaultName = "Don Toliver";
props.signature.name = defaultName;
await mount(NameAndSignature, target, { env, props });
assert.deepEqual(
[...target.querySelectorAll(".card-header .col-auto")].map((el) =>
el.textContent.trim()
),
["Auto", "Draw", "Load", "Style"]
assert.deepEqual(getNameAndSignatureButtonNames(target), ["Auto", "Draw", "Load"]);
assert.containsOnce(
target,
".o_web_sign_auto_select_style",
"should show font selection dropdown"
);
assert.containsOnce(target, ".card-header .active");
assert.strictEqual(target.querySelector(".card-header .active").textContent.trim(), "Auto");
@@ -49,26 +59,14 @@ QUnit.module("Components", ({ beforeEach }) => {
assert.strictEqual(target.querySelector(".o_web_sign_name_group input").value, defaultName);
await click(target, ".o_web_sign_draw_button");
assert.deepEqual(
[...target.querySelectorAll(".card-header .col-auto")].map((el) =>
el.textContent.trim()
),
["Auto", "Draw", "Load", "Clear"]
);
assert.deepEqual(getNameAndSignatureButtonNames(target), ["Auto", "Draw", "Load"]);
assert.containsOnce(target, ".o_web_sign_draw_clear");
assert.containsOnce(target, ".card-header .active");
assert.strictEqual(target.querySelector(".card-header .active").textContent.trim(), "Draw");
await click(target, ".o_web_sign_load_button");
assert.deepEqual(
[...target.querySelectorAll(".card-header .col-auto")].map((el) =>
el.textContent.trim()
),
["Auto", "Draw", "Load", ""]
);
assert.hasClass(
target.querySelectorAll(".card-header .col-auto")[3],
"o_web_sign_load_file"
);
assert.deepEqual(getNameAndSignatureButtonNames(target), ["Auto", "Draw", "Load"]);
assert.containsOnce(target, ".o_web_sign_load_file");
assert.containsOnce(target, ".card-header .active");
assert.strictEqual(target.querySelector(".card-header .active").textContent.trim(), "Load");
});
@@ -81,12 +79,8 @@ QUnit.module("Components", ({ beforeEach }) => {
await editInput(target, ".o_web_sign_name_group input", "plop");
await nextTick();
assert.deepEqual(
[...target.querySelectorAll(".card-header .col-auto")].map((el) =>
el.textContent.trim()
),
["Auto", "Draw", "Load", "Style"]
);
assert.deepEqual(getNameAndSignatureButtonNames(target), ["Auto", "Draw", "Load"]);
assert.containsOnce(target, ".o_web_sign_auto_select_style");
assert.strictEqual(target.querySelector(".card-header .active").textContent.trim(), "Auto");
assert.containsOnce(target, ".o_web_sign_name_group input");
assert.strictEqual(target.querySelector(".o_web_sign_name_group input").value, "plop");
@@ -106,12 +100,8 @@ QUnit.module("Components", ({ beforeEach }) => {
};
props.signature.name = defaultName;
await mount(NameAndSignature, target, { env, props });
assert.deepEqual(
[...target.querySelectorAll(".card-header .col-auto")].map((el) =>
el.textContent.trim()
),
["Auto", "Draw", "Load", "Style"]
);
assert.deepEqual(getNameAndSignatureButtonNames(target), ["Auto", "Draw", "Load"]);
assert.containsOnce(target, ".o_web_sign_auto_select_style");
assert.containsOnce(target, ".card-header .active");
assert.strictEqual(
target.querySelector(".card-header .active").textContent.trim(),
@@ -128,12 +118,8 @@ QUnit.module("Components", ({ beforeEach }) => {
noInputName: true,
};
await mount(NameAndSignature, target, { env, props });
assert.deepEqual(
[...target.querySelectorAll(".card-header .col-auto")].map((el) =>
el.textContent.trim()
),
["Draw", "Load", "Clear"]
);
assert.deepEqual(getNameAndSignatureButtonNames(target), ["Draw", "Load"]);
assert.containsOnce(target, ".o_web_sign_draw_clear");
assert.containsOnce(target, ".card-header .active");
assert.strictEqual(
target.querySelector(".card-header .active").textContent.trim(),