Skip to content

Commit

Permalink
Scroller: cache a scrollable element and ignore its "overflow" style
Browse files Browse the repository at this point in the history
E.g.: YouTube sidebar: only `overflow: auto` on hover.

So either click it first, or `map f LinkHints.activateMode scroll="force"`

This is for #147 .
  • Loading branch information
gdh1995 committed Apr 4, 2020
1 parent 0538fed commit 960506f
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 44 deletions.
1 change: 1 addition & 0 deletions content/dom_ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ var VCui = {
findCss_: null as never as FindCSS,
/** @NEED_SAFE_ELEMENTS */
activeEl_: null as SafeElement | null,
cachedScrollable_: 0 as SafeElement | 0 | null,
add_: (function <T extends HTMLElement> (this: void, element: T, adjust?: AdjustType): void {
let a = VCui, box = a.box_ = VDom.createElement_("div"),
root: VUIRoot = a.root_ = VDom.createShadowRoot_(box),
Expand Down
4 changes: 3 additions & 1 deletion content/frontend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,7 @@ if (Build.BTypes & BrowserType.Chrome && Build.BTypes & ~BrowserType.Chrome) { v
if (!lastWndFocusTime || Date.now() - lastWndFocusTime > 30) {
vCui.activeEl_ = Build.BTypes & ~BrowserType.Firefox
? vDom.SafeEl_(target as Element) || vCui.activeEl_ : target as SafeElement;
vCui.cachedScrollable_ = 0;
}
lastWndFocusTime = 0;
if (vDom.getEditableType_<2>(target)) {
Expand Down Expand Up @@ -331,6 +332,7 @@ if (Build.BTypes & BrowserType.Chrome && Build.BTypes & ~BrowserType.Chrome) { v
? path : path && (path as EventTarget[]).length > 1)
? (path as EventTarget[])[0] as Element : event.target as Element;
vCui.activeEl_ = Build.BTypes & ~BrowserType.Firefox ? vDom.SafeEl_(el) : el as SafeElement | null;
vCui.cachedScrollable_ = 0;
}
}
function onWndBlur(this: void): void {
Expand Down Expand Up @@ -485,7 +487,7 @@ if (Build.BTypes & BrowserType.Chrome && Build.BTypes & ~BrowserType.Chrome) { v
/* kFgCmd.vomnibar: */ VOmni.activateO_ ,
/* kFgCmd.reset: */ (isAlive): void => {
const a = InsertMode;
vCui.activeEl_ = vDom.lastHovered_ = a.last_ = insertLock = a.global_ = null;
vCui.activeEl_ = vCui.cachedScrollable_ = vDom.lastHovered_ = a.last_ = insertLock = a.global_ = null;
a.mutable_ = true;
a.ExitGrab_(); events.setupSuppress_();
vHints.clear_(isAlive ? 2 : 0); VVisual.deactivateV_();
Expand Down
55 changes: 28 additions & 27 deletions content/link_hints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ var VHints = {
count_: 0,
lastMode_: 0 as HintMode,
tooHigh_: false as null | boolean,
forceToScroll_: 0,
promptTimer_: TimerID.None as TimerID,
isClickListened_: true,
ngEnabled_: null as boolean | null,
Expand Down Expand Up @@ -215,9 +216,28 @@ var VHints = {
const a = this;
a._master = Build.BTypes & BrowserType.Firefox ? master && a.unwrap_(master) : master;
a.resetHints_();
a.setModeOpt_(count, options);
if (a.options_ === options) { return; }
/** ensured by {@link ../background/commands.ts#Commands.makeCommand_} */
let modeOpt: HintsNS.ModeOpt | undefined, mode = options.mode as number;
for (let modes of a.Modes_) {
if (Build.BTypes & BrowserType.Chrome && Build.MinCVer < BrowserVer.MinEnsuredES6$Array$$Includes
? modes.indexOf(mode & ~HintMode.queue) > 0
: (modes as Ensure<HintsNS.ModeOpt, "includes">).includes(mode & ~HintMode.queue)) {
modeOpt = modes;
break;
}
}
if (!modeOpt) {
modeOpt = a.Modes_[8];
mode = HintMode.DEFAULT;
}
mode = count > 1 ? mode ? mode | HintMode.queue : HintMode.OPEN_WITH_QUEUE : mode;
a.modeOpt_ = modeOpt;
a.options_ = options;
a.count_ = count;
a.chars_ = chars;
a.useFilter_ = useFilter;
a.setMode_(mode, 1);
if (!VDom.isHTML_()) {
return;
}
Expand All @@ -229,6 +249,7 @@ var VHints = {
a.tooHigh_ = (VDom.scrollingEl_(1) as HTMLElement).scrollHeight / innerHeight
> GlobalConsts.LinkHintTooHighThreshold;
}
a.forceToScroll_ = options.scroll === "force" ? 2 : 0;
a._addChildFrame = addChildFrame;
const elements = a.getVisibleElements_(view);
const hintItems = elements.map(a.createHint_, a);
Expand Down Expand Up @@ -260,29 +281,6 @@ var VHints = {
a._master && VKey.SetupEventListener_(0, "unload", a.clear_);
a.isInLH_ = true;
},
setModeOpt_ (count: number, options: HintsNS.ContentOptions): void {
const a = this;
if (a.options_ === options) { return; }
/** ensured by {@link ../background/commands.ts#Commands.makeCommand_} */
let modeOpt: HintsNS.ModeOpt | undefined, mode = options.mode as number;
for (let modes of a.Modes_) {
if (Build.BTypes & BrowserType.Chrome && Build.MinCVer < BrowserVer.MinEnsuredES6$Array$$Includes
? modes.indexOf(mode & ~HintMode.queue) > 0
: (modes as Ensure<HintsNS.ModeOpt, "includes">).includes(mode & ~HintMode.queue)) {
modeOpt = modes;
break;
}
}
if (!modeOpt) {
modeOpt = a.Modes_[8];
mode = HintMode.DEFAULT;
}
mode = count > 1 ? mode ? mode | HintMode.queue : HintMode.OPEN_WITH_QUEUE : mode;
a.modeOpt_ = modeOpt;
a.options_ = options;
a.count_ = count;
a.setMode_(mode, 1);
},
setMode_ (mode: HintMode, silent?: 1): void {
const a = this;
a.lastMode_ = a.mode_ = mode;
Expand Down Expand Up @@ -498,7 +496,8 @@ var VHints = {
&& (arr = tag === "img" ? VDom.getZoomedAndCroppedRect_(element as HTMLImageElement, null, true)
: arr || VDom.getVisibleClientRect_(element, null))
&& (type < ClickType.scrollX
|| VSc.shouldScroll_need_safe_(element, type - ClickType.scrollX as ScrollByY, 0) > 0)
|| VSc.shouldScroll_need_safe_(element
, ((type - ClickType.scrollX as ScrollByY) + _this.forceToScroll_) as BOOL | 2 | 3, 0) > 0)
&& VDom.isAriaNotTrue_(element, kAria.hidden)
&& (_this.mode_ > HintMode.min_job - 1 || VDom.isAriaNotTrue_(element, kAria.disabled))
) { hints.push([element, arr, type]); }
Expand Down Expand Up @@ -1408,7 +1407,7 @@ var VHints = {
a.options_ = a.modeOpt_ = null as never;
a.lastMode_ = a.mode_ = a.mode1_ = a.count_ =
a.maxLeft_ = a.maxTop_ = a.maxRight_ =
a.maxPrefixLen_ = a.hasExecuted_ = 0;
a.maxPrefixLen_ = a.hasExecuted_ = a.forceToScroll_ = 0;
a.keyCode_ = kKeyCode.None;
a.useFilter_ =
a.isInLH_ = a.noHUD_ = a.tooHigh_ = false;
Expand Down Expand Up @@ -2058,11 +2057,13 @@ Modes_: [
[
(element, rect): void => {
const a = VHints, type = VDom.getEditableType_<0>(element), toggleMap = a.options_.toggle;
const ui = VCui;
// here not check VDom.lastHovered on purpose
// so that "HOVER" -> any mouse events from users -> "HOVER" can still work
VCui.activeEl_ = element;
ui.activeEl_ = element;
VDom.hover_(element, VDom.center_(rect));
type || element.focus && !(<RegExpI> /^i?frame$/).test(VDom.htmlTag_(element)) && element.focus();
ui.cachedScrollable_ = ui.activeEl_;
if (a.mode1_ < HintMode.min_job) { // called from Modes[-1]
return a.hud_.tip_(kTip.hoverScrollable, 1000);
}
Expand Down
37 changes: 21 additions & 16 deletions content/scroller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ _animate (e: SafeElement | null, d: ScrollByY, a: number): void {

/** @NEED_SAFE_ELEMENTS */
top_: null as SafeElement | null,
doseForceToScroll_: 0 as BOOL,
keyIsDown_: 0,
preventPointEvents_: 1 as BOOL | boolean,
scale_: 1,
Expand Down Expand Up @@ -202,11 +203,10 @@ _animate (e: SafeElement | null, d: ScrollByY, a: number): void {
, options?: CmdOptions[kFgCmd.scroll]): void {
const a = this as typeof VSc;
a.prepareTop_();
let amount = amount0;
const element = a.findScrollable_(di, isTo ? fromMax ? 1 : -1 : amount);
amount = !factor ? a._adjustAmount(di, amount, element)
: factor === 1 ? amount
: amount * a.getDimension_(element, di, factor === "max" ? kScrollDim.scrollSize : kScrollDim.viewSize);
const element = a.findScrollable_(di, isTo ? fromMax ? 1 : -1 : amount0);
let amount = !factor ? a._adjustAmount(di, amount0, element)
: factor === 1 ? amount0
: amount0 * a.getDimension_(element, di, factor === "max" ? kScrollDim.scrollSize : kScrollDim.viewSize);
if (isTo) {
const curPos = a.getDimension_(element, di, kScrollDim.position),
viewSize = a.getDimension_(element, di, kScrollDim.viewSize),
Expand Down Expand Up @@ -299,12 +299,14 @@ _animate (e: SafeElement | null, d: ScrollByY, a: number): void {
* @param amount should not be 0
*/
findScrollable_ (di: ScrollByY, amount: number): SafeElement | null {
const a = this, top = a.top_;
let element: SafeElement | null = VCui.activeEl_;
const a = this, top = a.top_, ui = VCui, activeEl: SafeElement | null = ui.activeEl_;
let element = activeEl;
if (element) {
let reason, notNeedToRecheck = !di;
let reason: number, notNeedToRecheck = !di;
type Element2 = NonNullable<typeof element>;
while (element !== top && (reason = a.shouldScroll_need_safe_(element as Element2, di, amount)) < 1) {
while (element !== top && (reason = a.shouldScroll_need_safe_(element as Element2
, element === ui.cachedScrollable_ ? (di + 2) as 2 | 3 : di
, amount)) < 1) {
if (!reason) {
notNeedToRecheck = notNeedToRecheck || a._doesScroll(element as Element2, 1, -amount);
}
Expand All @@ -314,6 +316,7 @@ _animate (e: SafeElement | null, d: ScrollByY, a: number): void {
) || top;
}
element = element !== top || notNeedToRecheck ? element : null;
ui.cachedScrollable_ = element;
}
if (!element) {
// note: twitter auto focuses its dialog panel, so it's not needed to detect it here
Expand All @@ -324,11 +327,11 @@ _animate (e: SafeElement | null, d: ScrollByY, a: number): void {
if (!element && top) {
const candidate = a._selectFirst({ area_: 0, element_: top, height_: 0 });
element = candidate && candidate.element_ !== top
&& (!VCui.activeEl_ || candidate.height_ > innerHeight / 2)
&& (!activeEl || candidate.height_ > innerHeight / 2)
? candidate.element_ : top;
// if VCui.activeEl_, then delay update to VCui.activeEl_, until scrolling ends and ._checkCurrent is called;
// otherwise, cache selected element for less further cost
VCui.activeEl_ || (VCui.activeEl_ = element);
activeEl || (ui.activeEl_ = element, ui.cachedScrollable_ = 0);
}
return element;
},
Expand All @@ -347,8 +350,8 @@ _animate (e: SafeElement | null, d: ScrollByY, a: number): void {
this.scale_ = (Build.BTypes & BrowserType.Firefox ? 2 : 1) / Math.min(1, VDom.wdZoom_) / Math.min(1, VDom.bZoom_);
},
_checkCurrent (el: SafeElement | null): void {
const cur = VCui.activeEl_;
if (cur !== el && cur && VDom.NotVisible_(cur)) { VCui.activeEl_ = el; }
const ui = VCui, cur = ui.activeEl_;
if (cur !== el && cur && VDom.NotVisible_(cur)) { ui.activeEl_ = el; ui.cachedScrollable_ = 0; }
},
/** if `el` is null, then return viewSize for `kScrollDim.scrollSize` */
getDimension_ (el: SafeElement | null, di: ScrollByY, index: kScrollDim & number): number {
Expand Down Expand Up @@ -432,6 +435,7 @@ _animate (e: SafeElement | null, d: ScrollByY, a: number): void {
hasY = b < ihm ? max(b - ih + ihm, t - ihm) : ih < t + ihm ? min(b - ih + ihm, t - ihm) : 0,
hasX = r < 0 ? max(l - iwm, r - iw + iwm) : iw < l ? min(r - iw + iwm, l - iwm) : 0;
VCui.activeEl_ = el;
VCui.cachedScrollable_ = 0;
if (hasX || hasY) {
for (let el2: Element | null = el; el2; el2 = VDom.GetParent_(el2, PNType.RevealSlotAndGotoParent)) {
const pos = VDom.getComputedStyle_(el2).position;
Expand All @@ -453,10 +457,11 @@ _animate (e: SafeElement | null, d: ScrollByY, a: number): void {
},
scrolled_: 0,
/** @NEED_SAFE_ELEMENTS */
shouldScroll_need_safe_ (element: SafeElement, di: ScrollByY, amount: number): -1 | 0 | 1 {
shouldScroll_need_safe_ (element: SafeElement, di: BOOL | 2 | 3, amount: number): -1 | 0 | 1 {
const st = VDom.getComputedStyle_(element);
return (di ? st.overflowY : st.overflowX) === "hidden" || st.display === "none" || st.visibility !== "visible" ? -1
: <BOOL> +this._doesScroll(element, di
return (di ? st.overflowY : st.overflowX) === "hidden" && di < 2
|| st.display === "none" || st.visibility !== "visible" ? -1
: <BOOL> +this._doesScroll(element, (di & 1) as BOOL
, amount || +!(di ? element.scrollTop : element.scrollLeft));
},
suppressScroll_ (): void {
Expand Down
1 change: 1 addition & 0 deletions types/messages.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ declare namespace HintsNS {
dblclick?: boolean;
newtab?: boolean | "force" | "window";
button?: "right";
scroll?: "force";
touch?: null | boolean | "auto";
join?: FgReq[kFgReq.copy]["j"];
sed?: string;
Expand Down

0 comments on commit 960506f

Please sign in to comment.