Skip to content

Commit

Permalink
[18.0][IMP] sign_oca: Add guided arrow flow to sign_oca
Browse files Browse the repository at this point in the history
  • Loading branch information
kobros-tech committed Jan 30, 2025
1 parent 9074efa commit 372f066
Show file tree
Hide file tree
Showing 4 changed files with 219 additions and 1 deletion.
7 changes: 7 additions & 0 deletions sign_oca/__manifest__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@
"sign_oca/static/src/components/sign_oca_pdf/sign_oca_pdf.xml",
"sign_oca/static/src/elements/elements.xml",
"sign_oca/static/src/scss/sign_oca.scss",
# kobros
"sign_oca/static/src/components/sign_oca_pdf_common/sign_oca_navigator.esm.js",
#
"sign_oca/static/src/components/sign_oca_pdf_common/sign_oca_pdf_common.esm.js",
"sign_oca/static/src/components/sign_oca_configure/sign_oca_configure_field_dialog.esm.js",
"sign_oca/static/src/components/sign_oca_configure/sign_oca_configure_field_dialog.xml",
Expand Down Expand Up @@ -79,6 +82,10 @@
"sign_oca/static/src/components/sign_oca_pdf_portal/sign_oca_pdf_portal.xml",
"sign_oca/static/src/elements/elements.xml",
"sign_oca/static/src/scss/sign_oca.scss",
# kobros
"sign_oca/static/src/components/sign_oca_pdf_common/iframe.css",
"sign_oca/static/src/components/sign_oca_pdf_common/sign_oca_navigator.esm.js",
#
"sign_oca/static/src/components/sign_oca_pdf_common/sign_oca_pdf_common.esm.js",
"sign_oca/static/src/elements/text.esm.js",
"sign_oca/static/src/elements/signature.esm.js",
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
/** @odoo-module QWeb **/
/* global document, offset, console */
import {_t} from "@web/core/l10n/translation";

/**
* Starts the sign item navigator
* @param { SignablePDFIframe } parent
* @param { HTMLElement } target
* @param { Object } types
* @param { Environment } env
*/
export function startSignItemNavigator(parent, target, types, env) {
const state = {
started: false,
isScrolling: false,
};

const navigator = document.createElement("div");
navigator.classList.add("o_sign_sign_item_navigator");
const navLine = document.createElement("div");
navLine.classList.add("o_sign_sign_item_navline");

function _scrollToSignItemPromise(item) {
if (env.isSmall) {
return new Promise((resolve) => {
state.isScrolling = true;
item.scrollIntoView({
behavior: "smooth",
block: "center",
inline: "center",
});
resolve();
});
}
state.isScrolling = true;
const viewer = target.querySelector("#viewer");
const containerHeight = target.offsetHeight;
const viewerHeight = viewer.offsetHeight;

let scrollOffset = containerHeight / 4;
const scrollTop = offset(item).top - offset(viewer).top - scrollOffset;
if (scrollTop + containerHeight > viewerHeight) {
scrollOffset += scrollTop + containerHeight - viewerHeight;
}
if (scrollTop < 0) {
scrollOffset += scrollTop;
}
scrollOffset +=
offset(target).top -
navigator.offsetHeight / 2 +
item.getBoundingClientRect().height / 2;

const duration = Math.max(
Math.min(
500,
5 *
(Math.abs(target.scrollTop - scrollTop) +
Math.abs(navigator.getBoundingClientRect().top) -
scrollOffset)
),
100
);

return new Promise((resolve) => {
target.scrollTo({top: scrollTop, behavior: "smooth"});
const an = navigator.animate(
{top: `${scrollOffset}px`},
{duration, fill: "forwards"}
);
const an2 = navLine.animate(
{top: `${scrollOffset}px`},
{duration, fill: "forwards"}
);
Promise.all([an.finished, an2.finished]).then(() => resolve());
});
}

function setTip(text) {
navigator.style.fontFamily = "Helvetica";
navigator.innerText = text;
}

/**
* Sets the entire radio set on focus.
* @param {Number} radio_set_id
*/
function highligtRadioSet(radio_set_id) {
parent
.checkSignItemsCompletion()
.filter((item) => item.data.radio_set_id === radio_set_id)
.forEach((item) => {
item.el.classList.add("ui-selected");
});
}

function scrollToSignItem({el: item, data}) {
_scrollToSignItemPromise(item).then(() => {
const type = types[data.type_id];
if (type.item_type === "text" && item.querySelector("input")) {
item.value = item.querySelector("input").value;
item.focus = () => item.querySelector("input").focus();
}
// Maybe store signature in data rather than in the dataset
if (item.value === "" && !item.dataset.signature) {
setTip(type.tip);
}
parent.refreshSignItems();
if (data.type === "radio") {
// We need to highligt the entire radio set items
highligtRadioSet(data.radio_set_id);
} else {
item.focus();
item.classList.add("ui-selected");
}
if (["signature", "initial"].includes(type.item_type)) {
if (item.dataset.hasFocus) {
const clickableElement = data.isSignItemEditable
? item.querySelector(".o_sign_item_display")
: item;
clickableElement.click();
} else {
item.dataset.hasFocus = true;
}
}
state.isScrolling = false;
});
}

function goToNextSignItem() {
if (!state.started) {
state.started = true;
parent.refreshSignItems();
goToNextSignItem();
return false;
}
const selectedElements = target.querySelectorAll(".ui-selected");
selectedElements.forEach((selectedElement) => {
selectedElement.classList.remove("ui-selected");
});
const signItemsToComplete = parent.checkSignItemsCompletion().sort((a, b) => {
return (
100 * (a.data.page - b.data.page) +
10 * (a.data.posY - b.data.posY) +
(a.data.posX - b.data.posX)
);
});

console.log("signItemsToComplete?", signItemsToComplete);

if (signItemsToComplete.length > 0) {
scrollToSignItem(signItemsToComplete[0]);
}
}

navigator.addEventListener("click", goToNextSignItem);
target.append(navigator);
navigator.before(navLine);

setTip(_t("Click to start"));
navigator.focus();

function toggle(force) {
navigator.style.display = force ? "" : "none";
navLine.style.display = force ? "" : "none";
}

return {
setTip,
goToNextSignItem,
toggle,
state,
};
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
/** @odoo-module QWeb **/
/* global window, setTimeout, document, clearTimeout */
/* global window, setTimeout, document, clearTimeout, console */
import {_t} from "@web/core/l10n/translation";
import {Component, onMounted, onWillStart, onWillUnmount, useRef} from "@odoo/owl";
import {AlertDialog} from "@web/core/confirmation_dialog/confirmation_dialog";
import {renderToString} from "@web/core/utils/render";
import {useService} from "@web/core/utils/hooks";
import {startSignItemNavigator} from "./sign_oca_navigator.esm";

export default class SignOcaPdfCommon extends Component {
setup() {
Expand Down Expand Up @@ -104,6 +105,10 @@ export default class SignOcaPdfCommon extends Component {
"sign_oca_ready"
);
this.iframeLoaded.resolve();

// Kobros
this.navigate();
//
}
postIframeField(item) {
if (this.items[item.id]) {
Expand All @@ -122,6 +127,39 @@ export default class SignOcaPdfCommon extends Component {
this.items[item.id] = signatureItem[0];
return signatureItem;
}

// Kobros
navigate() {
console.log("this.info.items", this.info.items);

// Add guided arrow to the first element if present
if (this.postIframeField(this.info.items[1])) {
const $signatureItem = this.postIframeField(this.info.items[1]);
const signatureItem = $signatureItem[0];

console.log("signatureItem", $signatureItem);
console.log("signatureItem", signatureItem);

const target = signatureItem;
this.navigator = startSignItemNavigator(
this,
target,
[{type_id: {item_type: "text"}}],
this.env
);
target.addEventListener("scroll", () => {
if (!this.navigator.state.isScrolling && this.navigator.state.started) {
this.navigator.setTip(_t("next"));
}

console.log("scrolling");
console.log(this.navigator);
console.log(this.navigator.state.isScrolling);
console.log(this.navigator.state.started);
});
}
}
//
}
SignOcaPdfCommon.template = "sign_oca.SignOcaPdfCommon";
SignOcaPdfCommon.props = [];

0 comments on commit 372f066

Please sign in to comment.