Skip to content

Commit

Permalink
Nuke msgsafe, since no need to message events any more, and fix ARIA
Browse files Browse the repository at this point in the history
`pick` in `msgsafe.ts` was not type safe and was concealing an error
where HTMLElements don't have a `pick` property. Then
`MsgSafeNode.pick` would have always been absent, which would have
caused `isTextEditable` to fail to detect elements with the ARIA role
of `application`. Using real types throughout allows us to fix this by
iterating over `Element.attributes`, which appears to do the right
thing.
  • Loading branch information
saulrh committed Sep 2, 2018
1 parent 6668aef commit 8c39371
Show file tree
Hide file tree
Showing 7 changed files with 37 additions and 208 deletions.
2 changes: 0 additions & 2 deletions src/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import * as itertools from "./itertools"
import * as keyseq from "./keyseq"
import * as request from "./requests"
import * as native from "./native_background"
import * as msgsafe from "./msgsafe"
import state from "./state"
import * as webext from "./lib/webext"
import { AutoContain } from "./lib/autocontainers"
Expand All @@ -31,7 +30,6 @@ import { AutoContain } from "./lib/autocontainers"
native,
keyseq,
request,
msgsafe,
state,
webext,
l: prom => prom.then(console.log).catch(console.error),
Expand Down
2 changes: 0 additions & 2 deletions src/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import * as hinting_content from "./hinting"
import * as finding_content from "./finding"
import * as itertools from "./itertools"
import * as messaging from "./messaging"
import * as msgsafe from "./msgsafe"
import state from "./state"
import * as webext from "./lib/webext"
import Mark from "mark.js"
Expand All @@ -55,7 +54,6 @@ import * as styling from "./styling"
Mark,
keyseq,
messaging,
msgsafe,
state,
webext,
l: prom => prom.then(console.log).catch(console.error),
Expand Down
14 changes: 5 additions & 9 deletions src/controller_content.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { MsgSafeKeyboardEvent, MsgSafeNode, KeyboardEvent } from "./msgsafe"
import { isTextEditable } from "./dom"
import { contentState, ModeName } from "./state_content"
import { repeat } from "./.excmds_background.generated"
Expand Down Expand Up @@ -30,15 +29,12 @@ function* ParserController() {
let keyEvents: KeyboardEvent[] = []
try {
while (true) {
let keyevent_raw: KeyboardEvent = yield
let keyevent_safe: MsgSafeKeyboardEvent = KeyboardEvent(
keyevent_raw,
)
let keyevent: KeyboardEvent = yield

// _just to be safe_, cache this to make the following
// code more thread-safe.
let currentMode = contentState.mode
let textEditable = isTextEditable(keyevent_safe.target)
let textEditable = isTextEditable(keyevent.target as Element)

// This code was sort of the cause of the most serious bug in Tridactyl
// to date (March 2018).
Expand All @@ -65,7 +61,7 @@ function* ParserController() {
// binding, so it can't grow indefinitely unless you
// have a combination of maps that permits bindings of
// unbounded length.
keyEvents.push(keyevent_raw)
keyEvents.push(keyevent)

let response = undefined
response = (parsers[contentState.mode] as any)(keyEvents)
Expand All @@ -77,8 +73,8 @@ function* ParserController() {
)

if (response.isMatch) {
keyevent_raw.preventDefault()
keyevent_raw.stopImmediatePropagation()
keyevent.preventDefault()
keyevent.stopImmediatePropagation()
}

if (response.exstr) {
Expand Down
47 changes: 30 additions & 17 deletions src/dom.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { MsgSafeNode } from "./msgsafe"
import * as config from "./config"
import { flatten } from "./itertools"
import state from "./state"
Expand All @@ -17,24 +16,38 @@ const logger = new Logging.Logger("dom")
* @param {HTMLElement} element
* @returns {boolean}
*/
export function isTextEditable(element: MsgSafeNode) {
export function isTextEditable(element: Element) {
if (element) {
// HTML is always upper case, but XHTML is not necessarily upper case
switch (element.nodeName.toUpperCase()) {
case "INPUT":
return isEditableHTMLInput(element)
case "SELECT":
case "TEXTAREA":
case "OBJECT":
return true
if (element.nodeName.toUpperCase() === "INPUT") {
return isEditableHTMLInput(element as HTMLInputElement)
}

if (
["SELECT", "TEXTAREA", "OBJECT"].includes(
element.nodeName.toUpperCase(),
)
) {
return true
}
switch (true) {
case element.contentEditable === undefined:

// These properties are only defined on HTMLElements
if (element instanceof HTMLElement) {
if (element.contentEditable === undefined) {
// This happens on e.g. svgs.
return false
case element.contentEditable.toUpperCase() === "TRUE":
case element.role === "application":
}
if (element.contentEditable.toUpperCase() === "TRUE") {
return true
}
}

// ARIA stuff isn't pulled out into fields, so we have to
// manually inspect the attributes to find it.
for (const attr of element.attributes) {
if (attr.name === "role" && attr.value === "application") {
return true
}
}
}
return false
Expand All @@ -44,8 +57,8 @@ export function isTextEditable(element: MsgSafeNode) {
* Returns whether the passed HTML input element is editable
* @param {HTMLInputElement} element
*/
function isEditableHTMLInput(element: MsgSafeNode) {
if (element.disabled || element.readonly) return false
function isEditableHTMLInput(element: HTMLInputElement) {
if (element.disabled || element.readOnly) return false
switch (element.type) {
case undefined:
case "text":
Expand Down Expand Up @@ -255,8 +268,8 @@ export function isVisible(element: Element) {
*/
export function getAllDocumentFrames(doc = document) {
if (!(doc instanceof HTMLDocument)) return []
let frames = (<HTMLIFrameElement[] & HTMLFrameElement[]>Array.from(
doc.getElementsByTagName("iframe"),
let frames = (<HTMLIFrameElement[] & HTMLFrameElement[]>(
Array.from(doc.getElementsByTagName("iframe"))
))
.concat(Array.from(doc.getElementsByTagName("frame")))
.filter(frame => !frame.src.startsWith("moz-extension://"))
Expand Down
4 changes: 1 addition & 3 deletions src/keyseq.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,7 @@ export class MinimalKey {
}
}

import { MsgSafeKeyboardEvent } from "./msgsafe"

type KeyEventLike = MinimalKey | MsgSafeKeyboardEvent | KeyboardEvent
type KeyEventLike = MinimalKey | KeyboardEvent

// }}}

Expand Down
173 changes: 0 additions & 173 deletions src/msgsafe.ts

This file was deleted.

3 changes: 1 addition & 2 deletions src/parsers/gobblemode.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { contentState } from "../state_content"
import { isSimpleKey } from "../keyseq"
import { MsgSafeKeyboardEvent } from "../msgsafe"

/** Simple container for the gobble state. */
class GobbleState {
Expand Down Expand Up @@ -28,7 +27,7 @@ function reset() {
}

/** Receive keypress. If applicable, execute a command. */
export function parser(keys: MsgSafeKeyboardEvent[]) {
export function parser(keys: KeyboardEvent[]) {
const key = keys[0].key

if (key === "Escape") {
Expand Down

0 comments on commit 8c39371

Please sign in to comment.