UNPKG

x-data-spreadsheet

Version:
282 lines (262 loc) 7.76 kB
//* global window */ import { h } from './element'; 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`); } } } 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); } function keydownEventHandler(evt) { const { keyCode, altKey } = evt; if (keyCode !== 13 && keyCode !== 9) evt.stopPropagation(); if (keyCode === 13 && altKey) { insertText.call(this, evt, '\n'); evt.stopPropagation(); } if (keyCode === 13 && !altKey) evt.preventDefault(); } function inputEventHandler(evt) { const v = evt.target.value; // 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); } else { evt.target.value = ''; } } else { 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); } } 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); } function suggestItemClick(it) { const { inputText, validator } = this; let position = 0; if (validator && validator.type === 'list') { this.inputText = it; position = this.inputText.length; } else { const start = inputText.lastIndexOf('='); const sit = inputText.substring(0, start + 1); let eit = inputText.substring(start + 1); if (eit.indexOf(')') !== -1) { eit = eit.substring(eit.indexOf(')')); } else { eit = ''; } this.inputText = `${sit + it.key}(`; // console.log('inputText:', this.inputText); position = this.inputText.length; this.inputText += `)${eit}`; } setText.call(this, this.inputText, position); } function resetSuggestItems() { this.suggest.setItems(this.formulas); } function dateFormat(d) { let month = d.getMonth() + 1; let date = d.getDate(); if (month < 10) month = `0${month}`; if (date < 10) date = `0${date}`; return `${d.getFullYear()}-${month}-${date}`; } export default class Editor { constructor(formulas, viewFn, rowHeight) { this.viewFn = viewFn; this.rowHeight = rowHeight; this.formulas = formulas; this.suggest = new Suggest(formulas, (it) => { suggestItemClick.call(this, it); }); this.datepicker = new Datepicker(); this.datepicker.change((d) => { // console.log('d:', d); this.setText(dateFormat(d)); this.clear(); }); this.areaEl = h('div', `${cssPrefix}-editor-area`) .children( this.textEl = h('textarea', '') .on('input', evt => inputEventHandler.call(this, evt)) .on('paste.stop', () => {}) .on('keydown', evt => keydownEventHandler.call(this, evt)), this.textlineEl = h('div', 'textline'), this.suggest.el, this.datepicker.el, ) .on('mousemove.stop', () => {}) .on('mousedown.stop', () => {}); this.el = h('div', `${cssPrefix}-editor`) .child(this.areaEl).hide(); this.suggest.bindInputEvents(this.textEl); this.areaOffset = null; this.freeze = { w: 0, h: 0 }; this.cell = null; this.inputText = ''; this.change = () => {}; } setFreezeLengths(width, height) { this.freeze.w = width; this.freeze.h = height; } clear() { // const { cell } = this; // const cellText = (cell && cell.text) || ''; if (this.inputText !== '') { this.change('finished', this.inputText); } this.cell = null; this.areaOffset = null; this.inputText = ''; this.el.hide(); this.textEl.val(''); this.textlineEl.html(''); resetSuggestItems.call(this); this.datepicker.hide(); } setOffset(offset, suggestPosition = 'top') { const { textEl, areaEl, suggest, freeze, el, } = this; if (offset) { this.areaOffset = offset; const { left, top, width, height, l, t, } = offset; // console.log('left:', left, ',top:', top, ', freeze:', freeze); const elOffset = { left: 0, top: 0 }; // top left if (freeze.w > l && freeze.h > t) { // } else if (freeze.w < l && freeze.h < t) { elOffset.left = freeze.w; elOffset.top = freeze.h; } else if (freeze.w > l) { elOffset.top = freeze.h; } else if (freeze.h > t) { elOffset.left = freeze.w; } 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 }); const sOffset = { left: 0 }; sOffset[suggestPosition] = height; suggest.setOffset(sOffset); suggest.hide(); } } setCell(cell, validator) { // console.log('::', validator); const { el, datepicker, suggest } = this; el.show(); this.cell = cell; const text = (cell && cell.text) || ''; this.setText(text); this.validator = validator; if (validator) { const { type } = validator; if (type === 'date') { datepicker.show(); if (!/^\s*$/.test(text)) { datepicker.setValue(text); } } if (type === 'list') { suggest.setItems(validator.values()); suggest.search(''); } } } setText(text) { this.inputText = text; // console.log('text>>:', text); setText.call(this, text, text.length); resetTextareaSize.call(this); } }