tridactyl/src/msgsafe.ts

164 lines
3.7 KiB
TypeScript
Raw Normal View History

2017-10-06 03:28:14 +01:00
/** Messaging-safe copies of objects. Drops non-primitive properties.
*
* Objects to be passed by messaging API must only comprise of the following,
* otherwise they're silently dropped. The silent drop is probably a bug. If
* you include a Symbol() you get a DataCloneError.
*
* - string
* - number
* - boolean
* - null
* - undefined
* - objects containing attributes only of the above types
*
* Could just copy all primitive attributes, but then we don't get the
* interface... If we have to do this again, consider generating automatically
* from typescript/lib/lib.dom.d.ts
*
* */
const messageSafeTypes = new Set([
"string",
"number",
"boolean",
"null",
"undefined",
])
function pick (o, ...props) {
return Object.assign({}, ...props.map(prop => ({[prop]: o[prop]})))
}
/** Messaging-safe, one level copy of obj
*
* Doesn't work for special objects like Events: Object.keys() is too
* parsimonious.
*
*/
export function generic(obj): any {
let ret = {}
for (let key of Object.keys(obj)) {
if (messageSafeTypes.has(typeof obj[key])) {
ret[key] = obj[key]
}
}
return ret
}
/** Messaging-safe, one level copy of obj
*
* Also looks at prototype properties. Works for e.g. Event.
*
*/
export function generic_all_props(obj): any {
let ret = {}
for (let key in obj) {
if (messageSafeTypes.has(typeof obj[key])) {
ret[key] = obj[key]
}
}
return ret
}
export interface MsgSafeKeyboardEvent {
// KeyboardEvent
readonly altKey: boolean
readonly shiftKey: boolean
readonly metaKey: boolean
readonly ctrlKey: boolean
readonly repeat: boolean
readonly isComposing: boolean
readonly key: string
readonly code: string
readonly location: number
readonly locale: string
// Event
readonly bubbles: boolean
readonly cancelable: boolean
readonly composed: boolean
readonly defaultPrevented: boolean
readonly eventPhase: number
readonly timeStamp: string
readonly type: string
readonly isTrusted: boolean
readonly target: MsgSafeNode
}
/** MsgSafe copy of keyevent. */
export function KeyboardEvent(ke): MsgSafeKeyboardEvent {
let copy = pick(
ke,
'shiftKey', 'metaKey', 'altKey', 'ctrlKey', 'repeat', 'key',
'bubbles', 'composed', 'defaultPrevented', 'eventPhase',
'timeStamp', 'type', 'isTrusted'
)
copy.target = Node(ke.target)
// Works but adds > 200 properties.
// let copy = generic_all_props(ke)
// copy.target = generic_all_props(ke.target)
return copy
}
export interface MsgSafeNode {
// w3 Node interface
readonly nodeName: string
readonly nodeValue: string
readonly nodeType: number
readonly namespaceURI: string
readonly prefix?: string
2017-10-06 03:28:14 +01:00
readonly localName: string
readonly baseURI: string
readonly textContent: string
// w3 Element interface
readonly tagName?: string
2017-10-06 03:28:14 +01:00
// InputElement
readonly type?: string
2017-10-06 03:28:14 +01:00
// WAI-ARIA
readonly role?: string
2017-10-06 03:28:14 +01:00
// unknown spec
readonly contentEditable?: string
readonly isContentEditable?: boolean
readonly disabled?: boolean
readonly readonly?: boolean
2017-10-06 03:28:14 +01:00
}
export function Node(node: HTMLElement): MsgSafeNode {
return pick(
node,
// w3 Node interface
'nodeName',
'nodeValue',
'nodeType',
'namespaceURI',
'prefix',
'localName',
'baseURI',
'textContent',
// w3 Element interface
'tagName',
// InputElement
'type',
// WAI-ARIA
'role',
// unknown spec
'contentEditable',
'isContentEditable',
'disabled',
'readonly',
)
}