Skip to content

Commit

Permalink
add insert_last2_ to store a secondary element to re-focus
Browse files Browse the repository at this point in the history
and fix checks for `style.visibility` in focusInput
  • Loading branch information
gdh1995 committed Feb 14, 2024
1 parent e6ee811 commit 604c7fc
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 39 deletions.
33 changes: 22 additions & 11 deletions content/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@ import {
isHTML_, hasTag_, createElement_, querySelectorAll_unsafe_, SafeEl_not_ff_, docEl_unsafe_, MDW, CLK, derefInDoc_,
querySelector_unsafe_, DAC, removeEl_s, appendNode_s, setClassName_s, INP, contains_s, toggleClass_s, modifySel,
focus_, testMatch, docHasFocus_, deepActiveEl_unsafe_, getEditableType_, textOffset_, fullscreenEl_unsafe_, IsInDOM_,
inputSelRange, dispatchAsync_, notSafe_not_ff_, activeEl_unsafe_, isIFrameElement, elFromPoint_
inputSelRange, dispatchAsync_, notSafe_not_ff_, activeEl_unsafe_, isIFrameElement, elFromPoint_, isStyleVisible_
} from "../lib/dom_utils"
import {
replaceOrSuppressMost_, removeHandler_, getMappedKey, prevent_, isEscape_, keybody_, DEL, BSP, ENTER, handler_stack,
getKeyStat_, suppressTail_, isRepeated_
} from "../lib/keyboard_utils"
import {
view_, wndSize_, isNotInViewport, getZoom_, prepareCrop_, getViewBox_, padClientRect_, isSelARange, center_,
getBoundingClientRect_, setBoundary_, wdZoom_, dScale_, getVisibleClientRect_, getVisibleBoundingRect_, isSelMultiline
view_, wndSize_, isNotInViewport, getZoom_, prepareCrop_, getViewBox_, padClientRect_, isSelARange, center_, dScale_,
getBoundingClientRect_, setBoundary_, wdZoom_, getVisibleClientRect_, getVisibleBoundingRect_, isSelMultiline,
kInvisibility
} from "../lib/rect"
import { post_, set_contentCommands_, runFallbackKey, send_ } from "./port"
import {
Expand All @@ -37,7 +38,7 @@ import {
import {
exitInputHint, insert_inputHint, insert_last_, raw_insert_lock, insert_Lock_, resetInsert, set_is_last_mutable,
set_inputHint, set_insert_global_, set_isHintingInput, set_insert_last_, exitInsertMode, set_passAsNormal,
insert_global_
insert_global_, insert_last2_, set_insert_last2_, insert_last_mutable
} from "./insert"
import { activate as visualActivate, deactivate as visualDeactivate } from "./visual"
import { activate as scActivate, onActivate, currentScrolling, setNewScrolling, scrollTick } from "./scroller"
Expand Down Expand Up @@ -240,27 +241,37 @@ set_contentCommands_([
},
/* kFgCmd.focusInput: */ (options: CmdOptions[kFgCmd.focusInput], count: number): void => {
const S = "IH IHS"
const act = options.act || options.action, selAction = options.select, known_last = derefInDoc_(insert_last_)
const act = options.act || options.action, selAction = options.select
const checkOrView = act === "last-visible" ? isNotInViewport : view_
const first_last = derefInDoc_(insert_last_), second_last = derefInDoc_(insert_last2_)
const known_last = first_last || second_last
const selectOrClick = (el: SafeHTMLElement, rect?: Rect | null, onlyOnce?: true): Promise<void> => {
return getEditableType_(el) ? select_(el, rect, onlyOnce, selAction, onlyOnce)
: click_async(el, rect, 1).then((): void => { onlyOnce && flash_(el) })
}
let actRet: kTip | 0 | -1 = 0
OnFirefox && insert_Lock_()
if (OnEdge || OnFirefox || OnChrome && Build.MinCVer < BrowserVer.MinEnsured$WeakRef) {
first_last || set_insert_last_(null)
second_last || set_insert_last2_(null)
}
if (act && (act[0] !== "l" || known_last && !raw_insert_lock)) { /*#__ENABLE_SCOPED__*/
let newEl: LockableElement | null | undefined = raw_insert_lock;
if (newEl) {
if (act === BSP) {
if (!view_(newEl, 1)) { execCommand(DEL, doc); }
if (!view_(newEl, 1) && isStyleVisible_(newEl)) { execCommand(DEL, doc); }
} else {
insert_last_mutable && set_insert_last2_(insert_last_)
set_insert_last_(OnFirefox ? weakRef_ff(newEl, kElRef.lastEditable) : weakRef_not_ff!(newEl))
set_is_last_mutable(0)
newEl.blur();
}
} else if (!(newEl = known_last)) {
} else if (!known_last) {
actRet = kTip.noFocused
} else if (!(act === "last-visible" ? isNotInViewport : view_)(newEl)) {
set_insert_last_(null)
} else if (!(actRet = checkOrView(newEl = known_last) as number) && isStyleVisible_(newEl)
|| actRet as number - kInvisibility.OutOfView && second_last && !checkOrView(newEl = second_last)
&& isStyleVisible_(newEl)) {
actRet = 0
set_is_last_mutable(1)
getZoom_(newEl);
prepareCrop_();
Expand All @@ -275,7 +286,7 @@ set_contentCommands_([
actRet = act[0] === "l" ? -1 : (flash_(newEl), kTip.focusedIsHidden)
}
if (actRet >= 0) {
runFallbackKey(options, actRet)
runFallbackKey(options, actRet satisfies kTip | 0)
return;
}
if (OnChrome && Build.MinCVer < BrowserVer.MinTestedES6Environment) { newEl = null } // clean the `var newEl`
Expand Down Expand Up @@ -333,7 +344,7 @@ set_contentCommands_([
if (abs_(count) > 2 * sel) {
sel = count < 0 ? 0 : sel - 1
} else {
for (ind = 0; ind < sel && hints[ind].d !== known_last; ind++) { /* empty */ }
for (ind = 0; ind < sel && hints[ind].d !== known_last && hints[ind].d !== second_last; ) { ind++ }
if (preferredSelector.endsWith("!") ? (preferredSelector = preferredSelector.slice(0, -1)) : ind >= sel) {
for (ind = preferredSelector && safeCall(testMatch, preferredSelector, visibleInputs[0]) === false ? 0 : sel;
ind < sel && !testMatch(preferredSelector, visibleInputs[ind]); ind++) { /* empty */ }
Expand Down
27 changes: 18 additions & 9 deletions content/insert.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {
doc, keydownEvents_, safeObj, isTop, set_keydownEvents_, setupEventListener, Stop_, OnChrome, OnFirefox, weakRef_ff,
esc, onWndFocus, isEnabled_, readyState_, recordLog, weakRef_not_ff, OnEdge, getTime, abs_, fgCache,
esc, onWndFocus, isEnabled_, readyState_, recordLog, weakRef_not_ff, OnEdge, getTime, abs_, fgCache, deref_,
safeCall, timeout_, timeStamp_
} from "../lib/utils"
import {
Expand Down Expand Up @@ -31,6 +31,7 @@ let isHintingInput: BOOL = 0
let inputHint: { /** box */ b: HTMLDivElement | null; /** hints */ h: InputHintItem[] } | null = null
let suppressType: string | 0 = 0
let insert_last_: WeakRef<LockableElement> | null | undefined
let insert_last2_: WeakRef<LockableElement> | null | undefined
let is_last_mutable: BOOL = 1
let lastWndFocusTime = 0
// the `readyState_ > "i"` is to grab focus on `chrome://*/*` URLs and `about:*` iframes
Expand All @@ -41,11 +42,12 @@ let passAsNormal: BOOL = 0

export {
lock_ as raw_insert_lock, insert_global_, passAsNormal,
insert_last_, is_last_mutable as insert_last_mutable,
insert_last_, insert_last2_, is_last_mutable as insert_last_mutable,
grabBackFocus, suppressType, inputHint as insert_inputHint, onWndBlur2,
}
export function set_insert_global_ (_newIGlobal: typeof insert_global_): void { insert_global_ = _newIGlobal }
export function set_insert_last_ (_newILast: WeakRef<LockableElement> | null): void { insert_last_ = _newILast }
export function set_insert_last2_ (_newILast2: typeof insert_last2_): void { insert_last2_ = _newILast2 }
export function set_is_last_mutable (_newIsLastMutable: BOOL): void { is_last_mutable = _newIsLastMutable }
export function set_inputHint (_newIHint: typeof inputHint): void { inputHint = _newIHint }
export function set_isHintingInput (_newIsHintingInput: BOOL): void { isHintingInput = _newIsHintingInput }
Expand All @@ -60,7 +62,7 @@ export const insertInit = (doesGrab?: boolean | null, inLoading?: 1): void => {
if (doesGrab) {
if (activeEl && getEditableType_(activeEl)) {
if (inLoading) {
insert_last_ = null;
insert_last_ = insert_last2_ = null
counter = 1
recordLog(kTip.logGrabFocus)()
}
Expand Down Expand Up @@ -207,7 +209,7 @@ export const exitInputHint = (): void => {
}

export const resetInsert = (): void => {
insert_last_ = lock_ = insert_global_ = null;
insert_last_ = insert_last2_ = lock_ = insert_global_ = null
is_last_mutable = 1;
exitGrab()
setupSuppress()
Expand All @@ -218,6 +220,7 @@ export const onFocus = (event: Event | FocusEvent): void => {
? !event.isTrusted : event.isTrusted === false) { return; }
// on Firefox, target may also be `document`
let target: EventTarget | Element | Window | Document = event.target;
let el2: SafeElement & { _: 1 } | LockableElement | null | undefined
if (target === window) {
lastWndFocusTime = timeStamp_(event)
onWndFocus()
Expand Down Expand Up @@ -248,8 +251,8 @@ export const onFocus = (event: Event | FocusEvent): void => {
}
if (!lastWndFocusTime || timeStamp_(event) - lastWndFocusTime > 30) {
if (!OnFirefox) {
let el: SafeElement | null = SafeEl_not_ff_!(target as Element)
el && setNewScrolling(el)
el2 = SafeEl_not_ff_!(target as Element) satisfies SafeElement | null as SafeElement & { _: 1 } | null
el2 && setNewScrolling(el2)
} else {
setNewScrolling(target as SafeElement)
}
Expand All @@ -261,10 +264,16 @@ export const onFocus = (event: Event | FocusEvent): void => {
} else {
esc!(HandlerResult.Nothing)
lock_ = target
if (is_last_mutable) {
// here ignore the rare case of an XMLDocument with a editable node on Firefox, for smaller code
if (activeEl_unsafe_() !== doc.body) {
// here ignore the rare case of an XMLDocument with a editable node on Firefox, for smaller code
if (activeEl_unsafe_() !== doc.body) {
if (is_last_mutable) {
el2 = deref_(insert_last_)
insert_last2_ = !el2 || el2 === target ? insert_last2_
: OnFirefox && Build.MinFFVer < FirefoxBrowserVer.MinWeakRefReliableForDom
? weakRef_ff(el2, kElRef.lastEditable2) : insert_last_
insert_last_ = OnFirefox ? weakRef_ff(target, kElRef.lastEditable) : weakRef_not_ff!(target)
} else {
insert_last2_ = OnFirefox ? weakRef_ff(target, kElRef.lastEditable2) : weakRef_not_ff!(target)
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions content/link_hints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ import {
} from "../lib/dom_utils"
import {
ViewBox, getViewBox_, prepareCrop_, wndSize_, bZoom_, wdZoom_, dScale_, boundingRect_,
docZoom_, bScale_, dimSize_, isSelARange, view_, isNotInViewport, VisibilityType,
docZoom_, bScale_, dimSize_, isSelARange, view_, isNotInViewport, kInvisibility,
} from "../lib/rect"
import {
replaceOrSuppressMost_, removeHandler_, getMappedKey, keybody_, isEscape_, getKeyStat_, keyNames_, suppressTail_,
Expand All @@ -107,7 +107,9 @@ import {
} from "./dom_ui"
import { scrollTick, beginScroll, currentScrolling } from "./scroller"
import { hudTip, hudShow, hudHide, hud_tipTimer } from "./hud"
import { set_onWndBlur2, insert_Lock_, set_grabBackFocus, insertInit, raw_insert_lock, insert_last_ } from "./insert"
import {
set_onWndBlur2, insert_Lock_, set_grabBackFocus, insertInit, raw_insert_lock, insert_last_, insert_last2_
} from "./insert"
import {
getVisibleElements, localLinkClear, frameNested_, checkNestedFrame, set_frameNested_, filterOutNonReachable, traverse,
ClickType, initTestRegExps, excludeHints
Expand Down Expand Up @@ -558,7 +560,8 @@ export const findAnElement_ = (options: OptionsToFindElement, count: number, als
: testD("el") // selected
? isSelARange(getSelection_()) && (el = getSelectionFocusEdge_(getSelected()), isSel = !!el, el)
: testD("sc") || testD("ac") ? derefInDoc_(currentScrolling) // currentScrollable / DOMActivate
: testD("la") || testD("ec") ? /* last-focused / recently-focused */ derefInDoc_(insert_last_)
: testD("la") || testD("ec")
? /* last-focused / recently-focused */ derefInDoc_(insert_last_) || derefInDoc_(insert_last2_)
: testD("f") ? /* focused */ insert_Lock_() || (OnFirefox ? <SafeElement | null> deepActiveEl_unsafe_(alsoBody)
: SafeEl_not_ff_!(deepActiveEl_unsafe_(alsoBody)))
: (testD("h") || testD("cl")) ? derefInDoc_(lastHovered_) // hovered | clicked
Expand All @@ -573,7 +576,7 @@ export const findAnElement_ = (options: OptionsToFindElement, count: number, als
&& chromeVer_ < BrowserVer.MinEnsured$Element$$Closest) ? OnFirefox ? el.closest!(j) as SafeElement | null
: SafeEl_not_ff_!(el.closest!(j)) : el2
}
el = el && isNotInViewport(el) < (wholeDoc ? VisibilityType.OutOfView+1 : VisibilityType.Visible + 1)
el = el && isNotInViewport(el) < (wholeDoc ? kInvisibility.OutOfView + 1 : kInvisibility.Visible + 1)
&& excludeHints([[el as SafeElementForMouse]], options, 1).length > 0 ? el : null
}
if (el) { break }
Expand Down
14 changes: 7 additions & 7 deletions content/pagination.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
htmlTag_, isAriaFalse_, isStyleVisible_, querySelectorAll_unsafe_, isIFrameElement, ALA, attr_s, findAnchor_,
contains_s, notSafe_not_ff_, hasTag_, AriaArray, testMatch, uneditableInputs_, findSelectorByHost
} from "../lib/dom_utils"
import { getBoundingClientRect_, isNotInViewport, view_, VisibilityType } from "../lib/rect"
import { getBoundingClientRect_, isNotInViewport, view_, kInvisibility } from "../lib/rect"
import { kSafeAllSelector, detectUsableChild } from "./link_hints"
import { traverse, ngEnabled, extraClickable_ } from "./local_links"
import { find_box } from "./mode_find"
Expand Down Expand Up @@ -173,7 +173,7 @@ export const findNextInRel = (options: CmdOptions[kFgCmd.goNext]
: ":-webkit-any" + query.slice(3).replace("~= i", ""))!
let s: string | null | undefined;
type HTMLElementWithRel = HTMLAnchorElement | HTMLAreaElement | HTMLLinkElement;
let matched: HTMLElementWithRel | undefined, invisible: VisibilityType | 9 = 9, tag: "a" | "area" | "link" | ""
let matched: HTMLElementWithRel | undefined, invisible: kInvisibility | 9 = 9, tag: "a" | "area" | "link" | ""
const re1 = <RegExpOne> /\s/
if (OnChrome && Build.MinCVer < BrowserVer.MinEnsured$ForOf$ForDOMListTypes
&& Build.MinCVer >= BrowserVer.BuildMinForOf
Expand All @@ -195,12 +195,12 @@ export const findNextInRel = (options: CmdOptions[kFgCmd.goNext]
}
if (!matched || (invisible < 9 ? invisible : (invisible = isNotInViewport(matched as typeof element)))
|| !options.n && !isNotInViewport(element)) {
invisible = !matched || invisible ? 9 : VisibilityType.Visible
invisible = !matched || invisible ? 9 : kInvisibility.Visible
matched = element as HTMLElementWithRel
}
}
}
if (matched && (invisible < 9 ? invisible : isNotInViewport(matched as SafeHTMLElement)) > VisibilityType.OutOfView) {
if (matched && (invisible < 9 ? invisible : isNotInViewport(matched as SafeHTMLElement)) > kInvisibility.OutOfView) {
s = matched.href
options.match = `a[href*="${OnEdge || OnChrome && Build.MinCVer < BrowserVer.Min$CSS$$escape
? s.slice(new URL(s).origin.length).replace(<RegExpG> /"|\\/g, "\\$&")
Expand All @@ -217,16 +217,16 @@ export const findNextInRel = (options: CmdOptions[kFgCmd.goNext]
}

export const jumpToNextLink: VApiTy["j"] = (linkElement: GoNextBaseCandidate[0], options): void => {
const invisible = options.a ? VisibilityType.NoSpace : isNotInViewport(linkElement)
const avoidClick = invisible > VisibilityType.OutOfView
const invisible = options.a ? kInvisibility.NoSpace : isNotInViewport(linkElement)
const avoidClick = invisible > kInvisibility.OutOfView
const url = (avoidClick || invisible && !options.v)
&& ((linkElement as TypeToPick<Element, HTMLLinkElement, "href">).href ||
(findAnchor_(linkElement) || linkElement as TypeToPick<Element, HTMLLinkElement, "href">).href)
url && vApi.t({ k: kTip.raw, t: url.slice(0, 256), d: 2, l: 1 })
if (avoidClick && url) {
contentCommands_[kFgCmd.framesGoBack](safer<CmdOptions[kFgCmd.framesGoBack]>({ r: 1, u: url }))
} else {
options.v && invisible === VisibilityType.OutOfView && view_(linkElement, 1)
options.v && invisible === kInvisibility.OutOfView && view_(linkElement, 1)
flash_(linkElement) // here calls getRect -> preparCrop_
timeout_((): void => { void catchAsyncErrorSilently(click_async(linkElement)) }, 100)
}
Expand Down
4 changes: 3 additions & 1 deletion lib/base.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,4 +292,6 @@ interface KnownDataset {
canonicalSrc: string // used in HintMode.{OPEN_IMAGE,COPY_IMAGE,DOWNLOAD_MEDIA}
}

declare const enum kElRef { lastHovered = 1, lastEditable, lastClicked, currentScrolling, cachedScrollable }
declare const enum kElRef {
lastHovered = 1, lastEditable, lastEditable2, lastClicked, currentScrolling, cachedScrollable
}
14 changes: 7 additions & 7 deletions lib/rect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
IsInDOM_, scrollIntoView_, rangeCount_, removeEl_s, append_not_ff, htmlTag_, getRootNode_mounted
} from "./dom_utils"

export declare const enum VisibilityType { Visible = 0, OutOfView = 1, NotInFullscreen = 2, NoSpace = 3 }
export declare const enum kInvisibility { Visible = 0, OutOfView = 1, NotInFullscreen = 2, NoSpace = 3 }
export type Point2D = readonly [ left: number, top: number ]
export type ViewBox = readonly [ left: number, top: number, width: number, height: number, maxLeft: number ]
export type ViewOffset = readonly [ left: number, top: number ] | ViewBox
Expand Down Expand Up @@ -393,13 +393,13 @@ export const getViewBox_ = function (needBox?: 1 | /** dialog-found */ 2): ViewB
(): ViewOffset
}

export const isNotInViewport = (element: SafeElement, rect?: Rect): VisibilityType => {
export const isNotInViewport = (element: SafeElement, rect?: Rect): kInvisibility => {
let fs: Element | null
rect = rect || boundingRect_(element!)
return rect.b - rect.t < 1 || rect.r - rect.l < 1 ? VisibilityType.NoSpace
: (fs = fullscreenEl_unsafe_()) && !IsInDOM_(element, fs) ? VisibilityType.NotInFullscreen
return rect.b - rect.t < 1 || rect.r - rect.l < 1 ? kInvisibility.NoSpace
: (fs = fullscreenEl_unsafe_()) && !IsInDOM_(element, fs) ? kInvisibility.NotInFullscreen
: rect.b <= 0 || rect.t >= wndSize_() || rect.r <= 0 || rect.l >= wndSize_(1)
? VisibilityType.OutOfView : VisibilityType.Visible
? kInvisibility.OutOfView : kInvisibility.Visible
}

export const isSelARange = (sel: Selection): boolean => sel.type === "Range"
Expand All @@ -425,10 +425,10 @@ export const isSelMultiline = (sel: Selection): boolean => {
return rects === !1
}

export const view_ = (el: SafeElement, allowSmooth?: BOOL | boolean, oldY?: number): VisibilityType => {
export const view_ = (el: SafeElement, allowSmooth?: BOOL | boolean, oldY?: number): kInvisibility => {
let rect = boundingRect_(el), secondScroll: number,
ty = isNotInViewport(el, rect)
if (ty === VisibilityType.OutOfView) {
if (ty === kInvisibility.OutOfView) {
let ih = wndSize_(), delta = rect.t < 0 ? -1 : rect.t > ih ? 1 : 0, f = oldY != null,
elHeight = rect.b - rect.t
const kBh = "scroll-behavior"
Expand Down

0 comments on commit 604c7fc

Please sign in to comment.