mirror of
https://github.com/vale981/tridactyl
synced 2025-03-05 17:41:40 -05:00
Merge branch 'port_hints_to_new_fangled_way'
This commit is contained in:
commit
4f1d96767b
3 changed files with 314 additions and 275 deletions
|
@ -147,6 +147,8 @@ const DEFAULTS = o({
|
|||
F: "hint -b",
|
||||
gF: "hint -br",
|
||||
";i": "hint -i",
|
||||
";b": "hint -b",
|
||||
";o": "hint",
|
||||
";I": "hint -I",
|
||||
";k": "hint -k",
|
||||
";y": "hint -y",
|
||||
|
@ -161,6 +163,25 @@ const DEFAULTS = o({
|
|||
";#": "hint -#",
|
||||
";v": "hint -W exclaim_quiet mpv",
|
||||
";w": "hint -w",
|
||||
";O": "hint -W fillcmdline_notrail open ",
|
||||
";W": "hint -W fillcmdline_notrail winopen ",
|
||||
";T": "hint -W fillcmdline_notrail tabopen ",
|
||||
"g;i": "hint -qi",
|
||||
"g;I": "hint -qI",
|
||||
"g;k": "hint -qk",
|
||||
"g;y": "hint -qy",
|
||||
"g;p": "hint -qp",
|
||||
"g;P": "hint -qP",
|
||||
"g;r": "hint -qr",
|
||||
"g;s": "hint -qs",
|
||||
"g;S": "hint -qS",
|
||||
"g;a": "hint -qa",
|
||||
"g;A": "hint -qA",
|
||||
"g;;": "hint -q;",
|
||||
"g;#": "hint -q#",
|
||||
"g;v": "hint -qW exclaim_quiet mpv",
|
||||
"g;w": "hint -qw",
|
||||
"g;b": "hint -qb",
|
||||
"<S-Insert>": "mode ignore",
|
||||
"<CA-Esc>": "mode ignore",
|
||||
"<CA-`>": "mode ignore",
|
||||
|
|
399
src/excmds.ts
399
src/excmds.ts
|
@ -96,7 +96,7 @@
|
|||
|
||||
// Shared
|
||||
import * as Messaging from "./messaging"
|
||||
import { browserBg, activeTabId, activeTabContainerId, openInNewTab } from "./lib/webext"
|
||||
import { browserBg, activeTabId, activeTabContainerId, openInNewTab, openInNewWindow } from "./lib/webext"
|
||||
import * as Container from "./lib/containers"
|
||||
import state from "./state"
|
||||
import * as UrlUtil from "./url_util"
|
||||
|
@ -2893,7 +2893,6 @@ import * as hinting from "./hinting"
|
|||
|
||||
@param option
|
||||
- -b open in background
|
||||
- -br repeatedly open in background
|
||||
- -y copy (yank) link's target to clipboard
|
||||
- -p copy an element's text to the clipboard
|
||||
- -P copy an element's title/alt text to the clipboard
|
||||
|
@ -2910,14 +2909,13 @@ import * as hinting from "./hinting"
|
|||
- -c [selector] hint links that match the css selector
|
||||
- `bind ;c hint -c [class*="expand"],[class="togg"]` works particularly well on reddit and HN
|
||||
- -w open in new window
|
||||
-wp open in new private window
|
||||
- `-pipe selector key` e.g, `-pipe * href` returns the key. Only makes sense with `composite`, e.g, `composite hint -pipe * textContent | yank`.
|
||||
- **DEPRECATED** `-W excmd...` append hint href to excmd and execute, e.g, `hint -W exclaim mpv` to open YouTube videos. Use `composite hint -pipe | [excmd]` instead.
|
||||
- -wp open in new private window
|
||||
- `-pipe selector key` e.g, `-pipe * href` returns the key. Only makes sense with `composite`, e.g, `composite hint -pipe * textContent | yank`. If you don't select a hint (i.e. press <Esc>), will return an empty string.
|
||||
- `-W excmd...` append hint href to excmd and execute, e.g, `hint -W exclaim mpv` to open YouTube videos.
|
||||
- -q* quick (or rapid) hints mode. Stay in hint mode until you press <Esc>, e.g. `:hint -qb` to open multiple hints in the background or `:hint -qW excmd` to execute excmd once for each hint. This will return an array containing all elements or the result of executed functions (e.g. `hint -qpipe a href` will return an array of links).
|
||||
- -br deprecated, use `-qb` instead
|
||||
|
||||
|
||||
Excepting the custom selector mode and background hint mode, each of these
|
||||
hint modes is available by default as `;<option character>`, so e.g. `;y`
|
||||
to yank a link's target.
|
||||
Excepting the custom selector mode and background hint mode, each of these hint modes is available by default as `;<option character>`, so e.g. `;y` to yank a link's target; `g;<option character>` starts rapid hint mode for all modes where it makes sense, and some others.
|
||||
|
||||
To open a hint in the background, the default bind is `F`.
|
||||
|
||||
|
@ -2944,150 +2942,257 @@ import * as hinting from "./hinting"
|
|||
*/
|
||||
//#content
|
||||
export async function hint(option?: string, selectors?: string, ...rest: string[]) {
|
||||
// NB: if you want something to work with rapid hinting, make it return a tuple of [something, hintCount] see option === "-b" below.
|
||||
if (!option) option = ""
|
||||
|
||||
if (option == "-br") option = "-qb"
|
||||
|
||||
let rapid = false
|
||||
if (option.startsWith("-q")) {
|
||||
option = "-" + option.slice(2)
|
||||
rapid = true
|
||||
}
|
||||
|
||||
let selectHints = new Promise(r => r())
|
||||
let onSelected = a => a
|
||||
let hintTabOpen = async (href, active = !rapid) => {
|
||||
let containerId = await activeTabContainerId()
|
||||
if (containerId) {
|
||||
return await openInNewTab(href, {
|
||||
active,
|
||||
related: true,
|
||||
cookieStoreId: containerId,
|
||||
})
|
||||
} else {
|
||||
return await openInNewTab(href, {
|
||||
active,
|
||||
related: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Open in background
|
||||
if (option === "-b") {
|
||||
selectHints = hinting.pipe(DOM.HINTTAGS_selectors)
|
||||
onSelected = async result => {
|
||||
let [link, hintCount] = result as [HTMLAnchorElement, number]
|
||||
link.focus()
|
||||
if (link.href) {
|
||||
let containerId = await activeTabContainerId()
|
||||
if (containerId) {
|
||||
openInNewTab(link.href, {
|
||||
active: false,
|
||||
related: true,
|
||||
cookieStoreId: containerId,
|
||||
}).catch(() => DOM.simulateClick(link))
|
||||
} else {
|
||||
openInNewTab(link.href, {
|
||||
active: false,
|
||||
related: true,
|
||||
}).catch(() => DOM.simulateClick(link))
|
||||
}
|
||||
switch (option) {
|
||||
case "-b":
|
||||
// Open in background
|
||||
selectHints = hinting.pipe(
|
||||
DOM.HINTTAGS_selectors,
|
||||
async link => {
|
||||
link.focus()
|
||||
if (link.href) {
|
||||
hintTabOpen(link.href, false).catch(() => DOM.simulateClick(link))
|
||||
} else {
|
||||
DOM.simulateClick(link)
|
||||
}
|
||||
return link
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-y":
|
||||
// Yank link
|
||||
selectHints = hinting.pipe(
|
||||
DOM.HINTTAGS_selectors,
|
||||
elem => {
|
||||
// /!\ Warning: This is racy! This can easily be fixed by adding an await but do we want this? yank can be pretty slow, especially with yankto=selection
|
||||
run_exstr("yank " + elem["href"])
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-p":
|
||||
// Yank text content
|
||||
selectHints = hinting.pipe_elements(
|
||||
DOM.elementsWithText(),
|
||||
elem => {
|
||||
// /!\ Warning: This is racy! This can easily be fixed by adding an await but do we want this? yank can be pretty slow, especially with yankto=selection
|
||||
run_exstr("yank " + elem["textContent"])
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-P":
|
||||
// Yank link alt text
|
||||
// ???: Neither anchors nor links posses an "alt" attribute. I'm assuming that the person who wrote this code also wanted to select the alt text of images
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link
|
||||
selectHints = hinting.pipe_elements(
|
||||
DOM.getElemsBySelector("[title], [alt]", [DOM.isVisible]),
|
||||
link => {
|
||||
// /!\ Warning: This is racy! This can easily be fixed by adding an await but do we want this? yank can be pretty slow, especially with yankto=selection
|
||||
run_exstr("yank " + (link.title ? link.title : link.alt))
|
||||
return link
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-#":
|
||||
// Yank anchor
|
||||
selectHints = hinting.pipe_elements(
|
||||
DOM.anchors(),
|
||||
link => {
|
||||
let anchorUrl = new URL(window.location.href)
|
||||
// ???: What purpose does selecting elements with a name attribute have? Selecting values that only have meaning in forms doesn't seem very useful.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
|
||||
anchorUrl.hash = link.id || link.name
|
||||
// /!\ Warning: This is racy! This can easily be fixed by adding an await but do we want this? yank can be pretty slow, especially with yankto=selection
|
||||
run_exstr("yank " + anchorUrl.href)
|
||||
return link
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-c":
|
||||
selectHints = hinting.pipe(
|
||||
selectors,
|
||||
elem => {
|
||||
DOM.simulateClick(elem as HTMLElement)
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-W":
|
||||
selectHints = hinting.pipe(
|
||||
DOM.HINTTAGS_selectors,
|
||||
elem => {
|
||||
// /!\ RACY RACY RACY!
|
||||
run_exstr(selectors + " " + rest.join(" ") + " " + elem)
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-pipe":
|
||||
selectHints = hinting.pipe(selectors, elem => elem[rest.join(" ")], rapid)
|
||||
break
|
||||
|
||||
case "-i":
|
||||
selectHints = hinting.pipe_elements(
|
||||
hinting.hintableImages(),
|
||||
elem => {
|
||||
open(new URL(elem.getAttribute("src"), window.location.href).href)
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-I":
|
||||
selectHints = hinting.pipe_elements(
|
||||
hinting.hintableImages(),
|
||||
async elem => {
|
||||
await hintTabOpen(new URL(elem.getAttribute("src"), window.location.href).href)
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-k":
|
||||
selectHints = hinting.pipe_elements(
|
||||
hinting.killables(),
|
||||
elem => {
|
||||
elem.remove()
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-s":
|
||||
case "-a":
|
||||
case "-S":
|
||||
case "-A":
|
||||
let elems = []
|
||||
// s: don't ask the user where to save the file
|
||||
// a: ask the user where to save the file
|
||||
let saveAs = true
|
||||
if (option[1].toLowerCase() == "s") saveAs = false
|
||||
// Lowercase: anchors
|
||||
// Uppercase: images
|
||||
let attr = "href"
|
||||
if (option[1].toLowerCase() == option[1]) {
|
||||
attr = "href"
|
||||
elems = hinting.saveableElements()
|
||||
} else {
|
||||
DOM.simulateClick(link)
|
||||
attr = "src"
|
||||
elems = hinting.hintableImages()
|
||||
}
|
||||
return [link.href, hintCount]
|
||||
}
|
||||
selectHints = hinting.pipe_elements(
|
||||
elems,
|
||||
elem => {
|
||||
Messaging.message("download_background", "downloadUrl", [new URL(elem[attr], window.location.href).href, saveAs])
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-;":
|
||||
selectHints = hinting.pipe_elements(
|
||||
hinting.hintables(selectors),
|
||||
elem => {
|
||||
elem.focus()
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-r":
|
||||
selectHints = hinting.pipe_elements(
|
||||
DOM.elementsWithText(),
|
||||
elem => {
|
||||
TTS.readText(elem.textContent)
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-w":
|
||||
selectHints = hinting.pipe_elements(
|
||||
hinting.hintables(),
|
||||
elem => {
|
||||
elem.focus()
|
||||
if (elem.href) openInNewWindow({ url: new URL(elem.href, window.location.href).href })
|
||||
else DOM.simulateClick(elem)
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
case "-wp":
|
||||
selectHints = hinting.pipe_elements(
|
||||
hinting.hintables(),
|
||||
elem => {
|
||||
elem.focus()
|
||||
if (elem.href) return openInNewWindow({ url: elem.href, incognito: true })
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
break
|
||||
|
||||
default:
|
||||
selectHints = hinting.pipe(
|
||||
DOM.HINTTAGS_selectors,
|
||||
elem => {
|
||||
DOM.simulateClick(elem as HTMLElement)
|
||||
return elem
|
||||
},
|
||||
rapid,
|
||||
)
|
||||
}
|
||||
|
||||
// Yank link
|
||||
else if (option === "-y") {
|
||||
selectHints = hinting.pipe(DOM.HINTTAGS_selectors)
|
||||
onSelected = result => {
|
||||
// /!\ Warning: This is racy! This can easily be fixed by adding an await but do we want this? yank can be pretty slow, especially with yankto=selection
|
||||
run_exstr("yank " + result[0]["href"])
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// Yank text content
|
||||
else if (option === "-p") {
|
||||
selectHints = hinting.pipe_elements(DOM.elementsWithText())
|
||||
onSelected = result => {
|
||||
// /!\ Warning: This is racy! This can easily be fixed by adding an await but do we want this? yank can be pretty slow, especially with yankto=selection
|
||||
run_exstr("yank " + result["textContent"])
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// Yank link alt text
|
||||
// ???: Neither anchors nor links posses an "alt" attribute. I'm assuming that the person who wrote this code also wanted to select the alt text of images
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/link
|
||||
else if (option === "-P") {
|
||||
selectHints = hinting.pipe_elements(DOM.getElemsBySelector("[title], [alt]", [DOM.isVisible]))
|
||||
onSelected = result => {
|
||||
let link = result[0] as HTMLAnchorElement & HTMLImageElement
|
||||
// /!\ Warning: This is racy! This can easily be fixed by adding an await but do we want this? yank can be pretty slow, especially with yankto=selection
|
||||
run_exstr("yank " + (link.title ? link.title : link.alt))
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
// Yank anchor
|
||||
else if (option === "-#") {
|
||||
selectHints = hinting.pipe_elements(DOM.anchors())
|
||||
onSelected = result => {
|
||||
let anchorUrl = new URL(window.location.href)
|
||||
let link = result[0] as any
|
||||
// ???: What purpose does selecting elements with a name attribute have? Selecting values that only have meaning in forms doesn't seem very useful.
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes
|
||||
anchorUrl.hash = link.id || link.name
|
||||
// /!\ Warning: This is racy! This can easily be fixed by adding an await but do we want this? yank can be pretty slow, especially with yankto=selection
|
||||
run_exstr("yank " + anchorUrl.href)
|
||||
return result
|
||||
}
|
||||
} else if (option === "-c") {
|
||||
selectHints = hinting.pipe(selectors)
|
||||
onSelected = result => {
|
||||
DOM.simulateClick(result[0] as HTMLElement)
|
||||
return result
|
||||
}
|
||||
}
|
||||
// Deprecated: hint exstr
|
||||
else if (option === "-W") {
|
||||
selectHints = hinting.pipe(DOM.HINTTAGS_selectors)
|
||||
onSelected = result => {
|
||||
// /!\ RACY RACY RACY!
|
||||
run_exstr(selectors + " " + rest.join(" ") + " " + result[0])
|
||||
return result
|
||||
}
|
||||
} else if (option === "-pipe") {
|
||||
selectHints = hinting.pipe(selectors)
|
||||
onSelected = result => result[0][rest.join(" ")]
|
||||
} else if (option === "-br") {
|
||||
while (true) {
|
||||
// The typecast can be removed once the function is completely ported
|
||||
let result = (await hint("-b")) as [HTMLElement, number]
|
||||
if (result === null) return null
|
||||
let [_, hintCount] = result
|
||||
if (hintCount < 2) break
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: port these to new fangled way
|
||||
else if (option === "-i") hinting.hintImage(false)
|
||||
else if (option === "-I") hinting.hintImage(true)
|
||||
else if (option === "-k") hinting.hintKill()
|
||||
else if (option === "-s") hinting.hintSave("link", false)
|
||||
else if (option === "-S") hinting.hintSave("img", false)
|
||||
else if (option === "-a") hinting.hintSave("link", true)
|
||||
else if (option === "-A") hinting.hintSave("img", true)
|
||||
else if (option === "-;") hinting.hintFocus(selectors)
|
||||
else if (option === "-r") hinting.hintRead()
|
||||
else if (option === "-w") hinting.hintPageWindow()
|
||||
else if (option === "-wp") hinting.hintPageWindowPrivate()
|
||||
else {
|
||||
selectHints = hinting.pipe(DOM.HINTTAGS_selectors)
|
||||
onSelected = result => {
|
||||
DOM.simulateClick(result[0] as HTMLElement)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) =>
|
||||
selectHints.then(
|
||||
async result => resolve(await onSelected(result)),
|
||||
rejectionReason => {
|
||||
// We have to resolve when we don't want to have our messages be logged in the command line but this feels wrong since no hint has been selected
|
||||
// Perhaps we should implement a mechanism to allow specific errors to go unreported?
|
||||
if (rejectionReason == hinting.HintRejectionReason.User) {
|
||||
logger.debug("Hint promise rejected because user left hint mode without selecting a hint")
|
||||
resolve(null)
|
||||
} else if (rejectionReason == hinting.HintRejectionReason.NoHints) {
|
||||
logger.debug("Hint promise rejected because there are no hints to select")
|
||||
resolve(null)
|
||||
} else {
|
||||
reject(rejectionReason)
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
return selectHints
|
||||
}
|
||||
|
||||
// how 2 crash pc
|
||||
|
|
169
src/hinting.ts
169
src/hinting.ts
|
@ -28,31 +28,25 @@ import Logger from "./logging"
|
|||
import * as Messaging from "./messaging"
|
||||
const logger = new Logger("hinting")
|
||||
|
||||
export enum HintRejectionReason {
|
||||
Err,
|
||||
User,
|
||||
NoHints,
|
||||
}
|
||||
|
||||
/** Simple container for the state of a single frame's hints. */
|
||||
class HintState {
|
||||
public focusedHint: Hint
|
||||
readonly hintHost = document.createElement("div")
|
||||
readonly hints: Hint[] = []
|
||||
public selectedHints: Hint[] = []
|
||||
public filter = ""
|
||||
public hintchars = ""
|
||||
|
||||
constructor(
|
||||
public filterFunc: HintFilter,
|
||||
public resolve: (Hint) => void,
|
||||
public reject: (HintRejectionReason) => any,
|
||||
public reject: (any) => void,
|
||||
public rapid: boolean,
|
||||
) {
|
||||
this.hintHost.classList.add("TridactylHintHost", "cleanslate")
|
||||
}
|
||||
|
||||
destructor(abort) {
|
||||
if (!this.focusedHint) this.focusedHint = this.hints[0]
|
||||
|
||||
destructor() {
|
||||
// Undo any alterations of the hinted elements
|
||||
for (const hint of this.hints) {
|
||||
hint.hidden = true
|
||||
|
@ -61,9 +55,10 @@ class HintState {
|
|||
// Remove all hints from the DOM.
|
||||
this.hintHost.remove()
|
||||
|
||||
if (abort) this.reject(HintRejectionReason.User)
|
||||
else if (!this.focusedHint) this.reject(HintRejectionReason.NoHints)
|
||||
else this.resolve([this.focusedHint.target, this.hints.length])
|
||||
if (this.rapid)
|
||||
this.resolve(this.selectedHints.map(h => h.result))
|
||||
else
|
||||
this.resolve(this.selectedHints[0] ? this.selectedHints[0].result : "")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -75,13 +70,25 @@ export function hintPage(
|
|||
onSelect: HintSelectedCallback,
|
||||
resolve = () => {},
|
||||
reject = () => {},
|
||||
rapid = false,
|
||||
) {
|
||||
let buildHints: HintBuilder = defaultHintBuilder()
|
||||
let filterHints: HintFilter = defaultHintFilter()
|
||||
state.mode = "hint"
|
||||
modeState = new HintState(filterHints, resolve, reject)
|
||||
modeState = new HintState(filterHints, resolve, reject, rapid)
|
||||
|
||||
buildHints(hintableElements, onSelect)
|
||||
if (rapid == false) {
|
||||
buildHints(hintableElements, hint => {
|
||||
hint.result = onSelect(hint.target)
|
||||
modeState.selectedHints.push(hint)
|
||||
reset()
|
||||
})
|
||||
} else {
|
||||
buildHints(hintableElements, hint => {
|
||||
hint.result = onSelect(hint.target)
|
||||
modeState.selectedHints.push(hint)
|
||||
})
|
||||
}
|
||||
|
||||
if (modeState.hints.length) {
|
||||
let firstTarget = modeState.hints[0].target
|
||||
|
@ -227,6 +234,7 @@ type HintSelectedCallback = (Hint) => any
|
|||
/** Place a flag by each hintworthy element */
|
||||
class Hint {
|
||||
public readonly flag = document.createElement("span")
|
||||
public result: any = null
|
||||
|
||||
constructor(
|
||||
public readonly target: Element,
|
||||
|
@ -444,8 +452,10 @@ function filterHintsVimperator(fstr, reflow = false) {
|
|||
* If abort is true, we're resetting because the user pressed escape.
|
||||
* If it is false, we're resetting because the user selected a hint.
|
||||
**/
|
||||
function reset(abort = false) {
|
||||
modeState.destructor(abort)
|
||||
function reset() {
|
||||
if (modeState) {
|
||||
modeState.destructor()
|
||||
}
|
||||
modeState = undefined
|
||||
state.mode = "normal"
|
||||
}
|
||||
|
@ -473,7 +483,7 @@ function pushKey(ke) {
|
|||
1. Within viewport
|
||||
2. Not hidden by another element
|
||||
*/
|
||||
function hintables(selectors = DOM.HINTTAGS_selectors, withjs = false) {
|
||||
export function hintables(selectors = DOM.HINTTAGS_selectors, withjs = false) {
|
||||
let elems = DOM.getElemsBySelector(selectors, [])
|
||||
if (withjs) {
|
||||
elems = elems.concat(DOM.hintworthy_js_elems)
|
||||
|
@ -484,19 +494,19 @@ function hintables(selectors = DOM.HINTTAGS_selectors, withjs = false) {
|
|||
|
||||
/** Returns elements that point to a saveable resource
|
||||
*/
|
||||
function saveableElements() {
|
||||
export function saveableElements() {
|
||||
return DOM.getElemsBySelector(DOM.HINTTAGS_saveable, [DOM.isVisible])
|
||||
}
|
||||
|
||||
/** Get array of images in the viewport
|
||||
*/
|
||||
function hintableImages() {
|
||||
export function hintableImages() {
|
||||
return DOM.getElemsBySelector(DOM.HINTTAGS_img_selectors, [DOM.isVisible])
|
||||
}
|
||||
|
||||
/** Array of items that can be killed with hint kill
|
||||
*/
|
||||
function killables() {
|
||||
export function killables() {
|
||||
return DOM.getElemsBySelector(DOM.HINTTAGS_killable_selectors, [
|
||||
DOM.isVisible,
|
||||
])
|
||||
|
@ -505,130 +515,33 @@ function killables() {
|
|||
import { openInNewTab, activeTabContainerId } from "./lib/webext"
|
||||
import { openInNewWindow } from "./lib/webext"
|
||||
|
||||
export function hintPageWindow() {
|
||||
hintPage(hintables(), hint => {
|
||||
hint.target.focus()
|
||||
if (hint.target.href) {
|
||||
openInNewWindow({ url: hint.target.href })
|
||||
} else {
|
||||
// This is to mirror vimperator behaviour.
|
||||
DOM.simulateClick(hint.target)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function hintPageWindowPrivate() {
|
||||
hintPage(hintables(), hint => {
|
||||
hint.target.focus()
|
||||
if (hint.target.href) {
|
||||
openInNewWindow({ url: hint.target.href, incognito: true })
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function pipe(
|
||||
selectors = DOM.HINTTAGS_selectors,
|
||||
action: HintSelectedCallback = _ => _,
|
||||
rapid = false,
|
||||
): Promise<[Element, number]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
hintPage(hintables(selectors, true), () => {}, resolve, reject)
|
||||
hintPage(hintables(selectors, true), action, resolve, reject, rapid)
|
||||
})
|
||||
}
|
||||
|
||||
export function pipe_elements(
|
||||
elements: any = DOM.elementsWithText,
|
||||
action: HintSelectedCallback = _ => _,
|
||||
rapid = false,
|
||||
): Promise<[Element, number]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
hintPage(elements, () => {}, resolve, reject)
|
||||
})
|
||||
}
|
||||
|
||||
/** Hint images, opening in the same tab, or in a background tab
|
||||
*
|
||||
* @param inBackground opens the image source URL in a background tab,
|
||||
* as opposed to the current tab
|
||||
*/
|
||||
export function hintImage(inBackground) {
|
||||
hintPage(hintableImages(), hint => {
|
||||
let img_src = hint.target.getAttribute("src")
|
||||
|
||||
if (inBackground) {
|
||||
openInNewTab(new URL(img_src, window.location.href).href, {
|
||||
active: false,
|
||||
related: true,
|
||||
})
|
||||
} else {
|
||||
window.location.href = img_src
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** Hint elements to focus */
|
||||
export function hintFocus(selectors?) {
|
||||
hintPage(hintables(selectors), hint => {
|
||||
hint.target.focus()
|
||||
})
|
||||
}
|
||||
|
||||
/** Hint items and read out the content of the selection */
|
||||
export function hintRead() {
|
||||
hintPage(DOM.elementsWithText(), hint => {
|
||||
TTS.readText(hint.target.textContent)
|
||||
})
|
||||
}
|
||||
|
||||
/** Hint elements and delete the selection from the page
|
||||
*/
|
||||
export function hintKill() {
|
||||
hintPage(killables(), hint => {
|
||||
hint.target.remove()
|
||||
})
|
||||
}
|
||||
|
||||
/** Type for "hint save" actions:
|
||||
* - "link": elements that point to another resource (eg
|
||||
* links to pages/files) - the link target is saved
|
||||
* - "img": image elements
|
||||
*/
|
||||
export type HintSaveType = "link" | "img"
|
||||
|
||||
/** Hint link elements to save
|
||||
*
|
||||
* @param hintType the type of elements to hint and save:
|
||||
* - "link": elements that point to another resource (eg
|
||||
* links to pages/files) - the link targer is saved
|
||||
* - "img": image elements
|
||||
* @param saveAs prompt for save location
|
||||
*/
|
||||
export function hintSave(hintType: HintSaveType, saveAs: boolean) {
|
||||
function saveHintElems(hintType) {
|
||||
return hintType === "link" ? saveableElements() : hintableImages()
|
||||
}
|
||||
|
||||
function urlFromElem(hintType, elem) {
|
||||
return hintType === "link" ? elem.href : elem.src
|
||||
}
|
||||
|
||||
hintPage(saveHintElems(hintType), hint => {
|
||||
const urlToSave = new URL(
|
||||
urlFromElem(hintType, hint.target),
|
||||
window.location.href,
|
||||
)
|
||||
|
||||
// Pass to background context to allow saving from data URLs.
|
||||
// Convert to href because can't clone URL across contexts
|
||||
message("download_background", "downloadUrl", [urlToSave.href, saveAs])
|
||||
hintPage(elements, action, resolve, reject, rapid)
|
||||
})
|
||||
}
|
||||
|
||||
function selectFocusedHint(delay = false) {
|
||||
logger.debug("Selecting hint.", state.mode)
|
||||
const focused = modeState.focusedHint
|
||||
let select = () => {
|
||||
reset()
|
||||
focused.select()
|
||||
}
|
||||
if (delay) setTimeout(select, config.get("hintdelay"))
|
||||
else select()
|
||||
modeState.filter = ""
|
||||
modeState.hints.forEach(h => (h.hidden = false))
|
||||
if (delay) setTimeout(() => focused.select(), config.get("hintdelay"))
|
||||
else focused.select()
|
||||
}
|
||||
|
||||
import { addListener, attributeCaller } from "./messaging"
|
||||
|
|
Loading…
Add table
Reference in a new issue