mirror of
https://github.com/vale981/tridactyl
synced 2025-03-06 01:51:40 -05:00
Merge branch 'master' into ivcz/master
This commit is contained in:
commit
905db67c99
38 changed files with 1445 additions and 777 deletions
|
@ -41,7 +41,7 @@
|
|||
" "
|
||||
"
|
||||
" " Comment toggler for Reddit, Hacker News and Lobste.rs
|
||||
" bind ;c hint -Jc [class*="expand"],[class="togg"],[class="comment_folder"]
|
||||
" bind ;c hint -Jc [class*="expand"],[class*="togg"],[class="comment_folder"]
|
||||
"
|
||||
" " GitHub pull request checkout command to clipboard (only works if you're a collaborator or above)
|
||||
" bind yp composite js document.getElementById("clone-help-step-1").textContent.replace("git checkout -b", "git checkout -B").replace("git pull ", "git fetch ") + "git reset --hard " + document.getElementById("clone-help-step-1").textContent.split(" ")[3].replace("-","/") | yank
|
||||
|
@ -71,9 +71,8 @@
|
|||
" bindurl www.google.com F hint -Jbc #search div:not(.action-menu) > a
|
||||
"
|
||||
"
|
||||
" " DDG binds are broken as of May 2021
|
||||
" " bindurl ^https://duckduckgo.com f hint -Jc [class=result__a]
|
||||
" " bindurl ^https://duckduckgo.com F hint -Jbc [class=result__a]
|
||||
" bindurl ^https://duckduckgo.com f hint -Jc [class~=result__a]
|
||||
" bindurl ^https://duckduckgo.com F hint -Jbc [class~=result__a]
|
||||
"
|
||||
" " Allow Ctrl-a to select all in the commandline
|
||||
" unbind --mode=ex <C-a>
|
||||
|
|
124
CHANGELOG.md
124
CHANGELOG.md
|
@ -1,78 +1,90 @@
|
|||
# Tridactyl changelog
|
||||
|
||||
# Release 1.22.0 / Unreleased
|
||||
# Release 1.22.1 / 2022-03-23
|
||||
|
||||
- New features
|
||||
|
||||
- A `superignore` setting has been added which nearly totally disables Tridactyl, per page. Use it with `:seturl` only. If you break Tridactyl with it, remember that you can always use the `tri` keyword in the address bar to execute ex-commands (#3497)
|
||||
|
||||
- `:drawing{start,stop,erasertoggle}` added to scribble on pages
|
||||
|
||||
- `:hint -V` hint mode added, bound to `;V`, which adds hints to all matching elements on the page, including ones outside the viewport (#3534)
|
||||
|
||||
- `:set completionfuzziness [0-1]` added to control strictness of completion matches (#3556)
|
||||
|
||||
- The cursor is no longer shown in no mouse mode (#3891)
|
||||
|
||||
- For our own `:find` mode, there is now a `findhighlighttimeout` setting (in milliseconds) which allows you to control how long text stays highlighted after a search (#3854)
|
||||
|
||||
- Tabs may now be renamed with `:tabrename` (#3577)
|
||||
|
||||
- Hint mode now tidies up any previous hints when it is entered
|
||||
|
||||
- `:colours midnight` added - a dark theme based on shydactyl (#3750)
|
||||
|
||||
- `:urlmodify` can now accept a URL as an argument (#3748)
|
||||
|
||||
- `:tabpush` now pushes to the next most recently used window if no other argument is given
|
||||
- Tridactyl will prompt you if you try to leave a page while `:editor` is running ([#3915](https://github.com/tridactyl/tridactyl/issues/3915))
|
||||
- Tridactyl pages will not flash white if your system theme is set to dark mode ([#2510](https://github.com/tridactyl/tridactyl/issues/2510))
|
||||
- `:goto` added to jump to a heading on a page, see `:help gotoselector` for configuration ([#4116](https://github.com/tridactyl/tridactyl/issues/4116))
|
||||
- `:wintitle` command added to add a prefix to the current window title ([#4049](https://github.com/tridactyl/tridactyl/issues/4049))
|
||||
|
||||
- Bug fixes
|
||||
|
||||
- The new tab page no longer has invisible links on it when set to `about:blank` (#1743)
|
||||
|
||||
- `:viewconfig` might now work more reliably but we are not sure (#3653)
|
||||
|
||||
- it also works from Tridactyl pages now, at least some of the time
|
||||
|
||||
- `:nmode` is now shown in the mode indicator
|
||||
|
||||
- `:open` will now always run in its own tab (#3583)
|
||||
|
||||
- Hint modes now accept a much wider array of arguments (#3534)
|
||||
|
||||
- `:source --url` now works on data URIs (#3540)
|
||||
|
||||
- `:guiset` now gives a more useful error on reading a malformed userChrome.css (#3541)
|
||||
|
||||
- `:mpvsafe` now leaves MPV running after Firefox exits on all platforms (#3538)
|
||||
|
||||
- `:viewcontainers` uses `:jsonview` internally which should fix how it is displayed from Tridactyl pages (#3539)
|
||||
|
||||
- `:containerdelete` no longer closes all normal tabs if an invalid container is given (#3536)
|
||||
|
||||
- `:set auconcreatecontainer fales` is now respected (#3537)
|
||||
|
||||
- GitHub and other SVG favicons should appear in the tab completions (#3892)
|
||||
|
||||
- `:editor` now correctly returns a value (#3800)
|
||||
- The mode indicator should no longer show up on printed pages ([#453](https://github.com/tridactyl/tridactyl/issues/453))
|
||||
- The changelog is more readable on dark themes ([#4005](https://github.com/tridactyl/tridactyl/issues/4005))
|
||||
- `:tabpush` will no longer show the current window ([#4114](https://github.com/tridactyl/tridactyl/issues/4114))
|
||||
- nor will `:tabgrab` ([#3283](https://github.com/tridactyl/tridactyl/issues/3283))
|
||||
- `:autocontain` will now pick the longest regex that matches a container if multiple filters match ([#3545](https://github.com/tridactyl/tridactyl/issues/3545))
|
||||
- `:elementunhide` works again ([#4069](https://github.com/tridactyl/tridactyl/issues/4069))
|
||||
- The mode indicator can reappear after leaving a mode in which it was disabled with `:set modeindicatormodes.[mode] false` ([#2690](https://github.com/tridactyl/tridactyl/issues/2690))
|
||||
- The `:editor` icon should now be correctly removed when finished ([#3909](https://github.com/tridactyl/tridactyl/issues/3909))
|
||||
- `:set newtab about:newtab` will no longer cause two tabs to be opened ([#3656](https://github.com/tridactyl/tridactyl/issues/3656))
|
||||
|
||||
- Miscellaneous
|
||||
|
||||
- We've switched from webpack to esbuild which has reduced dev-build times from 40 seconds to about 1 second (#3645)
|
||||
- The hacker news comment toggler in the exemplar RC file has been fixed ([#4124](https://github.com/tridactyl/tridactyl/issues/4124))
|
||||
- Warnings added to the new tab page about upcoming permission requests
|
||||
|
||||
- Tridactyl can now be built from ~5MB of source, down from ~100MB (#3632)
|
||||
Thanks to all of our contributors for this release: Oliver Blanthorn, dependabot[bot], pvs, David Scotson, Calvin T. Nesbitt, Colin Caine, Gerard Bosch, Icelk, Liam Hupfer, Mo, Mo Hijazi and glacambre
|
||||
|
||||
- We've switched from ramda to rambda which is a bit faster (#3628)
|
||||
Extra special thanks go to Calvin T. Nesbitt, David Scotson, Gerard Bosch, Icelk, Liam Hupfer, Mo and Mo Hijazi who all contributed for the first time.
|
||||
|
||||
Last, but not least - thank you to everyone who reported issues.
|
||||
|
||||
# Release 1.22.0 / 2021-11-29
|
||||
|
||||
- New features
|
||||
|
||||
- A `superignore` setting has been added which nearly totally disables Tridactyl, per page. Use it with `:seturl` only. If you break Tridactyl with it, remember that you can always use the `tri` keyword in the address bar to execute ex-commands ([#3497](https://github.com/tridactyl/tridactyl/issues/3497))
|
||||
- `:drawing{start,stop,erasertoggle}` added to scribble on pages
|
||||
- `:hint -V` hint mode added, bound to `;V`, which adds hints to all matching elements on the page, including ones outside the viewport ([#3534](https://github.com/tridactyl/tridactyl/issues/3534))
|
||||
- `:set completionfuzziness [0-1]` added to control strictness of completion matches ([#3556](https://github.com/tridactyl/tridactyl/issues/3556))
|
||||
- The cursor is no longer shown in no mouse mode ([#3891](https://github.com/tridactyl/tridactyl/issues/3891))
|
||||
- For our own `:find` mode, there is now a `findhighlighttimeout` setting (in milliseconds) which allows you to control how long text stays highlighted after a search ([#3854](https://github.com/tridactyl/tridactyl/issues/3854))
|
||||
- Tabs may now be renamed with `:tabrename` ([#3577](https://github.com/tridactyl/tridactyl/issues/3577))
|
||||
- Hint mode now tidies up any previous hints when it is entered
|
||||
- `:colours midnight` added - a dark theme based on shydactyl ([#3750](https://github.com/tridactyl/tridactyl/issues/3750))
|
||||
- `:urlmodify` can now accept a URL as an argument ([#3748](https://github.com/tridactyl/tridactyl/issues/3748))
|
||||
- `:tabpush` now pushes to the next most recently used window if no other argument is given
|
||||
- `:colourscheme auto` theme added which follows your system's dark/light mode setting ([#3923](https://github.com/tridactyl/tridactyl/issues/3923))
|
||||
- `:setmode [mode] allowautofocus [true|false]` added, currently only for the `allowautofocus` setting, to control the setting per-mode ([#3740](https://github.com/tridactyl/tridactyl/issues/3740))
|
||||
|
||||
- Bug fixes
|
||||
|
||||
- The new tab page no longer has invisible links on it when set to `about:blank` ([#1743](https://github.com/tridactyl/tridactyl/issues/1743))
|
||||
- `:viewconfig` might now work more reliably but we are not sure ([#3653](https://github.com/tridactyl/tridactyl/issues/3653))
|
||||
- it also works from Tridactyl pages now, at least some of the time
|
||||
- `:nmode` is now shown in the mode indicator
|
||||
- `:open` will now always run in its own tab ([#3583](https://github.com/tridactyl/tridactyl/issues/3583))
|
||||
- Hint modes now accept a much wider array of arguments ([#3534](https://github.com/tridactyl/tridactyl/issues/3534))
|
||||
- `:source --url` now works on data URIs ([#3540](https://github.com/tridactyl/tridactyl/issues/3540))
|
||||
- `:guiset` now gives a more useful error on reading a malformed userChrome.css ([#3541](https://github.com/tridactyl/tridactyl/issues/3541))
|
||||
- `:mpvsafe` now leaves MPV running after Firefox exits on all platforms ([#3538](https://github.com/tridactyl/tridactyl/issues/3538))
|
||||
- `:viewcontainers` uses `:jsonview` internally which should fix how it is displayed from Tridactyl pages ([#3539](https://github.com/tridactyl/tridactyl/issues/3539))
|
||||
|
||||
- `:containerdelete` no longer closes all normal tabs if an invalid container is given ([#3536](https://github.com/tridactyl/tridactyl/issues/3536))
|
||||
- `:set auconcreatecontainer fales` is now respected ([#3537](https://github.com/tridactyl/tridactyl/issues/3537))
|
||||
- GitHub and other SVG favicons should appear in the tab completions ([#3892](https://github.com/tridactyl/tridactyl/issues/3892))
|
||||
- `:editor` now correctly returns a value ([#3800](https://github.com/tridactyl/tridactyl/issues/3800))
|
||||
|
||||
- Miscellaneous
|
||||
|
||||
- We've switched from webpack to esbuild which has reduced dev-build times from 40 seconds to about 1 second ([#3645](https://github.com/tridactyl/tridactyl/issues/3645))
|
||||
- Tridactyl can now be built from ~5MB of source, down from ~100MB ([#3632](https://github.com/tridactyl/tridactyl/issues/3632))
|
||||
- We've switched from ramda to rambda which is a bit faster ([#3628](https://github.com/tridactyl/tridactyl/issues/3628))
|
||||
- We've switched from web-ext-types to definitely typed types, which are a bit better maintained
|
||||
|
||||
- We update the DOM in place a bit less, which could speed up `:tab` completions
|
||||
- Hint mode is a bit faster ([#3582](https://github.com/tridactyl/tridactyl/issues/3582))
|
||||
- Dev builds of Tridactyl now open a new tab page when Tridactyl code is updated ([#3564](https://github.com/tridactyl/tridactyl/issues/3564))
|
||||
- We're now using `firenvim`s web-editor library which means that CodeMirror, Monaco and other in-browser code editors now work with `:editor` ([#3851](https://github.com/tridactyl/tridactyl/issues/3851))
|
||||
- Native messenger bumped to version 0.3.6 from 0.3.4; fixes .tridactylrc search paths on windows and saving files to directories without specifying a filename
|
||||
|
||||
- Hint mode is a bit faster (#3582)
|
||||
Thanks to all of our contributors for this release: dependabot-preview[bot], Oliver Blanthorn, dependabot[bot], Vincent Tavernier, Rummskartoffel, Dhruva Sambrani, karizma, Jay Kamat, Aaron Rancsik, Simon H Moore, glacambre, ivcz, Caleb Maclennan, Eugene, Ivan Oleynikov, Søren Knudsen, meep, mozbug and slmb3.
|
||||
|
||||
- Dev builds of Tridactyl now open a new tab page when Tridactyl code is updated (#3564)
|
||||
Extra special thanks go to Aaron Rancsik, Eugene, Ivan Oleynikov, ivcz, karizma, meep, slmb3, Søren Knudsen and Vincent Tavernier who all contributed for the first time.
|
||||
|
||||
- We're now using `firenvim`s web-editor library which means that CodeMirror, Monaco and other in-browser code editors now work with `:editor` (#3851)
|
||||
Last, but not least - thank you to everyone who reported issues.
|
||||
|
||||
# Release 1.21.1 / 2021-03-19
|
||||
|
||||
|
|
36
package.json
36
package.json
|
@ -16,10 +16,10 @@
|
|||
"csp-serdes": "github:cmcaine/csp-serdes",
|
||||
"css": "^3.0.0",
|
||||
"editor-adapter": "^0.0.3",
|
||||
"esbuild": "^0.13.6",
|
||||
"fuse.js": "^6.4.6",
|
||||
"esbuild": "^0.14.38",
|
||||
"fuse.js": "^6.6.2",
|
||||
"nearley": "^2.20.1",
|
||||
"ramda": "^0.27.1",
|
||||
"ramda": "^0.28.0",
|
||||
"semver-compare": "^1.0.0",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"tsdef": "^0.0.14",
|
||||
|
@ -28,33 +28,33 @@
|
|||
},
|
||||
"devDependencies": {
|
||||
"@types/css": "0.0.33",
|
||||
"@types/firefox-webext-browser": "^82.0.1",
|
||||
"@types/jest": "^27.0.2",
|
||||
"@types/firefox-webext-browser": "^94.0.1",
|
||||
"@types/jest": "^27.5.0",
|
||||
"@types/nearley": "^2.11.2",
|
||||
"@types/selenium-webdriver": "^4.0.15",
|
||||
"@types/selenium-webdriver": "^4.0.20",
|
||||
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "^5.0.0",
|
||||
"@typescript-eslint/eslint-plugin-tslint": "^5.22.0",
|
||||
"@typescript-eslint/parser": "^4.33.0",
|
||||
"command-line-args": "^5.2.0",
|
||||
"command-line-args": "^5.2.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-prettier": "^8.3.0",
|
||||
"eslint-plugin-import": "^2.25.2",
|
||||
"eslint-plugin-jsdoc": "^36.1.1",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jsdoc": "^39.2.9",
|
||||
"eslint-plugin-prefer-arrow": "^1.2.3",
|
||||
"eslint-plugin-sonarjs": "^0.7.0",
|
||||
"geckodriver": "^2.0.4",
|
||||
"eslint-plugin-sonarjs": "^0.12.0",
|
||||
"geckodriver": "^3.0.1",
|
||||
"jasmine-fail-fast": "^2.0.1",
|
||||
"jest": "^25.5.4",
|
||||
"jest-webextension-mock": "^3.7.19",
|
||||
"marked": "^3.0.7",
|
||||
"prettier": "^2.4.1",
|
||||
"selenium-webdriver": "^4.0.0",
|
||||
"jest-webextension-mock": "^3.7.22",
|
||||
"marked": "^4.0.15",
|
||||
"prettier": "^2.6.2",
|
||||
"selenium-webdriver": "^4.1.2",
|
||||
"ts-jest": "^25.5.1",
|
||||
"tslint": "^5.20.1",
|
||||
"tslint-etc": "^1.13.10",
|
||||
"tslint-sonarts": "^1.9.0",
|
||||
"typescript": "^3.9.10",
|
||||
"web-ext": "^6.5.0"
|
||||
"web-ext": "^6.8.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "sh scripts/build.sh",
|
||||
|
|
10
readme.md
10
readme.md
|
@ -55,6 +55,8 @@ Tridactyl stable can be installed from the [Mozilla add-ons website (the AMO)][a
|
|||
|
||||
If you want to use advanced features such as edit-in-Vim, you'll also need to install the native messenger or executable, instructions for which can be found by typing `:installnative` and hitting enter once you are in Tridactyl. Arch users can install the [AUR package](https://aur.archlinux.org/packages/firefox-tridactyl-native/) `firefox-tridactyl-native` instead.
|
||||
|
||||
> **Notice**: `native` seems that does not work on Firefox instances installed with Snap (and probably other sandboxing/containerised package managers). See https://github.com/tridactyl/tridactyl/issues/2406
|
||||
|
||||
### Migrating between beta and stable builds
|
||||
|
||||
Our beta and stable versions store their configurations in separate places. To migrate between the two, see [the wiki](https://github.com/tridactyl/tridactyl/wiki/Migration-from-stable-to-beta).
|
||||
|
@ -65,7 +67,7 @@ The changelog for the stable versions can be found [here](https://github.com/tri
|
|||
|
||||
## First look
|
||||
|
||||
Type `:help` or press `<F1>` for online help once you're in :)
|
||||
Type `:help` or press `<F1>` for online help once you're in, or `:tutor` for a friendly introduction. You might also find the [unofficial Tridactyl Memrise course](https://app.memrise.com/course/5995499/tridactyls-main-shortcuts/) useful for memorising keybinds.
|
||||
|
||||
Remember that Tridactyl cannot run on any page on about:\*, data:\*, view-source:\* and file:\*. We're sorry about that and we're working with Firefox to improve this situation by removing restrictions on existing APIs and developing a new API.
|
||||
|
||||
|
@ -172,7 +174,7 @@ You can bind your own shortcuts in normal mode with the `:bind` command. For exa
|
|||
|
||||
- Navigation to any about:\* pages using `:open` requires the native messenger.
|
||||
- Firefox will not load Tridactyl on about:\*, some file:\* URIs, view-source:\*, or data:\*. On these pages `<C-,>` - that's "Ctrl-Comma" - and the `tri` [omnibox keyword](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/user_interface/Omnibox) are your escape hatches.
|
||||
- addons.mozilla.org is now supported so long as you run `fixamo` first.
|
||||
- addons.mozilla.org is not supported.
|
||||
- Tridactyl now supports changing the Firefox GUI if you have the native messenger installed via `guiset`. There's quite a few options available, but `guiset gui none` is probably what you want, perhaps followed up with `guiset tabs always`. See `:help guiset` for a list of all possible options.
|
||||
|
||||
## Frequently asked questions (FAQ)
|
||||
|
@ -254,7 +256,9 @@ You can bind your own shortcuts in normal mode with the `:bind` command. For exa
|
|||
|
||||
- How do I disable Tridactyl on certain sites?
|
||||
|
||||
You can use `blacklistadd`, like this: `blacklistadd mail.google.com/mail`. See `:help blacklistadd`. Also note that if you want something like the passkeys or ignorekeys features vimperator/pentadactyl had, you can use `bindurl`. See `:help bindurl`.
|
||||
To enter ignore mode automatically on a website, use `blacklistadd` like this: `blacklistadd mail.google.com/mail`. See `:help blacklistadd`. Also note that if you want something like the passkeys or ignorekeys features vimperator/pentadactyl had, you can use `bindurl`. See `:help bindurl`.
|
||||
|
||||
If you want to more thoroughly disable Tridactyl on a website, for example to prevent it from injecting its CSS, use `:seturl [url regex] superignore true`. See `:help seturl` and `:help superignore` for more details.
|
||||
|
||||
- How can I list the current bindings?
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@ import * as webrequests from "@src/background/webrequests"
|
|||
import * as commands from "@src/background/commands"
|
||||
import * as meta from "@src/background/meta"
|
||||
import * as Logging from "@src/lib/logging"
|
||||
import * as Proxy from "@src/lib/proxy"
|
||||
|
||||
// Add various useful modules to the window for debugging
|
||||
;(window as any).tri = Object.assign(Object.create(null), {
|
||||
|
@ -84,6 +85,10 @@ browser.tabs.onActivated.addListener(ev => {
|
|||
})
|
||||
})
|
||||
|
||||
browser.proxy.onRequest.addListener(Proxy.onRequestListener, {
|
||||
urls: ["<all_urls>"],
|
||||
})
|
||||
|
||||
/**
|
||||
* Declare Tab Event Listeners
|
||||
*/
|
||||
|
|
|
@ -101,7 +101,15 @@ export async function downloadUrlAs(
|
|||
urlToDownload = urlToSave.href
|
||||
}
|
||||
|
||||
const fileName = getDownloadFilenameForUrl(urlToSave)
|
||||
let fileName = getDownloadFilenameForUrl(urlToSave)
|
||||
const regex_matcher = new RegExp("[" + config.get("downloadforbiddenchars") + "]", "g")
|
||||
fileName = fileName.replace(regex_matcher, config.get("downloadforbiddenreplacement"))
|
||||
|
||||
config.get("downloadforbiddennames").split(",").forEach((item) => {
|
||||
if (item.trim() === fileName) {
|
||||
fileName = fileName + config.get("downloadforbiddenreplacement")
|
||||
}
|
||||
})
|
||||
|
||||
const downloadId = await browser.downloads.download({
|
||||
conflictAction: "uniquify",
|
||||
|
|
|
@ -26,6 +26,7 @@ import { CompositeCompletionSource } from "@src/completions/Composite"
|
|||
import { ExcmdCompletionSource } from "@src/completions/Excmd"
|
||||
import { ExtensionsCompletionSource } from "@src/completions/Extensions"
|
||||
import { FileSystemCompletionSource } from "@src/completions/FileSystem"
|
||||
import { GotoCompletionSource } from "@src/completions/Goto"
|
||||
import { GuisetCompletionSource } from "@src/completions/Guiset"
|
||||
import { HelpCompletionSource } from "@src/completions/Help"
|
||||
import { HistoryCompletionSource } from "@src/completions/History"
|
||||
|
@ -38,6 +39,7 @@ import { TabAllCompletionSource } from "@src/completions/TabAll"
|
|||
import { ThemeCompletionSource } from "@src/completions/Theme"
|
||||
import { TabHistoryCompletionSource } from "@src/completions/TabHistory"
|
||||
import { WindowCompletionSource } from "@src/completions/Window"
|
||||
import { ProxyCompletionSource } from "@src/completions/Proxy"
|
||||
import { contentState } from "@src/content/state_content"
|
||||
import { theme } from "@src/content/styling"
|
||||
import { getCommandlineFns } from "@src/lib/commandline_cmds"
|
||||
|
@ -121,6 +123,7 @@ export function enableCompletions() {
|
|||
TabHistoryCompletionSource,
|
||||
CompositeCompletionSource,
|
||||
FileSystemCompletionSource,
|
||||
GotoCompletionSource,
|
||||
GuisetCompletionSource,
|
||||
HelpCompletionSource,
|
||||
AproposCompletionSource,
|
||||
|
@ -131,6 +134,7 @@ export function enableCompletions() {
|
|||
SettingsCompletionSource,
|
||||
WindowCompletionSource,
|
||||
ExtensionsCompletionSource,
|
||||
ProxyCompletionSource,
|
||||
]
|
||||
.map(constructorr => {
|
||||
try {
|
||||
|
|
78
src/completions/Goto.ts
Normal file
78
src/completions/Goto.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
import * as Messaging from "@src/lib/messaging"
|
||||
import * as Completions from "@src/completions"
|
||||
import * as config from "@src/lib/config"
|
||||
|
||||
class GotoCompletionOption
|
||||
extends Completions.CompletionOptionHTML
|
||||
implements Completions.CompletionOptionFuse {
|
||||
public fuseKeys = []
|
||||
|
||||
constructor(public level, public y, public title, public value) {
|
||||
super()
|
||||
this.fuseKeys.push(title)
|
||||
|
||||
this.html = html`<tr class="GotoCompletionOption option">
|
||||
<td class="title" style="padding-left: ${level * 4}ch">${title}</td>
|
||||
</tr>`
|
||||
}
|
||||
}
|
||||
|
||||
export class GotoCompletionSource extends Completions.CompletionSourceFuse {
|
||||
public options: GotoCompletionOption[] = []
|
||||
private shouldSetStateFromScore = true
|
||||
|
||||
constructor(private _parent) {
|
||||
super(["goto"], "GotoCompletionSource", "Headings")
|
||||
|
||||
this.updateOptions()
|
||||
this.shouldSetStateFromScore =
|
||||
config.get("completions", "Goto", "autoselect") === "true"
|
||||
this._parent.appendChild(this.node)
|
||||
}
|
||||
|
||||
setStateFromScore(scoredOpts: Completions.ScoredOption[]) {
|
||||
super.setStateFromScore(scoredOpts, this.shouldSetStateFromScore)
|
||||
}
|
||||
|
||||
onInput(...whatever) {
|
||||
return this.updateOptions(...whatever)
|
||||
}
|
||||
|
||||
private async updateOptions(exstr = "") {
|
||||
this.lastExstr = exstr
|
||||
const [prefix] = this.splitOnPrefix(exstr)
|
||||
|
||||
// Hide self and stop if prefixes don't match
|
||||
if (prefix) {
|
||||
// Show self if prefix and currently hidden
|
||||
if (this.state === "hidden") {
|
||||
this.state = "normal"
|
||||
}
|
||||
} else {
|
||||
this.state = "hidden"
|
||||
return
|
||||
}
|
||||
|
||||
if (this.options.length < 1) {
|
||||
this.options = (
|
||||
await Messaging.messageOwnTab(
|
||||
"excmd_content",
|
||||
"getGotoSelectors",
|
||||
[],
|
||||
)
|
||||
)
|
||||
.sort((a, b) => a.y - b.y)
|
||||
.map(heading => {
|
||||
const opt = new GotoCompletionOption(
|
||||
heading.level,
|
||||
heading.y,
|
||||
heading.title,
|
||||
heading.selector,
|
||||
)
|
||||
opt.state = "normal"
|
||||
return opt
|
||||
})
|
||||
}
|
||||
return this.updateChain()
|
||||
}
|
||||
}
|
79
src/completions/Proxy.ts
Normal file
79
src/completions/Proxy.ts
Normal file
|
@ -0,0 +1,79 @@
|
|||
import * as Completions from "@src/completions"
|
||||
import * as config from "@src/lib/config"
|
||||
|
||||
class ProxyCompletionOption extends Completions.CompletionOptionHTML
|
||||
implements Completions.CompletionOptionFuse {
|
||||
public fuseKeys = []
|
||||
|
||||
constructor(
|
||||
public value: string,
|
||||
proxy: { name: string; value: string; },
|
||||
) {
|
||||
super()
|
||||
this.html = html`<tr class="ProxyCompletionOption option">
|
||||
<td class="name">${proxy.name}</td>
|
||||
<td class="content">${proxy.value}</td>
|
||||
</tr>`
|
||||
}
|
||||
}
|
||||
|
||||
export class ProxyCompletionSource extends Completions.CompletionSourceFuse {
|
||||
public options: ProxyCompletionOption[]
|
||||
|
||||
constructor(private _parent) {
|
||||
super(
|
||||
["proxyadd", "proxyremove"],
|
||||
"ProxyCompletionSource",
|
||||
"Proxy",
|
||||
)
|
||||
|
||||
this._parent.appendChild(this.node)
|
||||
}
|
||||
|
||||
public async filter(exstr: string) {
|
||||
this.lastExstr = exstr
|
||||
let [prefix, query] = this.splitOnPrefix(exstr)
|
||||
const args = query ? query.split(/\s+/) : []
|
||||
|
||||
// Hide self and stop if prefixes don't match
|
||||
if (prefix) {
|
||||
// Show self if prefix and currently hidden
|
||||
if (this.state === "hidden") {
|
||||
this.state = "normal"
|
||||
}
|
||||
} else {
|
||||
this.state = "hidden"
|
||||
return
|
||||
}
|
||||
|
||||
const proxies = config.get("proxies")
|
||||
|
||||
if (!proxies) {
|
||||
this.options = []
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
query = args.join(" ").toLowerCase()
|
||||
this.options = Object.keys(proxies)
|
||||
.filter(x => x.toLowerCase().startsWith(query))
|
||||
.sort()
|
||||
.map(
|
||||
key =>
|
||||
new ProxyCompletionOption(key, {
|
||||
name: key,
|
||||
value: JSON.stringify(proxies[key]),
|
||||
}
|
||||
),
|
||||
)
|
||||
|
||||
return this.updateChain()
|
||||
}
|
||||
|
||||
updateChain() {
|
||||
// Options are pre-trimmed to the right length.
|
||||
this.options.forEach(option => (option.state = "normal"))
|
||||
|
||||
// Call concrete class
|
||||
return this.updateDisplay()
|
||||
}
|
||||
}
|
|
@ -173,6 +173,8 @@ export class BufferCompletionSource extends Completions.CompletionSourceFuse {
|
|||
const useMruTabOrder = config.get("tabsort") === "mru"
|
||||
if (!useMruTabOrder) {
|
||||
tabs.sort((a, b) => a.index - b.index)
|
||||
} else {
|
||||
tabs.push(tabs.shift()) // If using MRU, move the current tab to the bottom (issue #4168)
|
||||
}
|
||||
|
||||
const container_all = await browserBg.contextualIdentities.query({})
|
||||
|
|
|
@ -147,6 +147,10 @@ export class TabAllCompletionSource extends Completions.CompletionSourceFuse {
|
|||
return a.windowId - b.windowId
|
||||
})
|
||||
|
||||
// Check to see if this is a command that needs to exclude the current
|
||||
// window
|
||||
const excludeCurrentWindow = ["tabgrab"].includes(prefix.trim())
|
||||
const currentWindow = await browserBg.windows.getCurrent()
|
||||
// Window Ids don't make sense so we're using LASTID and WININDEX to compute a window index
|
||||
// This relies on the fact that tabs are sorted by window ids
|
||||
let lastId = 0
|
||||
|
@ -156,6 +160,9 @@ export class TabAllCompletionSource extends Completions.CompletionSourceFuse {
|
|||
lastId = tab.windowId
|
||||
winindex += 1
|
||||
}
|
||||
// if we are excluding the current window and this tab is in the current window
|
||||
// then skip it
|
||||
if (excludeCurrentWindow && tab.windowId === currentWindow.id) continue
|
||||
options.push(
|
||||
new TabAllCompletionOption(
|
||||
tab.id.toString(),
|
||||
|
|
|
@ -69,7 +69,10 @@ export class WindowCompletionSource extends Completions.CompletionSourceFuse {
|
|||
return
|
||||
}
|
||||
|
||||
this.options = (await browserBg.windows.getAll({ populate: true })).map(
|
||||
const excludeCurrentWindow = ["tabpush"].includes(prefix.trim())
|
||||
this.options = (await browserBg.windows.getAll({ populate: true }))
|
||||
.filter( win => !(excludeCurrentWindow && win.focused))
|
||||
.map(
|
||||
win => {
|
||||
const o = new WindowCompletionOption(win)
|
||||
o.state = "normal"
|
||||
|
|
|
@ -241,7 +241,7 @@ if (
|
|||
window.location.pathname === "/static/newtab.html"
|
||||
) {
|
||||
config.getAsync("newtab").then(newtab => {
|
||||
if (newtab !== "about:blank") {
|
||||
if (!["about:blank", "about:newtab"].includes(newtab)) {
|
||||
if (newtab) {
|
||||
excmds.open_quiet(newtab)
|
||||
} else {
|
||||
|
@ -388,7 +388,9 @@ config.getAsync("modeindicator").then(mode => {
|
|||
config.get("modeindicator") !== "true" ||
|
||||
config.get("modeindicatormodes", mode) === "false"
|
||||
) {
|
||||
statusIndicator.remove()
|
||||
statusIndicator.classList.add("TridactylInvisible")
|
||||
} else {
|
||||
statusIndicator.classList.remove("TridactylInvisble")
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
@ -10,7 +10,10 @@
|
|||
|
||||
export function jack_in() {
|
||||
// chinese characters - taken from the unicode charset
|
||||
const chinese = "田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑".split("")
|
||||
const chinese =
|
||||
"田由甲申甴电甶男甸甹町画甼甽甾甿畀畁畂畃畄畅畆畇畈畉畊畋界畍畎畏畐畑".split(
|
||||
"",
|
||||
)
|
||||
const colour = "#0F0" // green text
|
||||
rain(makeBlock(), chinese, colour)
|
||||
}
|
||||
|
@ -54,7 +57,7 @@ const clickY = []
|
|||
const clickDrag = []
|
||||
let ink
|
||||
|
||||
let eraser = false;
|
||||
let eraser = false
|
||||
export function eraser_toggle() {
|
||||
eraser = !eraser
|
||||
}
|
||||
|
@ -66,7 +69,7 @@ function addClick(x, y, dragging) {
|
|||
}
|
||||
|
||||
function redraw(context) {
|
||||
if(eraser) {
|
||||
if (eraser) {
|
||||
context.globalCompositeOperation = "destination-out"
|
||||
context.lineWidth = 18
|
||||
} else {
|
||||
|
@ -75,26 +78,26 @@ function redraw(context) {
|
|||
}
|
||||
context.strokeStyle = "#000000"
|
||||
context.lineJoin = "miter"
|
||||
for(let i=0; i < clickX.length; i++) {
|
||||
for (let i = 0; i < clickX.length; i++) {
|
||||
context.beginPath()
|
||||
if(clickDrag[i] && i){
|
||||
context.moveTo(clickX[i-1], clickY[i-1])
|
||||
if (clickDrag[i] && i) {
|
||||
context.moveTo(clickX[i - 1], clickY[i - 1])
|
||||
} else {
|
||||
context.moveTo(clickX[i]-1, clickY[i])
|
||||
context.moveTo(clickX[i] - 1, clickY[i])
|
||||
}
|
||||
context.lineTo(clickX[i], clickY[i])
|
||||
context.closePath()
|
||||
context.stroke()
|
||||
}
|
||||
}
|
||||
function handleDown(e, context){
|
||||
function handleDown(e, context) {
|
||||
ink = true
|
||||
addClick(e.pageX, e.pageY, false)
|
||||
redraw(context)
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
function handleUp(e){
|
||||
function handleUp(e) {
|
||||
ink = false
|
||||
clickX.length = 0
|
||||
clickY.length = 0
|
||||
|
@ -103,9 +106,9 @@ function handleUp(e){
|
|||
e.preventDefault()
|
||||
}
|
||||
function handleMove(e, context) {
|
||||
if(ink){
|
||||
addClick(e.pageX, e.pageY, true);
|
||||
redraw(context);
|
||||
if (ink) {
|
||||
addClick(e.pageX, e.pageY, true)
|
||||
redraw(context)
|
||||
}
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
@ -118,20 +121,22 @@ function make_drawable(overlaydiv) {
|
|||
const context = c.getContext("2d")
|
||||
// making the canvas full screen
|
||||
c.height = document.documentElement.scrollHeight
|
||||
c.width = window.innerWidth*0.98 // workaround to fix canvas overflow
|
||||
c.width = window.innerWidth * 0.98 // workaround to fix canvas overflow
|
||||
c.style.touchAction = "none" // for pen tablet to work
|
||||
c.addEventListener("pointerdown", e=>handleDown(e,context))
|
||||
c.addEventListener("pointerdown", e => handleDown(e, context))
|
||||
c.addEventListener("pointerup", handleUp)
|
||||
c.addEventListener("pointermove", e=>handleMove(e,context))
|
||||
c.addEventListener("pointermove", e => handleMove(e, context))
|
||||
}
|
||||
|
||||
export function removeBlock() {
|
||||
Array.from(document.getElementsByClassName("_tridactyl_no_mouse_")).map((el: Element & { intid?: number | null}) => {
|
||||
if(typeof el.intid === "number") {
|
||||
clearInterval(el.intid)
|
||||
}
|
||||
el.remove()
|
||||
})
|
||||
Array.from(document.getElementsByClassName("_tridactyl_no_mouse_")).forEach(
|
||||
(el: Element & { intid?: number | null }) => {
|
||||
if (typeof el.intid === "number") {
|
||||
clearInterval(el.intid)
|
||||
}
|
||||
el.remove()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
export const snow = () => rain(makeBlock(), ["❄"], "#FFF", 0.15)
|
||||
|
|
138
src/excmds.ts
138
src/excmds.ts
|
@ -94,6 +94,7 @@ import * as escape from "@src/lib/escape"
|
|||
import semverCompare from "semver-compare"
|
||||
import * as hint_util from "@src/lib/hint_util"
|
||||
import { OpenMode } from "@src/lib/hint_util"
|
||||
import * as Proxy from "@src/lib/proxy"
|
||||
|
||||
/**
|
||||
* This is used to drive some excmd handling in `composite`.
|
||||
|
@ -301,16 +302,13 @@ export function getInputSelector() {
|
|||
/** @hidden */
|
||||
//#content
|
||||
export function addTridactylEditorClass(selector: string) {
|
||||
const elem = document.querySelector(selector)
|
||||
elem.className = elem.className + " TridactylEditing "
|
||||
return elem
|
||||
document.querySelector(selector)?.classList.add("TridactylEditing")
|
||||
}
|
||||
|
||||
/** @hidden */
|
||||
//#content
|
||||
export function removeTridactylEditorClass(selector: string) {
|
||||
const elem = document.querySelector(selector)
|
||||
elem.className = elem.className.replace(" TridactylEditing ", "")
|
||||
document.querySelector(selector)?.classList.remove("TridactylEditing")
|
||||
}
|
||||
|
||||
//#content_helper
|
||||
|
@ -347,6 +345,12 @@ export async function editor() {
|
|||
return undefined
|
||||
}
|
||||
|
||||
const beforeUnloadListener = (event: BeforeUnloadEvent) => {
|
||||
event.preventDefault()
|
||||
event.returnValue = true
|
||||
}
|
||||
window.addEventListener("beforeunload", beforeUnloadListener)
|
||||
|
||||
let ans
|
||||
try {
|
||||
const editor = getEditor(elem, { preferHTML: true })
|
||||
|
@ -371,6 +375,7 @@ export async function editor() {
|
|||
throw new Error(`:editor failed: ${e}`)
|
||||
} finally {
|
||||
removeTridactylEditorClass(selector)
|
||||
window.removeEventListener("beforeunload", beforeUnloadListener)
|
||||
return ans
|
||||
}
|
||||
}
|
||||
|
@ -641,7 +646,11 @@ export async function nativeopen(...args: string[]) {
|
|||
try {
|
||||
const profile = await Native.getProfile()
|
||||
if (profile.Name !== undefined) {
|
||||
firefoxArgs = [`-p ${profile.Name}`]
|
||||
if (os === "win") {
|
||||
firefoxArgs = [`-p "${profile.Name}"`]
|
||||
} else {
|
||||
firefoxArgs = [`-p '${profile.Name}'`]
|
||||
}
|
||||
} else if (profile.absolutePath !== undefined) {
|
||||
if (os === "win") {
|
||||
firefoxArgs = [`--profile "${profile.absolutePath}"`]
|
||||
|
@ -1368,14 +1377,8 @@ export async function open(...urlarr: string[]) {
|
|||
// Open URLs that firefox won't let us by running `firefox <URL>` on the command line
|
||||
return nativeopen(url)
|
||||
} else if (/^javascript:/.exec(url)) {
|
||||
const bookmarklet = url.replace(/^javascript:/, "")
|
||||
document.body.append(
|
||||
html`
|
||||
<script>
|
||||
${bookmarklet}
|
||||
</script>
|
||||
`,
|
||||
)
|
||||
const escapeUrl = url.replace(/[\\"]/g, "\\$&")
|
||||
window.eval(`window.location.href = "${escapeUrl}"`)
|
||||
} else {
|
||||
const tab = await ownTab()
|
||||
return openInTab(tab, {}, urlarr)
|
||||
|
@ -2509,7 +2512,7 @@ export async function tabopen(...addressarr: string[]): Promise<browser.tabs.Tab
|
|||
|
||||
const aucon = new AutoContain()
|
||||
if (!container && aucon.autocontainConfigured()) {
|
||||
const autoContainer = await aucon.getAuconForUrl(address)
|
||||
const [autoContainer, ] = await aucon.getAuconAndProxiesForUrl(address)
|
||||
if (autoContainer && autoContainer !== "firefox-default") {
|
||||
container = autoContainer
|
||||
logger.debug("tabopen setting container automatically using autocontain directive")
|
||||
|
@ -3024,6 +3027,19 @@ export async function winclose(...ids: string[]) {
|
|||
return Promise.all(ids.map(id => browser.windows.remove(parseInt(id, 10))))
|
||||
}
|
||||
|
||||
/**
|
||||
* Add/change a prefix to the current window title
|
||||
*
|
||||
* Example: `wintitle [Hovercraft research]`
|
||||
*
|
||||
* Protip: unicode emojis work :)
|
||||
*/
|
||||
//#background
|
||||
export async function wintitle(...title: string[]) {
|
||||
const id = (await browser.windows.getCurrent()).id
|
||||
return browser.windows.update(id, { titlePreface: title.join(" ") + " " })
|
||||
}
|
||||
|
||||
/** Close all windows */
|
||||
// It's unclear if this will leave a session that can be restored.
|
||||
// We might have to do it ourselves.
|
||||
|
@ -3959,7 +3975,11 @@ export function set(key: string, ...values: string[]) {
|
|||
throw msg
|
||||
}
|
||||
|
||||
return config.set(...validateSetArgs(key, values))
|
||||
const target = validateSetArgs(key, values)
|
||||
|
||||
key === "proxy" && Proxy.exists(target.slice(-1))
|
||||
|
||||
return config.set(...target)
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -4055,11 +4075,19 @@ export function autocmd(event: string, url: string, ...excmd: string[]) {
|
|||
*
|
||||
* The domain is passed through as a regular expression so there are a few gotchas to be aware of:
|
||||
* * Unescaped periods will match *anything*. `autocontain -s google.co.uk work` will match `google!co$uk`. Escape your periods (i.e. `\.`) or accept that you might get some false positives.
|
||||
* * You can use regex in your pattern. `autocontain -s google\.(co\.uk|com) work` will match either `google.co.uk` or `google.com`.
|
||||
* * You can use regex in your pattern. `autocontain -s google\.(co\.uk|com) work` will match either `google.co.uk` or `google.com`. If multiple rules match a certain URL, the one with the longest regex will be picked.
|
||||
*
|
||||
* This *should* now peacefully coexist with the Temporary Containers and Multi-Account Containers addons. Do not trust this claim. If a fight starts the participants will try to open infinite tabs. It is *strongly* recommended that you use a tridactylrc so that you can abort a sorceror's-apprentice scenario by killing firefox, commenting out all of autocontainer directives in your rc file, and restarting firefox to clean up the mess. There are a number of strange behaviors resulting from limited coordination between extensions. Redirects can be particularly surprising; for example, with `:autocontain -s will-redirect.example.org example` set and `will-redirect.example.org` redirecting to `redirected.example.org`, navigating to `will-redirect.example.org` will result in the new tab being in the `example` container under some conditions and in the `firefox-default` container under others.
|
||||
*
|
||||
* @param args a regex pattern to match URLs followed by the container to open the URL in.
|
||||
* Pass an optional space-separated list of proxy names to assign a proxy (followed by failover proxies) to a URL and open in a specified container.
|
||||
* For example: `autocontain [-{u,s}] pattern container proxy1 proxy2`
|
||||
*
|
||||
* To assign a proxy and open in no container, use "firefox-default" or "none" as a container name.
|
||||
* See also:
|
||||
* - [[proxyadd]]
|
||||
* - [[proxyremove]]
|
||||
*
|
||||
* @param args a regex pattern to match URLs followed by the container to open the URL in followed by an optional space-separated list of proxy names.
|
||||
*/
|
||||
//#background
|
||||
export function autocontain(...args: string[]) {
|
||||
|
@ -4070,15 +4098,50 @@ export function autocontain(...args: string[]) {
|
|||
if (urlMode || saneMode) {
|
||||
args.splice(0, 1)
|
||||
}
|
||||
if (args.length !== 2) throw new Error("syntax: autocontain [-{u,s}] pattern container")
|
||||
if (args.length < 2) throw new Error("syntax: autocontain [-{u,s}] pattern container proxy1 proxy2")
|
||||
|
||||
let [pattern, container] = args
|
||||
let [pattern, container, ...proxies] = args
|
||||
|
||||
if (!urlMode) {
|
||||
pattern = saneMode ? `^https?://([^/]*\\.|)${pattern}/` : `^https?://[^/]*${pattern}/`
|
||||
}
|
||||
|
||||
return config.set("autocontain", pattern, container)
|
||||
proxies.length && Proxy.exists(proxies)
|
||||
|
||||
return config.set("autocontain", pattern, proxies.length ? [container, proxies.join(",")].join("+") : container)
|
||||
}
|
||||
|
||||
/** Add a proxy for use with [[autocontain]] or `:set proxy`
|
||||
|
||||
@param name The name of the proxy you want to set
|
||||
|
||||
@param url The proxy URL. List of supported protcols are "http", "https" or equivalently "ssl", "socks5" or equivalently "socks" and "socks4".
|
||||
|
||||
Examples:
|
||||
- `proxyadd work https://admin:hunter2@bigcorp.example:1337`
|
||||
- `proxyadd kyoto socks://10.0.100.10:1080?proxyDNS=false`
|
||||
- `proxyadd alice socks4://10.0.100.10:3128`
|
||||
|
||||
These proxy settings are used by autocontainers. See [[autocontain]]
|
||||
*/
|
||||
//#background
|
||||
export function proxyadd(name: string, url: string) {
|
||||
if (!name || !url) throw new Error(":proxyadd requires two arguments. See `:help proxyadd` for more information.")
|
||||
|
||||
Proxy.proxyFromUrl(url)
|
||||
|
||||
return config.set("proxies", name, url)
|
||||
}
|
||||
|
||||
/** Remove proxies.
|
||||
@param name The proxy name that should be removed.
|
||||
*/
|
||||
//#background
|
||||
export function proxyremove(name: string) {
|
||||
if (!name) {
|
||||
throw new Error("proxyremove syntax: `proxyremove proxyname`")
|
||||
}
|
||||
config.unset("proxies", name)
|
||||
}
|
||||
|
||||
/** Remove autocmds
|
||||
|
@ -4102,7 +4165,7 @@ export function autocmddelete(event: string, url: string) {
|
|||
*
|
||||
* Remove sites from the blacklist with `blacklistremove [url]` or `autocmddelete DocStart [url]`.
|
||||
*
|
||||
* If you're looking for a way to temporarily disable Tridactyl, this might be what you're looking for.
|
||||
* If you're looking for a way to temporarily disable Tridactyl, this might be what you're looking for. If you need to disable Tridactyl more thoroughly on a page look at `:help superignore` instead.
|
||||
*
|
||||
* <!-- this should probably be moved to an ex alias once configuration has better help --!>
|
||||
*
|
||||
|
@ -4620,6 +4683,7 @@ export async function hint(...args: string[]): Promise<any> {
|
|||
|
||||
case OpenMode.KillTridactyl:
|
||||
elem.classList.add("TridactylKilledElem")
|
||||
KILL_STACK.push(elem)
|
||||
return elem
|
||||
|
||||
case OpenMode.SaveResource:
|
||||
|
@ -4812,6 +4876,36 @@ export async function gobble(nChars: number, endCmd: string) {
|
|||
|
||||
// }}}
|
||||
|
||||
/** @hidden
|
||||
* This function is used by goto completions.
|
||||
*/
|
||||
//#content
|
||||
export async function getGotoSelectors(): Promise<Array<{ level: number; y: number; title: string; selector: string }>> {
|
||||
const result = []
|
||||
let level = 1
|
||||
for (const selector of config.get("gotoselector").split(",")) {
|
||||
result.push(
|
||||
...(Array.from(document.querySelectorAll(selector)) as HTMLElement[])
|
||||
.filter(e => e.innerText)
|
||||
.map(e => ({ level, y: e.getClientRects()[0]?.y, title: e.innerText, selector: DOM.getSelector(e) }))
|
||||
.filter(e => e.y !== undefined),
|
||||
)
|
||||
level += 1
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump to selector.
|
||||
*/
|
||||
//#content
|
||||
export async function goto(...selector: string[]) {
|
||||
const element = document.querySelector(selector.join(" "))
|
||||
if (element) {
|
||||
element.scrollIntoView()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize n [mode] mode.
|
||||
*
|
||||
|
|
|
@ -42,7 +42,7 @@ interface IAutoContain {
|
|||
getCancelledRequest(tabId: number): ICancelledRequest
|
||||
completedRequestListener(details): void
|
||||
autocontainConfigured(): boolean
|
||||
getAuconForUrl(url: string): Promise<string>
|
||||
getAuconAndProxiesForUrl(url: string): Promise<[string, string[]]>
|
||||
getAuconForDetails(details): Promise<string>
|
||||
}
|
||||
|
||||
|
@ -270,33 +270,38 @@ export class AutoContain implements IAutoContain {
|
|||
return willContainInDefault
|
||||
}
|
||||
|
||||
getAuconForUrl = async (url: string): Promise<string> => {
|
||||
getAuconAndProxiesForUrl = async (url: string): Promise<[string, string[]]> => {
|
||||
const aucons = Config.get("autocontain")
|
||||
const ausites = Object.keys(aucons)
|
||||
const aukeyarr = ausites.filter(e => url.search(e) >= 0)
|
||||
if (aukeyarr.length > 1) {
|
||||
logger.error(
|
||||
"Too many autocontain directives match this url. Not containing.",
|
||||
)
|
||||
return "firefox-default"
|
||||
} else if (aukeyarr.length === 0) {
|
||||
return "firefox-default"
|
||||
const aukeyarr = ausites.filter(e => url.search(e) >= 0).sort((a, b) => b.length - a.length)
|
||||
if (!aukeyarr.length) {
|
||||
return ["firefox-default", []]
|
||||
} else {
|
||||
const containerExists = await Container.exists(aucons[aukeyarr[0]])
|
||||
const val = aucons[aukeyarr[0]]
|
||||
const matches = val.match(/(.*)\+(.*)/)
|
||||
const [aucon, proxies] = matches
|
||||
? [matches[1], matches[2].split(",")]
|
||||
: [val, []]
|
||||
if (aucon.toLowerCase() === "firefox-default" || aucon.toLowerCase() === "none") {
|
||||
return ["firefox-default", proxies]
|
||||
}
|
||||
const containerExists = await Container.exists(aucon)
|
||||
if (!containerExists) {
|
||||
if (Config.get("auconcreatecontainer") === "true") {
|
||||
await Container.create(aucons[aukeyarr[0]])
|
||||
await Container.create(aucon)
|
||||
} else {
|
||||
logger.error(
|
||||
"Specified container doesn't exist. consider setting 'auconcreatecontainer' to true",
|
||||
)
|
||||
}
|
||||
}
|
||||
return Container.getId(aucons[aukeyarr[0]])
|
||||
return [await Container.getId(aucon), proxies]
|
||||
}
|
||||
}
|
||||
|
||||
// Parses autocontain directives and returns valid cookieStoreIds or errors.
|
||||
getAuconForDetails = async (details): Promise<string> =>
|
||||
this.getAuconForUrl(details.url)
|
||||
getAuconForDetails = async (details): Promise<string> => {
|
||||
const [aucon, ] = await this.getAuconAndProxiesForUrl(details.url)
|
||||
return aucon
|
||||
}
|
||||
}
|
||||
|
|
|
@ -114,8 +114,8 @@ export function getCommandlineFns(cmdline_state: {
|
|||
cmdline_state.clInput.value.substring(0, selectionStart) +
|
||||
" " +
|
||||
cmdline_state.clInput.value.substring(selectionEnd)
|
||||
cmdline_state.clInput.selectionStart = cmdline_state.clInput.selectionEnd =
|
||||
selectionStart + 1
|
||||
cmdline_state.clInput.selectionStart =
|
||||
cmdline_state.clInput.selectionEnd = selectionStart + 1
|
||||
}
|
||||
return cmdline_state.refresh_completions(
|
||||
cmdline_state.clInput.value,
|
||||
|
@ -148,10 +148,7 @@ export function getCommandlineFns(cmdline_state: {
|
|||
|
||||
const func = command.trim().split(/\s+/)[0]
|
||||
|
||||
if (func.length === 0 || func.startsWith("#")) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return !(func.length === 0 || func.startsWith("#"))
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -543,6 +543,29 @@ export class default_config {
|
|||
// "youtube.com": "google",
|
||||
})
|
||||
|
||||
/**
|
||||
* Default proxy to use for all URLs. Has to be the name of a proxy. To add a proxy, see `:help proxyadd`. NB: usage with `:seturl` is buggy, use `:autocontain -s [regex to match URL] none [proxy]` instead
|
||||
*/
|
||||
proxy = ""
|
||||
|
||||
/**
|
||||
* Definitions of proxies.
|
||||
*
|
||||
* You can add a new proxy with `proxyadd proxyname proxyurl`
|
||||
*/
|
||||
proxies = o({
|
||||
// "socksName": "socks://hostname:port",
|
||||
// "socks4": "socks4://hostname:port",
|
||||
// "https": "https://username:password@hostname:port"
|
||||
})
|
||||
|
||||
/**
|
||||
* Whether to use proxy settings.
|
||||
*
|
||||
* If set to `true`, all proxy settings will be ignored.
|
||||
*/
|
||||
noproxy: "true" | "false" = "false"
|
||||
|
||||
/**
|
||||
* Strict mode will always ensure a domain is open in the correct container, replacing the current tab if necessary.
|
||||
*
|
||||
|
@ -622,7 +645,7 @@ export class default_config {
|
|||
"mktridactylrc!": "mktridactylrc -f",
|
||||
mpvsafe:
|
||||
"js -p tri.excmds.shellescape(JS_ARG).then(url => tri.excmds.exclaim_quiet('mpv --no-terminal ' + url))",
|
||||
drawingstop: "no_mouse_mode",
|
||||
drawingstop: "mouse_mode",
|
||||
exto: "extoptions",
|
||||
extpreferences: "extoptions",
|
||||
extp: "extpreferences",
|
||||
|
@ -651,7 +674,7 @@ export class default_config {
|
|||
/**
|
||||
* Definitions of search engines for use via `open [keyword]`.
|
||||
*
|
||||
* `%s` will be replaced with your whole query and `%s1`, `%s2`, ..., `%sn` will be replaced with the first, second and nth word of your query. If there are none of these patterns in your search urls, your query will simply be appended to the searchurl.
|
||||
* `%s` will be replaced with your whole query and `%s1`, `%s2`, ..., `%sn` will be replaced with the first, second and nth word of your query. Also supports array slicing, e.g. `%s[2:4]`, `%s[5:]`. If there are none of these patterns in your search urls, your query will simply be appended to the searchurl.
|
||||
*
|
||||
* Examples:
|
||||
* - When running `open gi cute puppies`, with a `gi` searchurl defined with `set searchurls.gi https://www.google.com/search?q=%s&tbm=isch`, tridactyl will navigate to `https://www.google.com/search?q=cute puppies&tbm=isch`.
|
||||
|
@ -685,6 +708,13 @@ export class default_config {
|
|||
qwant: "https://www.qwant.com/?q=",
|
||||
}
|
||||
|
||||
/**
|
||||
* Like [[searchurls]] but must be a Javascript function that takes one argument (a single string with the remainder of the command line including spaces) and maps it to a valid href that will be followed, e.g. `set jsurls.googleloud query => "https://google.com/search?q=" + query.toUpperCase()`
|
||||
*
|
||||
* NB: the href must be valid, i.e. it must include the protocol (e.g. "http://") and not just be e.g. "www.".
|
||||
*/
|
||||
jsurls = {}
|
||||
|
||||
/**
|
||||
* URL the newtab will redirect to.
|
||||
*
|
||||
|
@ -957,6 +987,23 @@ export class default_config {
|
|||
*/
|
||||
downloadsskiphistory: "true" | "false" = "false"
|
||||
|
||||
/**
|
||||
* Set of characters that are to be considered illegal as download filenames.
|
||||
*/
|
||||
downloadforbiddenchars = "/\0"
|
||||
|
||||
/**
|
||||
* Value that will be used to replace the illegal character(s), if found, in the download filename.
|
||||
*/
|
||||
downloadforbiddenreplacement = "_"
|
||||
|
||||
/**
|
||||
* Comma-separated list of whole filenames which, if match
|
||||
* with the download filename, will be suffixed with the
|
||||
* "downloadforbiddenreplacement" value.
|
||||
*/
|
||||
downloadforbiddennames = ""
|
||||
|
||||
/**
|
||||
* Set this to something weird if you want to have fun every time Tridactyl tries to update its native messenger.
|
||||
*
|
||||
|
@ -1029,10 +1076,18 @@ export class default_config {
|
|||
*/
|
||||
bmarkweight = 100
|
||||
|
||||
/**
|
||||
* Default selector for :goto command.
|
||||
*/
|
||||
gotoselector = "h1, h2, h3, h4, h5, h6"
|
||||
|
||||
/**
|
||||
* General completions options - NB: options are set according to our internal completion source name - see - `src/completions/[name].ts` in the Tridactyl source.
|
||||
*/
|
||||
completions = {
|
||||
Goto: {
|
||||
autoselect: "true",
|
||||
},
|
||||
Tab: {
|
||||
/**
|
||||
* Whether to automatically select the closest matching completion
|
||||
|
@ -1138,7 +1193,7 @@ export class default_config {
|
|||
visualenterauto: "true" | "false" = "true"
|
||||
|
||||
/**
|
||||
* Whether to return to visual mode when text is deselected.
|
||||
* Whether to return to normal mode when text is deselected.
|
||||
*/
|
||||
visualexitauto: "true" | "false" = "true"
|
||||
|
||||
|
@ -1183,6 +1238,10 @@ const platform_defaults = {
|
|||
(New-Object System.Net.WebClient).DownloadFile('https://raw.githubusercontent.com/tridactyl/native_messenger/master/installers/windows.ps1', '%TEMP%/tridactyl_installnative.ps1');\
|
||||
& '%TEMP%/tridactyl_installnative.ps1' -Tag %TAG;\
|
||||
Remove-Item '%TEMP%/tridactyl_installnative.ps1'"`,
|
||||
downloadforbiddenchars: "#%&{}\\<>*?/$!'\":@+`|=",
|
||||
downloadforbiddennames: "CON, PRN, AUX, NUL, COM1, COM2,"
|
||||
+ "COM3, COM4, COM5, COM6, COM7, COM8, COM9, LPT1,"
|
||||
+ "LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT9,",
|
||||
},
|
||||
linux: {
|
||||
nmaps: {
|
||||
|
|
|
@ -116,7 +116,7 @@ export class HintConfig implements HintOptions {
|
|||
let newOpenMode: undefined | OpenMode
|
||||
let newState: undefined | State
|
||||
|
||||
// eslint-disable-next-line sonarjs/max-switch-cases
|
||||
// eslint-disable-next-line sonarjs/max-switch-cases, sonarjs/no-nested-switch
|
||||
switch (flag) {
|
||||
case "br":
|
||||
// Equivalent to -qb, but deprecated
|
||||
|
|
|
@ -38,7 +38,7 @@ interface MessageResp {
|
|||
/**
|
||||
* Posts using the one-time message API; native is killed after message returns
|
||||
*/
|
||||
async function sendNativeMsg(
|
||||
export async function sendNativeMsg(
|
||||
cmd: MessageCommand,
|
||||
opts: Record<string, unknown>,
|
||||
quiet = false,
|
||||
|
|
163
src/lib/proxy.ts
Normal file
163
src/lib/proxy.ts
Normal file
|
@ -0,0 +1,163 @@
|
|||
import * as config from "@src/lib/config"
|
||||
import * as Logging from "@src/lib/logging"
|
||||
import { AutoContain } from "@src/lib/autocontainers"
|
||||
|
||||
const logger = new Logging.Logger("proxy")
|
||||
|
||||
const proxyTypes = ["http", "https", "socks", "socks4"] as const
|
||||
|
||||
type ProxyType = typeof proxyTypes[number]
|
||||
|
||||
interface ProxyInfo {
|
||||
type: ProxyType
|
||||
host: string
|
||||
port: number
|
||||
username: string
|
||||
password: string
|
||||
proxyDNS: boolean
|
||||
failoverTimeout: number
|
||||
}
|
||||
|
||||
function isProxyType(proxyType: string): proxyType is ProxyType {
|
||||
return proxyTypes.includes(proxyType as ProxyType)
|
||||
}
|
||||
|
||||
const authListener = (url: string, proxy: ProxyInfo): void => {
|
||||
const listener: (
|
||||
details: browser.webRequest._OnAuthRequiredDetails,
|
||||
) => browser.webRequest.BlockingResponse = details => {
|
||||
const info = details.challenger
|
||||
|
||||
if (
|
||||
!details.isProxy ||
|
||||
details.url !== url ||
|
||||
info.host !== proxy.host ||
|
||||
info.port !== proxy.port
|
||||
)
|
||||
return {}
|
||||
|
||||
const result = {
|
||||
authCredentials: {
|
||||
username: proxy.username,
|
||||
password: proxy.password,
|
||||
},
|
||||
}
|
||||
browser.webRequest.onAuthRequired.removeListener(listener)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
browser.webRequest.onAuthRequired.addListener(
|
||||
listener,
|
||||
{ urls: ["<all_urls>"] },
|
||||
["blocking"],
|
||||
)
|
||||
}
|
||||
|
||||
export const proxyFromUrl = (proxyUrl: string): ProxyInfo => {
|
||||
const regex = new RegExp(/.+:\/\//)
|
||||
const match = regex.exec(proxyUrl)
|
||||
if (!match) {
|
||||
throw new Error(`Not a valid URL`)
|
||||
}
|
||||
|
||||
let protocol: string
|
||||
let url: URL
|
||||
|
||||
if (match[0] !== "http://" && match[0] !== "https://") {
|
||||
proxyUrl = "http://" + proxyUrl.substring(match[0].length)
|
||||
url = new URL(proxyUrl)
|
||||
protocol = match[0].substring(0, match[0].length - 2)
|
||||
} else {
|
||||
url = new URL(proxyUrl)
|
||||
protocol = url.protocol
|
||||
}
|
||||
|
||||
protocol = protocol.replace(":", "")
|
||||
protocol =
|
||||
protocol === "socks5"
|
||||
? "socks"
|
||||
: protocol === "ssl"
|
||||
? "https"
|
||||
: protocol
|
||||
|
||||
if (!isProxyType(protocol)) {
|
||||
throw new Error(`Invalid proxy type: ${protocol}`)
|
||||
}
|
||||
|
||||
return {
|
||||
type: protocol,
|
||||
host: url.hostname,
|
||||
port: parseInt(url.port, 10),
|
||||
username: url.username,
|
||||
password: url.password,
|
||||
proxyDNS: url.searchParams.get("proxyDNS") === "true",
|
||||
failoverTimeout: 5,
|
||||
}
|
||||
}
|
||||
|
||||
export function exists(names: string[]) {
|
||||
const currProxies = Object.keys(config.get("proxies"))
|
||||
const missingProxies = names.filter(name => !currProxies.includes(name))
|
||||
if (missingProxies.length) {
|
||||
throw new Error(
|
||||
`${
|
||||
missingProxies.length === 1 ? "Proxy" : "Proxies"
|
||||
} ${missingProxies.join(
|
||||
", ",
|
||||
)} does not exist. See :help proxyadd for more info.`,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const getProxies = (): { [key: string]: ProxyInfo } => {
|
||||
const userProxies = config.get("proxies")
|
||||
return Object.entries(userProxies).reduce((acc, [name, url]) => {
|
||||
acc[name] = proxyFromUrl(url as string)
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
const getProxiesForUrl = async (url: string): Promise<ProxyInfo[]> => {
|
||||
const aucon = new AutoContain()
|
||||
const [, containerProxies] = await aucon.getAuconAndProxiesForUrl(url)
|
||||
const proxies = getProxies()
|
||||
const filteredProxies = Object.entries(proxies)
|
||||
.filter(([name, ]) => containerProxies.includes(name))
|
||||
.map(([, proxy]) => proxy)
|
||||
const defaultProxy = config.get("proxy")
|
||||
if (
|
||||
defaultProxy in proxies &&
|
||||
!containerProxies.includes(defaultProxy)
|
||||
) {
|
||||
filteredProxies.push(proxies[defaultProxy])
|
||||
}
|
||||
return filteredProxies
|
||||
}
|
||||
|
||||
export const onRequestListener = async (
|
||||
details: Pick<browser.proxy._OnRequestDetails, "url">,
|
||||
): Promise<ProxyInfo[] | never[]> => {
|
||||
const noProxy = []
|
||||
|
||||
if (config.get("noproxy") === "true") {
|
||||
return noProxy
|
||||
}
|
||||
|
||||
try {
|
||||
const proxies = await getProxiesForUrl(details.url)
|
||||
|
||||
if (!proxies.length) return noProxy
|
||||
|
||||
proxies.forEach(proxy => {
|
||||
if (proxy.type === "http" || proxy.type === "https") {
|
||||
authListener(details.url, proxy)
|
||||
}
|
||||
})
|
||||
|
||||
return proxies
|
||||
} catch (e) {
|
||||
logger.error(`Error in onRequest listener: ${e}`)
|
||||
return noProxy
|
||||
}
|
||||
}
|
|
@ -347,6 +347,16 @@ function test_url_query_interpolation() {
|
|||
"a/query",
|
||||
"http://example.com/?query=a%2Fquery&q2=v2",
|
||||
],
|
||||
[ // array indexing
|
||||
"http://example.com/?q1=%s1&q2=%s2",
|
||||
"a query",
|
||||
"http://example.com/?q1=a&q2=query"
|
||||
],
|
||||
[ // array slicing
|
||||
"http://example.com/?q1=%s1&q2=%s[2:]",
|
||||
"a query with several words",
|
||||
"http://example.com/?q1=a&q2=query%20with%20several%20words"
|
||||
]
|
||||
]
|
||||
|
||||
for (let [url, qy, exp_res] of cases) {
|
||||
|
|
|
@ -409,6 +409,14 @@ export function interpolateSearchItem(urlPattern: URL, query: string): URL {
|
|||
}
|
||||
|
||||
return queryWords[index]
|
||||
}).replace(/%s\[(-?\d+)?:(-?\d+)?\]/g, function(match, p1, p2) {
|
||||
const l = (x => x >= 1 ? x - 1 : x)
|
||||
// slices are 1-indexed
|
||||
const start = p1 ? l(parseInt(p1, 10)) : 0;
|
||||
const slice = p2 ?
|
||||
queryWords.slice(start, l(parseInt(p2, 10))) :
|
||||
queryWords.slice(start)
|
||||
return slice.join(" ")
|
||||
}),
|
||||
)
|
||||
|
||||
|
|
|
@ -263,6 +263,11 @@ export async function queryAndURLwrangler(
|
|||
return url.href
|
||||
}
|
||||
|
||||
const jsurls = config.get("jsurls")
|
||||
if (jsurls[firstWord]) {
|
||||
return eval(jsurls[firstWord])(rest)
|
||||
}
|
||||
|
||||
const searchEngines = await browserBg.search.get()
|
||||
let engine = searchEngines.find(engine => engine.alias === firstWord)
|
||||
// Maybe firstWord is the name of a firefox search engine?
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
{
|
||||
"manifest_version": 2,
|
||||
"name": "Tridactyl",
|
||||
"version": "1.21.1",
|
||||
"version_name": "1.21.1",
|
||||
"version": "1.22.1",
|
||||
"version_name": "1.22.1",
|
||||
"icons": {
|
||||
"64": "static/logo/Tridactyl_64px.png",
|
||||
"100": "static/logo/Tridactyl_100px.png",
|
||||
|
@ -97,12 +97,13 @@
|
|||
"webNavigation",
|
||||
"webRequest",
|
||||
"webRequestBlocking",
|
||||
"proxy",
|
||||
"<all_urls>"
|
||||
],
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "tridactyl.vim.betas@cmcaine.co.uk",
|
||||
"strict_min_version": "68.0"
|
||||
"strict_min_version": "91.1.0"
|
||||
}
|
||||
},
|
||||
"options_ui": {
|
||||
|
@ -123,4 +124,4 @@
|
|||
"omnibox": {
|
||||
"keyword": "tri"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
24
src/perf.ts
24
src/perf.ts
|
@ -340,25 +340,11 @@ export class StatsFilter {
|
|||
|
||||
matches(entry: PerformanceEntry): boolean {
|
||||
const metricNameInfo = extractMetricName(entry.name)
|
||||
if (
|
||||
this.config.kind === "functionName" &&
|
||||
this.config.functionName !== metricNameInfo.functionName
|
||||
) {
|
||||
return false
|
||||
}
|
||||
if (
|
||||
this.config.kind === "ownerName" &&
|
||||
this.config.ownerName !== metricNameInfo.ownerName
|
||||
) {
|
||||
return false
|
||||
}
|
||||
if (
|
||||
this.config.kind === "eventType" &&
|
||||
this.config.eventType !== entry.entryType
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return !(
|
||||
(this.config.kind === "functionName" && this.config.functionName !== metricNameInfo.functionName) ||
|
||||
(this.config.kind === "ownerName" && this.config.ownerName !== metricNameInfo.ownerName) ||
|
||||
(this.config.kind === "eventType" && this.config.eventType !== entry.entryType)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ Hello. If you've just installed Tridactyl for the first time, welcome! Tridactyl
|
|||
|
||||
Welcome to the Tridactyl tutorial. Here, you will learn how to get started with this extension. If you ever want to get back to this page, just type `:tutor`.
|
||||
|
||||
It will not cover advanced topics. For those, [`:help`](../docs/modules/_src_excmds_.html) is always at hand.
|
||||
It will not cover advanced topics. For those, [`:help`](../docs/modules/_src_excmds_.html) is always at hand. You might also find the [unofficial Tridactyl Memrise course](https://app.memrise.com/course/5995499/tridactyls-main-shortcuts/) useful for memorising binds.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ Tridactyl uses a similar notation to Vim for keys with modifiers: `<C-x>` means
|
|||
- `o` in the current tab
|
||||
- `t` in a new tab
|
||||
- Using a capital letter in place of any of the previous commands opens the command with the current URL pasted into it, i.e, `W`,`O`,`T`
|
||||
- `s` lets you search easily in the current tab and `S` does so in a new tab.
|
||||
- `s` lets you easily start a search with your default search engine in the current tab and `S` does so in a new tab.
|
||||
- in general, you can search many search engines straight from these prompts by simply starting your query with the search engine, such as `bing` `duckduckgo` or `scholar`
|
||||
- Navigate history with `H` and `L`
|
||||
- `yy` copies the current URL to your clipboard
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import url("../themes/default/default.css");
|
||||
@import url("../themes/auto/auto.css");
|
||||
|
||||
/* Adapted from https://css-tricks.com/snippets/css/star-wars-crawl-text/ */
|
||||
body {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import url("../themes/default/default.css");
|
||||
@import url("../themes/auto/auto.css");
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import url("../themes/default/default.css");
|
||||
@import url("../themes/auto/auto.css");
|
||||
|
||||
#cmdline_iframe {
|
||||
position: fixed !important;
|
||||
|
@ -47,7 +47,11 @@
|
|||
}
|
||||
|
||||
@media print {
|
||||
.TridactylStatusIndicator {
|
||||
span.TridactylStatusIndicator {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#cmdline_iframe {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import url("../themes/default/default.css");
|
||||
@import url("../themes/auto/auto.css");
|
||||
|
||||
span.TridactylHint {
|
||||
position: absolute !important;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import url("../themes/default/default.css");
|
||||
@import url("../themes/auto/auto.css");
|
||||
|
||||
body {
|
||||
font-family: var(--tridactyl-font-family-sans);
|
||||
|
@ -6,7 +6,6 @@ body {
|
|||
color: var(--tridactyl-fg);
|
||||
background: var(--tridactyl-bg);
|
||||
max-width: 40em;
|
||||
line-height: 140%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
@ -78,6 +77,7 @@ p,
|
|||
li {
|
||||
hyphens: auto;
|
||||
text-align: justify;
|
||||
line-height: 140%;
|
||||
}
|
||||
|
||||
div.align-left * {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import url("../themes/default/default.css");
|
||||
@import url("../themes/auto/auto.css");
|
||||
|
||||
#TridactylViewsourceElement {
|
||||
position: absolute !important;
|
||||
|
|
|
@ -6,6 +6,8 @@ Tridactyl has to override your new tab page due to WebExtension limitations. You
|
|||
|
||||
- Tridactyl funding 👀: [donate via GitHub sponsors here](https://github.com/users/bovine3dom/sponsorship). All GitHub and Patreon donors get a nice little newsletter once every few months; people who donate at least 10USD a month get a "tips & tricks" newsletter roughly once a month ([see an example here](https://github.com/tridactyl/tridactyl/blob/master/doc/newsletters/tips-and-tricks/1-hint-css-selectors.md)). You can also donate via [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=7JQHV4N2YZCTY), but they charge fairly high fees and you won't get any newsletters. Donations currently go towards ensuring that bovine3dom can afford to work one day a week on Tridactyl. Previously the donations have funded an in-person developer retreat.
|
||||
|
||||
- __Upcoming new permission requests__: the next version of Tridactyl will require the "hide tabs" and "proxy" permissions in order to provide `:tgroup*` tab group commands and add proxy support to `:autocontain`. You will need to click on a small pale yellow notification in the top right of the browser window to update to this version once it is available.
|
||||
|
||||
* If Tridactyl breaks a website or is broken by a website, trying the steps in the [troubleshooting guide](https://github.com/tridactyl/tridactyl/blob/master/doc/troubleshooting.md) might help.
|
||||
|
||||
* You can contact the developers, other users and contributors for support or whatever on [Matrix][matrix-link], [Gitter][gitter-link], [Discord][discord-link] or [IRC][libera-link].
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
@import '../default/default.css';
|
||||
@import '../dark/dark.css' (prefers-color-scheme: dark);
|
||||
@import '../default/default.css' (prefers-color-scheme: light);
|
||||
|
|
|
@ -101,7 +101,7 @@
|
|||
--tridactyl-of-bg: #ffec8b;
|
||||
|
||||
/*new tab spoiler box*/
|
||||
--tridactyl-highlight-box-bg: #eee;
|
||||
--tridactyl-highlight-box-bg: rgba(0, 0, 0, 0.07);
|
||||
--tridactyl-highlight-box-fg: var(--tridactyl-fg);
|
||||
|
||||
--tridactyl-private-window-icon-url: url("chrome://browser/skin/privatebrowsing/private-browsing.svg");
|
||||
|
|
Loading…
Add table
Reference in a new issue