2017-10-06 03:28:14 +01:00
|
|
|
import {MsgSafeKeyboardEvent, MsgSafeNode} from './msgsafe'
|
2017-10-02 00:59:51 +01:00
|
|
|
import * as Parsing from "./parsing"
|
2017-10-05 18:01:44 +01:00
|
|
|
import state from "./state"
|
|
|
|
|
|
|
|
// {{{ From saka-key lib/dom.js, under Apachev2
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Given a DOM element, returns true if you can edit it with key presses or
|
|
|
|
* if the element is of a type that should handle its own keypresses
|
|
|
|
* (e.g. role=application for google docs/sheets)
|
|
|
|
* TODO: work on case sensitivity
|
|
|
|
* consider all the possible cases
|
|
|
|
* @param {HTMLElement} element
|
|
|
|
* @returns {boolean}
|
|
|
|
*/
|
2017-10-06 03:28:14 +01:00
|
|
|
export function isTextEditable (element: MsgSafeNode) {
|
2017-10-05 18:01:44 +01:00
|
|
|
if (element) {
|
|
|
|
switch (element.nodeName) {
|
|
|
|
case 'INPUT':
|
|
|
|
return isEditableHTMLInput(element)
|
|
|
|
case 'TEXTAREA':
|
|
|
|
case 'OBJECT':
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
switch (true) {
|
|
|
|
case element.contentEditable.toUpperCase() === 'TRUE':
|
|
|
|
case element.role === 'application':
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns whether the passed HTML input element is editable
|
|
|
|
* @param {HTMLInputElement} element
|
|
|
|
*/
|
2017-10-06 03:28:14 +01:00
|
|
|
function isEditableHTMLInput (element: MsgSafeNode) {
|
2017-10-05 18:01:44 +01:00
|
|
|
if (element.disabled || element.readonly) return false
|
|
|
|
switch (element.type) {
|
|
|
|
case undefined:
|
|
|
|
case 'text':
|
|
|
|
case 'search':
|
|
|
|
case 'email':
|
|
|
|
case 'url':
|
|
|
|
case 'number':
|
|
|
|
case 'password':
|
|
|
|
case 'date':
|
|
|
|
case 'tel':
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// }}}
|
2017-10-02 00:59:51 +01:00
|
|
|
|
|
|
|
/** Accepts keyevents, resolves them to maps, maps to exstrs, executes exstrs */
|
|
|
|
function *ParserController () {
|
|
|
|
while (true) {
|
|
|
|
let ex_str = ""
|
|
|
|
let keys = []
|
|
|
|
try {
|
|
|
|
while (true) {
|
2017-10-06 03:28:14 +01:00
|
|
|
let keyevent: MsgSafeKeyboardEvent = yield
|
2017-10-02 00:59:51 +01:00
|
|
|
let keypress = keyevent.key
|
|
|
|
|
2017-10-05 18:01:44 +01:00
|
|
|
if (isTextEditable(keyevent.target)) {
|
|
|
|
state.mode = "INSERT"
|
|
|
|
} else {
|
|
|
|
state.mode = "NORMAL"
|
|
|
|
}
|
2017-10-06 03:28:14 +01:00
|
|
|
console.log(keyevent, state.mode)
|
2017-10-05 18:01:44 +01:00
|
|
|
|
2017-10-02 00:59:51 +01:00
|
|
|
// Special keys (e.g. Backspace) are not handled properly
|
|
|
|
// yet. So drop them. This also drops all modifier keys.
|
|
|
|
// When we put in handling for other special keys, remember
|
|
|
|
// to continue to ban modifiers.
|
|
|
|
if (keypress.length > 1) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
keys.push(keypress)
|
|
|
|
let response = Parsing.normalmode.parser(keys)
|
2017-10-05 18:01:44 +01:00
|
|
|
switch(state.mode){
|
2017-10-02 21:09:10 +01:00
|
|
|
case "NORMAL":
|
|
|
|
response = Parsing.normalmode.parser(keys)
|
|
|
|
break
|
|
|
|
|
|
|
|
case "INSERT":
|
|
|
|
response = Parsing.insertmode.parser(keys)
|
|
|
|
break
|
|
|
|
}
|
2017-10-02 00:59:51 +01:00
|
|
|
|
|
|
|
console.debug(keys, response)
|
|
|
|
|
|
|
|
if (response.ex_str){
|
|
|
|
ex_str = response.ex_str
|
|
|
|
break
|
|
|
|
} else {
|
|
|
|
keys = response.keys
|
|
|
|
}
|
|
|
|
}
|
|
|
|
acceptExCmd(ex_str)
|
|
|
|
} catch (e) {
|
|
|
|
// Rumsfeldian errors are caught here
|
|
|
|
console.error("Tridactyl ParserController fatally wounded:", e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let generator = ParserController() // var rather than let stops weirdness in repl.
|
|
|
|
generator.next()
|
|
|
|
|
|
|
|
/** Feed keys to the ParserController */
|
2017-10-06 03:28:14 +01:00
|
|
|
export function acceptKey(keyevent: MsgSafeKeyboardEvent) {
|
2017-10-02 00:59:51 +01:00
|
|
|
generator.next(keyevent)
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Parse and execute ExCmds */
|
|
|
|
export function acceptExCmd(ex_str: string) {
|
2017-10-05 13:26:28 +01:00
|
|
|
// TODO: Errors should go to CommandLine.
|
2017-10-02 00:59:51 +01:00
|
|
|
try {
|
2017-10-05 13:26:28 +01:00
|
|
|
let [func, args] = Parsing.exmode.parser(ex_str)
|
|
|
|
try {
|
|
|
|
func(...args)
|
|
|
|
} catch (e) {
|
|
|
|
// Errors from func are caught here (e.g. no next tab)
|
|
|
|
console.error(e)
|
|
|
|
}
|
2017-10-02 00:59:51 +01:00
|
|
|
} catch (e) {
|
2017-10-05 13:26:28 +01:00
|
|
|
// Errors from parser caught here
|
2017-10-02 00:59:51 +01:00
|
|
|
console.error(e)
|
|
|
|
}
|
|
|
|
}
|