Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Better Formula Editing (by ChieveiT) #382

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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