From f17e692349f560186b7159522e91b86a132de7da Mon Sep 17 00:00:00 2001 From: gdh1995 Date: Tue, 30 Apr 2024 04:38:49 +0800 Subject: [PATCH] linkhints: rewrite .onTop --- content/dom_ui.ts | 37 ++++++++++++++++++++++--------------- content/link_hints.ts | 9 +++++---- content/request_handlers.ts | 3 ++- lib/rect.ts | 18 +++++++++--------- 4 files changed, 38 insertions(+), 29 deletions(-) diff --git a/content/dom_ui.ts b/content/dom_ui.ts index e4728b4f7..c61aa125d 100644 --- a/content/dom_ui.ts +++ b/content/dom_ui.ts @@ -10,7 +10,7 @@ import { isSafeEl_, CLK, frameElement_, runJS_, isStyleVisible_, rangeCount_, getAccessibleSelectedNode, removeEl_s, appendNode_s, append_not_ff, setClassName_s, isNode_, contains_s, setOrRemoveAttr_s, textContent_s, inputSelRange, parentNode_unsafe_s, setDisplaying_s, getRootNode_mounted, singleSelectionElement_unsafe, isHTML_, - getDirectionOfNormalSelection, showPicker_, htmlTag_, + getDirectionOfNormalSelection, showPicker_, htmlTag_, HTMLElementProto, } from "../lib/dom_utils" import { bZoom_, dScale_, getZoom_, wdZoom_, boundingRect_, prepareCrop_, getClientRectsForAreas_, @@ -36,7 +36,7 @@ let uiParent_: VUIRoot | HTMLSpanElement let cssPatch_: [string | number, (css: string) => string] | null = null let lastFlashEl: SafeHTMLElement | null = null let toExitOnClick_ = kExitOnClick.NONE -let curModalElement: HTMLDialogElement | null | undefined +let curModalElement: HTMLDialogElement | PopoverElement | null | undefined let helpBox: HTMLElement | null | undefined let hideHelp: ((event?: EventToPrevent) => void) | undefined | null let hasPopover_ = 0 @@ -45,12 +45,13 @@ export { box_ as ui_box, root_ as ui_root, styleIn_ as style_ui, lastFlashEl, curModalElement, hasPopover_, helpBox, hideHelp, toExitOnClick_, } -export const removeModal = WithDialog ? (): void => { - curModalElement && (removeEl_s(curModalElement), curModalElement = null) -} : (): void => { /* empty */ } export function set_hideHelp (_newHide: typeof hideHelp): void { hideHelp = _newHide } export function set_helpBox (_newHelpBox: typeof helpBox): void { helpBox = _newHelpBox } +export const removeModal = WithDialog ? (): void => { + curModalElement && (removeEl_s(curModalElement), curModalElement = null, hasPopover_ &= ~1) +} : (): void => { /* empty */ } + export let addUIElement = function (element: HTMLElement, adjust_type?: AdjustType): void { box_ = createElement_("div"); root_ = attachShadow_(box_) @@ -121,19 +122,21 @@ export const getBoxTagName_old_cr = OnChrome && Build.MinCVer < BrowserVer.MinFo ? "body" : "div" : 0 as never -export const addElementList = function ( - array: readonly DrawableHintItem[], offset: { readonly [index in 0 | 1]: number }, dialogContainer?: T - ): (T extends 1 | 3 ? HTMLDialogElement : HTMLDivElement) & SafeElement { +export const addElementList = function ( + array: readonly DrawableHintItem[], offset: { readonly [index in 0 | 1]: number }, onTop?: TopType + ): (TopType extends 1 | 3 ? HTMLDialogElement | HTMLDivElement : HTMLDivElement) & SafeElement { const kMaxSlice = 2048, needToSlice = array.length > kMaxSlice - const parent = createElement_(WithDialog && dialogContainer ? "dialog" + const topWithoutPopover = onTop && !(array.length && (OnChrome && Build.MinCVer >= BrowserVer.MinEnsuredPopover + || !OnEdge && (HTMLElementProto! satisfies HTMLElement as Partial).showPopover)) + const parent = createElement_(WithDialog && topWithoutPopover ? "dialog" : OnChrome && Build.MinCVer < BrowserVer.MinForcedColorsMode ? getBoxTagName_old_cr() : "div"); const style = parent.style - const cls = "R HM" + fgCache.d, zoom = bZoom_ / (WithDialog && dialogContainer ? 1 : dScale_) + const cls = "R HM" + fgCache.d, zoom = bZoom_ / (WithDialog && onTop ? 1 : dScale_) let innerBox: HTMLDivElement | HTMLBodyElement | HTMLDialogElement | undefined = parent let i = 0 - setClassName_s(parent, WithDialog && dialogContainer ? cls + " DLG" : cls) + setClassName_s(parent, WithDialog && topWithoutPopover ? cls + " DLG" : cls) if (OnChrome && Build.MinCVer < BrowserVer.MinForcedColorsMode - && dialogContainer && array.length && getBoxTagName_old_cr() < "d") { // + && WithDialog && topWithoutPopover && array.length && getBoxTagName_old_cr() < "d") { // innerBox = createElement_(getBoxTagName_old_cr()) appendNode_s(parent, innerBox) setClassName_s(innerBox, cls) @@ -158,11 +161,12 @@ export const addElementList = function ( zoom - 1 && (style.zoom = zoom as number | string as string); } fullscreenEl_unsafe_() && (style.position = "fixed"); - if (WithDialog && dialogContainer) { + if (WithDialog && onTop) { curModalElement = parent as HTMLDialogElement + hasPopover_ |= !(topWithoutPopover satisfies boolean | 0 | undefined) as boolean | BOOL as BOOL } addUIElement(parent, AdjustType.DEFAULT, lastFlashEl) - return parent as (T extends 1 | 3 ? HTMLDialogElement : HTMLDivElement) & SafeElement + return parent as (TopType extends 1 | 3 ? HTMLDialogElement : HTMLDivElement) & SafeElement } export const adjustUI = (event?: Event | /* enable */ 1 | /* disable */ 2): void => { @@ -182,7 +186,6 @@ export const adjustUI = (event?: Event | /* enable */ 1 | /* disable */ 2): void const sin = styleIn_, s = sin && (sin as HTMLStyleElement).sheet s && (s.disabled = false); if (WithDialog) { - disableUI || curModalElement && !curModalElement.open && curModalElement.showModal() if (disableUI) { /* empty */ } else if (hasPopover_ || isReplacedEl && (OnChrome && Build.MinCVer >= BrowserVer.MinEnsuredPopover || (uiParent_ as PopoverElement).showPopover)) { @@ -193,6 +196,10 @@ export const adjustUI = (event?: Event | /* enable */ 1 | /* disable */ 2): void } else if ((uiParent_ as PopoverElement).popover) { (uiParent_ as PopoverElement).popover = null setClassName_s(uiParent_ as SafeHTMLElement, "") + } else if (curModalElement) { + // if box_ has been re-added, then `.open` is true and `.showModal()` throws without a `.close()` + (curModalElement as HTMLDialogElement).open && (curModalElement as HTMLDialogElement).close(); + (curModalElement as HTMLDialogElement).showModal() } } if (el || event) { diff --git a/content/link_hints.ts b/content/link_hints.ts index 9aa34f65c..46a1cf92f 100644 --- a/content/link_hints.ts +++ b/content/link_hints.ts @@ -91,7 +91,8 @@ import { import { querySelector_unsafe_, isHTML_, scrollingEl_, docEl_unsafe_, IsInDOM_, GetParent_unsafe_, hasInCSSFilter_,derefInDoc_, getComputedStyle_, isStyleVisible_, htmlTag_, fullscreenEl_unsafe_, removeEl_s, PGH, toggleClass_s, doesSupportDialog, - getSelectionFocusEdge_, SafeEl_not_ff_, compareDocumentPosition, deepActiveEl_unsafe_, frameElement_, getSelection_, findSelectorByHost + getSelectionFocusEdge_, SafeEl_not_ff_, compareDocumentPosition, deepActiveEl_unsafe_, frameElement_, getSelection_, + findSelectorByHost } from "../lib/dom_utils" import { ViewBox, getViewBox_, prepareCrop_, wndSize_, bZoom_, wdZoom_, dScale_, boundingRect_, @@ -203,8 +204,8 @@ export const activate = (options: ContentOptions, count: number, force?: 2 | Tim } coreHints.d = !(OnChrome && Build.MinCVer >= BrowserVer.MinEnsuredHTMLDialogElement || doesSupportDialog()) ? 0 : hasPopover_ > 1 || querySelector_unsafe_("dialog[open]") ? 3 - : +!!(wantDialogMode_ != null ? wantDialogMode_ : isTY(wantTop) ? findSelectorByHost(wantTop) - : options.onTop || hasInCSSFilter_() || querySelector_unsafe_("dialog[open]")) + : +!!(wantDialogMode_ != null ? wantDialogMode_ + : isTY(wantTop) ? findSelectorByHost(wantTop) : wantTop != null ? wantTop : hasInCSSFilter_()) } let allHints: readonly HintItem[], child: ChildFrame | undefined, insertPos = 0 , frameInfo: FrameHintsInfo, total: number @@ -773,7 +774,7 @@ export const clear = (onlySelfOrEvent?: 0 | 1 | Event, suppressTimeout?: number) hasManager && frame.c(0, suppressTimeout) })) coreHints.y = frameArray = []; - setupEventListener(0, PGH, clear, 1) + manager && setupEventListener(0, PGH, clear, 1) coreHints.v() removeHandler_(kHandler.linkHints) suppressTimeout != null && suppressTail_(suppressTimeout); diff --git a/content/request_handlers.ts b/content/request_handlers.ts index 57c959b63..8760ed7ef 100644 --- a/content/request_handlers.ts +++ b/content/request_handlers.ts @@ -300,7 +300,8 @@ set_hookOnWnd((((action: HookAction): void => { f("focus", onFocus, t) // https://developer.chrome.com/blog/page-lifecycle-api/ OnChrome && f("freeze", onFreezePort, t) - if (OnChrome && Build.MinCVer >= BrowserVer.MinEnsuredPopover || !OnEdge && "popover" in HTMLElementProto!) { + if (OnChrome && Build.MinCVer >= BrowserVer.MinEnsuredPopover + || !OnEdge && (HTMLElementProto! as Partial).showPopover) { f("toggle", onToggle, t) } } diff --git a/lib/rect.ts b/lib/rect.ts index 072301de4..ab59e8483 100644 --- a/lib/rect.ts +++ b/lib/rect.ts @@ -335,18 +335,18 @@ export const getViewBox_ = function (needBox?: 1 | /** dialog-or-popover-found * paintingLimited = ( /c|p/).test(docContain), notPropagate = OnChrome && (Build.MinCVer >= BrowserVer.MinNotPropagateBodyStyleIfContained || chromeVer_ > BrowserVer.MinNotPropagateBodyStyleIfContained - 1) && ( /s|t/).test(docContain), - stacking = !(WithDialog && needBox === 3) && (st.position !== "static" || (OnChrome - && Build.MinCVer < BrowserVer.MinContainLayoutOnDocAffectPositions - && chromeVer_ < BrowserVer.MinContainLayoutOnDocAffectPositions ? paintingLimited - : ( /a|c/).test(docContain)) || st.transform !== NONE), // NOTE: if box.zoom > 1, although doc.documentElement.scrollHeight is integer, // its real rect may has a float width, such as 471.333 / 472 - rect = boundingRect_(box) - let zoom = OnChrome && Build.MinCVer < BrowserVer.MinDevicePixelRatioNotImplyZoomOfDocEl - ? _fixDocZoom_old_cr!(+st.zoom || 1, box, ratio) : !OnFirefox && +st.zoom || 1, - iw = wndSize_(1), ih = wndSize_(), + rect = boundingRect_(box), + zoom = OnChrome && Build.MinCVer < BrowserVer.MinDevicePixelRatioNotImplyZoomOfDocEl + ? _fixDocZoom_old_cr!(+st.zoom || 1, box, ratio) : !OnFirefox && +st.zoom || 1 + let iw = wndSize_(1), ih = wndSize_(), _trans = st.transform // ignore the case that x != y in "transform: scale(x, y)"" - _trans = st.transform, scale = dScale_ = _trans && !_trans.startsWith(kM) && float(_trans.slice(7)) || 1 + const scale = dScale_ = _trans && !_trans.startsWith(kM) && float(_trans.slice(7)) || 1 + const stacking = !(WithDialog && needBox === 3) && (st.position !== "static" || (OnChrome + && Build.MinCVer < BrowserVer.MinContainLayoutOnDocAffectPositions + && chromeVer_ < BrowserVer.MinContainLayoutOnDocAffectPositions ? paintingLimited + : ( /a|c/).test(docContain)) || _trans !== NONE) if (fullscreenEl_unsafe_()) { getZoom_(1) dScale_ = bScale_ = 1