Skip to content

Commit

Permalink
add editor => editor and editor/text
Browse files Browse the repository at this point in the history
  • Loading branch information
myliang committed Apr 14, 2023
1 parent 5092fa2 commit a17688f
Show file tree
Hide file tree
Showing 7 changed files with 197 additions and 228 deletions.
156 changes: 28 additions & 128 deletions src/editor/index.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,27 @@
import HElement, { h } from '../element';
import { borderWidth, stylePrefix } from '../config';
import { borderWidth } from '../config';
import { Rect } from '@wolf-table/table-renderer';
import { DataCell } from '../data';

type MoveDirection = 'up' | 'down' | 'left' | 'right' | 'none';
type InputChanger = (value: string) => void;
type moveChanger = (direction: MoveDirection, value: string) => void;
type MoveChanger = (direction: MoveDirection) => void;
type Changer = (value: DataCell) => void;

/**
* new -> cellIndex -> rect -> target -> hide
*/
export default class Editor {
_: HElement = h('div', `${stylePrefix}-editor`);
_text: HElement = h('textarea', '');
_textMeasure: HElement = h('div', 'measure');
_: HElement;
_target: HElement | null = null;

_rect: Rect | null = null;
_value: string = '';
_editing: boolean = false;
_value: DataCell;
_visible: boolean = false;

_maxWidth: () => number;
_maxHeight: () => number;
_fontSize: string;
_fontFamily: string;

_inputChange: InputChanger = () => {};
_moveChange: moveChanger = () => {};

constructor(
target: HElement,
maxWidth: () => number,
maxHeight: () => number,
fontSize: string,
fontFamily: string
) {
this._maxHeight = maxHeight;
this._maxWidth = maxWidth;
this._fontFamily = fontFamily;
this._fontSize = fontSize;
_moveChanger: MoveChanger = () => {};
_changer: Changer = () => {};

target.append(this._);
this._.append(this._text, this._textMeasure);
this._text
.on('keydown', (evt) => {
keydownHandler(this, evt);
})
.on('input', ({ target }) => {
const { value } = target;
this._editing = true;
this._value = value;
this._inputChange(target.value);
resizeSize(this);
});
constructor(cssClass: String) {
this._ = h('div', cssClass);
}

get visible() {
Expand All @@ -62,22 +34,17 @@ export default class Editor {
return this;
}

value(): string;
value(text: string): void;
value(text?: string) {
if (text !== undefined) {
this._value = text;
this._text.value(text);
resizeSize(this);
} else {
return this._value;
}
cellIndex(r: number, c: number): Editor {
return this;
}

finished() {
if (this._editing) {
this._moveChange('none', this._value);
}
value(v: DataCell): Editor {
this._value = v;
return this;
}

changed() {
this._changer(this._value);
this.hide();
}

Expand All @@ -92,90 +59,23 @@ export default class Editor {
width: width - borderWidth,
height: height - borderWidth,
}).show();
setTimeout(() => {
const position = this._value.length;
const el = this._text.element();
el.focus();
el.setSelectionRange(position, position);
}, 0);
}
return this;
}

hide() {
this._editing = false;
this._visible = false;
this.value('');
this._.hide();
}

inputChange(value: InputChanger) {
this._inputChange = value;
}

moveChange(value: moveChanger) {
this._moveChange = value;
}
}

function resizeSize(editor: Editor) {
const { _, _value, _rect, _textMeasure, _target } = editor;

// const txts = _value.split('\n');
let measureHtml = _value.replace('\n', '<br/>');
if (_value.endsWith('\n')) measureHtml += 'T';
_textMeasure.html(measureHtml);

if (_rect && _target) {
const padding = parseInt(
_textMeasure.computedStyle().getPropertyValue('padding')
);
const toffset = _target.offset();
const maxWidth = toffset.width - _rect.x - borderWidth;
const maxHeight = toffset.height - _rect.y - borderWidth;
_.css('max-width', `${maxWidth}px`);
_textMeasure.css('max-width', `${maxWidth - padding * 2}px`);
const { width, height } = _textMeasure.rect();
const minWidth = _rect.width - borderWidth;
if (width > minWidth) {
_.css({ width: width });
}
if (height > _rect.height && height <= maxHeight) {
_.css({ height: height });
} else if (height < _rect.height) {
_.css({ height: _rect.height - borderWidth });
}
moveChanger(value: MoveChanger) {
this._moveChanger = value;
return this;
}
}

function keydownHandler(editor: Editor, evt: any) {
const { code, shiftKey, metaKey, altKey, ctrlKey, target } = evt;
const moveChanger = (direction: MoveDirection) => {
editor._moveChange(direction, editor._value);
editor.hide();
};
// console.log('code:', code, shiftKey, ctrlKey, isComposing);
if (code === 'Enter') {
if (ctrlKey || metaKey || altKey) {
target.value += '\n';
editor.value(target.value);
} else if (shiftKey) {
// move to up cell
moveChanger('up');
} else {
// move to down cell
moveChanger('down');
}
evt.preventDefault();
} else if (code === 'Tab' && !ctrlKey && !metaKey && !altKey) {
if (shiftKey) {
// move to left cell
moveChanger('left');
} else {
// move to right cell
moveChanger('right');
}
evt.preventDefault();
// evt.stopPropagation();
changer(value: Changer) {
this._changer = value;
return this;
}
}
120 changes: 120 additions & 0 deletions src/editor/text/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import HElement, { h } from '../../element';
import { borderWidth, stylePrefix } from '../../config';
import { Rect } from '@wolf-table/table-renderer';
import Editor from '..';
import { MoveDirection } from '../..';
import { cellValueString, DataCell } from '../../data';

export default class TextEditor extends Editor {
_text: HElement = h('textarea', '');
_textMeasure: HElement = h('div', 'measure');

_editing: boolean = false;

constructor() {
super(`${stylePrefix}-editor`);
this._.append(this._text, this._textMeasure);
this._text
.on('keydown', (evt) => {
keydownHandler(this, evt);
})
.on('input', ({ target }) => {
const { value } = target;
this._editing = true;
this._value = value;
this._changer(value);
resizeSize(this);
});
}

value(v: DataCell): Editor {
super.value(v);
this._text.value(cellValueString(v) || '');
resizeSize(this);
return this;
}

rect(rect: Rect | null) {
super.rect(rect);
if (rect) {
setTimeout(() => {
const { _value } = this;
let position = 0;
if (_value !== null) {
position = cellValueString(_value).length;
}
const el = this._text.element();
el.focus();
el.setSelectionRange(position, position);
}, 0);
}
return this;
}

hide() {
super.hide();
this._editing = false;
}
}

function resizeSize(editor: TextEditor) {
const { _, _value, _rect, _textMeasure, _target } = editor;
if (typeof _value !== 'string') return;
// const txts = _value.split('\n');
let measureHtml = _value.replace('\n', '<br/>');
if (_value.endsWith('\n')) measureHtml += 'T';
_textMeasure.html(measureHtml);

if (_rect && _target) {
const padding = parseInt(
_textMeasure.computedStyle().getPropertyValue('padding')
);
const toffset = _target.offset();
const maxWidth = toffset.width - _rect.x - borderWidth;
const maxHeight = toffset.height - _rect.y - borderWidth;
_.css('max-width', `${maxWidth}px`);
_textMeasure.css('max-width', `${maxWidth - padding * 2}px`);
const { width, height } = _textMeasure.rect();
const minWidth = _rect.width - borderWidth;
if (width > minWidth) {
_.css({ width: width });
}
if (height > _rect.height && height <= maxHeight) {
_.css({ height: height });
} else if (height < _rect.height) {
_.css({ height: _rect.height - borderWidth });
}
}
}

function keydownHandler(editor: TextEditor, evt: any) {
const { code, shiftKey, metaKey, altKey, ctrlKey, target } = evt;
const moveChanger = (direction: MoveDirection) => {
editor._moveChanger(direction);
editor.hide();
};
// console.log('code:', code, shiftKey, ctrlKey, isComposing);
if (code === 'Enter') {
if (ctrlKey || metaKey || altKey) {
target.value += '\n';
editor.value(target.value);
} else if (shiftKey) {
// move to up cell
moveChanger('up');
} else {
// move to down cell
moveChanger('down');
}
evt.preventDefault();
} else if (code === 'Tab' && !ctrlKey && !metaKey && !altKey) {
if (shiftKey) {
// move to left cell
moveChanger('left');
} else {
// move to right cell
moveChanger('right');
}
evt.preventDefault();
// evt.stopPropagation();
}
}
48 changes: 31 additions & 17 deletions src/index.editor.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,30 @@
import Table from '.';
import Editor from './editor';
import selector from './index.selector';
import { cellValueString } from './data';
import { DataCell } from './data';
import TextEditor from './editor/text';
import Editor from './editor';

function init(t: Table) {
t._editor = new Editor(t._container, t._width, t._height, `13px`, 'Lato');
const { _editor, _selector } = t;
// _editor.inputChange((text) => {});
_editor.moveChange((direction, value) => {
selector.setCellValue(t, value);
function get(t: Table, cell: DataCell) {
let type = 'text';
if (cell instanceof Object && cell.type) type = cell.type;
const { _editors } = t;
if (!_editors.has(type)) {
_editors.set(type, new TextEditor());
}
const editor: Editor = _editors.get(type);
editor.changer((value) => {
if (value !== null) {
selector.setCellValue(t, value);
}
});
editor.moveChanger((direction) => {
const { _selector } = t;
if (direction !== 'none' && _selector) {
selector.move(t, true, direction, 1);
t._canvas.focus();
}
});
return editor;
}

function move(t: Table) {
Expand All @@ -32,24 +43,27 @@ function move(t: Table) {
}

function reset(t: Table) {
const { _selector, _editor } = t;
if (_selector && _editor) {
const { _selector } = t;
if (_selector) {
const { _focusRange, _focusArea } = _selector;
if (_focusRange && _focusArea) {
const { _rect, _target } = _focusArea;
if (_rect && _target) {
_editor.rect(_rect).target(_target);
}
const cell = t.cell(_focusRange.startRow, _focusRange.startCol);
if (cell) {
_editor.value(cellValueString(cell));
const { startRow, startCol } = _focusRange;
const cell = t.cell(startRow, startCol);
const editor = get(t, cell);
t._editor = editor;
if (editor && _rect && _target) {
// console.log('row:', startRow, ', col:', startCol, ', rect:', _rect);
editor.cellIndex(startRow, startCol).rect(_rect).target(_target);
if (cell) {
editor.value(cell);
}
}
}
}
}

export default {
init,
move,
reset,
};
Loading

0 comments on commit a17688f

Please sign in to comment.