Skip to content

Commit

Permalink
Improve formula editing process within cells
Browse files Browse the repository at this point in the history
  • Loading branch information
chieveit authored and jkirschner committed May 13, 2021
1 parent 549f5cf commit ee61ed6
Show file tree
Hide file tree
Showing 6 changed files with 394 additions and 115 deletions.
191 changes: 86 additions & 105 deletions src/component/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,17 @@ import Suggest from './suggest';
import Datepicker from './datepicker';
import { cssPrefix } from '../config';
// import { mouseMoveUp } from '../event';

function resetTextareaSize() {
const { inputText } = this;
if (!/^\s*$/.test(inputText)) {
const {
textlineEl, textEl, areaOffset,
} = this;
const txts = inputText.split('\n');
const maxTxtSize = Math.max(...txts.map(it => it.length));
const tlOffset = textlineEl.offset();
const fontWidth = tlOffset.width / inputText.length;
const tlineWidth = (maxTxtSize + 1) * fontWidth + 5;
const maxWidth = this.viewFn().width - areaOffset.left - fontWidth;
let h1 = txts.length;
if (tlineWidth > areaOffset.width) {
let twidth = tlineWidth;
if (tlineWidth > maxWidth) {
twidth = maxWidth;
h1 += parseInt(tlineWidth / maxWidth, 10);
h1 += (tlineWidth % maxWidth) > 0 ? 1 : 0;
}
textEl.css('width', `${twidth}px`);
}
h1 *= this.rowHeight;
if (h1 > areaOffset.height) {
textEl.css('height', `${h1}px`);
}
}
}
import Formula from './formula';
import { setCaretPosition, saveCaretPosition } from '../core/caret';

function insertText({ target }, itxt) {
const { value, selectionEnd } = target;
const ntxt = `${value.slice(0, selectionEnd)}${itxt}${value.slice(selectionEnd)}`;
target.value = ntxt;
target.setSelectionRange(selectionEnd + 1, selectionEnd + 1);

this.inputText = ntxt;
this.textlineEl.html(ntxt);
resetTextareaSize.call(this);
this.render();

setCaretPosition(target, selectionEnd + 1);
}

function keydownEventHandler(evt) {
Expand All @@ -55,72 +27,36 @@ function keydownEventHandler(evt) {
if (keyCode === 13 && !altKey) evt.preventDefault();
}

function inputEventHandler(evt) {
const v = evt.target.value;
function inputEventHandler() {
// save caret position
const restore = saveCaretPosition(this.textEl.el);

const text = this.textEl.el.textContent;
this.inputText = text;
// console.log(evt, 'v:', v);
const { suggest, textlineEl, validator } = this;
const { cell } = this;
if (cell !== null) {
if (('editable' in cell && cell.editable === true) || (cell.editable === undefined)) {
this.inputText = v;
if (validator) {
if (validator.type === 'list') {
suggest.search(v);
} else {
suggest.hide();
}
} else {
const start = v.lastIndexOf('=');
if (start !== -1) {
suggest.search(v.substring(start + 1));
} else {
suggest.hide();
}
}
textlineEl.html(v);
resetTextareaSize.call(this);
this.change('input', v);

const { suggest, validator } = this;

if (validator) {
if (validator.type === 'list') {
suggest.search(text);
} else {
evt.target.value = cell.text;
suggest.hide();
}
} else {
this.inputText = v;
if (validator) {
if (validator.type === 'list') {
suggest.search(v);
} else {
suggest.hide();
}
const start = text.lastIndexOf('=');
if (start !== -1) {
suggest.search(text.substring(start + 1));
} else {
const start = v.lastIndexOf('=');
if (start !== -1) {
suggest.search(v.substring(start + 1));
} else {
suggest.hide();
}
suggest.hide();
}
textlineEl.html(v);
resetTextareaSize.call(this);
this.change('input', v);
}
}
this.render();
this.change('input', text);

function setTextareaRange(position) {
const { el } = this.textEl;
setTimeout(() => {
el.focus();
el.setSelectionRange(position, position);
}, 0);
}

function setText(text, position) {
const { textEl, textlineEl } = this;
// firefox bug
textEl.el.blur();

textEl.val(text);
textlineEl.html(text);
setTextareaRange.call(this, position);
// restore caret postion
// to avoid caret postion missing when this.el.innerHTML changed
restore();
}

function suggestItemClick(it) {
Expand All @@ -143,7 +79,8 @@ function suggestItemClick(it) {
position = this.inputText.length;
this.inputText += `)${eit}`;
}
setText.call(this, this.inputText, position);
this.render();
setCaretPosition(this.textEl.el, position);
}

function resetSuggestItems() {
Expand All @@ -159,9 +96,10 @@ function dateFormat(d) {
}

export default class Editor {
constructor(formulas, viewFn, rowHeight) {
constructor(formulas, viewFn, data) {
this.data = data;
this.viewFn = viewFn;
this.rowHeight = rowHeight;
this.rowHeight = data.rows.height;
this.formulas = formulas;
this.suggest = new Suggest(formulas, (it) => {
suggestItemClick.call(this, it);
Expand All @@ -172,27 +110,34 @@ export default class Editor {
this.setText(dateFormat(d));
this.clear();
});
this.composing = false;
this.areaEl = h('div', `${cssPrefix}-editor-area`)
.children(
this.textEl = h('textarea', '')
this.textEl = h('div', 'textarea')
.attr('contenteditable', 'true')
.on('input', evt => inputEventHandler.call(this, evt))
.on('paste.stop', () => {})
.on('keydown', evt => keydownEventHandler.call(this, evt)),
.on('paste.stop', () => { })
.on('keydown', evt => keydownEventHandler.call(this, evt))
.on('compositionstart.stop', () => this.composing = true)
.on('compositionend.stop', () => this.composing = false),
this.textlineEl = h('div', 'textline'),
this.suggest.el,
this.datepicker.el,
)
.on('mousemove.stop', () => {})
.on('mousedown.stop', () => {});
.on('mousemove.stop', () => { })
.on('mousedown.stop', () => { });
this.el = h('div', `${cssPrefix}-editor`)
.child(this.areaEl).hide();
.children(this.areaEl).hide();
this.cellEl = h('div', `${cssPrefix}-formula-cell`)
this.suggest.bindInputEvents(this.textEl);

this.areaOffset = null;
this.freeze = { w: 0, h: 0 };
this.cell = null;
this.inputText = '';
this.change = () => {};
this.change = () => { };

this.formula = new Formula(this);
}

setFreezeLengths(width, height) {
Expand All @@ -212,13 +157,19 @@ export default class Editor {
this.el.hide();
this.textEl.val('');
this.textlineEl.html('');
this.formula.clear();
resetSuggestItems.call(this);
this.datepicker.hide();
}

resetData(data) {
this.data = data;
this.rowHeight = data.rows.height;
}

setOffset(offset, suggestPosition = 'top') {
const {
textEl, areaEl, suggest, freeze, el,
textEl, areaEl, suggest, freeze, el, formula
} = this;
if (offset) {
this.areaOffset = offset;
Expand All @@ -240,11 +191,13 @@ export default class Editor {
}
el.offset(elOffset);
areaEl.offset({ left: left - elOffset.left - 0.8, top: top - elOffset.top - 0.8 });
textEl.offset({ width: width - 9 + 0.8, height: height - 3 + 0.8 });
textEl.css('min-width', `${width - 9 + 0.8}px`);
textEl.css('min-height', `${height - 3 + 0.8}px`);
const sOffset = { left: 0 };
sOffset[suggestPosition] = height;
suggest.setOffset(sOffset);
suggest.hide();
formula.renderCells();
}
}

Expand Down Expand Up @@ -275,7 +228,35 @@ export default class Editor {
setText(text) {
this.inputText = text;
// console.log('text>>:', text);
setText.call(this, text, text.length);
resetTextareaSize.call(this);

// firefox bug
this.textEl.el.blur();

this.render();
setTimeout(() => {
setCaretPosition(this.textEl.el, text.length);
})
}

render() {
if (this.composing) return;

const text = this.inputText;

if (text[0] != '=') {
this.textEl.html(text);
} else {
this.formula.render();
}

this.textlineEl.html(text);
}

formulaCellSelecting() {
return Boolean(this.formula.cell);
}

formulaSelectCell(ri, ci) {
this.formula.selectCell(ri, ci);
}
}
Loading

0 comments on commit ee61ed6

Please sign in to comment.