Merge branch 'master' of github.com:cmcaine/tridactyl into nativemessenger

Merge in version 1.9.4: I wanted the about:newtab code.
This commit is contained in:
Oliver Blanthorn 2018-04-20 21:41:15 +01:00
commit 98734fb3a8
No known key found for this signature in database
GPG key ID: 2BB8C36BB504BFF3
13 changed files with 190 additions and 35 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
AMOKEYS
build build
node_modules node_modules
src/excmds_background.ts src/excmds_background.ts

View file

@ -1,5 +1,27 @@
# Tridactyl changelogs # Tridactyl changelogs
## Release 1.9.4
- Add jumplist for inputs bound to `g;`
- Editor's impartial note: this is pretty cool
- Add `hint -W [exstr]` to execute exstr on hint's href
- Update new tab page:
- Add changelogs
- Remove welcome to new users as we have `tutor` for that now
- Fix newtab redirection on `set newtab [url]`
- `set newtab about:blank` now works thanks to a Mozilla bug fix!
- Warn users about native messenger update
- Bug fixes
- input-mode now correctly exits to normal mode on focus loss
- Stop treating "std::map" or "Error: foo" as URIs: searching for them will now work.
## Release 1.9.3
- Fix unbind issues
- Add more default binds from Vimperator
- Change the `^` bind to `<c-6>` (matches vim)
- :bmark now supports folders
## Release 1.9.2 ## Release 1.9.2
- Fix #392 (bug with keyseq) - Fix #392 (bug with keyseq)

View file

@ -5,7 +5,24 @@
cd src/static cd src/static
newtab="../../generated/static/newtab.html" newtab="../../generated/static/newtab.html"
newtabtemp="../../generated/static/newtab.temp.html"
sed "/REPLACETHIS/,$ d" newtab.template.html > "$newtab" sed "/REPLACETHIS/,$ d" newtab.template.html > "$newtabtemp"
marked newtab.md >> "$newtab" marked newtab.md >> "$newtabtemp"
sed "1,/REPLACETHIS/ d" newtab.template.html >> "$newtab" sed "1,/REPLACETHIS/ d" newtab.template.html >> "$newtabtemp"
# Why think when you can pattern match?
sed "/REPLACE_ME_WITH_THE_CHANGE_LOG_USING_SED/,$ d" "$newtabtemp" > "$newtab"
echo """
<input type="checkbox" id="spoilerbutton" />
<label for="spoilerbutton" onclick="">Changelogs</label>
<div class="spoiler">
""" >> "$newtab"
marked ../../doc/changelog.md >> "$newtab"
echo """
</div>
""" >> "$newtab"
sed "1,/REPLACE_ME_WITH_THE_CHANGE_LOG_USING_SED/ d" "$newtabtemp" >> "$newtab"
rm "$newtabtemp"

View file

@ -19,6 +19,7 @@ publish_stable() {
npm run clean npm run clean
npm run build npm run build
sign_and_submit sign_and_submit
tar --exclude-from=.gitignore --exclude=.git/* -czf ../public_html/betas/tridactyl_source.tar.gz .
} }
case $1 in case $1 in

View file

@ -79,6 +79,7 @@ const DEFAULTS = o({
r: "reload", r: "reload",
R: "reloadhard", R: "reloadhard",
gi: "focusinput -l", gi: "focusinput -l",
"g;": "changelistjump -1",
gt: "tabnext_gt", gt: "tabnext_gt",
gT: "tabprev", gT: "tabprev",
// "<c-n>": "tabnext_gt", // c-n is reserved for new window // "<c-n>": "tabnext_gt", // c-n is reserved for new window

View file

@ -49,15 +49,17 @@ import * as native from "./native_background"
native, native,
}) })
dom.setupFocusHandler() // Don't hijack on the newtab page.
dom.hijackPageListenerFunctions() if (webext.inContentScript()) {
dom.setupFocusHandler()
dom.hijackPageListenerFunctions()
} else {
console.error("No export func")
}
if ( if (
window.location.protocol === "moz-extension:" && window.location.protocol === "moz-extension:" &&
window.location.pathname === "/static/newtab.html" window.location.pathname === "/static/newtab.html"
) { ) {
;(window as any).tri.config.getAsync("newtab").then(newtab => { config.getAsync("newtab").then(newtab => newtab && excmds.open(newtab))
if (newtab !== "")
window.location.href = (window as any).tri.excmds.forceURI(newtab)
})
} }

View file

@ -41,14 +41,13 @@ function* ParserController() {
if ( if (
state.mode != "ignore" && state.mode != "ignore" &&
state.mode != "hint" && state.mode != "hint" &&
state.mode != "input" &&
state.mode != "find" state.mode != "find"
) { ) {
if (isTextEditable(keyevent.target)) { if (isTextEditable(keyevent.target)) {
if (state.mode !== "insert") { if (state.mode !== "insert") {
state.mode = "insert" state.mode = "insert"
} }
} else if (state.mode === "insert") { } else if (["insert", "input"].includes(state.mode)) {
state.mode = "normal" state.mode = "normal"
} }
} }

View file

@ -1,6 +1,8 @@
import { MsgSafeNode } from "./msgsafe" import { MsgSafeNode } from "./msgsafe"
import * as config from "./config" import * as config from "./config"
import { flatten } from "./itertools" import { flatten } from "./itertools"
import state from "./state"
import { activeTabId } from "./lib/webext"
// From saka-key lib/dom.js, under Apachev2 // From saka-key lib/dom.js, under Apachev2
@ -432,8 +434,8 @@ export function focus(e: HTMLElement): void {
//#content_helper //#content_helper
let LAST_USED_INPUT: HTMLElement = null let LAST_USED_INPUT: HTMLElement = null
export function getLastUsedInput () { export function getLastUsedInput() {
return LAST_USED_INPUT return LAST_USED_INPUT
} }
/** WARNING: This function can potentially recieve malicious input! For the /** WARNING: This function can potentially recieve malicious input! For the
@ -447,17 +449,23 @@ export function getLastUsedInput () {
function onPageFocus(elem: HTMLElement, args: any[]): void { function onPageFocus(elem: HTMLElement, args: any[]): void {
if (isTextEditable(elem)) { if (isTextEditable(elem)) {
LAST_USED_INPUT = elem LAST_USED_INPUT = elem
config.getAsync("allowautofocus").then((allow) => { config.getAsync("allowautofocus").then(allow => {
if (allow === "true") if (allow === "true") elem.focus(args)
elem.focus(args) })
});
} }
} }
async function setInput(el) {
let tab = await activeTabId()
// store maximum of 10 elements to stop this getting bonkers huge
const arr = state.prevInputs.concat({ tab, inputId: el.id })
state.prevInputs = arr.slice(Math.max(arr.length - 10, 0))
}
/** Replaces the page's HTMLElement.prototype.focus with our own, onPageFocus */ /** Replaces the page's HTMLElement.prototype.focus with our own, onPageFocus */
function hijackPageFocusFunction(): void { function hijackPageFocusFunction(): void {
let exportedName = "onPageFocus"; let exportedName = "onPageFocus"
exportFunction(onPageFocus, window, {defineAs: exportedName}) exportFunction(onPageFocus, window, { defineAs: exportedName })
let eval_str = `HTMLElement.prototype.focus = ((realFocus, ${exportedName}) => { let eval_str = `HTMLElement.prototype.focus = ((realFocus, ${exportedName}) => {
return function (...args) { return function (...args) {
@ -465,14 +473,16 @@ function hijackPageFocusFunction(): void {
} }
})(HTMLElement.prototype.focus, ${exportedName})` })(HTMLElement.prototype.focus, ${exportedName})`
window.eval(eval_str + `;delete ${exportedName}`) window.eval(eval_str + `;delete ${exportedName}`)
} }
export function setupFocusHandler(): void { export function setupFocusHandler(): void {
// Handles when a user selects an input // Handles when a user selects an input
document.addEventListener("focusin", e => { document.addEventListener("focusin", e => {
if (isTextEditable(e.target as HTMLElement)) if (isTextEditable(e.target as HTMLElement)) {
LAST_USED_INPUT = e.target as HTMLElement LAST_USED_INPUT = e.target as HTMLElement
setInput(e.target as HTMLInputElement)
}
}) })
// Handles when the page tries to select an input // Handles when the page tries to select an input
hijackPageFocusFunction() hijackPageFocusFunction()

View file

@ -87,7 +87,7 @@
// Shared // Shared
import * as Messaging from "./messaging" import * as Messaging from "./messaging"
import { l } from "./lib/webext" import { l, browserBg, activeTabId } from "./lib/webext"
import state from "./state" import state from "./state"
import * as UrlUtil from "./url_util" import * as UrlUtil from "./url_util"
import * as config from "./config" import * as config from "./config"
@ -114,7 +114,7 @@ import { flatten } from "./itertools"
import "./number.mod" import "./number.mod"
import { ModeName } from "./state" import { ModeName } from "./state"
import * as keydown from "./keydown_background" import * as keydown from "./keydown_background"
import { activeTab, activeTabId, firefoxVersionAtLeast, openInNewTab } from "./lib/webext" import { activeTab, firefoxVersionAtLeast, openInNewTab } from "./lib/webext"
import * as CommandLineBackground from "./commandline_background" import * as CommandLineBackground from "./commandline_background"
//#background_helper //#background_helper
@ -211,15 +211,24 @@ function searchURL(provider: string, query: string) {
return UrlUtil.interpolateSearchItem(new URL(searchurlprovider), query) return UrlUtil.interpolateSearchItem(new URL(searchurlprovider), query)
} }
/** If maybeURI doesn't have a schema, affix http:// */ /** Take a string and find a way to interpret it as a URI or search query. */
/** @hidden */ /** @hidden */
export function forceURI(maybeURI: string): string { export function forceURI(maybeURI: string): string {
// Need undefined to be able to open about:newtab // Need undefined to be able to open about:newtab
if (maybeURI == "") return undefined if (maybeURI == "") return undefined
try {
return new URL(maybeURI).href // If the uri looks like it might contain a schema and a domain, try url()
} catch (e) { // test for a non-whitespace, non-colon character after the colon to avoid
if (e.name !== "TypeError") throw e // false positives like "error: can't reticulate spline" and "std::map".
//
// These heuristics mean that very unusual URIs will be coerced to
// something else by this function.
if (/^[a-zA-Z0-9+.-]+:[^\s:]/.test(maybeURI)) {
try {
return new URL(maybeURI).href
} catch (e) {
if (e.name !== "TypeError") throw e
}
} }
// Else if search keyword: // Else if search keyword:
@ -449,10 +458,16 @@ export async function reloadhard(n = 1) {
"searchengine": "google" or any of [[SEARCH_URLS]] "searchengine": "google" or any of [[SEARCH_URLS]]
*/ */
//#content //#content
export function open(...urlarr: string[]) { export async function open(...urlarr: string[]) {
let url = urlarr.join(" ") let url = urlarr.join(" ")
if (url === "") url = config.get("newtab") || browser.extension.getURL("static/newtab.html")
window.location.href = forceURI(url) // Setting window.location to about:blank results in a page we can't access, tabs.update works.
// tabs.update goes to the new tab page if url === "".
if (["", "about:blank"].includes(url)) {
browserBg.tabs.update(await activeTabId(), { url })
} else {
window.location.href = forceURI(url)
}
} }
/** @hidden */ /** @hidden */
@ -911,6 +926,41 @@ export function focusinput(nth: number | string) {
} }
} }
/**
* Focus the tab which contains the last focussed input element. If you're lucky, it will focus the right input, too.
*
* Currently just goes to the last focussed input; being able to jump forwards and backwards is planned.
*/
//#background
export async function changelistjump(n?: number) {
let tail = state.prevInputs[state.prevInputs.length - 1]
let jumppos = tail.jumppos ? tail.jumppos : state.prevInputs.length - 1
const input = state.prevInputs[jumppos]
await browser.tabs.update(input.tab, { active: true })
const id = input.inputId
// Not all elements have an ID, so this will do for now.
if (id) focusbyid(input.inputId)
else focusinput("-l")
// Really want to bin the input we just focussed ^ and edit the real last input to tell us where to jump to next.
// It doesn't work in practice as the focus events get added after we try to delete them.
// Even editing focusbyid/focusinput doesn't work to try to delete their own history doesn't work.
// I'm bored of working on it for now, though.
// Probable solution: add an event listener to state.prevInputs changing, delete the focussed element, then delete event listener.
//
// let arr = state.prevInputs
// arr.splice(-2,2)
// tail.jumppos = jumppos - 1
// arr = arr.concat(tail)
// state.prevInputs = arr
}
//#content
export function focusbyid(id: string) {
document.getElementById(id).focus()
}
// }}} // }}}
// {{{ TABS // {{{ TABS

View file

@ -1,7 +1,7 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "Tridactyl", "name": "Tridactyl",
"version": "1.9.2", "version": "1.9.4",
"icons": { "icons": {
"64": "static/logo/Tridactyl_64px.png", "64": "static/logo/Tridactyl_64px.png",
"100": "static/logo/Tridactyl_100px.png", "100": "static/logo/Tridactyl_100px.png",

View file

@ -28,6 +28,13 @@ export type ModeName =
class State { class State {
mode: ModeName = "normal" mode: ModeName = "normal"
cmdHistory: string[] = [] cmdHistory: string[] = []
prevInputs: { inputId: string; tab: number; jumppos?: number }[] = [
{
inputId: undefined,
tab: undefined,
jumppos: undefined,
},
]
last_ex_str: string = "" last_ex_str: string = ""
} }

View file

@ -6,6 +6,47 @@ body {
margin: auto; margin: auto;
} }
input[id^="spoiler"]{
display: none;
}
/* Borrowed from https://codepen.io/oloman/pen/odnqy */
input[id^="spoiler"] + label {
display: block;
width: 8em;
margin: 0 auto;
padding: 0.25em, 0.25em;
background: #1f9947;
color: #fff;
text-align: center;
font-size: 12pt;
border-radius: 2px;
cursor: pointer;
transition: all .6s;
}
input[id^="spoiler"]:checked + label {
color: #333;
background: #ccc;
}
input[id^="spoiler"] ~ .spoiler {
width: 90%;
height: 0;
overflow: hidden;
opacity: 0;
margin: 10px auto 0;
padding: 10px;
background: #eee;
border: 1px solid #ccc;
border-radius: 2px;
transition: all .6s;
}
input[id^="spoiler"]:checked + label + .spoiler{
height: auto;
opacity: 1;
padding: 10px;
}
h1 { h1 {
padding-top: 1em; padding-top: 1em;
} }

View file

@ -2,7 +2,7 @@
# Tridactyl REPLACE_ME_WITH_THE_VERSION_USING_SED # Tridactyl REPLACE_ME_WITH_THE_VERSION_USING_SED
Tridactyl has to override your new tab page due to WebExtension limitations. You can learn how to change it at the bottom of the page, otherwise please read on for some tips and tricks. (If you've just installed Tridactyl for the first time and are seeing this page, hello! Welcome! You'll probably be seeing this page a lot until you figure out how to disable it or uninstall the addon). Tridactyl has to override your new tab page due to WebExtension limitations. You can learn how to change it at the bottom of the page, otherwise please read on for some tips and tricks.
- You can view the main help page by typing [`:help`][help], and access the tutorial with [`:tutor`][tutor]. - You can view the main help page by typing [`:help`][help], and access the tutorial with [`:tutor`][tutor].
@ -12,6 +12,11 @@ Tridactyl has to override your new tab page due to WebExtension limitations. You
- If you're enjoying Tridactyl (or not), please leave a review on [addons.mozilla.org][amo]. - If you're enjoying Tridactyl (or not), please leave a review on [addons.mozilla.org][amo].
- **NB:** Tridactyl will soon support a native messenger. When this version is released, Firefox **will not update to it** unless you click the menu in the top right and allow it to update. A small yellow exclamation mark will appear on the menu's icon to notify you of this fact; please keep an eye out for it over the next week or so.
REPLACE_ME_WITH_THE_CHANGE_LOG_USING_SED
## Highlighted features: ## Highlighted features:
- `f`/`F` — enter the "hint mode" to select a link to follow. `F` to open it in a background tab. - `f`/`F` — enter the "hint mode" to select a link to follow. `F` to open it in a background tab.
@ -47,8 +52,7 @@ Tridactyl overrides your newtab page because it cannot insert its content script
### How can I get rid of it? ### How can I get rid of it?
- `:set newtab [URL]` - `:set newtab [URL]`
<!-- - If you just want a blank page, you can use `set newtab data:text/html, <html style="background:white"></html>`. You can replace "white" with any CSS colour of your choosing. --> - e.g, `:set newtab about:blank`
- `d`, Alt-F4, Ctrl-W and other such jokes.
## FAQ ## FAQ