mirror of
https://github.com/vale981/tridactyl
synced 2025-03-04 09:01:39 -05:00
Re-enable no-extra-semi
and prettier
Prettier re-enabled as the semi-colon removal made quite a few files uglier than they were previously.
This commit is contained in:
parent
f2cd6a7988
commit
96f763e42e
8 changed files with 379 additions and 273 deletions
|
@ -198,7 +198,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",
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
@ -145,7 +153,7 @@ import * as scrolling from "@src/content/scrolling"
|
|||
import * as R from "ramda"
|
||||
import * as visual from "@src/lib/visual"
|
||||
/* tslint:disable:import-spacing */
|
||||
; (window as any).tri = Object.assign(Object.create(null), {
|
||||
;(window as any).tri = Object.assign(Object.create(null), {
|
||||
browserBg: webext.browserBg,
|
||||
commandline_content,
|
||||
convert,
|
||||
|
@ -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 => {
|
||||
if (protkey.indexOf(e.key) !== -1 && contentState.mode === "normal") {
|
||||
e.cancelBubble = true
|
||||
e.stopImmediatePropagation()
|
||||
}
|
||||
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"
|
||||
}
|
||||
|
@ -380,6 +396,6 @@ document.addEventListener("selectionchange", () => {
|
|||
// background for collection. Attach the observer to the window object
|
||||
// since there's apparently a bug that causes performance observers to
|
||||
// be GC'd even if they're still the target of a callback.
|
||||
; (window as any).tri = Object.assign(window.tri, {
|
||||
;(window as any).tri = Object.assign(window.tri, {
|
||||
perfObserver: perf.listenForCounters(),
|
||||
})
|
||||
|
|
|
@ -19,7 +19,7 @@ function getFindHost() {
|
|||
elem.style.top = "0px"
|
||||
elem.style.left = "0px"
|
||||
document.body.appendChild(elem)
|
||||
host = elem.attachShadow({mode: "closed"})
|
||||
host = elem.attachShadow({ mode: "closed" })
|
||||
return host
|
||||
}
|
||||
|
||||
|
@ -28,14 +28,17 @@ class FindHighlight extends HTMLSpanElement {
|
|||
|
||||
constructor(private rects, private node) {
|
||||
super()
|
||||
; (this as any).unfocus = () => {
|
||||
;(this as any).unfocus = () => {
|
||||
for (const node of this.children) {
|
||||
(node as HTMLElement).style.background = `rgba(127,255,255,0.5)`
|
||||
}
|
||||
}
|
||||
; (this as any).focus = () => {
|
||||
;(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,27 +120,31 @@ 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)) {
|
||||
focused = true
|
||||
; (high as any).focus()
|
||||
;(high as any).focus()
|
||||
selected = lastHighlights.length - 1
|
||||
}
|
||||
}
|
||||
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 */
|
||||
; (lastHighlights[selected] as any).focus()
|
||||
;(lastHighlights[selected] as any).focus()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -141,7 +154,7 @@ function drawHighlights(highlights) {
|
|||
}
|
||||
|
||||
export function removeHighlighting() {
|
||||
const host = getFindHost();
|
||||
const host = getFindHost()
|
||||
while (host.firstChild) host.removeChild(host.firstChild)
|
||||
}
|
||||
|
||||
|
@ -158,8 +171,8 @@ 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()
|
||||
;(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],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -320,7 +382,7 @@ export function hintPage(
|
|||
hintableElements: Element[],
|
||||
onSelect: HintSelectedCallback,
|
||||
resolve = () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
reject = () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
reject = () => {}, // eslint-disable-line @typescript-eslint/no-empty-function
|
||||
rapid = false,
|
||||
) {
|
||||
const buildHints: HintBuilder = defaultHintBuilder()
|
||||
|
@ -339,13 +401,16 @@ 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()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (! modeState.hints.length) {
|
||||
if (!modeState.hints.length) {
|
||||
// No more hints to display
|
||||
reset()
|
||||
return
|
||||
|
@ -364,22 +429,29 @@ export function hintPage(
|
|||
const firstTarget = modeState.hints[0].target
|
||||
|
||||
const firstTargetIsSelectable = (): boolean => {
|
||||
return firstTarget instanceof HTMLAnchorElement &&
|
||||
return (
|
||||
firstTarget instanceof HTMLAnchorElement &&
|
||||
firstTarget.href !== "" &&
|
||||
!firstTarget.href.startsWith("javascript:")
|
||||
)
|
||||
}
|
||||
|
||||
const allTargetsAreEqual = (): boolean => {
|
||||
return undefined === modeState.hints.find(h => {
|
||||
return (
|
||||
!(h.target instanceof HTMLAnchorElement) ||
|
||||
h.target.href !== (firstTarget as HTMLAnchorElement).href
|
||||
)
|
||||
})
|
||||
return (
|
||||
undefined ===
|
||||
modeState.hints.find(h => {
|
||||
return (
|
||||
!(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()
|
||||
|
@ -552,7 +624,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 +703,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 +827,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 +926,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 +936,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 +962,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
|
||||
|
@ -908,7 +989,7 @@ export function hintableImages() {
|
|||
* text or RegExp rule
|
||||
* @hidden
|
||||
*/
|
||||
export function hintByText(match: string|RegExp) {
|
||||
export function hintByText(match: string | RegExp) {
|
||||
return DOM.getElemsBySelector(DOM.HINTTAGS_filter_by_text_selectors, [
|
||||
DOM.isVisible,
|
||||
hint => {
|
||||
|
@ -924,7 +1005,7 @@ export function hintByText(match: string|RegExp) {
|
|||
} else {
|
||||
return text.toUpperCase().includes(match.toUpperCase())
|
||||
}
|
||||
}
|
||||
},
|
||||
])
|
||||
}
|
||||
|
||||
|
@ -1008,9 +1089,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 +1106,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 +1133,5 @@ export function getHintCommands() {
|
|||
pushSpace,
|
||||
pushKeyCodePoint,
|
||||
popKey,
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
165
src/excmds.ts
165
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)
|
||||
|
@ -967,7 +958,7 @@ export function addJump() {
|
|||
JUMPED = false
|
||||
return
|
||||
}
|
||||
const {scrollX, scrollY} = window
|
||||
const { scrollX, scrollY } = window
|
||||
// Prevent pending jump from being registered
|
||||
clearTimeout(JUMP_TIMEOUTID)
|
||||
// Schedule the registering of the current jump
|
||||
|
@ -992,7 +983,7 @@ export function addJump() {
|
|||
}
|
||||
|
||||
//#content_helper
|
||||
document.addEventListener("scroll", addJump, {passive: true})
|
||||
document.addEventListener("scroll", addJump, { passive: true })
|
||||
|
||||
// Try to restore the previous jump position every time a page is loaded
|
||||
//#content_helper
|
||||
|
@ -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 =>
|
||||
new Promise ((resolve, reject) => {
|
||||
function openNextTab(activeInfo) {
|
||||
if (activeInfo.tabId === tab.id) {
|
||||
resolve(tabqueue(...(addresses.slice(1))));
|
||||
removeTabqueueListeners(tab.id);
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
function removeTabqueueListeners(tabId) {
|
||||
if (tabId === tab.id) {
|
||||
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);
|
||||
function removeTabqueueListeners(tabId) {
|
||||
if (tabId === tab.id) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
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({
|
||||
currentWindow: true,
|
||||
index: index - 1,
|
||||
}))[0].id
|
||||
return (
|
||||
await browser.tabs.query({
|
||||
currentWindow: true,
|
||||
index: index - 1,
|
||||
})
|
||||
)[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({
|
||||
|
@ -2692,11 +2686,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.
|
||||
|
@ -2849,30 +2839,27 @@ 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) => {
|
||||
await prev_pipeline
|
||||
const cmds = cmd.split("|")
|
||||
.reduce(async (prev_pipeline, cmd) => {
|
||||
await prev_pipeline
|
||||
const cmds = cmd.split("|")
|
||||
|
||||
// Compute the first piped value.
|
||||
//
|
||||
// We could invoke controller.acceptExCmd, but
|
||||
// that would cause our pipeline section to be
|
||||
// stored as the last executed command for the
|
||||
// purposes of :repeat, which would be
|
||||
// nonsense. So we copy-paste the important
|
||||
// parts of the body of that function instead.
|
||||
const [fn, args] = excmd_parser.parser(cmds[0], ALL_EXCMDS)
|
||||
const first_value = fn.call({}, ...args)
|
||||
// Compute the first piped value.
|
||||
//
|
||||
// We could invoke controller.acceptExCmd, but
|
||||
// that would cause our pipeline section to be
|
||||
// stored as the last executed command for the
|
||||
// purposes of :repeat, which would be
|
||||
// nonsense. So we copy-paste the important
|
||||
// parts of the body of that function instead.
|
||||
const [fn, args] = excmd_parser.parser(cmds[0], ALL_EXCMDS)
|
||||
const first_value = fn.call({}, ...args)
|
||||
|
||||
// Exec the rest of the pipe in sequence.
|
||||
return cmds.slice(1).reduce(async (pipedValue, cmd) => {
|
||||
const [fn, args] = excmd_parser.parser(cmd, ALL_EXCMDS)
|
||||
return fn.call({}, ...args, await pipedValue)
|
||||
}, first_value)
|
||||
},
|
||||
null as any,
|
||||
)
|
||||
// Exec the rest of the pipe in sequence.
|
||||
return cmds.slice(1).reduce(async (pipedValue, cmd) => {
|
||||
const [fn, args] = excmd_parser.parser(cmd, ALL_EXCMDS)
|
||||
return fn.call({}, ...args, await pipedValue)
|
||||
}, first_value)
|
||||
}, null as any)
|
||||
)
|
||||
} catch (e) {
|
||||
logger.error(e)
|
||||
|
@ -3722,31 +3709,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 +4000,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 +4462,7 @@ async function js_helper(str: string[]) {
|
|||
done = true
|
||||
break
|
||||
}
|
||||
if (!done)
|
||||
str.shift()
|
||||
if (!done) str.shift()
|
||||
}
|
||||
|
||||
if (doSource) {
|
||||
|
@ -4509,8 +4473,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(" ")
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -897,7 +907,7 @@ export class default_config {
|
|||
*
|
||||
* Replaces %WINTAG with "-Tag $TRI_VERSION", similarly to [[nativeinstallcmd]].
|
||||
*/
|
||||
win_nativeinstallcmd = `powershell -NoProfile -InputFormat None -Command "Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/cmcaine/tridactyl/master/native/win_install.ps1'))"`
|
||||
win_nativeinstallcmd = `powershell -NoProfile -InputFormat None -Command "Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/cmcaine/tridactyl/master/native/win_install.ps1'))"`
|
||||
|
||||
/**
|
||||
* Used by :updatecheck and related built-in functionality to automatically check for updates and prompt users to upgrade.
|
||||
|
@ -1056,10 +1066,13 @@ export const DEFAULTS = o(new default_config())
|
|||
*/
|
||||
function getDeepProperty(obj, target: string[]) {
|
||||
if (obj !== undefined && obj !== null && target.length) {
|
||||
if (obj["🕷🕷INHERITS🕷🕷"] === undefined) {
|
||||
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,18 +1151,15 @@ 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) => {
|
||||
const curVal = getDeepProperty(
|
||||
conf.subconfigs[curKey],
|
||||
target,
|
||||
)
|
||||
if (acc instanceof Object && curVal instanceof Object)
|
||||
return mergeDeep(acc, curVal)
|
||||
return curVal
|
||||
},
|
||||
undefined as any,
|
||||
)
|
||||
.reduce((acc, curKey) => {
|
||||
const curVal = getDeepProperty(
|
||||
conf.subconfigs[curKey],
|
||||
target,
|
||||
)
|
||||
if (acc instanceof Object && curVal instanceof Object)
|
||||
return mergeDeep(acc, curVal)
|
||||
return curVal
|
||||
}, undefined as any)
|
||||
)
|
||||
}
|
||||
const user = _getURL(USERCONFIG, url, target)
|
||||
|
@ -1266,9 +1280,13 @@ export async function set(...args) {
|
|||
|
||||
setDeepProperty(USERCONFIG, value, target)
|
||||
|
||||
if (target.length === 1 && target[0] === "storageloc" && previousValue !== value) {
|
||||
// ensure storageloc is saved locally before switching
|
||||
await save(previousValue)
|
||||
if (
|
||||
target.length === 1 &&
|
||||
target[0] === "storageloc" &&
|
||||
previousValue !== value
|
||||
) {
|
||||
// ensure storageloc is saved locally before switching
|
||||
await save(previousValue)
|
||||
}
|
||||
return save()
|
||||
} else {
|
||||
|
@ -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,18 +1482,22 @@ 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": {
|
||||
const autocontain = getDeepProperty(USERCONFIG, ["autocontain"])
|
||||
unset("autocontain")
|
||||
if (autocontain !== undefined) {
|
||||
Object.entries(autocontain).forEach(([domain, container]) => {
|
||||
set("autocontain", `^https?://[^/]*${domain}/`, container)
|
||||
})
|
||||
Object.entries(autocontain).forEach(([domain, container]) => {
|
||||
set("autocontain", `^https?://[^/]*${domain}/`, container)
|
||||
})
|
||||
}
|
||||
set("configversion", "1.8")
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -1508,7 +1536,7 @@ async function init() {
|
|||
if (localConfig === undefined || localConfig.storageloc !== "local") {
|
||||
const syncConfig = await browser.storage.sync.get(CONFIGNAME)
|
||||
if (syncConfig !== undefined) {
|
||||
schlepp(syncConfig[CONFIGNAME])
|
||||
schlepp(syncConfig[CONFIGNAME])
|
||||
}
|
||||
} else {
|
||||
// These could be merged instead, but the current design does not allow for that
|
||||
|
@ -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,21 +1633,22 @@ 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= []) => {
|
||||
const parseConfigHelper = (pconf, parseobj, prefix = []) => {
|
||||
for (const i of Object.keys(pconf)) {
|
||||
if (typeof pconf[i] !== "object") {
|
||||
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(".")}`)
|
||||
|
@ -1647,7 +1675,7 @@ const parseConfigHelper = (pconf, parseobj, prefix= []) => {
|
|||
parseobj.binds.push(`un${cmd} ${e}`)
|
||||
}
|
||||
} else if (pconf[i][e] === null) {
|
||||
parseobj.nulls.push(`setnull ${i}.${e}`)
|
||||
parseobj.nulls.push(`setnull ${i}.${e}`)
|
||||
} else if (i === "exaliases") {
|
||||
// Only really useful if mapping the entire config and not just pconf.
|
||||
if (e === "alias") {
|
||||
|
@ -1701,33 +1729,28 @@ browser.storage.onChanged.addListener((changes, areaname) => {
|
|||
// storageloc=local means ignoring changes that aren't set by us
|
||||
} else if (newValue !== undefined) {
|
||||
if (areaname === "sync") {
|
||||
// prevent storageloc from being set remotely
|
||||
delete old.storageloc
|
||||
delete newValue.storageloc
|
||||
// prevent storageloc from being set remotely
|
||||
delete old.storageloc
|
||||
delete newValue.storageloc
|
||||
}
|
||||
|
||||
// A key has been :unset if it exists in USERCONFIG and doesn't in changes and if its value in USERCONFIG is different from the one it has in default_config
|
||||
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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
@ -541,7 +541,7 @@
|
|||
(node._replacedWith && node.childNodes.length === 0) ||
|
||||
(parentNode && parentNode.childNodes.length === 0)
|
||||
) {
|
||||
;(parentNode || node).remove()
|
||||
(parentNode || node).remove()
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
|
|
Loading…
Add table
Reference in a new issue