mirror of
https://github.com/vale981/tridactyl
synced 2025-03-06 01:51:40 -05:00
commit
65869e7530
25 changed files with 586 additions and 521 deletions
42
.eslintrc.js
42
.eslintrc.js
|
@ -129,17 +129,18 @@ module.exports = {
|
|||
"@typescript-eslint/prefer-for-of": "error",
|
||||
"@typescript-eslint/prefer-function-type": "error",
|
||||
"@typescript-eslint/prefer-namespace-keyword": "error",
|
||||
"@typescript-eslint/prefer-regexp-exec": "off", //"error",
|
||||
"@typescript-eslint/prefer-regexp-exec": "error",
|
||||
"@typescript-eslint/quotes": [
|
||||
"off", //"error",
|
||||
"error",
|
||||
"double",
|
||||
{
|
||||
"avoidEscape": true
|
||||
}
|
||||
"avoidEscape": true,
|
||||
"allowTemplateLiterals": true,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/require-await": "off", //"error",
|
||||
"@typescript-eslint/restrict-plus-operands": "off", //"error",
|
||||
"@typescript-eslint/restrict-template-expressions": "off", //"error",
|
||||
"@typescript-eslint/require-await": "error",
|
||||
"@typescript-eslint/restrict-plus-operands": "off", //"error", // We use this a lot - fixing it is a problem for a rainy day
|
||||
"@typescript-eslint/restrict-template-expressions": "off",
|
||||
"@typescript-eslint/semi": [
|
||||
"off",
|
||||
null
|
||||
|
@ -153,15 +154,15 @@ module.exports = {
|
|||
}
|
||||
],
|
||||
"@typescript-eslint/type-annotation-spacing": "error",
|
||||
"@typescript-eslint/unbound-method": "off", //"error",
|
||||
"@typescript-eslint/unified-signatures": "off", //"error",
|
||||
"arrow-body-style": "off", //"error",
|
||||
"@typescript-eslint/unbound-method": "error",
|
||||
"@typescript-eslint/unified-signatures": "error",
|
||||
"arrow-body-style": "error",
|
||||
"arrow-parens": [
|
||||
"off",
|
||||
"always"
|
||||
],
|
||||
"brace-style": [
|
||||
"off", //"error",
|
||||
"error",
|
||||
"1tbs"
|
||||
],
|
||||
"camelcase": "off",
|
||||
|
@ -174,7 +175,7 @@ module.exports = {
|
|||
"off",
|
||||
"always"
|
||||
],
|
||||
"guard-for-in": "off", //"error",
|
||||
"guard-for-in": "error",
|
||||
"id-blacklist": "off",
|
||||
"id-match": "off",
|
||||
"import/order": "off",
|
||||
|
@ -198,7 +199,7 @@ module.exports = {
|
|||
],
|
||||
"no-empty-function": "off",
|
||||
"no-eval": "off",
|
||||
"no-extra-semi": "off", //"off",
|
||||
"no-extra-semi": "error",
|
||||
"no-fallthrough": "off",
|
||||
"no-invalid-this": "off",
|
||||
"no-multiple-empty-lines": "error",
|
||||
|
@ -252,11 +253,12 @@ module.exports = {
|
|||
"use-isnan": "error",
|
||||
"valid-typeof": "off"
|
||||
},
|
||||
// // We ultimately didn't need this but I thought I should document it anyway
|
||||
// "overrides": [{
|
||||
// "files": ["src/completions/*.ts",],
|
||||
// "rules": {
|
||||
// "@typescript-eslint/no-empty-function": "off",
|
||||
// },
|
||||
// }],
|
||||
"overrides": [{
|
||||
"files": ["src/completions/*.ts", "src/excmds.ts"],
|
||||
"rules": {
|
||||
// We have methods that must be async in some classes but not in others
|
||||
// In src/excmds anything that crosses between content<->background must be async even if it looks like it isn't
|
||||
"@typescript-eslint/require-await": "off",
|
||||
},
|
||||
}],
|
||||
};
|
||||
|
|
|
@ -40,7 +40,7 @@ main() {
|
|||
lock .git/index.lock
|
||||
case "$file" in
|
||||
*.md | *.css) prettier --write "$file";;
|
||||
*) eslint --fix "$file";;
|
||||
*) prettier --write "$file"; eslint --fix "$file";;
|
||||
esac
|
||||
unlock .git/index.lock
|
||||
git add "$file"
|
||||
|
|
|
@ -54,9 +54,9 @@ import { HintingCmds } from "@src/background/hinting"
|
|||
// here.
|
||||
controller.setExCmds({
|
||||
"": excmds_background,
|
||||
"ex": CmdlineCmds,
|
||||
"text": EditorCmds,
|
||||
"hint": HintingCmds
|
||||
ex: CmdlineCmds,
|
||||
text: EditorCmds,
|
||||
hint: HintingCmds,
|
||||
})
|
||||
|
||||
// {{{ tri.contentLocation
|
||||
|
@ -78,13 +78,11 @@ browser.tabs.onActivated.addListener(ev => {
|
|||
})
|
||||
})
|
||||
// Update on navigation too (but remember that sometimes people open tabs in the background :) )
|
||||
browser.webNavigation.onDOMContentLoaded.addListener(
|
||||
() => {
|
||||
browser.webNavigation.onDOMContentLoaded.addListener(() => {
|
||||
browser.tabs.query({ currentWindow: true, active: true }).then(t => {
|
||||
(window as any).tri.contentLocation = new URL(t[0].url)
|
||||
})
|
||||
},
|
||||
)
|
||||
})
|
||||
|
||||
// Prevent Tridactyl from being updated while it is running in the hope of fixing #290
|
||||
browser.runtime.onUpdateAvailable.addListener(_ => undefined)
|
||||
|
@ -98,7 +96,7 @@ browser.runtime.onStartup.addListener(_ => {
|
|||
} else {
|
||||
native.run("hostname").then(hostname => {
|
||||
for (const host of hosts) {
|
||||
if (hostname.content.match(host)) {
|
||||
if ((new RegExp(host)).exec(hostname.content)) {
|
||||
controller.acceptExCmd(aucmds[host])
|
||||
}
|
||||
}
|
||||
|
@ -164,9 +162,7 @@ browser.webRequest.onBeforeRequest.addListener(
|
|||
["blocking"],
|
||||
)
|
||||
|
||||
browser.tabs.onCreated.addListener(
|
||||
aucon.tabCreatedListener,
|
||||
)
|
||||
browser.tabs.onCreated.addListener(aucon.tabCreatedListener)
|
||||
|
||||
// }}}
|
||||
|
||||
|
@ -182,7 +178,7 @@ const messages = {
|
|||
downloadUrl: download_background.downloadUrl,
|
||||
downloadUrlAs: download_background.downloadUrlAs,
|
||||
},
|
||||
browser_proxy_background: {shim: proxy_background.shim}
|
||||
browser_proxy_background: { shim: proxy_background.shim },
|
||||
}
|
||||
export type Messages = typeof messages
|
||||
|
||||
|
@ -211,6 +207,6 @@ omnibox.init()
|
|||
|
||||
// {{{ Obey Mozilla's orders https://github.com/tridactyl/tridactyl/issues/1800
|
||||
|
||||
native.unfixamo();
|
||||
native.unfixamo()
|
||||
|
||||
/// }}}
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
*/
|
||||
import * as controller from "@src/lib/controller"
|
||||
|
||||
export async function inputEnteredListener(
|
||||
input: string, disposition:
|
||||
browser.omnibox.OnInputEnteredDisposition) {
|
||||
export function inputEnteredListener(
|
||||
input: string,
|
||||
disposition: browser.omnibox.OnInputEnteredDisposition,
|
||||
) {
|
||||
controller.acceptExCmd(input)
|
||||
}
|
||||
|
||||
export async function init() {
|
||||
export function init() {
|
||||
browser.omnibox.onInputEntered.addListener(inputEnteredListener)
|
||||
browser.omnibox.setDefaultSuggestion({
|
||||
description: `Execute a Tridactyl exstr (for example, "tabopen -c container www.google.com")`,
|
||||
|
|
|
@ -239,9 +239,7 @@ export abstract class CompletionSourceFuse extends CompletionSource {
|
|||
|
||||
/** Rtn sorted array of {option, score} */
|
||||
scoredOptions(query: string, options = this.options): ScoredOption[] {
|
||||
const searchThis = this.options.map((elem, index) => {
|
||||
return { index, fuseKeys: elem.fuseKeys }
|
||||
})
|
||||
const searchThis = this.options.map((elem, index) => ({ index, fuseKeys: elem.fuseKeys }))
|
||||
this.fuse = new Fuse(searchThis, this.fuseOptions)
|
||||
return this.fuse.search(query).map(result => {
|
||||
// console.log(result, result.item, query)
|
||||
|
|
|
@ -64,14 +64,12 @@ export class BindingsCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options = Object.keys(patterns)
|
||||
.filter(pattern => pattern.startsWith(urlPattern))
|
||||
.sort()
|
||||
.map(pattern => {
|
||||
return new BindingsCompletionOption(
|
||||
.map(pattern => new BindingsCompletionOption(
|
||||
pattern, {
|
||||
name: pattern,
|
||||
value: "",
|
||||
mode: "URL Pattern",
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
return this.updateChain()
|
||||
}
|
||||
|
@ -84,14 +82,12 @@ export class BindingsCompletionSource extends Completions.CompletionSourceFuse {
|
|||
const modeStr = margs.length > 1 ? margs[1] : ""
|
||||
this.options = Binding.modes
|
||||
.filter(k => k.startsWith(modeStr))
|
||||
.map(name => {
|
||||
return new BindingsCompletionOption(
|
||||
.map(name => new BindingsCompletionOption(
|
||||
options + "--mode=" + name, {
|
||||
name,
|
||||
value: "",
|
||||
mode: "Mode Name",
|
||||
})
|
||||
})
|
||||
}))
|
||||
return this.updateChain()
|
||||
}
|
||||
}
|
||||
|
@ -124,14 +120,12 @@ export class BindingsCompletionSource extends Completions.CompletionSourceFuse {
|
|||
this.options = Object.keys(bindings)
|
||||
.filter(x => x.toLowerCase().startsWith(query) )
|
||||
.sort()
|
||||
.map(keystr => {
|
||||
return new BindingsCompletionOption(
|
||||
.map(keystr => new BindingsCompletionOption(
|
||||
options + keystr + " " + bindings[keystr], {
|
||||
name: keystr,
|
||||
value: JSON.stringify(bindings[keystr]),
|
||||
mode: `${configName} (${modeName})`,
|
||||
})
|
||||
})
|
||||
}))
|
||||
|
||||
return this.updateChain()
|
||||
}
|
||||
|
|
|
@ -38,16 +38,15 @@ class BufferCompletionOption extends Completions.CompletionOptionHTML
|
|||
const favIconUrl = tab.favIconUrl
|
||||
? tab.favIconUrl
|
||||
: Completions.DEFAULT_FAVICON
|
||||
this.html = html`<tr class="BufferCompletionOption option container_${container.color} container_${container.icon} container_${container.name}"
|
||||
this.html = html`<tr
|
||||
class="BufferCompletionOption option container_${container.color} container_${container.icon} container_${container.name}"
|
||||
>
|
||||
<td class="prefix">${pre.padEnd(2)}</td>
|
||||
<td class="container"></td>
|
||||
<td class="icon"><img src="${favIconUrl}" /></td>
|
||||
<td class="title">${tab.index + 1}: ${tab.title}</td>
|
||||
<td class="content">
|
||||
<a class="url" target="_blank" href=${tab.url}
|
||||
>${tab.url}</a
|
||||
>
|
||||
<a class="url" target="_blank" href=${tab.url}>${tab.url}</a>
|
||||
</td>
|
||||
</tr>`
|
||||
}
|
||||
|
@ -126,15 +125,17 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
|||
/** Return the scoredOption[] result for the nth tab */
|
||||
private nthTabscoredOptions(
|
||||
n: number,
|
||||
options: BufferCompletionOption[]
|
||||
options: BufferCompletionOption[],
|
||||
): Completions.ScoredOption[] {
|
||||
for (const [index, option] of enumerate(options)) {
|
||||
if (option.tabIndex === n) {
|
||||
return [{
|
||||
return [
|
||||
{
|
||||
index,
|
||||
option,
|
||||
score: 0,
|
||||
}, ]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -142,10 +143,10 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
|||
/** Return the scoredOption[] result for the tab index startswith n */
|
||||
private TabscoredOptionsStartsWithN(
|
||||
n: number,
|
||||
options: BufferCompletionOption[]
|
||||
options: BufferCompletionOption[],
|
||||
): Completions.ScoredOption[] {
|
||||
const nstr = (n + 1).toString()
|
||||
const res = [];
|
||||
const res = []
|
||||
for (const [index, option] of enumerate(options)) {
|
||||
if ((option.tabIndex + 1).toString().startsWith(nstr)) {
|
||||
res.push({
|
||||
|
@ -158,7 +159,7 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
|||
|
||||
// old input will change order: 12 => 123 => 12
|
||||
res.sort((a, b) => a.option.tabIndex - b.option.tabIndex)
|
||||
return res;
|
||||
return res
|
||||
}
|
||||
|
||||
private async fillOptions() {
|
||||
|
@ -167,17 +168,19 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
|||
})
|
||||
const options = []
|
||||
// Get alternative tab, defined as last accessed tab.
|
||||
tabs.sort((a, b) => (b.lastAccessed - a.lastAccessed))
|
||||
tabs.sort((a, b) => b.lastAccessed - a.lastAccessed)
|
||||
const alt = tabs[1]
|
||||
|
||||
const useMruTabOrder = (config.get("tabsort") === "mru")
|
||||
const useMruTabOrder = config.get("tabsort") === "mru"
|
||||
if (!useMruTabOrder) {
|
||||
tabs.sort((a, b) => (a.index - b.index))
|
||||
tabs.sort((a, b) => a.index - b.index)
|
||||
}
|
||||
|
||||
const container_all = await browserBg.contextualIdentities.query({})
|
||||
const container_map = new Map()
|
||||
container_all.forEach(elem => container_map.set(elem.cookieStoreId, elem))
|
||||
container_all.forEach(elem =>
|
||||
container_map.set(elem.cookieStoreId, elem),
|
||||
)
|
||||
// firefox-default is not in contextualIdenetities
|
||||
container_map.set("firefox-default", Containers.DefaultContainer)
|
||||
|
||||
|
@ -191,7 +194,7 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
|||
(tab.index + 1).toString(),
|
||||
tab,
|
||||
tab === alt,
|
||||
tab_container
|
||||
tab_container,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
@ -219,7 +222,7 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
|||
|
||||
// When the user is asking for tabmove completions, don't autoselect if the query looks like a relative move https://github.com/tridactyl/tridactyl/issues/825
|
||||
this.shouldSetStateFromScore = !(
|
||||
prefix === "tabmove " && query.match("^[+-][0-9]+$")
|
||||
prefix === "tabmove " && /^[+-][0-9]+$/.exec(query)
|
||||
)
|
||||
|
||||
if (!this.options) {
|
||||
|
|
|
@ -35,12 +35,18 @@ import { EditorCmds } from "@src/content/editor"
|
|||
import * as hinting_content from "@src/content/hinting"
|
||||
controller.setExCmds({
|
||||
"": excmds_content,
|
||||
"ex": CmdlineCmds,
|
||||
"text": EditorCmds,
|
||||
"hint": hinting_content.getHintCommands()
|
||||
ex: CmdlineCmds,
|
||||
text: EditorCmds,
|
||||
hint: hinting_content.getHintCommands(),
|
||||
})
|
||||
messaging.addListener("excmd_content", messaging.attributeCaller(excmds_content))
|
||||
messaging.addListener("controller_content", messaging.attributeCaller(controller))
|
||||
messaging.addListener(
|
||||
"excmd_content",
|
||||
messaging.attributeCaller(excmds_content),
|
||||
)
|
||||
messaging.addListener(
|
||||
"controller_content",
|
||||
messaging.attributeCaller(controller),
|
||||
)
|
||||
|
||||
// Hook the keyboard up to the controller
|
||||
import * as ContentController from "@src/content/controller_content"
|
||||
|
@ -87,7 +93,7 @@ config.getAsync("preventautofocusjackhammer").then(allowautofocus => {
|
|||
const preventAutoFocus = () => {
|
||||
// First, blur whatever element is active. This will make sure
|
||||
// activeElement is the "default" active element
|
||||
; (document.activeElement as any).blur()
|
||||
(document.activeElement as any).blur()
|
||||
const elem = document.activeElement as any
|
||||
// ???: We need to set tabIndex, otherwise we won't get focus/blur events!
|
||||
elem.tabIndex = 0
|
||||
|
@ -97,7 +103,9 @@ config.getAsync("preventautofocusjackhammer").then(allowautofocus => {
|
|||
// On top of blur/focusout events, we need to periodically check the
|
||||
// activeElement is the one we want because blur/focusout events aren't
|
||||
// always triggered when document.activeElement changes
|
||||
const interval = setInterval(() => { if (document.activeElement != elem) focusElem() }, 200)
|
||||
const interval = setInterval(() => {
|
||||
if (document.activeElement != elem) focusElem()
|
||||
}, 200)
|
||||
// When the user starts interacting with the page, stop resetting focus
|
||||
function stopResettingFocus(event: Event) {
|
||||
if (!event.isTrusted) return
|
||||
|
@ -240,7 +248,9 @@ config.getAsync("modeindicator").then(mode => {
|
|||
.then(container => {
|
||||
statusIndicator.setAttribute(
|
||||
"style",
|
||||
`border: ${(container as any).colorCode} solid 1.5px !important`,
|
||||
`border: ${
|
||||
(container as any).colorCode
|
||||
} solid 1.5px !important`,
|
||||
)
|
||||
})
|
||||
.catch(error => {
|
||||
|
@ -338,14 +348,12 @@ config.getAsync("modeindicator").then(mode => {
|
|||
|
||||
function protectSlash(e) {
|
||||
if (!e.isTrusted) return
|
||||
config.get("blacklistkeys").map(
|
||||
protkey => {
|
||||
config.get("blacklistkeys").map(protkey => {
|
||||
if (protkey.indexOf(e.key) !== -1 && contentState.mode === "normal") {
|
||||
e.cancelBubble = true
|
||||
e.stopImmediatePropagation()
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
// Some sites like to prevent firefox's `/` from working so we need to protect
|
||||
|
@ -366,11 +374,19 @@ config.getAsync("leavegithubalone").then(v => {
|
|||
|
||||
document.addEventListener("selectionchange", () => {
|
||||
const selection = document.getSelection()
|
||||
if ((contentState.mode == "visual") && (config.get("visualexitauto") == "true") && (selection.anchorOffset == selection.focusOffset)) {
|
||||
if (
|
||||
contentState.mode == "visual" &&
|
||||
config.get("visualexitauto") == "true" &&
|
||||
selection.anchorOffset == selection.focusOffset
|
||||
) {
|
||||
contentState.mode = "normal"
|
||||
return
|
||||
}
|
||||
if ((contentState.mode !== "normal") || (config.get("visualenterauto") == "false")) return
|
||||
if (
|
||||
contentState.mode !== "normal" ||
|
||||
config.get("visualenterauto") == "false"
|
||||
)
|
||||
return
|
||||
if (selection.anchorOffset !== selection.focusOffset) {
|
||||
contentState.mode = "visual"
|
||||
}
|
||||
|
|
|
@ -62,12 +62,12 @@ class KeyCanceller {
|
|||
this.keyUp.push(ke)
|
||||
}
|
||||
|
||||
cancelKeyPress(ke: KeyboardEvent) {
|
||||
public cancelKeyPress = (ke: KeyboardEvent) => {
|
||||
if (!ke.isTrusted) return
|
||||
this.cancelKey(ke, this.keyPress)
|
||||
}
|
||||
|
||||
cancelKeyUp(ke: KeyboardEvent) {
|
||||
public cancelKeyUp = (ke: KeyboardEvent) => {
|
||||
if (!ke.isTrusted) return
|
||||
this.cancelKey(ke, this.keyUp)
|
||||
}
|
||||
|
|
|
@ -35,7 +35,10 @@ class FindHighlight extends HTMLSpanElement {
|
|||
}
|
||||
;(this as any).focus = () => {
|
||||
if (!DOM.isVisible(this.children[0])) {
|
||||
this.children[0].scrollIntoView({ block: "center", inline: "center" })
|
||||
this.children[0].scrollIntoView({
|
||||
block: "center",
|
||||
inline: "center",
|
||||
})
|
||||
}
|
||||
let parentNode = this.node.parentNode
|
||||
while (parentNode && !(parentNode instanceof HTMLAnchorElement)) {
|
||||
|
@ -50,8 +53,8 @@ class FindHighlight extends HTMLSpanElement {
|
|||
}
|
||||
|
||||
this.style.position = "absolute"
|
||||
this.style.top = "0px";
|
||||
this.style.left = "0px";
|
||||
this.style.top = "0px"
|
||||
this.style.left = "0px"
|
||||
for (const rect of rects) {
|
||||
if (rect.top < this.top) {
|
||||
this.top = rect.top
|
||||
|
@ -67,9 +70,8 @@ class FindHighlight extends HTMLSpanElement {
|
|||
highlight.style.pointerEvents = "none"
|
||||
this.appendChild(highlight)
|
||||
}
|
||||
; (this as any).unfocus()
|
||||
(this as any).unfocus()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
customElements.define("find-highlight", FindHighlight, { extends: "span" })
|
||||
|
@ -82,7 +84,9 @@ let selected = 0
|
|||
export async function jumpToMatch(searchQuery, reverse) {
|
||||
// First, search for the query
|
||||
const findcase = config.get("findcase")
|
||||
const sensitive = findcase === "sensitive" || (findcase === "smart" && /[A-Z]/.test(searchQuery))
|
||||
const sensitive =
|
||||
findcase === "sensitive" ||
|
||||
(findcase === "smart" && /[A-Z]/.test(searchQuery))
|
||||
const findPromise = await browserBg.find.find(searchQuery, {
|
||||
tabId: await activeTabId(),
|
||||
caseSensitive: sensitive,
|
||||
|
@ -95,7 +99,12 @@ export async function jumpToMatch(searchQuery, reverse) {
|
|||
removeHighlighting()
|
||||
|
||||
// We need to grab all text nodes in order to find the corresponding element
|
||||
const walker = document.createTreeWalker(document, NodeFilter.SHOW_TEXT, null, false)
|
||||
const walker = document.createTreeWalker(
|
||||
document,
|
||||
NodeFilter.SHOW_TEXT,
|
||||
null,
|
||||
false,
|
||||
)
|
||||
const nodes = []
|
||||
let node
|
||||
do {
|
||||
|
@ -111,10 +120,13 @@ export async function jumpToMatch(searchQuery, reverse) {
|
|||
const data = results.rectData[i]
|
||||
if (data.rectsAndTexts.rectList.length < 1) {
|
||||
// When a result does not have any rectangles, it's not visible
|
||||
continue;
|
||||
continue
|
||||
}
|
||||
const range = results.rangeData[i]
|
||||
const high = new FindHighlight(data.rectsAndTexts.rectList, nodes[range.startTextNodePos])
|
||||
const high = new FindHighlight(
|
||||
data.rectsAndTexts.rectList,
|
||||
nodes[range.startTextNodePos],
|
||||
)
|
||||
host.appendChild(high)
|
||||
lastHighlights.push(high)
|
||||
if (!focused && DOM.isVisible(high)) {
|
||||
|
@ -126,8 +138,9 @@ export async function jumpToMatch(searchQuery, reverse) {
|
|||
if (lastHighlights.length < 1) {
|
||||
throw new Error("Pattern not found: " + searchQuery)
|
||||
}
|
||||
lastHighlights
|
||||
.sort(reverse ? (a, b) => b.top - a.top : (a, b) => a.top - b.top)
|
||||
lastHighlights.sort(
|
||||
reverse ? (a, b) => b.top - a.top : (a, b) => a.top - b.top,
|
||||
)
|
||||
if (!focused) {
|
||||
selected = 0
|
||||
/* tslint:disable:no-useless-cast */
|
||||
|
@ -141,7 +154,7 @@ function drawHighlights(highlights) {
|
|||
}
|
||||
|
||||
export function removeHighlighting() {
|
||||
const host = getFindHost();
|
||||
const host = getFindHost()
|
||||
while (host.firstChild) host.removeChild(host.firstChild)
|
||||
}
|
||||
|
||||
|
@ -158,7 +171,7 @@ export async function jumpToNextMatch(n: number) {
|
|||
throw new Error("Pattern not found: " + lastSearchQuery)
|
||||
}
|
||||
/* tslint:disable:no-useless-cast */
|
||||
; (lastHighlights[selected] as any).unfocus()
|
||||
(lastHighlights[selected] as any).unfocus()
|
||||
selected = (selected + n + lastHighlights.length) % lastHighlights.length
|
||||
/* tslint:disable:no-useless-cast */
|
||||
;(lastHighlights[selected] as any).focus()
|
||||
|
|
|
@ -122,15 +122,29 @@ class HintState {
|
|||
const focusedRect = this.focusedHint.rect
|
||||
|
||||
// Get all hints from the top area
|
||||
const topHints = this.activeHints.filter(h => h.rect.top < focusedRect.top && h.rect.bottom < focusedRect.bottom)
|
||||
const topHints = this.activeHints.filter(
|
||||
h =>
|
||||
h.rect.top < focusedRect.top &&
|
||||
h.rect.bottom < focusedRect.bottom,
|
||||
)
|
||||
if (!topHints.length) {
|
||||
return
|
||||
}
|
||||
|
||||
// Find the next top hint
|
||||
const nextFocusedHint = topHints.reduce((a, b) => {
|
||||
const aDistance = distance(a.rect.left, a.rect.right, focusedRect.left, focusedRect.right)
|
||||
const bDistance = distance(b.rect.left, b.rect.right, focusedRect.left, focusedRect.right)
|
||||
const aDistance = distance(
|
||||
a.rect.left,
|
||||
a.rect.right,
|
||||
focusedRect.left,
|
||||
focusedRect.right,
|
||||
)
|
||||
const bDistance = distance(
|
||||
b.rect.left,
|
||||
b.rect.right,
|
||||
focusedRect.left,
|
||||
focusedRect.right,
|
||||
)
|
||||
if (aDistance < bDistance) {
|
||||
return a
|
||||
} else if (aDistance > bDistance) {
|
||||
|
@ -156,15 +170,29 @@ class HintState {
|
|||
const focusedRect = this.focusedHint.rect
|
||||
|
||||
// Get all hints from the bottom area
|
||||
const bottomHints = this.activeHints.filter(h => h.rect.top > focusedRect.top && h.rect.bottom > focusedRect.bottom)
|
||||
const bottomHints = this.activeHints.filter(
|
||||
h =>
|
||||
h.rect.top > focusedRect.top &&
|
||||
h.rect.bottom > focusedRect.bottom,
|
||||
)
|
||||
if (!bottomHints.length) {
|
||||
return
|
||||
}
|
||||
|
||||
// Find the next bottom hint
|
||||
const nextFocusedHint = bottomHints.reduce((a, b) => {
|
||||
const aDistance = distance(a.rect.left, a.rect.right, focusedRect.left, focusedRect.right)
|
||||
const bDistance = distance(b.rect.left, b.rect.right, focusedRect.left, focusedRect.right)
|
||||
const aDistance = distance(
|
||||
a.rect.left,
|
||||
a.rect.right,
|
||||
focusedRect.left,
|
||||
focusedRect.right,
|
||||
)
|
||||
const bDistance = distance(
|
||||
b.rect.left,
|
||||
b.rect.right,
|
||||
focusedRect.left,
|
||||
focusedRect.right,
|
||||
)
|
||||
if (aDistance < bDistance) {
|
||||
return a
|
||||
} else if (aDistance > bDistance) {
|
||||
|
@ -190,15 +218,29 @@ class HintState {
|
|||
const focusedRect = this.focusedHint.rect
|
||||
|
||||
// Get all hints from the left area
|
||||
const leftHints = this.activeHints.filter(h => h.rect.left < focusedRect.left && h.rect.right < focusedRect.right)
|
||||
const leftHints = this.activeHints.filter(
|
||||
h =>
|
||||
h.rect.left < focusedRect.left &&
|
||||
h.rect.right < focusedRect.right,
|
||||
)
|
||||
if (!leftHints.length) {
|
||||
return
|
||||
}
|
||||
|
||||
// Find the next left hint
|
||||
const nextFocusedHint = leftHints.reduce((a, b) => {
|
||||
const aDistance = distance(a.rect.top, a.rect.bottom, focusedRect.top, focusedRect.bottom)
|
||||
const bDistance = distance(b.rect.top, b.rect.bottom, focusedRect.top, focusedRect.bottom)
|
||||
const aDistance = distance(
|
||||
a.rect.top,
|
||||
a.rect.bottom,
|
||||
focusedRect.top,
|
||||
focusedRect.bottom,
|
||||
)
|
||||
const bDistance = distance(
|
||||
b.rect.top,
|
||||
b.rect.bottom,
|
||||
focusedRect.top,
|
||||
focusedRect.bottom,
|
||||
)
|
||||
if (aDistance < bDistance) {
|
||||
return a
|
||||
} else if (aDistance > bDistance) {
|
||||
|
@ -224,15 +266,29 @@ class HintState {
|
|||
const focusedRect = this.focusedHint.rect
|
||||
|
||||
// Get all hints from the right area
|
||||
const rightHints = this.activeHints.filter(h => h.rect.left > focusedRect.left && h.rect.right > focusedRect.right)
|
||||
const rightHints = this.activeHints.filter(
|
||||
h =>
|
||||
h.rect.left > focusedRect.left &&
|
||||
h.rect.right > focusedRect.right,
|
||||
)
|
||||
if (!rightHints.length) {
|
||||
return
|
||||
}
|
||||
|
||||
// Find the next right hint
|
||||
const nextFocusedHint = rightHints.reduce((a, b) => {
|
||||
const aDistance = distance(a.rect.top, a.rect.bottom, focusedRect.top, focusedRect.bottom)
|
||||
const bDistance = distance(b.rect.top, b.rect.bottom, focusedRect.top, focusedRect.bottom)
|
||||
const aDistance = distance(
|
||||
a.rect.top,
|
||||
a.rect.bottom,
|
||||
focusedRect.top,
|
||||
focusedRect.bottom,
|
||||
)
|
||||
const bDistance = distance(
|
||||
b.rect.top,
|
||||
b.rect.bottom,
|
||||
focusedRect.top,
|
||||
focusedRect.bottom,
|
||||
)
|
||||
if (aDistance < bDistance) {
|
||||
return a
|
||||
} else if (aDistance > bDistance) {
|
||||
|
@ -264,8 +320,12 @@ class HintState {
|
|||
|
||||
// To do this, compute the number of hints between the last selected
|
||||
// hint and the hint selected before it
|
||||
const lastIndex = this.hints.indexOf(this.selectedHints[this.selectedHints.length - 1])
|
||||
const prevIndex = this.hints.indexOf(this.selectedHints[this.selectedHints.length - 2])
|
||||
const lastIndex = this.hints.indexOf(
|
||||
this.selectedHints[this.selectedHints.length - 1],
|
||||
)
|
||||
const prevIndex = this.hints.indexOf(
|
||||
this.selectedHints[this.selectedHints.length - 2],
|
||||
)
|
||||
const distance = lastIndex - prevIndex
|
||||
|
||||
if (distance > 0) {
|
||||
|
@ -302,7 +362,9 @@ class HintState {
|
|||
|
||||
// Set the names that should go at the end
|
||||
for (let i = 0; i < savedNames.length; ++i) {
|
||||
this.hints[this.hints.length + distance + i].setName(savedNames[i])
|
||||
this.hints[this.hints.length + distance + i].setName(
|
||||
savedNames[i],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -339,8 +401,11 @@ export function hintPage(
|
|||
buildHints(hintableElements, hint => {
|
||||
hint.result = onSelect(hint.target)
|
||||
modeState.selectedHints.push(hint)
|
||||
if (modeState.selectedHints.length > 1 && (config.get("hintshift") === "true")) {
|
||||
modeState.shiftHints();
|
||||
if (
|
||||
modeState.selectedHints.length > 1 &&
|
||||
config.get("hintshift") === "true"
|
||||
) {
|
||||
modeState.shiftHints()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -363,23 +428,24 @@ export function hintPage(
|
|||
|
||||
const firstTarget = modeState.hints[0].target
|
||||
|
||||
const firstTargetIsSelectable = (): boolean => {
|
||||
return firstTarget instanceof HTMLAnchorElement &&
|
||||
const firstTargetIsSelectable = (): boolean => (
|
||||
firstTarget instanceof HTMLAnchorElement &&
|
||||
firstTarget.href !== "" &&
|
||||
!firstTarget.href.startsWith("javascript:")
|
||||
}
|
||||
)
|
||||
|
||||
const allTargetsAreEqual = (): boolean => {
|
||||
return undefined === modeState.hints.find(h => {
|
||||
return (
|
||||
const allTargetsAreEqual = (): boolean => (
|
||||
undefined ===
|
||||
modeState.hints.find(h => (
|
||||
!(h.target instanceof HTMLAnchorElement) ||
|
||||
h.target.href !== (firstTarget as HTMLAnchorElement).href
|
||||
))
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
if (modeState.hints.length == 1 ||
|
||||
(firstTargetIsSelectable() && allTargetsAreEqual())) {
|
||||
if (
|
||||
modeState.hints.length == 1 ||
|
||||
(firstTargetIsSelectable() && allTargetsAreEqual())
|
||||
) {
|
||||
// There is just a single link or all the links point to the same
|
||||
// place. Select it.
|
||||
modeState.cleanUpHints()
|
||||
|
@ -479,9 +545,7 @@ function* hintnames_uniform(
|
|||
// And return first n permutations
|
||||
yield* map(
|
||||
islice(permutationsWithReplacement(hintchars, taglen), n),
|
||||
perm => {
|
||||
return perm.join("")
|
||||
},
|
||||
perm => perm.join(""),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -552,7 +616,7 @@ class Hint {
|
|||
left: rect.left + offsetLeft,
|
||||
right: rect.right + offsetLeft,
|
||||
width: rect.width,
|
||||
height: rect.height
|
||||
height: rect.height,
|
||||
}
|
||||
|
||||
this.flag.textContent = name
|
||||
|
@ -631,9 +695,13 @@ export const vimpHelper = {
|
|||
// escape the hintchars string so that strange things don't happen
|
||||
// when special characters are used as hintchars (for example, ']')
|
||||
const escapedHintChars = defaultHintChars().replace(
|
||||
/^\^|[-\\\]]/g, "\\$&")
|
||||
/^\^|[-\\\]]/g,
|
||||
"\\$&",
|
||||
)
|
||||
const filterableTextFilter = new RegExp(
|
||||
"[" + escapedHintChars + "]", "g")
|
||||
"[" + escapedHintChars + "]",
|
||||
"g",
|
||||
)
|
||||
vimpHelper.filterableTextFilter = filterableTextFilter
|
||||
}
|
||||
return str.replace(vimpHelper.filterableTextFilter, "")
|
||||
|
@ -751,7 +819,9 @@ function filterHintsVimperator(fstr, reflow = false) {
|
|||
active = active.filter(hint => hint.name.startsWith(run.str))
|
||||
} else {
|
||||
// By text
|
||||
active = active.filter(hint => vimpHelper.matchHint(hint.filterData, run.str))
|
||||
active = active.filter(hint =>
|
||||
vimpHelper.matchHint(hint.filterData, run.str),
|
||||
)
|
||||
|
||||
if (reflow) rename(active)
|
||||
}
|
||||
|
@ -848,7 +918,7 @@ export function hintables(selectors = DOM.HINTTAGS_selectors, withjs = false) {
|
|||
elems = [...elemSet]
|
||||
}
|
||||
elems = elems.filter(DOM.isVisible)
|
||||
return changeHintablesToLargestChild(elems);
|
||||
return changeHintablesToLargestChild(elems)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -858,21 +928,24 @@ export function hintables(selectors = DOM.HINTTAGS_selectors, withjs = false) {
|
|||
*/
|
||||
function changeHintablesToLargestChild(elements: Element[]): Element[] {
|
||||
elements.forEach((element, index) => {
|
||||
if (element.childNodes.length === 0) return;
|
||||
let largestChild: Element;
|
||||
if (element.childNodes.length === 0) return
|
||||
let largestChild: Element
|
||||
// Find largest child.
|
||||
element.childNodes.forEach((c) => {
|
||||
const currentChild = (c as Element);
|
||||
if (!largestChild || isElementLargerThan(currentChild, largestChild)) {
|
||||
largestChild = currentChild;
|
||||
element.childNodes.forEach(c => {
|
||||
const currentChild = c as Element
|
||||
if (
|
||||
!largestChild ||
|
||||
isElementLargerThan(currentChild, largestChild)
|
||||
) {
|
||||
largestChild = currentChild
|
||||
}
|
||||
})
|
||||
// Change element if child is larger
|
||||
if (isElementLargerThan(largestChild, element)) {
|
||||
elements[index] = largestChild;
|
||||
elements[index] = largestChild
|
||||
}
|
||||
})
|
||||
return elements;
|
||||
return elements
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -881,13 +954,13 @@ function changeHintablesToLargestChild(elements: Element[]): Element[] {
|
|||
*/
|
||||
function isElementLargerThan(e1: Element, e2: Element): boolean {
|
||||
if (typeof e1.getBoundingClientRect !== "function") {
|
||||
return false;
|
||||
return false
|
||||
} else if (typeof e2.getBoundingClientRect !== "function") {
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
const e1BR = e1.getBoundingClientRect();
|
||||
const e2BR = e2.getBoundingClientRect();
|
||||
return e1BR.height > e2BR.height && e1BR.width > e2BR.width;
|
||||
const e1BR = e1.getBoundingClientRect()
|
||||
const e2BR = e2.getBoundingClientRect()
|
||||
return e1BR.height > e2BR.height && e1BR.width > e2BR.width
|
||||
}
|
||||
|
||||
/** Returns elements that point to a saveable resource
|
||||
|
@ -924,7 +997,7 @@ export function hintByText(match: string|RegExp) {
|
|||
} else {
|
||||
return text.toUpperCase().includes(match.toUpperCase())
|
||||
}
|
||||
}
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -1008,9 +1081,16 @@ function focusRightHint() {
|
|||
|
||||
/** @hidden */
|
||||
export function parser(keys: KeyboardEvent[]) {
|
||||
const parsed = keyseq.parse(keys,
|
||||
keyseq.mapstrMapToKeyMap(new Map((Object.entries(config.get("hintmaps")) as any)
|
||||
.filter(([key, value]) => value != ""))))
|
||||
const parsed = keyseq.parse(
|
||||
keys,
|
||||
keyseq.mapstrMapToKeyMap(
|
||||
new Map(
|
||||
(Object.entries(config.get("hintmaps")) as any).filter(
|
||||
([key, value]) => value != "",
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
if (parsed.isMatch === true) {
|
||||
return parsed
|
||||
}
|
||||
|
@ -1018,7 +1098,10 @@ export function parser(keys: KeyboardEvent[]) {
|
|||
const simplekeys = keys.filter(key => !keyseq.hasModifiers(key))
|
||||
let exstr
|
||||
if (simplekeys.length > 1) {
|
||||
exstr = simplekeys.reduce((acc, key) => `hint.pushKey ${key.key};`, "composite ")
|
||||
exstr = simplekeys.reduce(
|
||||
(acc, key) => `hint.pushKey ${key.key};`,
|
||||
"composite ",
|
||||
)
|
||||
} else if (simplekeys.length === 1) {
|
||||
exstr = `hint.pushKeyCodePoint ${simplekeys[0].key.codePointAt(0)}`
|
||||
} else {
|
||||
|
@ -1042,5 +1125,5 @@ export function getHintCommands() {
|
|||
pushSpace,
|
||||
pushKeyCodePoint,
|
||||
popKey,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
135
src/excmds.ts
135
src/excmds.ts
|
@ -257,7 +257,7 @@ export function fillinput(selector: string, ...content: string[]) {
|
|||
let inputToFill = document.querySelector(selector)
|
||||
if (!inputToFill) inputToFill = DOM.getLastUsedInput()
|
||||
if ("value" in inputToFill) {
|
||||
; (inputToFill as HTMLInputElement).value = content.join(" ")
|
||||
(inputToFill as HTMLInputElement).value = content.join(" ")
|
||||
} else {
|
||||
inputToFill.textContent = content.join(" ")
|
||||
}
|
||||
|
@ -336,7 +336,7 @@ export async function editor() {
|
|||
let line = 0
|
||||
let col = 0
|
||||
wrap_input((t, start, end) => {
|
||||
; [text, line, col] = getLineAndColNumber(t, start, end)
|
||||
[text, line, col] = getLineAndColNumber(t, start, end)
|
||||
return [null, null, null]
|
||||
})(elem)
|
||||
const file = (await Native.temp(text, document.location.hostname)).content
|
||||
|
@ -444,16 +444,7 @@ export async function loadtheme(themename: string) {
|
|||
if (!(await Native.nativegate("0.1.9"))) return
|
||||
const separator = (await browserBg.runtime.getPlatformInfo()).os === "win" ? "\\" : "/"
|
||||
// remove the "tridactylrc" bit so that we're left with the directory
|
||||
const path =
|
||||
(await Native.getrcpath())
|
||||
.split(separator)
|
||||
.slice(0, -1)
|
||||
.join(separator) +
|
||||
separator +
|
||||
"themes" +
|
||||
separator +
|
||||
themename +
|
||||
".css"
|
||||
const path = (await Native.getrcpath()).split(separator).slice(0, -1).join(separator) + separator + "themes" + separator + themename + ".css"
|
||||
const file = await Native.read(path)
|
||||
if (file.code !== 0) throw new Error("Couldn't read theme " + path)
|
||||
return set("customthemes." + themename, file.content)
|
||||
|
@ -1028,7 +1019,7 @@ export async function scrollpx(a: number, b: number) {
|
|||
*/
|
||||
//#content
|
||||
export function scrollto(a: number | string, b: number | "x" | "y" = "y") {
|
||||
if (typeof a === "string" && a.match(/c$/i)) {
|
||||
if (typeof a === "string" && /c$/i.exec(a)) {
|
||||
a = (Number(a.replace(/c$/, "")) * 100) / (2 * Math.PI)
|
||||
}
|
||||
a = Number(a)
|
||||
|
@ -1208,10 +1199,10 @@ export async function open(...urlarr: string[]) {
|
|||
const url = urlarr.join(" ")
|
||||
|
||||
// Setting window.location to about:blank results in a page we can't access, tabs.update works.
|
||||
if (!ABOUT_WHITELIST.includes(url) && url.match(/^(about|file):.*/)) {
|
||||
if (!ABOUT_WHITELIST.includes(url) && /^(about|file):.*/.exec(url)) {
|
||||
// Open URLs that firefox won't let us by running `firefox <URL>` on the command line
|
||||
return nativeopen(url)
|
||||
} else if (url.match(/^javascript:/)) {
|
||||
} else if (/^javascript:/.exec(url)) {
|
||||
const bookmarklet = url.replace(/^javascript:/, "")
|
||||
document.body.append(
|
||||
html`
|
||||
|
@ -1245,7 +1236,7 @@ export async function bmarks(opt: string, ...urlarr: string[]) {
|
|||
export async function open_quiet(...urlarr: string[]) {
|
||||
const url = urlarr.join(" ")
|
||||
|
||||
if (!ABOUT_WHITELIST.includes(url) && url.match(/^(about|file):.*/)) {
|
||||
if (!ABOUT_WHITELIST.includes(url) && /^(about|file):.*/.exec(url)) {
|
||||
return nativeopen(url)
|
||||
}
|
||||
|
||||
|
@ -2143,7 +2134,7 @@ export async function tabopen(...addressarr: string[]) {
|
|||
const query = await argParse(addressarr)
|
||||
|
||||
const address = query.join(" ")
|
||||
if (!ABOUT_WHITELIST.includes(address) && address.match(/^(about|file):.*/)) {
|
||||
if (!ABOUT_WHITELIST.includes(address) && /^(about|file):.*/.exec(address)) {
|
||||
return nativeopen(address)
|
||||
}
|
||||
|
||||
|
@ -2186,34 +2177,35 @@ export async function tabopen(...addressarr: string[]) {
|
|||
export function tabqueue(...addresses: string[]) {
|
||||
// addresses[0] is a string when called with `tabopen a b c` but an array
|
||||
// when called from `composite hint -qpipe a href | tabqueue`.
|
||||
addresses = addresses.flat(Infinity);
|
||||
addresses = addresses.flat(Infinity)
|
||||
if (addresses.length === 0) {
|
||||
return Promise.resolve();
|
||||
return Promise.resolve()
|
||||
}
|
||||
return tabopen("-b", addresses[0]).then(tab =>
|
||||
return tabopen("-b", addresses[0]).then(
|
||||
tab =>
|
||||
new Promise((resolve, reject) => {
|
||||
function openNextTab(activeInfo) {
|
||||
if (activeInfo.tabId === tab.id) {
|
||||
resolve(tabqueue(...(addresses.slice(1))));
|
||||
removeTabqueueListeners(tab.id);
|
||||
resolve(tabqueue(...addresses.slice(1)))
|
||||
removeTabqueueListeners(tab.id)
|
||||
}
|
||||
}
|
||||
function removeTabqueueListeners(tabId) {
|
||||
if (tabId === tab.id) {
|
||||
browser.tabs.onActivated.removeListener(openNextTab);
|
||||
browser.tabs.onRemoved.removeListener(removeTabqueueListeners);
|
||||
browser.tabs.onActivated.removeListener(openNextTab)
|
||||
browser.tabs.onRemoved.removeListener(removeTabqueueListeners)
|
||||
// FIXME: This should actually be `reject(tab)` to
|
||||
// interrupt pipelines, but this results in an impossible
|
||||
// to debug `Error: undefined` message being printed on the
|
||||
// command line. So we silently resolve the promise and
|
||||
// hope for the best.
|
||||
resolve(tab);
|
||||
resolve(tab)
|
||||
}
|
||||
}
|
||||
browser.tabs.onActivated.addListener(openNextTab);
|
||||
browser.tabs.onRemoved.addListener(removeTabqueueListeners);
|
||||
})
|
||||
);
|
||||
browser.tabs.onActivated.addListener(openNextTab)
|
||||
browser.tabs.onRemoved.addListener(removeTabqueueListeners)
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/** Resolve a tab index to the tab id of the corresponding tab in this window.
|
||||
|
@ -2246,10 +2238,12 @@ async function idFromIndex(index?: number | "%" | "#" | string): Promise<number>
|
|||
index = (index - 1).mod((await browser.tabs.query({ currentWindow: true })).length) + 1
|
||||
|
||||
// Return id of tab with that index.
|
||||
return (await browser.tabs.query({
|
||||
return (
|
||||
await browser.tabs.query({
|
||||
currentWindow: true,
|
||||
index: index - 1,
|
||||
}))[0].id
|
||||
})
|
||||
)[0].id
|
||||
} else {
|
||||
return activeTabId()
|
||||
}
|
||||
|
@ -2336,7 +2330,7 @@ export async function tabclose(...indexes: string[]) {
|
|||
*/
|
||||
//#background
|
||||
export async function tabcloseallto(side: string) {
|
||||
if (!(["left", "right"].includes(side))) {
|
||||
if (!["left", "right"].includes(side)) {
|
||||
throw "side argument must be left or right"
|
||||
}
|
||||
const tabs = await browser.tabs.query({
|
||||
|
@ -2585,7 +2579,7 @@ export async function winopen(...args: string[]) {
|
|||
}
|
||||
|
||||
const address = args.join(" ")
|
||||
if (!ABOUT_WHITELIST.includes(address) && address.match(/^(about|file):.*/)) {
|
||||
if (!ABOUT_WHITELIST.includes(address) && /^(about|file):.*/.exec(address)) {
|
||||
return nativeopen(firefoxArgs, address)
|
||||
}
|
||||
|
||||
|
@ -2626,13 +2620,7 @@ export async function qall() {
|
|||
//#background
|
||||
export async function containerclose(name: string) {
|
||||
const containerId = await Container.getId(name)
|
||||
return browser.tabs.query({ cookieStoreId: containerId }).then(tabs => {
|
||||
return browser.tabs.remove(
|
||||
tabs.map(tab => {
|
||||
return tab.id
|
||||
}),
|
||||
)
|
||||
})
|
||||
return browser.tabs.query({ cookieStoreId: containerId }).then(tabs => browser.tabs.remove(tabs.map(tab => tab.id)))
|
||||
}
|
||||
/** Creates a new container. Note that container names must be unique and that the checks are case-insensitive.
|
||||
|
||||
|
@ -2679,7 +2667,7 @@ export async function containerupdate(name: string, uname: string, ucolor: strin
|
|||
logger.debug("containerupdate parameters: " + name + ", " + uname + ", " + ucolor + ", " + uicon)
|
||||
const containerId = await Container.fuzzyMatch(name)
|
||||
const containerObj = Container.fromString(uname, ucolor, uicon)
|
||||
await Container.update(containerId, containerObj)
|
||||
Container.update(containerId, containerObj)
|
||||
}
|
||||
|
||||
/** Shows a list of the current containers in Firefox's native JSON viewer in the current tab.
|
||||
|
@ -2692,11 +2680,7 @@ export async function viewcontainers() {
|
|||
// # and white space don't agree with FF's JSON viewer.
|
||||
// Probably other symbols too.
|
||||
const containers = await browserBg.contextualIdentities.query({}) // Can't access src/lib/containers.ts from a content script.
|
||||
window.location.href =
|
||||
"data:application/json," +
|
||||
JSON.stringify(containers)
|
||||
.replace(/#/g, "%23")
|
||||
.replace(/ /g, "%20")
|
||||
window.location.href = "data:application/json," + JSON.stringify(containers).replace(/#/g, "%23").replace(/ /g, "%20")
|
||||
}
|
||||
|
||||
/** Opens the current tab in another container.
|
||||
|
@ -2771,12 +2755,8 @@ async function getnexttabs(tabid: number, n?: number) {
|
|||
const tabs: browser.tabs.Tab[] = await browser.tabs.query({
|
||||
currentWindow: true,
|
||||
})
|
||||
const indexFilter = ((tab: browser.tabs.Tab) => {
|
||||
return curIndex <= tab.index && (n ? tab.index < curIndex + Number(n) : true)
|
||||
}).bind(n)
|
||||
return tabs.filter(indexFilter).map((tab: browser.tabs.Tab) => {
|
||||
return tab.id
|
||||
})
|
||||
const indexFilter = ((tab: browser.tabs.Tab) => curIndex <= tab.index && (n ? tab.index < curIndex + Number(n) : true)).bind(n)
|
||||
return tabs.filter(indexFilter).map((tab: browser.tabs.Tab) => tab.id)
|
||||
}
|
||||
|
||||
// Moderately slow; should load in results as they arrive, perhaps
|
||||
|
@ -2849,8 +2829,7 @@ export async function composite(...cmds: string[]) {
|
|||
// For each pipeline, wait for previous pipeline to finish, then
|
||||
// execute each cmd in pipeline in order, passing the result of the
|
||||
// previous cmd as the last argument to the next command.
|
||||
.reduce(
|
||||
async (prev_pipeline, cmd) => {
|
||||
.reduce(async (prev_pipeline, cmd) => {
|
||||
await prev_pipeline
|
||||
const cmds = cmd.split("|")
|
||||
|
||||
|
@ -2870,9 +2849,7 @@ export async function composite(...cmds: string[]) {
|
|||
const [fn, args] = excmd_parser.parser(cmd, ALL_EXCMDS)
|
||||
return fn.call({}, ...args, await pipedValue)
|
||||
}, first_value)
|
||||
},
|
||||
null as any,
|
||||
)
|
||||
}, null as any)
|
||||
)
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
|
@ -3122,7 +3099,7 @@ export async function tab(index: number | "#") {
|
|||
//#background
|
||||
export async function taball(id: string) {
|
||||
const windows = (await browser.windows.getAll()).map(w => w.id).sort((a, b) => a - b)
|
||||
if (id === null || id === undefined || !id.match(/\d+\.\d+/)) {
|
||||
if (id === null || id === undefined || /\d+\.\d+/.exec(id)) {
|
||||
const tab = await activeTab()
|
||||
const prevId = id
|
||||
id = windows.indexOf(tab.windowId) + "." + (tab.index + 1)
|
||||
|
@ -3590,7 +3567,7 @@ export async function sanitise(...args: string[]) {
|
|||
// If the -t flag has been given and there is an arg after it
|
||||
if (flagpos > -1) {
|
||||
if (flagpos < args.length - 1) {
|
||||
const match = args[flagpos + 1].match("^([0-9])+(m|h|d|w)$")
|
||||
const match = /^([0-9])+(m|h|d|w)$/.exec(args[flagpos + 1])
|
||||
// If the arg of the flag matches Pentadactyl's sanitisetimespan format
|
||||
if (match !== null && match.length === 3) {
|
||||
// Compute the timespan in milliseconds and get a Date object
|
||||
|
@ -3638,7 +3615,7 @@ export async function sanitise(...args: string[]) {
|
|||
*/
|
||||
}
|
||||
if (args.find(x => x === "all") !== undefined) {
|
||||
for (const attr in dts) dts[attr] = true
|
||||
for (const attr in dts) if (Object.prototype.hasOwnProperty.call(dts, attr)) dts[attr] = true
|
||||
} else {
|
||||
// We bother checking if dts[x] is false because
|
||||
// browser.browsingData.remove() is very strict on the format of the
|
||||
|
@ -3722,31 +3699,14 @@ export function get(...keys: string[]) {
|
|||
export function viewconfig(key?: string) {
|
||||
// # and white space don't agree with FF's JSON viewer.
|
||||
// Probably other symbols too.
|
||||
if (!key)
|
||||
window.location.href =
|
||||
"data:application/json," +
|
||||
JSON.stringify(config.get())
|
||||
.replace(/#/g, "%23")
|
||||
.replace(/ /g, "%20")
|
||||
if (!key) window.location.href = "data:application/json," + JSON.stringify(config.get()).replace(/#/g, "%23").replace(/ /g, "%20")
|
||||
// I think JS casts key to the string "undefined" if it isn't given.
|
||||
else if (key === "--default") {
|
||||
window.location.href =
|
||||
"data:application/json," +
|
||||
JSON.stringify(config.o(new config.default_config()))
|
||||
.replace(/#/g, "%23")
|
||||
.replace(/ /g, "%20")
|
||||
window.location.href = "data:application/json," + JSON.stringify(config.o(new config.default_config())).replace(/#/g, "%23").replace(/ /g, "%20")
|
||||
} else if (key === "--user") {
|
||||
window.location.href =
|
||||
"data:application/json," +
|
||||
JSON.stringify(config.USERCONFIG)
|
||||
.replace(/#/g, "%23")
|
||||
.replace(/ /g, "%20")
|
||||
window.location.href = "data:application/json," + JSON.stringify(config.USERCONFIG).replace(/#/g, "%23").replace(/ /g, "%20")
|
||||
}
|
||||
window.location.href =
|
||||
"data:application/json," +
|
||||
JSON.stringify(config.getDynamic(key))
|
||||
.replace(/#/g, "%23")
|
||||
.replace(/ /g, "%20")
|
||||
window.location.href = "data:application/json," + JSON.stringify(config.getDynamic(key)).replace(/#/g, "%23").replace(/ /g, "%20")
|
||||
// base 64 encoding is a cleverer way of doing this, but it doesn't seem to work for the whole config.
|
||||
//window.location.href = "data:application/json;base64," + btoa(JSON.stringify(config.get()))
|
||||
}
|
||||
|
@ -4030,12 +3990,7 @@ export async function hint(option?: string, selectors?: string, ...rest: string[
|
|||
break
|
||||
|
||||
case "-pipe":
|
||||
selectHints = hinting.pipe(
|
||||
selectors,
|
||||
elem => elem[rest.join(" ")],
|
||||
rapid,
|
||||
jshints,
|
||||
)
|
||||
selectHints = hinting.pipe(selectors, elem => elem[rest.join(" ")], rapid, jshints)
|
||||
break
|
||||
|
||||
case "-i":
|
||||
|
@ -4497,8 +4452,7 @@ async function js_helper(str: string[]) {
|
|||
done = true
|
||||
break
|
||||
}
|
||||
if (!done)
|
||||
str.shift()
|
||||
if (!done) str.shift()
|
||||
}
|
||||
|
||||
if (doSource) {
|
||||
|
@ -4509,8 +4463,7 @@ async function js_helper(str: string[]) {
|
|||
sourcePath = [...rcPath, sourcePath].join(sep)
|
||||
}
|
||||
const file = await Native.read(sourcePath)
|
||||
if (file.code !== 0)
|
||||
throw new Error("Couldn't read js file " + sourcePath)
|
||||
if (file.code !== 0) throw new Error("Couldn't read js file " + sourcePath)
|
||||
jsContent = file.content
|
||||
} else {
|
||||
jsContent = str.join(" ")
|
||||
|
|
|
@ -180,9 +180,7 @@ export class AutoContain implements IAutoContain {
|
|||
}, 2000)
|
||||
}
|
||||
|
||||
getCancelledRequest = (tabId: number): ICancelledRequest => {
|
||||
return this.cancelledRequests[tabId]
|
||||
}
|
||||
getCancelledRequest = (tabId: number): ICancelledRequest => this.cancelledRequests[tabId]
|
||||
|
||||
// Clear the cancelled requests.
|
||||
clearCancelledRequests = (tabId: number): void => {
|
||||
|
@ -311,7 +309,5 @@ export class AutoContain implements IAutoContain {
|
|||
// Parses autocontain directives and returns valid cookieStoreIds or errors.
|
||||
getAuconForDetails = async (
|
||||
details: browser.webRequest.IDetails,
|
||||
): Promise<string> => {
|
||||
return this.getAuconForUrl(details.url)
|
||||
}
|
||||
): Promise<string> => this.getAuconForUrl(details.url)
|
||||
}
|
||||
|
|
|
@ -93,16 +93,12 @@ export function getCommandlineFns(cmdline_state) {
|
|||
/**
|
||||
* Selects the next history line.
|
||||
*/
|
||||
"next_history": () => {
|
||||
return cmdline_state.history(1)
|
||||
},
|
||||
"next_history": () => cmdline_state.history(1),
|
||||
|
||||
/**
|
||||
* Selects the prev history line.
|
||||
*/
|
||||
"prev_history": () => {
|
||||
return cmdline_state.history(-1)
|
||||
},
|
||||
"prev_history": () => cmdline_state.history(-1),
|
||||
/**
|
||||
* Execute the content of the command line and hide it.
|
||||
**/
|
||||
|
|
|
@ -26,8 +26,8 @@ const removeNull = R.when(
|
|||
R.is(Object),
|
||||
R.pipe(
|
||||
R.reject(val => val === null),
|
||||
R.map(a => removeNull(a))
|
||||
)
|
||||
R.map(a => removeNull(a)),
|
||||
),
|
||||
)
|
||||
|
||||
/** @hidden */
|
||||
|
@ -276,7 +276,7 @@ export class default_config {
|
|||
";y": "hint -y",
|
||||
";p": "hint -p",
|
||||
";h": "hint -h",
|
||||
"v": "hint -h", // Easiest way of entering visual mode for now. Expect this bind to change
|
||||
v: "hint -h", // Easiest way of entering visual mode for now. Expect this bind to change
|
||||
";P": "hint -P",
|
||||
";r": "hint -r",
|
||||
";s": "hint -s",
|
||||
|
@ -339,23 +339,32 @@ export class default_config {
|
|||
}
|
||||
|
||||
vmaps = {
|
||||
"<Escape>": "composite js document.getSelection().empty(); mode normal; hidecmdline",
|
||||
"<C-[>": "composite js document.getSelection().empty(); mode normal ; hidecmdline",
|
||||
"y": "composite js document.getSelection().toString() | clipboard yank",
|
||||
"s": "composite js document.getSelection().toString() | fillcmdline open search",
|
||||
"S": "composite js document.getSelection().toString() | fillcmdline tabopen search",
|
||||
"l": 'js document.getSelection().modify("extend","forward","character")',
|
||||
"h": 'js document.getSelection().modify("extend","backward","character")',
|
||||
"e": 'js document.getSelection().modify("extend","forward","word")',
|
||||
"w": 'js document.getSelection().modify("extend","forward","word"); document.getSelection().modify("extend","forward","character")',
|
||||
"b": 'js document.getSelection().modify("extend","backward","character"); document.getSelection().modify("extend","backward","word"); document.getSelection().modify("extend","forward","character")',
|
||||
"j": 'js document.getSelection().modify("extend","forward","line")',
|
||||
"<Escape>":
|
||||
"composite js document.getSelection().empty(); mode normal; hidecmdline",
|
||||
"<C-[>":
|
||||
"composite js document.getSelection().empty(); mode normal ; hidecmdline",
|
||||
y: "composite js document.getSelection().toString() | clipboard yank",
|
||||
s:
|
||||
"composite js document.getSelection().toString() | fillcmdline open search",
|
||||
S:
|
||||
"composite js document.getSelection().toString() | fillcmdline tabopen search",
|
||||
l: 'js document.getSelection().modify("extend","forward","character")',
|
||||
h: 'js document.getSelection().modify("extend","backward","character")',
|
||||
e: 'js document.getSelection().modify("extend","forward","word")',
|
||||
w:
|
||||
'js document.getSelection().modify("extend","forward","word"); document.getSelection().modify("extend","forward","character")',
|
||||
b:
|
||||
'js document.getSelection().modify("extend","backward","character"); document.getSelection().modify("extend","backward","word"); document.getSelection().modify("extend","forward","character")',
|
||||
j: 'js document.getSelection().modify("extend","forward","line")',
|
||||
// "j": 'js document.getSelection().modify("extend","forward","paragraph")', // not implemented in Firefox
|
||||
"k": 'js document.getSelection().modify("extend","backward","line")',
|
||||
"$": 'js document.getSelection().modify("extend","forward","lineboundary")',
|
||||
"0": 'js document.getSelection().modify("extend","backward","lineboundary")',
|
||||
"=": "js let n = document.getSelection().anchorNode.parentNode; let s = window.getSelection(); let r = document.createRange(); s.removeAllRanges(); r.selectNodeContents(n); s.addRange(r)",
|
||||
"o": "js tri.visual.reverseSelection(document.getSelection())",
|
||||
k: 'js document.getSelection().modify("extend","backward","line")',
|
||||
$:
|
||||
'js document.getSelection().modify("extend","forward","lineboundary")',
|
||||
"0":
|
||||
'js document.getSelection().modify("extend","backward","lineboundary")',
|
||||
"=":
|
||||
"js let n = document.getSelection().anchorNode.parentNode; let s = window.getSelection(); let r = document.createRange(); s.removeAllRanges(); r.selectNodeContents(n); s.addRange(r)",
|
||||
o: "js tri.visual.reverseSelection(document.getSelection())",
|
||||
"🕷🕷INHERITS🕷🕷": "nmaps",
|
||||
}
|
||||
|
||||
|
@ -572,14 +581,15 @@ export class default_config {
|
|||
mkt: "mktridactylrc",
|
||||
"mkt!": "mktridactylrc -f",
|
||||
"mktridactylrc!": "mktridactylrc -f",
|
||||
mpvsafe: "js -p tri.excmds.shellescape(JS_ARG).then(url => tri.excmds.exclaim_quiet('mpv ' + url))",
|
||||
mpvsafe:
|
||||
"js -p tri.excmds.shellescape(JS_ARG).then(url => tri.excmds.exclaim_quiet('mpv ' + url))",
|
||||
exto: "extoptions",
|
||||
extpreferences: "extoptions",
|
||||
extp: "extpreferences",
|
||||
prefset: "setpref",
|
||||
prefremove: "removepref",
|
||||
tabclosealltoright: "tabcloseallto right",
|
||||
tabclosealltoleft: "tabcloseallto left"
|
||||
tabclosealltoleft: "tabcloseallto left",
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1059,7 +1069,10 @@ function getDeepProperty(obj, target: string[]) {
|
|||
if (obj["🕷🕷INHERITS🕷🕷"] === undefined) {
|
||||
return getDeepProperty(obj[target[0]], target.slice(1))
|
||||
} else {
|
||||
return getDeepProperty(mergeDeepCull(get(obj["🕷🕷INHERITS🕷🕷"]), obj)[target[0]], target.slice(1))
|
||||
return getDeepProperty(
|
||||
mergeDeepCull(get(obj["🕷🕷INHERITS🕷🕷"]), obj)[target[0]],
|
||||
target.slice(1),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
if (obj === undefined || obj === null) return obj
|
||||
|
@ -1102,7 +1115,11 @@ export function mergeDeep(o1, o2) {
|
|||
.filter(
|
||||
key => typeof o1[key] === "object" && typeof o2[key] === "object",
|
||||
)
|
||||
.forEach(key => r[key] == null ? null : Object.assign(r[key], mergeDeep(o1[key], o2[key])))
|
||||
.forEach(key =>
|
||||
r[key] == null
|
||||
? null
|
||||
: Object.assign(r[key], mergeDeep(o1[key], o2[key])),
|
||||
)
|
||||
return r
|
||||
}
|
||||
|
||||
|
@ -1134,8 +1151,7 @@ export function getURL(url: string, target: string[]) {
|
|||
(conf.subconfigs[k2].priority || 10),
|
||||
)
|
||||
// Merge their corresponding value if they're objects, otherwise return the last value
|
||||
.reduce(
|
||||
(acc, curKey) => {
|
||||
.reduce((acc, curKey) => {
|
||||
const curVal = getDeepProperty(
|
||||
conf.subconfigs[curKey],
|
||||
target,
|
||||
|
@ -1143,9 +1159,7 @@ export function getURL(url: string, target: string[]) {
|
|||
if (acc instanceof Object && curVal instanceof Object)
|
||||
return mergeDeep(acc, curVal)
|
||||
return curVal
|
||||
},
|
||||
undefined as any,
|
||||
)
|
||||
}, undefined as any)
|
||||
)
|
||||
}
|
||||
const user = _getURL(USERCONFIG, url, target)
|
||||
|
@ -1266,7 +1280,11 @@ export async function set(...args) {
|
|||
|
||||
setDeepProperty(USERCONFIG, value, target)
|
||||
|
||||
if (target.length === 1 && target[0] === "storageloc" && previousValue !== value) {
|
||||
if (
|
||||
target.length === 1 &&
|
||||
target[0] === "storageloc" &&
|
||||
previousValue !== value
|
||||
) {
|
||||
// ensure storageloc is saved locally before switching
|
||||
await save(previousValue)
|
||||
}
|
||||
|
@ -1381,7 +1399,7 @@ export async function update() {
|
|||
set("configversion", "1.2")
|
||||
}
|
||||
case "1.2": {
|
||||
; ["ignoremaps", "inputmaps", "imaps", "nmaps"]
|
||||
["ignoremaps", "inputmaps", "imaps", "nmaps"]
|
||||
.map(mapname => [
|
||||
mapname,
|
||||
getDeepProperty(USERCONFIG, [mapname]),
|
||||
|
@ -1413,7 +1431,7 @@ export async function update() {
|
|||
set("configversion", "1.3")
|
||||
}
|
||||
case "1.3": {
|
||||
; [
|
||||
[
|
||||
"priority",
|
||||
"hintdelay",
|
||||
"scrollduration",
|
||||
|
@ -1426,7 +1444,7 @@ export async function update() {
|
|||
set("configversion", "1.4")
|
||||
}
|
||||
case "1.4": {
|
||||
; (getDeepProperty(USERCONFIG, ["noiframeon"]) || []).forEach(
|
||||
(getDeepProperty(USERCONFIG, ["noiframeon"]) || []).forEach(
|
||||
site => {
|
||||
setURL(site, "noiframe", "true")
|
||||
},
|
||||
|
@ -1444,7 +1462,7 @@ export async function update() {
|
|||
mapObj["<Space>"] = mapObj[" "]
|
||||
delete mapObj[" "]
|
||||
}
|
||||
; [
|
||||
[
|
||||
"<A- >",
|
||||
"<C- >",
|
||||
"<M- >",
|
||||
|
@ -1464,9 +1482,13 @@ export async function update() {
|
|||
})
|
||||
return mapObj
|
||||
}
|
||||
; ["nmaps", "exmaps", "imaps", "inputmaps", "ignoremaps"].forEach(
|
||||
settingName => updateAll([settingName], updateSetting),
|
||||
)
|
||||
;[
|
||||
"nmaps",
|
||||
"exmaps",
|
||||
"imaps",
|
||||
"inputmaps",
|
||||
"ignoremaps",
|
||||
].forEach(settingName => updateAll([settingName], updateSetting))
|
||||
set("configversion", "1.7")
|
||||
}
|
||||
case "1.7": {
|
||||
|
@ -1487,9 +1509,15 @@ export async function update() {
|
|||
return val
|
||||
}, mapObj)
|
||||
}
|
||||
; ["nmaps", "exmaps", "imaps", "inputmaps", "ignoremaps", "hintmaps", "vmaps"].forEach(
|
||||
settingName => updateAll([settingName], updateSetting),
|
||||
)
|
||||
;[
|
||||
"nmaps",
|
||||
"exmaps",
|
||||
"imaps",
|
||||
"inputmaps",
|
||||
"ignoremaps",
|
||||
"hintmaps",
|
||||
"vmaps",
|
||||
].forEach(settingName => updateAll([settingName], updateSetting))
|
||||
set("configversion", "1.9")
|
||||
updated = true // NB: when adding a new updater, move this line to the end of it
|
||||
}
|
||||
|
@ -1516,8 +1544,7 @@ async function init() {
|
|||
}
|
||||
|
||||
const configUpdated = await update()
|
||||
if (configUpdated)
|
||||
await save()
|
||||
if (configUpdated) await save()
|
||||
|
||||
INITIALISED = true
|
||||
for (const waiter of WAITERS) {
|
||||
|
@ -1606,9 +1633,7 @@ export function parseConfig(): string {
|
|||
|
||||
const ftdetect = `" For syntax highlighting see https://github.com/tridactyl/vim-tridactyl\n" vim: set filetype=tridactyl`
|
||||
|
||||
return `${s.general}${s.binds}${s.subconfigs}${s.aliases}${s.aucmds}${
|
||||
s.aucons
|
||||
}${s.logging}${s.nulls}${ftdetect}`
|
||||
return `${s.general}${s.binds}${s.subconfigs}${s.aliases}${s.aucmds}${s.aucons}${s.logging}${s.nulls}${ftdetect}`
|
||||
}
|
||||
|
||||
const parseConfigHelper = (pconf, parseobj, prefix = []) => {
|
||||
|
@ -1617,10 +1642,13 @@ const parseConfigHelper = (pconf, parseobj, prefix= []) => {
|
|||
if (prefix[0] === "subconfigs") {
|
||||
prefix.shift()
|
||||
const pattern = prefix.shift()
|
||||
parseobj.subconfigs.push(`seturl ${pattern} ${[...prefix, i].join(".")} ${pconf[i]}`)
|
||||
parseobj.subconfigs.push(
|
||||
`seturl ${pattern} ${[...prefix, i].join(".")} ${pconf[i]}`,
|
||||
)
|
||||
} else {
|
||||
parseobj.conf.push(
|
||||
`set ${[...prefix, i].join(".")} ${pconf[i]}`)
|
||||
`set ${[...prefix, i].join(".")} ${pconf[i]}`,
|
||||
)
|
||||
}
|
||||
} else if (pconf[i] === null) {
|
||||
parseobj.nulls.push(`setnull ${[...prefix, i].join(".")}`)
|
||||
|
@ -1710,24 +1738,19 @@ browser.storage.onChanged.addListener((changes, areaname) => {
|
|||
const unsetKeys = Object.keys(old).filter(
|
||||
k =>
|
||||
newValue[k] === undefined &&
|
||||
JSON.stringify(old[k]) !==
|
||||
JSON.stringify(DEFAULTS[k]),
|
||||
JSON.stringify(old[k]) !== JSON.stringify(DEFAULTS[k]),
|
||||
)
|
||||
|
||||
// A key has changed if it is defined in USERCONFIG and its value in USERCONFIG is different from the one in `changes` or if the value in defaultConf is different from the one in `changes`
|
||||
const changedKeys = Object.keys(
|
||||
newValue,
|
||||
).filter(
|
||||
const changedKeys = Object.keys(newValue).filter(
|
||||
k =>
|
||||
JSON.stringify(
|
||||
old[k] !== undefined
|
||||
? old[k]
|
||||
: DEFAULTS[k],
|
||||
old[k] !== undefined ? old[k] : DEFAULTS[k],
|
||||
) !== JSON.stringify(newValue[k]),
|
||||
)
|
||||
|
||||
// TODO: this should be a deep comparison but this is better than nothing
|
||||
changedKeys.forEach(key => USERCONFIG[key] = newValue[key])
|
||||
changedKeys.forEach(key => (USERCONFIG[key] = newValue[key]))
|
||||
unsetKeys.forEach(key => delete USERCONFIG[key])
|
||||
|
||||
// Trigger listeners
|
||||
|
|
|
@ -80,7 +80,7 @@ export async function remove(name: string) {
|
|||
@param color the new color of the container
|
||||
@param icon the new icon of the container
|
||||
*/
|
||||
export async function update(
|
||||
export function update(
|
||||
containerId: string,
|
||||
updateObj: {
|
||||
name: string
|
||||
|
@ -122,9 +122,9 @@ export async function exists(cname: string): Promise<boolean> {
|
|||
let exists = false
|
||||
try {
|
||||
const containers = await getAll()
|
||||
const res = containers.filter(c => {
|
||||
return c.name.toLowerCase() === cname.toLowerCase()
|
||||
})
|
||||
const res = containers.filter(
|
||||
c => c.name.toLowerCase() === cname.toLowerCase(),
|
||||
)
|
||||
if (res.length > 0) {
|
||||
exists = true
|
||||
}
|
||||
|
|
|
@ -120,12 +120,7 @@ export function mouseEvent(
|
|||
}
|
||||
|
||||
export function elementsWithText() {
|
||||
return getElemsBySelector("*", [
|
||||
isVisible,
|
||||
hint => {
|
||||
return hint.textContent !== ""
|
||||
},
|
||||
])
|
||||
return getElemsBySelector("*", [isVisible, hint => hint.textContent !== ""])
|
||||
}
|
||||
|
||||
/** Iterable of elements that match xpath.
|
||||
|
@ -306,7 +301,7 @@ export function getAllDocumentFrames(doc = document) {
|
|||
export function getSelector(e: HTMLElement) {
|
||||
function uniqueSelector(e: HTMLElement) {
|
||||
// Only matching alphanumeric selectors because others chars might have special meaning in CSS
|
||||
if (e.id && e.id.match("^[a-zA-Z0-9]+$")) return "#" + e.id
|
||||
if (e.id && /^[a-zA-Z0-9]+$/.exec(e.id)) return "#" + e.id
|
||||
// If we reached the top of the document
|
||||
if (!e.parentElement) return "HTML"
|
||||
// Compute the position of the element
|
||||
|
@ -539,7 +534,10 @@ function onPageFocus(elem: HTMLElement, args: any[]): boolean {
|
|||
async function setInput(el) {
|
||||
const tab = await activeTabId()
|
||||
// store maximum of 10 elements to stop this getting bonkers huge
|
||||
const arr = (await State.getAsync("prevInputs")).concat({ tab, inputId: el.id })
|
||||
const arr = (await State.getAsync("prevInputs")).concat({
|
||||
tab,
|
||||
inputId: el.id,
|
||||
})
|
||||
state.prevInputs = arr.slice(Math.max(arr.length - 10, 0))
|
||||
}
|
||||
|
||||
|
|
|
@ -164,36 +164,30 @@ export const transpose_words = wrap_input(
|
|||
* Behaves like readline's [upcase_word](http://web.mit.edu/gnu/doc/html/rlman_1.html#SEC14). Makes the word the caret is in uppercase.
|
||||
**/
|
||||
export const upcase_word = wrap_input(
|
||||
needs_text((text, selectionStart, selectionEnd) => {
|
||||
return applyWord(text, selectionStart, selectionEnd, word =>
|
||||
needs_text((text, selectionStart, selectionEnd) => applyWord(text, selectionStart, selectionEnd, word =>
|
||||
word.toUpperCase(),
|
||||
)
|
||||
}),
|
||||
)),
|
||||
)
|
||||
|
||||
/**
|
||||
* Behaves like readline's [downcase_word](http://web.mit.edu/gnu/doc/html/rlman_1.html#SEC14). Makes the word the caret is in lowercase.
|
||||
**/
|
||||
export const downcase_word = wrap_input(
|
||||
needs_text((text, selectionStart, selectionEnd) => {
|
||||
return applyWord(text, selectionStart, selectionEnd, word =>
|
||||
needs_text((text, selectionStart, selectionEnd) => applyWord(text, selectionStart, selectionEnd, word =>
|
||||
word.toLowerCase(),
|
||||
)
|
||||
}),
|
||||
)),
|
||||
)
|
||||
|
||||
/**
|
||||
* Behaves like readline's [capitalize_word](http://web.mit.edu/gnu/doc/html/rlman_1.html#SEC14). Makes the initial character of the word the caret is in uppercase.
|
||||
**/
|
||||
export const capitalize_word = wrap_input(
|
||||
needs_text((text, selectionStart, selectionEnd) => {
|
||||
return applyWord(
|
||||
needs_text((text, selectionStart, selectionEnd) => applyWord(
|
||||
text,
|
||||
selectionStart,
|
||||
selectionEnd,
|
||||
word => word[0].toUpperCase() + word.substring(1),
|
||||
)
|
||||
}),
|
||||
)),
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -339,17 +333,13 @@ export const end_of_line = wrap_input(
|
|||
/**
|
||||
* Behaves like readline's [forward_char](http://web.mit.edu/gnu/doc/html/rlman_1.html#SEC12). Moves the caret one character to the right.
|
||||
**/
|
||||
export const forward_char = wrap_input((text, selectionStart, selectionEnd) => {
|
||||
return [null, selectionStart + 1, null]
|
||||
})
|
||||
export const forward_char = wrap_input((text, selectionStart, selectionEnd) => [null, selectionStart + 1, null])
|
||||
|
||||
/**
|
||||
* Behaves like readline's [backward_char](http://web.mit.edu/gnu/doc/html/rlman_1.html#SEC12). Moves the caret one character to the left.
|
||||
**/
|
||||
export const backward_char = wrap_input(
|
||||
(text, selectionStart, selectionEnd) => {
|
||||
return [null, selectionStart - 1, null]
|
||||
},
|
||||
(text, selectionStart, selectionEnd) => [null, selectionStart - 1, null],
|
||||
)
|
||||
|
||||
/**
|
||||
|
@ -383,21 +373,17 @@ export const backward_word = wrap_input(
|
|||
* Insert text in the current input.
|
||||
**/
|
||||
export const insert_text = wrap_input(
|
||||
(text, selectionStart, selectionEnd, arg) => {
|
||||
return [
|
||||
(text, selectionStart, selectionEnd, arg) => [
|
||||
text.slice(0, selectionStart) + arg + text.slice(selectionEnd),
|
||||
selectionStart + arg.length,
|
||||
null,
|
||||
]
|
||||
},
|
||||
],
|
||||
)
|
||||
|
||||
export const rot13 = wrap_input(
|
||||
(text, selectionStart, selectionEnd) => {
|
||||
return [
|
||||
(text, selectionStart, selectionEnd) => [
|
||||
rot13_helper(text.slice(0, selectionStart) + text.slice(selectionEnd)),
|
||||
selectionStart,
|
||||
null,
|
||||
]
|
||||
},
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
// We have a single dependency on config: getting the value of the WORDPATTERN setting
|
||||
// Perhaps we could find a way to get rid of it?
|
||||
import * as config from "@src/lib/config"
|
||||
|
@ -165,7 +164,11 @@ export function needs_text(fn: editor_function, arg?: any): editor_function {
|
|||
/**
|
||||
* Returns line and column number.
|
||||
*/
|
||||
export function getLineAndColNumber(text: string, start: number, end: number): [string, number, number] {
|
||||
export function getLineAndColNumber(
|
||||
text: string,
|
||||
start: number,
|
||||
end: number,
|
||||
): [string, number, number] {
|
||||
const lines = text.split("\n")
|
||||
let totalChars = 0
|
||||
for (let i = 0; i < lines.length; ++i) {
|
||||
|
@ -188,21 +191,18 @@ export function getWordBoundaries(
|
|||
): [number, number] {
|
||||
if (position < 0 || position > text.length)
|
||||
throw new Error(
|
||||
`getWordBoundaries: position (${position}) should be within text ("${text}") boundaries (0, ${
|
||||
text.length
|
||||
})`,
|
||||
`getWordBoundaries: position (${position}) should be within text ("${text}") boundaries (0, ${text.length})`,
|
||||
)
|
||||
const pattern = new RegExp(config.get("wordpattern"), "g")
|
||||
let boundary1 = position < text.length ? position : text.length - 1
|
||||
const direction = before ? -1 : 1
|
||||
// if the caret is not in a word, try to find the word before or after it
|
||||
// For `before`, we should check the char before the caret
|
||||
if (before && boundary1 > 0)
|
||||
boundary1 -= 1
|
||||
if (before && boundary1 > 0) boundary1 -= 1
|
||||
while (
|
||||
boundary1 >= 0 &&
|
||||
boundary1 < text.length &&
|
||||
!text[boundary1].match(pattern)
|
||||
!pattern.exec(text[boundary1])
|
||||
) {
|
||||
boundary1 += direction
|
||||
}
|
||||
|
@ -214,7 +214,7 @@ export function getWordBoundaries(
|
|||
while (
|
||||
boundary1 >= 0 &&
|
||||
boundary1 < text.length &&
|
||||
!text[boundary1].match(pattern)
|
||||
!pattern.exec(text[boundary1])
|
||||
) {
|
||||
boundary1 -= direction
|
||||
}
|
||||
|
@ -222,12 +222,10 @@ export function getWordBoundaries(
|
|||
if (boundary1 < 0) boundary1 = 0
|
||||
else if (boundary1 >= text.length) boundary1 = text.length - 1
|
||||
|
||||
if (!text[boundary1].match(pattern)) {
|
||||
if (!pattern.exec(text[boundary1])) {
|
||||
// there is no word in text
|
||||
throw new Error(
|
||||
`getWordBoundaries: no characters matching wordpattern (${
|
||||
pattern.source
|
||||
}) in text (${text})`,
|
||||
`getWordBoundaries: no characters matching wordpattern (${pattern.source}) in text (${text})`,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -235,7 +233,7 @@ export function getWordBoundaries(
|
|||
while (
|
||||
boundary1 >= 0 &&
|
||||
boundary1 < text.length &&
|
||||
!!text[boundary1].match(pattern)
|
||||
!!pattern.exec(text[boundary1])
|
||||
) {
|
||||
boundary1 += direction
|
||||
}
|
||||
|
@ -247,7 +245,7 @@ export function getWordBoundaries(
|
|||
while (
|
||||
boundary2 >= 0 &&
|
||||
boundary2 < text.length &&
|
||||
!!text[boundary2].match(pattern)
|
||||
!!pattern.exec(text[boundary2])
|
||||
) {
|
||||
boundary2 -= direction
|
||||
}
|
||||
|
@ -268,10 +266,10 @@ export function wordAfterPos(text: string, position: number) {
|
|||
throw new Error(`wordAfterPos: position (${position}) is less that 0`)
|
||||
const pattern = new RegExp(config.get("wordpattern"), "g")
|
||||
// move position out of the current word
|
||||
while (position < text.length && !!text[position].match(pattern))
|
||||
while (position < text.length && !!pattern.exec(text[position]))
|
||||
position += 1
|
||||
// try to find characters that match wordpattern
|
||||
while (position < text.length && !text[position].match(pattern))
|
||||
while (position < text.length && !pattern.exec(text[position]))
|
||||
position += 1
|
||||
if (position >= text.length) return -1
|
||||
return position
|
||||
|
@ -289,8 +287,8 @@ export const rot13_helper = (s: string, n: number = 13): string => {
|
|||
export const charesar = (c: string, n: number = 13): string => {
|
||||
const cn = c.charCodeAt(0)
|
||||
if (cn >= 65 && cn <= 90)
|
||||
return String.fromCharCode((((cn - 65) + n) % 26) + 65)
|
||||
return String.fromCharCode(((cn - 65 + n) % 26) + 65)
|
||||
if (cn >= 97 && cn <= 122)
|
||||
return String.fromCharCode((((cn - 97) + n) % 26) + 97)
|
||||
return String.fromCharCode(((cn - 97 + n) % 26) + 97)
|
||||
return c
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
;(function(window) {
|
||||
(function(window) {
|
||||
"use strict"
|
||||
|
||||
// test for es6 support of needed functionality
|
||||
try {
|
||||
// spread operator and template strings support
|
||||
;(function testSpreadOpAndTemplate() {
|
||||
(function testSpreadOpAndTemplate() {
|
||||
const tag = function tag(strings, ...values) {
|
||||
return
|
||||
}
|
||||
|
@ -311,14 +311,13 @@
|
|||
// use insertBefore() instead of replaceChild() so that the node Iterator
|
||||
// doesn't think the new tag should be the next node
|
||||
node.parentNode.insertBefore(tag, node)
|
||||
}
|
||||
|
||||
// special case for script tags:
|
||||
// using innerHTML with a string that contains a script tag causes the script
|
||||
// tag to not be executed when added to the DOM. We'll need to create a script
|
||||
// tag and append its contents which will make it execute correctly.
|
||||
// @see http://stackoverflow.com/questions/1197575/can-scripts-be-inserted-with-innerhtml
|
||||
else if (node.nodeName === "SCRIPT") {
|
||||
} else if (node.nodeName === "SCRIPT") {
|
||||
const script = document.createElement("script")
|
||||
tag = script
|
||||
|
||||
|
@ -420,12 +419,11 @@
|
|||
) {
|
||||
substitutionValue =
|
||||
'"' + substitutionValue + '"'
|
||||
}
|
||||
|
||||
// contextual auto-escaping:
|
||||
// if the attribute is a uri attribute then we need to uri encode it and
|
||||
// remove bad protocols
|
||||
else if (
|
||||
} else if (
|
||||
URI_ATTRIBUTES.indexOf(name) !== -1 ||
|
||||
CUSTOM_URI_ATTRIBUTES_REGEX.test(name)
|
||||
) {
|
||||
|
@ -438,10 +436,9 @@
|
|||
substitutionValue = encodeURIComponent(
|
||||
substitutionValue,
|
||||
)
|
||||
}
|
||||
|
||||
// entity encode if value is part of the URL
|
||||
else {
|
||||
} else {
|
||||
substitutionValue = encodeURI(
|
||||
encodeURIEntities(
|
||||
substitutionValue,
|
||||
|
@ -479,12 +476,11 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// contextual auto-escaping:
|
||||
// HTML encode attribute value if it is not a URL or URI to prevent
|
||||
// DOM Level 0 event handlers from executing xss code
|
||||
else if (
|
||||
} else if (
|
||||
typeof substitutionValue === "string"
|
||||
) {
|
||||
substitutionValue = encodeAttributeHTMLEntities(
|
||||
|
@ -541,7 +537,7 @@
|
|||
(node._replacedWith && node.childNodes.length === 0) ||
|
||||
(parentNode && parentNode.childNodes.length === 0)
|
||||
) {
|
||||
;(parentNode || node).remove()
|
||||
(parentNode || node).remove()
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
|
|
@ -102,7 +102,8 @@ export async function getBestEditor(): Promise<string> {
|
|||
const vim_positioning_arg = ` ${arg_quote}+normal!%lGzv%c|${arg_quote}`
|
||||
if (os === "mac") {
|
||||
gui_candidates = [
|
||||
"/Applications/MacVim.app/Contents/bin/mvim -f" + vim_positioning_arg,
|
||||
"/Applications/MacVim.app/Contents/bin/mvim -f" +
|
||||
vim_positioning_arg,
|
||||
"/usr/local/bin/vimr --wait --nvim +only",
|
||||
]
|
||||
// if anyone knows of any "sensible" terminals that let you send them commands to run,
|
||||
|
@ -149,7 +150,12 @@ export async function getBestEditor(): Promise<string> {
|
|||
]
|
||||
}
|
||||
|
||||
tui_editors = ["vim" + vim_positioning_arg, "nvim" + vim_positioning_arg, "nano %f", "emacs -nw %f"]
|
||||
tui_editors = [
|
||||
"vim" + vim_positioning_arg,
|
||||
"nvim" + vim_positioning_arg,
|
||||
"nano %f",
|
||||
"emacs -nw %f",
|
||||
]
|
||||
|
||||
// Consider GUI editors
|
||||
let cmd = await firstinpath(gui_candidates)
|
||||
|
@ -246,12 +252,17 @@ export async function firstinpath(cmdarray) {
|
|||
return cmd
|
||||
}
|
||||
|
||||
export async function editor(file: string, line: number, col: number, content?: string) {
|
||||
export async function editor(
|
||||
file: string,
|
||||
line: number,
|
||||
col: number,
|
||||
content?: string,
|
||||
) {
|
||||
if (content !== undefined) await write(file, content)
|
||||
const editorcmd =
|
||||
(config.get("editorcmd") === "auto"
|
||||
const editorcmd = (config.get("editorcmd") === "auto"
|
||||
? await getBestEditor()
|
||||
: config.get("editorcmd"))
|
||||
: config.get("editorcmd")
|
||||
)
|
||||
.replace(/%l/, line)
|
||||
.replace(/%c/, col)
|
||||
let exec
|
||||
|
@ -260,8 +271,7 @@ export async function editor(file: string, line: number, col: number, content?:
|
|||
} else {
|
||||
exec = await run(editorcmd + " " + file)
|
||||
}
|
||||
if (exec.code != 0)
|
||||
return exec
|
||||
if (exec.code != 0) return exec
|
||||
return read(file)
|
||||
}
|
||||
|
||||
|
@ -371,9 +381,7 @@ export async function clipboard(
|
|||
const result = await run(`${clipcmd} -i`, str)
|
||||
if (result.code !== 0)
|
||||
throw new Error(
|
||||
`External command failed with code ${
|
||||
result.code
|
||||
}: ${clipcmd}`,
|
||||
`External command failed with code ${result.code}: ${clipcmd}`,
|
||||
)
|
||||
return ""
|
||||
} else {
|
||||
|
@ -418,12 +426,12 @@ export async function parseProfilesIni(content: string, basePath: string) {
|
|||
let current = "General"
|
||||
const result = {}
|
||||
for (const line of lines) {
|
||||
let match = line.match(/^\[([^\]]+)\]$/)
|
||||
let match = /^\[([^\]]+)\]$/.exec(line)
|
||||
if (match !== null) {
|
||||
current = match[1]
|
||||
result[current] = {}
|
||||
} else {
|
||||
match = line.match(/^([^=]+)=([^=]+)$/)
|
||||
match = /^([^=]+)=([^=]+)$/.exec(line)
|
||||
if (match !== null) {
|
||||
result[current][match[1]] = match[2]
|
||||
}
|
||||
|
@ -448,9 +456,7 @@ export async function parseProfilesIni(content: string, basePath: string) {
|
|||
} else if (profile.IsRelative === "0") {
|
||||
if (profile.Path.substring(0, basePath.length) !== basePath) {
|
||||
throw new Error(
|
||||
`Error parsing profiles ini: basePath "${basePath}" doesn't match profile path ${
|
||||
profile.Path
|
||||
}`,
|
||||
`Error parsing profiles ini: basePath "${basePath}" doesn't match profile path ${profile.Path}`,
|
||||
)
|
||||
}
|
||||
profile.relativePath = profile.Path.substring(basePath.length)
|
||||
|
@ -509,8 +515,7 @@ export async function getProfileUncached() {
|
|||
// Then, try to find a profile path in the arguments given to Firefox
|
||||
const cmdline = await ff_cmdline().catch(e => "")
|
||||
let profile = cmdline.indexOf("--profile")
|
||||
if (profile === -1)
|
||||
profile = cmdline.indexOf("-profile")
|
||||
if (profile === -1) profile = cmdline.indexOf("-profile")
|
||||
if (profile >= 0 && profile < cmdline.length - 1) {
|
||||
const profilePath = cmdline[profile + 1]
|
||||
if (iniSucceeded) {
|
||||
|
@ -545,9 +550,7 @@ export async function getProfileUncached() {
|
|||
}
|
||||
}
|
||||
throw new Error(
|
||||
`native.ts:getProfile() : '${
|
||||
cmdline[p]
|
||||
}' found in command line arguments but no matching profile name found in "${iniPath}"`,
|
||||
`native.ts:getProfile() : '${cmdline[p]}' found in command line arguments but no matching profile name found in "${iniPath}"`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -562,10 +565,7 @@ export async function getProfileUncached() {
|
|||
profilecmd.content = profilecmd.content.trim()
|
||||
// If there's only one profile in use, use that to find the right profile
|
||||
if (profilecmd.content.split("\n").length === 1) {
|
||||
const path = profilecmd.content
|
||||
.split("/")
|
||||
.slice(0, -1)
|
||||
.join("/")
|
||||
const path = profilecmd.content.split("/").slice(0, -1).join("/")
|
||||
if (iniSucceeded) {
|
||||
for (const profileName of Object.keys(iniObject)) {
|
||||
const profile = iniObject[profileName]
|
||||
|
@ -602,8 +602,7 @@ export async function getProfileUncached() {
|
|||
// Disk operations are extremely slow on windows, let's cache our profile info
|
||||
let cachedProfile
|
||||
export async function getProfile() {
|
||||
if (cachedProfile === undefined)
|
||||
cachedProfile = await getProfileUncached()
|
||||
if (cachedProfile === undefined) cachedProfile = await getProfileUncached()
|
||||
return cachedProfile
|
||||
}
|
||||
// It makes sense to pre-fetch this value in the background script because it's
|
||||
|
@ -627,7 +626,7 @@ export async function getProfileDir() {
|
|||
return getProfile().then(p => p.absolutePath)
|
||||
}
|
||||
|
||||
export async function parsePrefs(prefFileContent: string) {
|
||||
export function parsePrefs(prefFileContent: string) {
|
||||
// This RegExp currently only deals with " but for correctness it should
|
||||
// also deal with ' and `
|
||||
// We could also just give up on parsing and eval() the whole thing
|
||||
|
@ -636,7 +635,7 @@ export async function parsePrefs(prefFileContent: string) {
|
|||
)
|
||||
// Fragile parsing
|
||||
return prefFileContent.split("\n").reduce((prefs, line) => {
|
||||
const matches = line.match(regex)
|
||||
const matches = regex.exec(line)
|
||||
if (!matches) {
|
||||
return prefs
|
||||
}
|
||||
|
@ -790,17 +789,23 @@ export async function unfixamo() {
|
|||
const tridactylPref2 = "tridactyl.unfixedamo_removed"
|
||||
const restricted = "extensions.webextensions.restrictedDomains"
|
||||
const amoblocker = "privacy.resistFingerprinting.block_mozAddonManager"
|
||||
const restrictedDomains = '"accounts-static.cdn.mozilla.net,accounts.firefox.com,addons.cdn.mozilla.net,addons.mozilla.org,api.accounts.firefox.com,content.cdn.mozilla.net,discovery.addons.mozilla.org,install.mozilla.org,oauth.accounts.firefox.com,profile.accounts.firefox.com,support.mozilla.org,sync.services.mozilla.com"'
|
||||
const restrictedDomains =
|
||||
'"accounts-static.cdn.mozilla.net,accounts.firefox.com,addons.cdn.mozilla.net,addons.mozilla.org,api.accounts.firefox.com,content.cdn.mozilla.net,discovery.addons.mozilla.org,install.mozilla.org,oauth.accounts.firefox.com,profile.accounts.firefox.com,support.mozilla.org,sync.services.mozilla.com"'
|
||||
|
||||
// Exit if we've already run this once
|
||||
if (userjs[tridactylPref2] === "true") return
|
||||
|
||||
if (userjs[restricted] === "" || userjs[restricted] === restrictedDomains) {
|
||||
if (
|
||||
userjs[restricted] === "" ||
|
||||
userjs[restricted] === restrictedDomains
|
||||
) {
|
||||
await removePref(tridactylPref) // Clean up after first attempt if it exists
|
||||
await removePref(restricted)
|
||||
await removePref(amoblocker)
|
||||
await writePref(tridactylPref2, "true")
|
||||
browserBg.tabs.create({url: browserBg.runtime.getURL("static/unfixamo.html")})
|
||||
browserBg.tabs.create({
|
||||
url: browserBg.runtime.getURL("static/unfixamo.html"),
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
|
|
|
@ -254,9 +254,7 @@ export function deleteQuery(url: URL, matchQuery: string): URL {
|
|||
|
||||
const qys = getUrlQueries(url)
|
||||
|
||||
const new_qys = qys.filter(q => {
|
||||
return q.split("=")[0] !== matchQuery
|
||||
})
|
||||
const new_qys = qys.filter(q => q.split("=")[0] !== matchQuery)
|
||||
|
||||
setUrlQueries(newUrl, new_qys)
|
||||
|
||||
|
|
|
@ -39,10 +39,12 @@ export const browserBg = inContentScript() ? browserProxy : browser
|
|||
*
|
||||
*/
|
||||
export async function activeTab() {
|
||||
return (await browserBg.tabs.query({
|
||||
return (
|
||||
await browserBg.tabs.query({
|
||||
active: true,
|
||||
currentWindow: true,
|
||||
}))[0]
|
||||
})
|
||||
)[0]
|
||||
}
|
||||
|
||||
export async function activeTabId() {
|
||||
|
@ -122,9 +124,11 @@ export async function openInNewTab(
|
|||
break
|
||||
case "last":
|
||||
// Infinity can't be serialised, apparently.
|
||||
options.index = (await browserBg.tabs.query({
|
||||
options.index = (
|
||||
await browserBg.tabs.query({
|
||||
currentWindow: true,
|
||||
})).length
|
||||
})
|
||||
).length
|
||||
break
|
||||
case "related":
|
||||
if (await firefoxVersionAtLeast(57)) {
|
||||
|
@ -135,16 +139,20 @@ export async function openInNewTab(
|
|||
break
|
||||
}
|
||||
|
||||
if (kwargs.active === false) { // load in background
|
||||
if (kwargs.active === false) {
|
||||
// load in background
|
||||
return browserBg.tabs.create(options)
|
||||
} else { // load in background and then activate, per issue #1993
|
||||
return browserBg.tabs.create(options).then(newtab => browserBg.tabs.update(newtab.id, { active: true }))
|
||||
} else {
|
||||
// load in background and then activate, per issue #1993
|
||||
return browserBg.tabs
|
||||
.create(options)
|
||||
.then(newtab => browserBg.tabs.update(newtab.id, { active: true }))
|
||||
}
|
||||
}
|
||||
|
||||
// lazily copied from excmds.ts' winopen - forceURI really ought to be moved to lib/webext
|
||||
// Should consider changing interface of this to match openInNewTab or vice versa
|
||||
export async function openInNewWindow(createData = {}) {
|
||||
export function openInNewWindow(createData = {}) {
|
||||
browserBg.windows.create(createData)
|
||||
}
|
||||
|
||||
|
@ -254,5 +262,5 @@ export async function openInTab(tab, opts = {}, strarr: string[]) {
|
|||
|
||||
// No search engine has been defined in Tridactyl, let's use firefox's default search engine
|
||||
browserBg.search.search({ tabId: tab.id, query: queryString })
|
||||
return tab;
|
||||
return tab
|
||||
}
|
||||
|
|
|
@ -278,7 +278,6 @@ export class StatsLogger {
|
|||
private incrementIdx() {
|
||||
this.idx = (this.idx + 1) % this.buffersize
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -388,7 +387,7 @@ const extractRegExp = new RegExp(
|
|||
// sample itself.
|
||||
)
|
||||
function extractMetricName(counterName: string): MetricNameInfo {
|
||||
const matchresult = counterName.match(extractRegExp)
|
||||
const matchresult = extractRegExp.exec(counterName)
|
||||
if (!matchresult) return
|
||||
const [ownerName, functionName, uniqueSuffix] = matchresult.slice(1)
|
||||
|
||||
|
@ -416,5 +415,9 @@ class MetricName {
|
|||
}
|
||||
|
||||
function sendStats(list: PerformanceEntryList) {
|
||||
messaging.message("performance_background", "receiveStatsJson", JSON.stringify(list))
|
||||
messaging.message(
|
||||
"performance_background",
|
||||
"receiveStatsJson",
|
||||
JSON.stringify(list),
|
||||
)
|
||||
}
|
||||
|
|
7
src/tridactyl.d.ts
vendored
7
src/tridactyl.d.ts
vendored
|
@ -48,9 +48,7 @@ interface findResult {
|
|||
interface HTMLElement {
|
||||
// Let's be future proof:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus
|
||||
focus(options: any): void
|
||||
// Let's also implement the current function signature.
|
||||
focus(): void
|
||||
focus(options?: any): void
|
||||
}
|
||||
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
|
@ -67,9 +65,10 @@ declare namespace browser.find {
|
|||
function find(query, object): any
|
||||
}
|
||||
|
||||
// setZoom has an optional first argument of tabId. Unclear how first argument can be optional.
|
||||
declare namespace browser.tabs {
|
||||
function setZoom(zoomFactor: number): Promise<void>
|
||||
// setZoom has an optional first argument of tabId: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/API/tabs/setZoom#Parameters
|
||||
// eslint-disable-next-line @typescript-eslint/unified-signatures
|
||||
function setZoom(tabId: number, zoomFactor: number): Promise<void>
|
||||
function toggleReaderMode(tabId?: number): Promise<void>
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue