UNPKG

@maxgraph/core

Version:

maxGraph is a fully client side JavaScript diagramming library that uses SVG and HTML for rendering.

307 lines (303 loc) 10.2 kB
import Rectangle from '../geometry/Rectangle.js'; import Cell from '../cell/Cell.js'; import InternalMouseEvent from '../event/InternalMouseEvent.js'; import CellState from '../cell/CellState.js'; import EventSource from '../event/EventSource.js'; import type { AbstractGraph } from '../AbstractGraph.js'; import type { AlignValue, GraphPlugin } from '../../types.js'; /** * In-place editor for the graph. * * To control this editor, use: * - {@link AbstractGraph.invokesStopCellEditing} * - {@link AbstractGraph.enterStopsCellEditing} * - {@link AbstractGraph.escapeEnabled} * * If {@link AbstractGraph.enterStopsCellEditing} is `true` then ctrl-enter or shift-enter can be used to create a linefeed. * * The F2 (accept change) and escape keys (undo change) can always be used to stop editing. * * To customize the location of the textbox in the graph, override {@link getEditorBounds} as follows: * * ```javascript * graph.cellEditor.getEditorBounds = (state) => { * const result = super.getEditorBounds(state); * * if (this.graph.getDataModel().isEdge(state.cell)) { * result.x = state.getCenterX() - result.width / 2; * result.y = state.getCenterY() - result.height / 2; * } * * return result; * }; * ``` * * Note that this hook is only called if {@link autoSize} is `false`. * If {@link autoSize} is `true`, then {@link Shape.getLabelBounds} is used to compute the current bounds of the textbox. * * The textarea uses the `mxCellEditor` CSS class. You can modify this class in your custom CSS. * Example: * * To only allow numeric input in the in-place editor, use the following code. * * ```javascript * const text = graph.cellEditor.textarea; * * InternalEvent.addListener(text, 'keydown', function (evt) { * if (!(evt.keyCode >= 48 && evt.keyCode <= 57) && * !(evt.keyCode >= 96 && evt.keyCode <= 105)) { * InternalEvent.consume(evt); * } * }); * ``` * * ### Placeholder * * To implement a placeholder for cells without a label, use the {@link emptyLabelText} variable. * * * ### Resize the textarea * * Resize of the textarea is disabled by default. * If you want to enable this feature extend {@link init} and set `this.textarea.style.resize = ''`. * * * ### Editing on key press * * To start editing on a key press event, the container of the graph * should have focus or a focusable parent should be used to add the * key press handler as follows. * * ```javascript * InternalEvent.addListener(graph.container, 'keypress', (evt) => { * if (!graph.isEditing() && !graph.isSelectionEmpty() && evt.which !== 0 * && !eventUtils.isAltDown(evt) * && !eventUtils.isControlDown(evt) * && !eventUtils.isMetaDown(evt)) { * graph.startEditing(); * * if (Client.IS_FF) { * graph.cellEditor.textarea.value = String.fromCharCode(evt.which); * } * } * }); * ``` * * To allow focus for a DIV, and hence to receive key press events, some browsers require it to have a valid tabindex attribute. * In this case the following code may be used to keep the container focused. * * ```javascript * const graphFireMouseEvent = graph.fireMouseEvent; * graph.fireMouseEvent = (evtName, me, sender) => { * if (evtName == mxEvent.MOUSE_DOWN) { * this.container.focus(); * } * * graphFireMouseEvent.apply(this, [evtName, me, sender]); * }; * ``` * * @category Plugin */ declare class CellEditorHandler implements GraphPlugin { static pluginId: string; constructor(graph: AbstractGraph); changeHandler: (sender: EventSource) => void; zoomHandler: () => void; clearOnChange: boolean; bounds: Rectangle | null; resizeThread: number | null; textDirection: '' | 'auto' | 'ltr' | 'rtl' | null; /** * Reference to the enclosing {@link AbstractGraph}. */ graph: AbstractGraph; /** * Holds the DIV that is used for text editing. Note that this may be null before the first * edit. Instantiated in <init>. */ textarea: HTMLElement | null; /** * Reference to the <Cell> that is currently being edited. */ editingCell: Cell | null; /** * Reference to the event that was used to start editing. */ trigger: InternalMouseEvent | MouseEvent | null; /** * Specifies if the label has been modified. */ modified: boolean; /** * Specifies if the textarea should be resized while the text is being edited. * Default is true. */ autoSize: boolean; /** * Specifies if the text should be selected when editing starts. Default is * true. */ selectText: boolean; /** * Text to be displayed for empty labels. Default is '' or '<br>' in Firefox as * a workaround for the missing cursor bug for empty content editable. This can * be set to eg. "[Type Here]" to easier visualize editing of empty labels. The * value is only displayed before the first keystroke and is never used as the * actual editing value. */ emptyLabelText: string; /** * If true, pressing the escape key will stop editing and not accept the new * value. Change this to false to accept the new value on escape, and cancel * editing on Shift+Escape instead. Default is true. */ escapeCancelsEditing: boolean; /** * Reference to the label DOM node that has been hidden. */ textNode: SVGGElement | null; /** * Specifies the zIndex for the textarea. Default is 5. */ zIndex: number; /** * Defines the minimum width and height to be used in <resize>. Default is 0x20px. */ minResize: Rectangle; /** * Correction factor for word wrapping width. Default is 2 in quirks, 0 in IE * 11 and 1 in all other browsers and modes. */ wordWrapPadding: number; /** * If <focusLost> should be called if <textarea> loses the focus. Default is false. */ blurEnabled: boolean; /** * Holds the initial editing value to check if the current value was modified. */ initialValue: string | null; /** * Holds the current temporary horizontal alignment for the cell style. If this * is modified then the current text alignment is changed and the cell style is * updated when the value is applied. */ align: AlignValue | null; /** * Creates the {@link textarea} and installs the event listeners. The key handler * updates the {@link modified} state. */ init(): void; /** * Called in <stopEditing> if cancel is false to invoke {@link AbstractGraph.labelChanged}. */ applyValue(state: CellState, value: any): void; /** * Sets the temporary horizontal alignment for the current editing session. */ setAlign(align: AlignValue): void; /** * Gets the initial editing value for the given cell. */ getInitialValue(state: CellState, trigger: MouseEvent | null): string; /** * Returns the current editing value. */ getCurrentValue(state: CellState): string | null; /** * Returns true if <escapeCancelsEditing> is true and shift, control and meta * are not pressed. */ isCancelEditingKeyEvent(evt: MouseEvent | KeyboardEvent): boolean; /** * Installs listeners for focus, change and standard key event handling. */ installListeners(elt: HTMLElement): void; /** * Returns true if the given keydown event should stop cell editing. This * returns true if F2 is pressed of if {@link AbstractGraph.enterStopsCellEditing} is true * and enter is pressed without control or shift. */ isStopEditingEvent(evt: KeyboardEvent): boolean; /** * Returns true if this editor is the source for the given native event. */ isEventSource(evt: MouseEvent | KeyboardEvent): boolean; /** * Returns {@link odified}. */ resize(): void; /** * Called if the textarea has lost focus. */ focusLost(): void; /** * Returns the background color for the in-place editor. This implementation * always returns NONE. */ getBackgroundColor(state: CellState): string; /** * Starts the editor for the given cell. * * @param cell <Cell> to start editing. * @param trigger Optional mouse event that triggered the editor. */ startEditing(cell: Cell, trigger?: MouseEvent | null): void; /** * Returns <selectText>. */ isSelectText(): boolean; /** clearSelection() { const selection = window.getSelection(); if (selection) { if (selection.empty) { selection.empty(); } else if (selection.removeAllRanges) { selection.removeAllRanges(); } } } /** * Stops the editor and applies the value if cancel is false. */ stopEditing(cancel?: boolean): void; /** * Prepares the textarea for getting its value in <stopEditing>. * This implementation removes the extra trailing linefeed in Firefox. */ prepareTextarea(): void; /** * Returns true if the label should be hidden while the cell is being * edited. */ isHideLabel(state?: CellState | null): boolean; /** * Returns the minimum width and height for editing the given state. */ getMinimumSize(state: CellState): Rectangle; /** * Returns the {@link Rectangle} that defines the bounds of the editor. */ getEditorBounds(state: CellState): Rectangle; /** * Returns the initial label value to be used of the label of the given * cell is empty. This label is displayed and cleared on the first keystroke. * This implementation returns <emptyLabelText>. * * @param cell <Cell> for which a text for an empty editing box should be * returned. */ getEmptyLabelText(cell?: Cell | null): string; /** * Returns the cell that is currently being edited or null if no cell is * being edited. */ getEditingCell(): Cell | null; /** * Destroys the editor and removes all associated resources. */ onDestroy(): void; } export default CellEditorHandler;