144 lines
3.5 KiB
Plaintext
144 lines
3.5 KiB
Plaintext
// @flow
|
|
/*eslint no-unused-vars: off*/
|
|
|
|
import EventEmitter from "eventemitter3"
|
|
|
|
import { createCustomEvent } from "./utils"
|
|
import SearchResult from "./search_result"
|
|
|
|
/** @typedef */
|
|
export type CursorOffset = {
|
|
lineHeight: number,
|
|
top: number,
|
|
left?: number,
|
|
right?: number,
|
|
clientTop?: number
|
|
}
|
|
|
|
type KeyCode = "ESC" | "ENTER" | "UP" | "DOWN" | "OTHER"
|
|
|
|
/**
|
|
* Abstract class representing a editor target.
|
|
*
|
|
* Editor classes must implement `#applySearchResult`, `#getCursorOffset` and
|
|
* `#getBeforeCursor` methods.
|
|
*
|
|
* Editor classes must invoke `#emitMoveEvent`, `#emitEnterEvent`,
|
|
* `#emitChangeEvent` and `#emitEscEvent` at proper timing.
|
|
*
|
|
* @abstract
|
|
*/
|
|
export default class Editor extends EventEmitter {
|
|
/**
|
|
* It is called when associated textcomplete object is destroyed.
|
|
*
|
|
* @return {this}
|
|
*/
|
|
destroy() {
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* It is called when a search result is selected by a user.
|
|
*/
|
|
applySearchResult(_: SearchResult): void {
|
|
throw new Error("Not implemented.")
|
|
}
|
|
|
|
/**
|
|
* The input cursor's absolute coordinates from the window's left
|
|
* top corner.
|
|
*/
|
|
getCursorOffset(): CursorOffset {
|
|
throw new Error("Not implemented.")
|
|
}
|
|
|
|
/**
|
|
* Editor string value from head to cursor.
|
|
* Returns null if selection type is range not cursor.
|
|
*/
|
|
getBeforeCursor(): ?string {
|
|
throw new Error("Not implemented.")
|
|
}
|
|
|
|
/**
|
|
* Emit a move event, which moves active dropdown element.
|
|
* Child class must call this method at proper timing with proper parameter.
|
|
*
|
|
* @see {@link Textarea} for live example.
|
|
*/
|
|
emitMoveEvent(code: "UP" | "DOWN"): CustomEvent {
|
|
const moveEvent = createCustomEvent("move", {
|
|
cancelable: true,
|
|
detail: {
|
|
code: code,
|
|
},
|
|
})
|
|
this.emit("move", moveEvent)
|
|
return moveEvent
|
|
}
|
|
|
|
/**
|
|
* Emit a enter event, which selects current search result.
|
|
* Child class must call this method at proper timing.
|
|
*
|
|
* @see {@link Textarea} for live example.
|
|
*/
|
|
emitEnterEvent(): CustomEvent {
|
|
const enterEvent = createCustomEvent("enter", { cancelable: true })
|
|
this.emit("enter", enterEvent)
|
|
return enterEvent
|
|
}
|
|
|
|
/**
|
|
* Emit a change event, which triggers auto completion.
|
|
* Child class must call this method at proper timing.
|
|
*
|
|
* @see {@link Textarea} for live example.
|
|
*/
|
|
emitChangeEvent(): CustomEvent {
|
|
const changeEvent = createCustomEvent("change", {
|
|
detail: {
|
|
beforeCursor: this.getBeforeCursor(),
|
|
},
|
|
})
|
|
this.emit("change", changeEvent)
|
|
return changeEvent
|
|
}
|
|
|
|
/**
|
|
* Emit a esc event, which hides dropdown element.
|
|
* Child class must call this method at proper timing.
|
|
*
|
|
* @see {@link Textarea} for live example.
|
|
*/
|
|
emitEscEvent(): CustomEvent {
|
|
const escEvent = createCustomEvent("esc", { cancelable: true })
|
|
this.emit("esc", escEvent)
|
|
return escEvent
|
|
}
|
|
|
|
/**
|
|
* Helper method for parsing KeyboardEvent.
|
|
*
|
|
* @see {@link Textarea} for live example.
|
|
*/
|
|
getCode(e: KeyboardEvent): KeyCode {
|
|
return e.keyCode === 9
|
|
? "ENTER" // tab
|
|
: e.keyCode === 13
|
|
? "ENTER" // enter
|
|
: e.keyCode === 27
|
|
? "ESC" // esc
|
|
: e.keyCode === 38
|
|
? "UP" // up
|
|
: e.keyCode === 40
|
|
? "DOWN" // down
|
|
: e.keyCode === 78 && e.ctrlKey
|
|
? "DOWN" // ctrl-n
|
|
: e.keyCode === 80 && e.ctrlKey
|
|
? "UP" // ctrl-p
|
|
: "OTHER"
|
|
}
|
|
}
|