diff --git a/frappe/public/js/frappe/form/form.js b/frappe/public/js/frappe/form/form.js index 4622c58155..3d0b1bbc6f 100644 --- a/frappe/public/js/frappe/form/form.js +++ b/frappe/public/js/frappe/form/form.js @@ -1414,8 +1414,13 @@ frappe.ui.form.Form = class FrappeForm { if (selector.length) { frappe.utils.scroll_to(selector); } - } else if (window.location.hash && $(window.location.hash).length) { - frappe.utils.scroll_to(window.location.hash, true, 200, null, null, true); + } else if (window.location.hash) { + if ($(window.location.hash).length) { + frappe.utils.scroll_to(window.location.hash, true, 200, null, null, true); + } else { + this.scroll_to_field(window.location.hash.replace("#", "")) && + history.replaceState(null, null, " "); + } } } @@ -1926,11 +1931,12 @@ frappe.ui.form.Form = class FrappeForm { } // highlight control inside field - let control_element = $el.find(".form-control"); + let control_element = $el.closest(".frappe-control"); control_element.addClass("highlight"); setTimeout(() => { control_element.removeClass("highlight"); }, 2000); + return true; } setup_docinfo_change_listener() { diff --git a/frappe/public/js/frappe/router.js b/frappe/public/js/frappe/router.js index def04cf37e..9ad917a57a 100644 --- a/frappe/public/js/frappe/router.js +++ b/frappe/public/js/frappe/router.js @@ -31,20 +31,21 @@ window.addEventListener("popstate", (e) => { return false; }); -// routing v2, capture all clicks so that the target is managed with push-state +// Capture all clicks so that the target is managed with push-state $("body").on("click", "a", function (e) { - let override = (route) => { + const target_element = e.currentTarget; + const href = target_element.getAttribute("href"); + const is_on_same_host = target_element.hostname === window.location.hostname; + + const override = (route) => { e.preventDefault(); frappe.set_route(route); return false; }; - const target_element = e.currentTarget; - const href = target_element.getAttribute("href"); - const is_on_same_host = target_element.hostname === window.location.hostname; - // click handled, but not by href if ( + !is_on_same_host || // external link target_element.getAttribute("onclick") || // has a handler e.ctrlKey || e.metaKey || // open in a new tab @@ -53,18 +54,13 @@ $("body").on("click", "a", function (e) { return; } - if (href === "") { - return override("/app"); - } - if (href && href.startsWith("#")) { // target startswith "#", this is a v1 style route, so remake it. return override(target_element.hash); } - if (is_on_same_host && frappe.router.is_app_route(target_element.pathname)) { + if (frappe.router.is_app_route(target_element.pathname)) { // target has "/app, this is a v2 style route. - if (target_element.search) { frappe.route_options = {}; let params = new URLSearchParams(target_element.search); @@ -72,7 +68,10 @@ $("body").on("click", "a", function (e) { frappe.route_options[key] = value; } } - return override(target_element.pathname + target_element.hash); + if (target_element.hash) { + frappe.route_hash = target_element.hash; + } + return override(target_element.pathname); } }); @@ -352,8 +351,8 @@ frappe.router = { route = this.get_route_from_arguments(route); route = this.convert_from_standard_route(route); let sub_path = this.make_url(route); - // replace each # occurrences in the URL with encoded character except for last - // sub_path = sub_path.replace(/[#](?=.*[#])/g, "%23"); + sub_path += frappe.route_hash || ""; + frappe.route_hash = null; if (frappe.open_in_new_tab) { localStorage["route_options"] = JSON.stringify(frappe.route_options); window.open(sub_path, "_blank"); diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 095b04c931..f9b6114539 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -340,9 +340,21 @@ Object.assign(frappe.utils, { scroll_top = 0; } + const highlight = () => { + if (highlight_element) { + $(element).addClass("highlight"); + document.addEventListener( + "click", + function () { + $(element).removeClass("highlight"); + }, + { once: true } + ); + } + }; // already there if (scroll_top == element_to_be_scrolled.scrollTop()) { - return; + return highlight(); } if (animate) { @@ -352,16 +364,7 @@ Object.assign(frappe.utils, { }) .promise() .then(() => { - if (highlight_element) { - $(element).addClass("highlight"); - document.addEventListener( - "click", - function () { - $(element).removeClass("highlight"); - }, - { once: true } - ); - } + highlight(); callback && callback(); }); } else { diff --git a/frappe/public/scss/desk/global.scss b/frappe/public/scss/desk/global.scss index b355dbdec2..98aeacf55d 100644 --- a/frappe/public/scss/desk/global.scss +++ b/frappe/public/scss/desk/global.scss @@ -597,11 +597,25 @@ details > summary:focus { display: none; } -.highlight { +.highlight:not(.frappe-control) { transition: 0.5s ease background-color; box-shadow: var(--highlight-shadow) !important; } +.frappe-control.highlight { + --wrap-padding: calc(-1 * var(--padding-sm)); + &::after { + content: " "; + border-radius: 5px; + box-shadow: var(--highlight-shadow) !important; + top: var(--wrap-padding); + position: absolute; + bottom: var(--wrap-padding); + left: var(--wrap-padding); + right: var(--wrap-padding); + } +} + .dropdown-menu.small { font-size: var(--text-sm); min-width: 140px;