From 5398c336ef8821d286a60fda593376eed99381a2 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Wed, 1 May 2019 15:36:32 -0700 Subject: Add better handling for launchpad --- .../frost/web/FrostUrlOverlayValidator.kt | 1 - app/src/web/ts/click_a.ts | 93 ++++++++++++++++------ app/src/web/ts/context_a.ts | 33 +++++--- 3 files changed, 92 insertions(+), 35 deletions(-) (limited to 'app') diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt index 81ade98f..b06208a6 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostUrlOverlayValidator.kt @@ -75,7 +75,6 @@ fun FrostWebView.requestWebOverlay(url: String): Boolean { } if (!Prefs.overlayEnabled) return false if (context is WebOverlayActivityBase) { - L.v { "Check web request from overlay" } val shouldUseDesktop = url.formattedFbUrl.shouldUseDesktopAgent //already overlay; manage user agent if (userAgentString != USER_AGENT_DESKTOP && shouldUseDesktop) { diff --git a/app/src/web/ts/click_a.ts b/app/src/web/ts/click_a.ts index 5023610e..8d1d545b 100644 --- a/app/src/web/ts/click_a.ts +++ b/app/src/web/ts/click_a.ts @@ -1,34 +1,81 @@ (function () { let prevented = false; + /** + * Go up at most [depth] times, to retrieve a parent matching the provided predicate + * If one is found, it is returned immediately. + * Otherwise, null is returned. + */ + function _parentEl(el: HTMLElement, depth: number, predicate: (el: HTMLElement) => boolean): HTMLElement | null { + for (let i = 0; i < depth + 1; i++) { + if (predicate(el)) { + return el + } + const parent = el.parentElement; + if (!parent) { + return null + } + el = parent + } + return null + } + + /** + * Attempts to find a url entry at most [depth] away + * A url is found if the element has tag 'A', and the url isn't blank + */ + function _parentUrl(el: HTMLElement, depth: number): string | null { + const element = _parentEl(el, depth, (el) => el.tagName === 'A'); + if (!element) { + return null; + } + const url = element.getAttribute('href'); + if (!url || url === '#') { + return null; + } + return url + } + + /** + * Given event and target, return true if handled and false otherwise. + */ + type EventHandler = (e: Event, target: HTMLElement) => Boolean + + const _frostGeneral: EventHandler = (e, target) => { + // Notifications are two layers under + const url = _parentUrl(target, 2); + return Frost.loadUrl(url); + }; + + const _frostLaunchpadClick: EventHandler = (e, target) => { + if (!_parentEl(target, 6, (el) => el.id === 'launchpad')) { + return false + } + console.log('Clicked launchpad'); + const url = _parentUrl(target, 5); + return Frost.loadUrl(url); + }; + + const handlers: EventHandler[] = [_frostLaunchpadClick, _frostGeneral]; + const _frostAClick = (e: Event) => { - // check for valid target + if (prevented) { + console.log("Click intercept prevented"); + return + } + /* + * Commonality; check for valid target + */ const target = e.target || e.currentTarget || e.srcElement; - if (!(target instanceof Element)) { + if (!(target instanceof HTMLElement)) { console.log("No element found"); return } - let element: Element = target; - // Notifications are two layers under - for (let i = 0; i < 2; i++) { - if (element.tagName !== 'A') { - element = element.parentElement; - } - } - if (element.tagName === 'A') { - if (!prevented) { - const url = element.getAttribute('href'); - if (!url || url === '#') { - return - } - console.log(`Click intercept ${url}`); - // If Frost is injected, check if loading the url through an overlay works - if (Frost.loadUrl(url)) { - e.stopPropagation(); - e.preventDefault(); - } - } else { - console.log("Click intercept prevented") + for (const h of handlers) { + if (h(e, target)) { + e.stopPropagation(); + e.preventDefault(); + return } } }; diff --git a/app/src/web/ts/context_a.ts b/app/src/web/ts/context_a.ts index 5eec7611..b9549f3f 100644 --- a/app/src/web/ts/context_a.ts +++ b/app/src/web/ts/context_a.ts @@ -6,6 +6,25 @@ (function () { let longClick = false; + /** + * Go up at most [depth] times, to retrieve a parent matching the provided predicate + * If one is found, it is returned immediately. + * Otherwise, null is returned. + */ + function _parentEl(el: HTMLElement, depth: number, predicate: (el: HTMLElement) => boolean): HTMLElement | null { + for (let i = 0; i < depth + 1; i++) { + if (predicate(el)) { + return el + } + const parent = el.parentElement; + if (!parent) { + return null + } + el = parent + } + return null + } + /** * Given event and target, return true if handled and false otherwise. */ @@ -55,16 +74,8 @@ * Opens image activity for posts with just one image */ const _frostImage: EventHandler = (e, target) => { - let element: Element = target; - // Notifications are two layers under - for (let i = 0; i < 2; i++) { - if (element.tagName !== 'A') { - element = element.parentElement; - } else { - break - } - } - if (element.tagName !== 'A') { + const element = _parentEl(target, 2, (el) => el.tagName === 'A'); + if (!element) { return false; } const url = element.getAttribute('href'); @@ -92,7 +103,7 @@ return true; }; - const handlers = [_frostImage, _frostCopyComment, _frostCopyPost]; + const handlers: EventHandler[] = [_frostImage, _frostCopyComment, _frostCopyPost]; const _frostAContext = (e: Event) => { Frost.longClick(true); -- cgit v1.2.3