feat: excel (#1004)
Co-authored-by: sealday <sealday@gmail.com> Reviewed-on: https://git.daoyoucloud.com:8443/daoyoucloud/tachybase/pulls/1004
This commit is contained in:
		
							parent
							
								
									a3dad189fe
								
							
						
					
					
						commit
						e772d9ad2b
					
				@ -1,5 +1,9 @@
 | 
			
		||||
import { DrawBox } from './DrawBox';
 | 
			
		||||
import { dpr, drawFontLine, npx, npxLine, thinLineWidth } from './utils';
 | 
			
		||||
import { npxLine } from './utils';
 | 
			
		||||
import { drawFontLine } from './utils';
 | 
			
		||||
import { npx } from './utils';
 | 
			
		||||
import { thinLineWidth } from './utils';
 | 
			
		||||
import { dpr } from './utils';
 | 
			
		||||
 | 
			
		||||
interface Attr {
 | 
			
		||||
  align?: 'left' | 'center' | 'right';
 | 
			
		||||
@ -159,7 +163,6 @@ export class Draw {
 | 
			
		||||
    const { ctx } = this;
 | 
			
		||||
    ctx.lineWidth = thinLineWidth();
 | 
			
		||||
    ctx.strokeStyle = color;
 | 
			
		||||
    // console.log('style:', style);
 | 
			
		||||
    if (style === 'medium') {
 | 
			
		||||
      ctx.lineWidth = npx(2) - 0.5;
 | 
			
		||||
    } else if (style === 'thick') {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import DropdownColor from './dropdown_color';
 | 
			
		||||
import DropdownLineType from './dropdown_linetype';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import DropdownColor from './dropdown_color';
 | 
			
		||||
import DropdownLineType from './dropdown_linetype';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
function buildTable(...trs) {
 | 
			
		||||
  return h('table', '').child(h('tbody', '').children(...trs));
 | 
			
		||||
@ -1,12 +1,12 @@
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bindClickoutside, unbindClickoutside } from './event';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import FormInput from './form_input';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
// Record: temp not used
 | 
			
		||||
// import { xtoast } from './message';
 | 
			
		||||
import { tf } from '../locale/locale';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bindClickoutside, unbindClickoutside } from './event';
 | 
			
		||||
import FormInput from './form_input';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
 | 
			
		||||
class DropdownMore extends Dropdown {
 | 
			
		||||
  constructor(click) {
 | 
			
		||||
@ -32,7 +32,10 @@ class DropdownMore extends Dropdown {
 | 
			
		||||
  setTitle() {}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const menuItems = [{ key: 'delete', title: tf('contextmenu.deleteSheet') }];
 | 
			
		||||
const menuItems = [
 | 
			
		||||
  { key: 'delete', title: tf('contextmenu.deleteSheet') },
 | 
			
		||||
  { key: 'rename', title: tf('contextmenu.renameSheet') },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
function buildMenuItem(item) {
 | 
			
		||||
  return h('div', `${cssPrefix}-item`)
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { HComponent } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import { HComponent } from './element';
 | 
			
		||||
 | 
			
		||||
export default class Button extends HComponent {
 | 
			
		||||
  // type: primary
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
 | 
			
		||||
function addMonth(date, step) {
 | 
			
		||||
  date.setMonth(date.getMonth() + step);
 | 
			
		||||
@ -21,7 +21,7 @@ function monthDays(year, month, cdate) {
 | 
			
		||||
      const index = i * 7 + j;
 | 
			
		||||
      const d = weekday(startDate, index);
 | 
			
		||||
      const disabled = d.getMonth() !== month;
 | 
			
		||||
      // console.log('d:', d, ', cdate:', cdate);
 | 
			
		||||
 | 
			
		||||
      const active = d.getMonth() === cdate.getMonth() && d.getDate() === cdate.getDate();
 | 
			
		||||
      datess[i][j] = { d, disabled, active };
 | 
			
		||||
    }
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
const themeColorPlaceHolders = [
 | 
			
		||||
  '#ffffff',
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { tf } from '../locale/locale';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bindClickoutside, unbindClickoutside } from './event';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { tf } from '../locale/locale';
 | 
			
		||||
 | 
			
		||||
const menuItems = [
 | 
			
		||||
  { key: 'copy', title: tf('contextmenu.copy'), label: 'Ctrl+C' },
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import Calendar from './calendar';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class Datepicker {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -9,10 +9,8 @@ export default class Datepicker {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setValue(date) {
 | 
			
		||||
    // console.log(':::::::', date, typeof date, date instanceof string);
 | 
			
		||||
    const { calendar } = this;
 | 
			
		||||
    if (typeof date === 'string') {
 | 
			
		||||
      // console.log(/^\d{4}-\d{1,2}-\d{1,2}$/.test(date));
 | 
			
		||||
      if (/^\d{4}-\d{1,2}-\d{1,2}$/.test(date)) {
 | 
			
		||||
        calendar.setValue(new Date(date.replace(new RegExp('-', 'g'), '/')));
 | 
			
		||||
      }
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h, HComponent } from './element';
 | 
			
		||||
import { HComponent, h } from './element';
 | 
			
		||||
import { bindClickoutside, unbindClickoutside } from './event';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class Dropdown extends HComponent {
 | 
			
		||||
  constructor(title, width, showArrow, placement, ...children) {
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
function buildItemWithIcon(iconName) {
 | 
			
		||||
  return h('div', `${cssPrefix}-item`).child(new Icon(iconName));
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import BorderPalette from './border_palette';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import BorderPalette from './border_palette';
 | 
			
		||||
 | 
			
		||||
export default class DropdownBorder extends Dropdown {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import ColorPalette from './color_palette';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import ColorPalette from './color_palette';
 | 
			
		||||
 | 
			
		||||
export default class DropdownColor extends Dropdown {
 | 
			
		||||
  constructor(iconName, color) {
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { baseFonts } from '../core/font';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { baseFonts } from '../core/font';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class DropdownFont extends Dropdown {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { fontSizes } from '../core/font';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { fontSizes } from '../core/font';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class DropdownFontSize extends Dropdown {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { baseFormats } from '../core/format';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { baseFormats } from '../core/format';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class DropdownFormat extends Dropdown {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { baseFormulas } from '../core/formula';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { baseFormulas } from '../core/formula';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class DropdownFormula extends Dropdown {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
const lineTypes = [
 | 
			
		||||
  [
 | 
			
		||||
@ -1,10 +1,7 @@
 | 
			
		||||
//* global window */
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import Datepicker from './datepicker';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Suggest from './suggest';
 | 
			
		||||
 | 
			
		||||
// import { mouseMoveUp } from '../event';
 | 
			
		||||
import Datepicker from './datepicker';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
function resetTextareaSize() {
 | 
			
		||||
  const { inputText } = this;
 | 
			
		||||
@ -56,7 +53,7 @@ function keydownEventHandler(evt) {
 | 
			
		||||
 | 
			
		||||
function inputEventHandler(evt) {
 | 
			
		||||
  const v = evt.target.value;
 | 
			
		||||
  // console.log(evt, 'v:', v);
 | 
			
		||||
 | 
			
		||||
  const { suggest, textlineEl, validator } = this;
 | 
			
		||||
  const { cell } = this;
 | 
			
		||||
  if (cell !== null) {
 | 
			
		||||
@ -138,7 +135,7 @@ function suggestItemClick(it) {
 | 
			
		||||
      eit = '';
 | 
			
		||||
    }
 | 
			
		||||
    this.inputText = `${sit + it.key}(`;
 | 
			
		||||
    // console.log('inputText:', this.inputText);
 | 
			
		||||
 | 
			
		||||
    position = this.inputText.length;
 | 
			
		||||
    this.inputText += `)${eit}`;
 | 
			
		||||
  }
 | 
			
		||||
@ -167,7 +164,6 @@ export default class Editor {
 | 
			
		||||
    });
 | 
			
		||||
    this.datepicker = new Datepicker();
 | 
			
		||||
    this.datepicker.change((d) => {
 | 
			
		||||
      // console.log('d:', d);
 | 
			
		||||
      this.setText(dateFormat(d));
 | 
			
		||||
      this.clear();
 | 
			
		||||
    });
 | 
			
		||||
@ -219,7 +215,7 @@ export default class Editor {
 | 
			
		||||
    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) {
 | 
			
		||||
@ -245,7 +241,6 @@ export default class Editor {
 | 
			
		||||
  setCell(cell, validator) {
 | 
			
		||||
    if (cell && cell.editable === false) return;
 | 
			
		||||
 | 
			
		||||
    // console.log('::', validator);
 | 
			
		||||
    const { el, datepicker, suggest } = this;
 | 
			
		||||
    el.show();
 | 
			
		||||
    this.cell = cell;
 | 
			
		||||
@ -270,7 +265,7 @@ export default class Editor {
 | 
			
		||||
 | 
			
		||||
  setText(text) {
 | 
			
		||||
    this.inputText = text;
 | 
			
		||||
    // console.log('text>>:', text);
 | 
			
		||||
 | 
			
		||||
    setText.call(this, text, text.length);
 | 
			
		||||
    resetTextareaSize.call(this);
 | 
			
		||||
  }
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
import _ from 'lodash';
 | 
			
		||||
 | 
			
		||||
class Element {
 | 
			
		||||
  el: HTMLElement;
 | 
			
		||||
  private _data: Record<string, any>;
 | 
			
		||||
@ -25,7 +24,6 @@ class Element {
 | 
			
		||||
    const [fen, ...oen] = eventNames.split('.');
 | 
			
		||||
    const eventName = fen;
 | 
			
		||||
    this.el.addEventListener(eventName, (evt) => {
 | 
			
		||||
      // console.log('excel debug', eventName, eventNames, oen, evt);
 | 
			
		||||
      handler(evt);
 | 
			
		||||
      for (let i = 0; i < oen.length; i += 1) {
 | 
			
		||||
        const k = oen[i];
 | 
			
		||||
@ -60,7 +58,7 @@ class Element {
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  scroll = _.throttle((v?) => {
 | 
			
		||||
  scroll = (v?) => {
 | 
			
		||||
    const { el } = this;
 | 
			
		||||
    if (v !== undefined) {
 | 
			
		||||
      if (v.left !== undefined) {
 | 
			
		||||
@ -71,7 +69,7 @@ class Element {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return { left: el.scrollLeft, top: el.scrollTop };
 | 
			
		||||
  }, 10);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  box() {
 | 
			
		||||
    return this.el.getBoundingClientRect();
 | 
			
		||||
@ -81,6 +79,9 @@ class Element {
 | 
			
		||||
    return new Element(this.el.parentElement);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  children(): NodeListOf<ChildNode>;
 | 
			
		||||
  children(...others: (string | Element)[]): this;
 | 
			
		||||
 | 
			
		||||
  children(...eles) {
 | 
			
		||||
    if (arguments.length === 0) {
 | 
			
		||||
      return this.el.childNodes;
 | 
			
		||||
@ -155,11 +156,11 @@ class Element {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // key, value
 | 
			
		||||
  // key
 | 
			
		||||
  // {k, v}...
 | 
			
		||||
  attr(key, value) {
 | 
			
		||||
    if (value !== undefined) {
 | 
			
		||||
  attr(key: string, value: string): this;
 | 
			
		||||
  attr(key: string, value: undefined): string;
 | 
			
		||||
  attr(key: Record<string, string>, value: undefined): this;
 | 
			
		||||
  attr(key: string | Record<string, string>, value: string | undefined): string | this {
 | 
			
		||||
    if (value !== undefined && typeof key === 'string') {
 | 
			
		||||
      this.el.setAttribute(key, value);
 | 
			
		||||
    } else {
 | 
			
		||||
      if (typeof key === 'string') {
 | 
			
		||||
@ -172,12 +173,15 @@ class Element {
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  removeAttr(key) {
 | 
			
		||||
  removeAttr(key: string): this {
 | 
			
		||||
    this.el.removeAttribute(key);
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  html(content) {
 | 
			
		||||
  html(content: undefined): string;
 | 
			
		||||
  html(content: string): this;
 | 
			
		||||
 | 
			
		||||
  html(content: string | undefined): string | this {
 | 
			
		||||
    if (content !== undefined) {
 | 
			
		||||
      this.el.innerHTML = content;
 | 
			
		||||
      return this;
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
/* global window */
 | 
			
		||||
export function bind(target, name, fn) {
 | 
			
		||||
  target.addEventListener(name, fn);
 | 
			
		||||
}
 | 
			
		||||
@ -18,7 +17,7 @@ export function unbindClickoutside(el) {
 | 
			
		||||
export function bindClickoutside(el, cb) {
 | 
			
		||||
  el.xclickoutside = (evt) => {
 | 
			
		||||
    // ignore double click
 | 
			
		||||
    // console.log('evt:', evt);
 | 
			
		||||
 | 
			
		||||
    if (evt.detail === 2 || el.contains(evt.target)) return;
 | 
			
		||||
    if (cb) cb(el);
 | 
			
		||||
    else {
 | 
			
		||||
@ -32,7 +31,6 @@ export function mouseMoveUp(target, movefunc, upfunc) {
 | 
			
		||||
  bind(target, 'mousemove', movefunc);
 | 
			
		||||
  const t = target;
 | 
			
		||||
  t.xEvtUp = (evt) => {
 | 
			
		||||
    // console.log('mouseup>>>');
 | 
			
		||||
    unbind(target, 'mousemove', movefunc);
 | 
			
		||||
    unbind(target, 'mouseup', target.xEvtUp);
 | 
			
		||||
    upfunc(evt);
 | 
			
		||||
@ -42,7 +40,7 @@ export function mouseMoveUp(target, movefunc, upfunc) {
 | 
			
		||||
 | 
			
		||||
function calTouchDirection(spanx, spany, evt, cb) {
 | 
			
		||||
  let direction = '';
 | 
			
		||||
  // console.log('spanx:', spanx, ', spany:', spany);
 | 
			
		||||
 | 
			
		||||
  if (Math.abs(spanx) > Math.abs(spany)) {
 | 
			
		||||
    // horizontal
 | 
			
		||||
    direction = spanx > 0 ? 'right' : 'left';
 | 
			
		||||
@ -68,7 +66,6 @@ export function bindTouch(target, { move, end }) {
 | 
			
		||||
    const spanx = pageX - startx;
 | 
			
		||||
    const spany = pageY - starty;
 | 
			
		||||
    if (Math.abs(spanx) > 10 || Math.abs(spany) > 10) {
 | 
			
		||||
      // console.log('spanx:', spanx, ', spany:', spany);
 | 
			
		||||
      calTouchDirection(spanx, spany, evt, move);
 | 
			
		||||
      startx = pageX;
 | 
			
		||||
      starty = pageY;
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
 | 
			
		||||
const patterns = {
 | 
			
		||||
  number: /(^\d+$)|(^\d+(\.\d{0,4})?$)/,
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class FormInput {
 | 
			
		||||
  constructor(width, hint) {
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Suggest from './suggest';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class FormSelect {
 | 
			
		||||
  constructor(key, items, width, getTitle = (it) => it, change = () => {}) {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { HComponent, h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h, HComponent } from './element';
 | 
			
		||||
 | 
			
		||||
export default class Icon extends HComponent {
 | 
			
		||||
  constructor(name) {
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
/* global document */
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export function xtoast(title, content) {
 | 
			
		||||
  const el = h('div', `${cssPrefix}-toast`);
 | 
			
		||||
@ -1,13 +1,15 @@
 | 
			
		||||
/* global document */
 | 
			
		||||
/* global window */
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bind, unbind } from './event';
 | 
			
		||||
import { h, HComponent } from './element';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { bind, unbind } from './event';
 | 
			
		||||
 | 
			
		||||
export default class Modal {
 | 
			
		||||
  constructor(title, content, width = '600px') {
 | 
			
		||||
    this.title = title;
 | 
			
		||||
  el: HComponent;
 | 
			
		||||
  constructor(
 | 
			
		||||
    private title,
 | 
			
		||||
    content,
 | 
			
		||||
    width = '600px',
 | 
			
		||||
  ) {
 | 
			
		||||
    this.el = h('div', `${cssPrefix}-modal`)
 | 
			
		||||
      .css('width', width)
 | 
			
		||||
      .children(
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import Button from './button';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import FormField from './form_field';
 | 
			
		||||
import Modal from './modal';
 | 
			
		||||
import FormInput from './form_input';
 | 
			
		||||
import FormSelect from './form_select';
 | 
			
		||||
import Modal from './modal';
 | 
			
		||||
import FormField from './form_field';
 | 
			
		||||
import Button from './button';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
const fieldLabelWidth = 100;
 | 
			
		||||
 | 
			
		||||
@ -146,9 +146,8 @@ export default class ModalValidation extends Modal {
 | 
			
		||||
      const attrs = ['mf', 'rf', 'cf', 'of', 'svf', 'vf', 'minvf', 'maxvf'];
 | 
			
		||||
      for (let i = 0; i < attrs.length; i += 1) {
 | 
			
		||||
        const field = this[attrs[i]];
 | 
			
		||||
        // console.log('field:', field);
 | 
			
		||||
 | 
			
		||||
        if (field.isShow()) {
 | 
			
		||||
          // console.log('it:', it);
 | 
			
		||||
          if (!field.validate()) return;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
@ -165,7 +164,7 @@ export default class ModalValidation extends Modal {
 | 
			
		||||
          value = this.vf.val();
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      // console.log(mode, ref, type, operator, value);
 | 
			
		||||
 | 
			
		||||
      this.change('save', mode, ref, {
 | 
			
		||||
        type,
 | 
			
		||||
        operator,
 | 
			
		||||
@ -1,10 +1,9 @@
 | 
			
		||||
/* global window document */
 | 
			
		||||
import { Draw } from '../canvas';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import Button from './button';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import Button from './button';
 | 
			
		||||
import { Draw } from '../canvas';
 | 
			
		||||
import { renderCell } from './table';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
 | 
			
		||||
// resolution: 72 => 595 x 842
 | 
			
		||||
// 150 => 1240 x 1754
 | 
			
		||||
@ -22,8 +21,8 @@ const PAGER_SIZES = [
 | 
			
		||||
 | 
			
		||||
const PAGER_ORIENTATIONS = ['landscape', 'portrait'];
 | 
			
		||||
 | 
			
		||||
function inches2px(inc) {
 | 
			
		||||
  return parseInt(96 * inc, 10);
 | 
			
		||||
function inches2px(inc: number) {
 | 
			
		||||
  return parseInt(String(96 * inc), 10);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function btnClick(type) {
 | 
			
		||||
@ -38,9 +37,8 @@ function pagerSizeChange(evt) {
 | 
			
		||||
  const { paper } = this;
 | 
			
		||||
  const { value } = evt.target;
 | 
			
		||||
  const ps = PAGER_SIZES[value];
 | 
			
		||||
  paper.w = inches2px(ps[1]);
 | 
			
		||||
  paper.h = inches2px(ps[2]);
 | 
			
		||||
  // console.log('paper:', ps, paper);
 | 
			
		||||
  paper.w = inches2px(ps[1] as number);
 | 
			
		||||
  paper.h = inches2px(ps[2] as number);
 | 
			
		||||
  this.preview();
 | 
			
		||||
}
 | 
			
		||||
function pagerOrientationChange(evt) {
 | 
			
		||||
@ -52,11 +50,15 @@ function pagerOrientationChange(evt) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class Print {
 | 
			
		||||
  constructor(data) {
 | 
			
		||||
  paper;
 | 
			
		||||
  el;
 | 
			
		||||
  contentEl;
 | 
			
		||||
  canvases;
 | 
			
		||||
  constructor(private data) {
 | 
			
		||||
    this.paper = {
 | 
			
		||||
      w: inches2px(PAGER_SIZES[0][1]),
 | 
			
		||||
      h: inches2px(PAGER_SIZES[0][2]),
 | 
			
		||||
      padding: 50,
 | 
			
		||||
      w: inches2px(PAGER_SIZES[0][1] as number),
 | 
			
		||||
      h: inches2px(PAGER_SIZES[0][2] as number),
 | 
			
		||||
      padding: 0,
 | 
			
		||||
      orientation: PAGER_ORIENTATIONS[0],
 | 
			
		||||
      get width() {
 | 
			
		||||
        return this.orientation === 'landscape' ? this.h : this.w;
 | 
			
		||||
@ -65,7 +67,6 @@ export default class Print {
 | 
			
		||||
        return this.orientation === 'landscape' ? this.w : this.h;
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
    this.data = data;
 | 
			
		||||
    this.el = h('div', `${cssPrefix}-print`)
 | 
			
		||||
      .children(
 | 
			
		||||
        h('div', `${cssPrefix}-print-bar`).children(
 | 
			
		||||
@ -120,7 +121,7 @@ export default class Print {
 | 
			
		||||
    const iwidth = width - padding * 2;
 | 
			
		||||
    const iheight = height - padding * 2;
 | 
			
		||||
    const cr = data.contentRange();
 | 
			
		||||
    const pages = parseInt(cr.h / iheight, 10) + 1;
 | 
			
		||||
    const pages = parseInt(String(cr.h / iheight), 10) + 1;
 | 
			
		||||
    const scale = iwidth / cr.w;
 | 
			
		||||
    let left = padding;
 | 
			
		||||
    const top = padding;
 | 
			
		||||
@ -143,12 +144,12 @@ export default class Print {
 | 
			
		||||
      const wrap = h('div', `${cssPrefix}-canvas-card`);
 | 
			
		||||
      const canvas = h('canvas', `${cssPrefix}-canvas`);
 | 
			
		||||
      this.canvases.push(canvas.el);
 | 
			
		||||
      const draw = new Draw(canvas.el, width, height);
 | 
			
		||||
      // FIXME 可以用泛型
 | 
			
		||||
      const draw = new Draw(canvas.el as HTMLCanvasElement, width, height);
 | 
			
		||||
      // cell-content
 | 
			
		||||
      draw.save();
 | 
			
		||||
      draw.translate(left, top);
 | 
			
		||||
      if (scale < 1) draw.scale(scale, scale);
 | 
			
		||||
      // console.log('ri:', ri, cr.eri, yoffset);
 | 
			
		||||
      for (; ri <= cr.eri; ri += 1) {
 | 
			
		||||
        const rh = data.rows.getHeight(ri);
 | 
			
		||||
        th += rh;
 | 
			
		||||
@ -188,13 +189,14 @@ export default class Print {
 | 
			
		||||
    const iframe = h('iframe', '').hide();
 | 
			
		||||
    const { el } = iframe;
 | 
			
		||||
    window.document.body.appendChild(el);
 | 
			
		||||
    const { contentWindow } = el;
 | 
			
		||||
    // FIXME 可以用泛型
 | 
			
		||||
    const { contentWindow } = el as HTMLIFrameElement;
 | 
			
		||||
    const idoc = contentWindow.document;
 | 
			
		||||
    const style = document.createElement('style');
 | 
			
		||||
    style.innerHTML = `
 | 
			
		||||
      @page { size: ${paper.width}px ${paper.height}px; };
 | 
			
		||||
      canvas {
 | 
			
		||||
        page-break-before: auto;        
 | 
			
		||||
        page-break-before: auto;
 | 
			
		||||
        page-break-after: always;
 | 
			
		||||
        image-rendering: pixelated;
 | 
			
		||||
      };
 | 
			
		||||
@ -1,7 +1,6 @@
 | 
			
		||||
/* global window */
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { mouseMoveUp } from './event';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class Resizer {
 | 
			
		||||
  constructor(vertical = false, minDistance) {
 | 
			
		||||
@ -80,14 +79,13 @@ export default class Resizer {
 | 
			
		||||
    let startEvt = evt;
 | 
			
		||||
    const { el, lineEl, cRect, vertical, minDistance } = this;
 | 
			
		||||
    let distance = vertical ? cRect.width : cRect.height;
 | 
			
		||||
    // console.log('distance:', distance);
 | 
			
		||||
 | 
			
		||||
    lineEl.show();
 | 
			
		||||
    mouseMoveUp(
 | 
			
		||||
      window,
 | 
			
		||||
      (e) => {
 | 
			
		||||
        this.moving = true;
 | 
			
		||||
        if (startEvt !== null && e.buttons === 1) {
 | 
			
		||||
          // console.log('top:', top, ', left:', top, ', cRect:', cRect);
 | 
			
		||||
          if (vertical) {
 | 
			
		||||
            distance += e.movementX;
 | 
			
		||||
            if (distance > minDistance) {
 | 
			
		||||
@ -1,11 +1,11 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h, HComponent } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default class Scrollbar {
 | 
			
		||||
  private el: HComponent;
 | 
			
		||||
  private contentEl: HComponent;
 | 
			
		||||
  private _moveFn: (type: string, handler: (e: Event) => void) => void;
 | 
			
		||||
  constructor(private vertical: 'vertical' | 'horizontal') {
 | 
			
		||||
  constructor(private vertical: boolean) {
 | 
			
		||||
    this._moveFn = null;
 | 
			
		||||
    this.el = h('div', `${cssPrefix}-scrollbar ${vertical ? 'vertical' : 'horizontal'}`)
 | 
			
		||||
      .child((this.contentEl = h('div', '')))
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { CellRange } from '../core/cell_range';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
 | 
			
		||||
const selectorHeightBorderWidth = 2 * 2 - 1;
 | 
			
		||||
let startZIndex = 10;
 | 
			
		||||
@ -128,7 +128,7 @@ function calLAreaOffset(offset) {
 | 
			
		||||
  const { top, width, height, l, t, scroll } = offset;
 | 
			
		||||
  const ftheight = data.freezeTotalHeight();
 | 
			
		||||
  let top0 = top - ftheight;
 | 
			
		||||
  // console.log('ftheight:', ftheight, ', t:', t);
 | 
			
		||||
 | 
			
		||||
  if (ftheight > t) top0 -= scroll.y;
 | 
			
		||||
  return {
 | 
			
		||||
    left: l,
 | 
			
		||||
@ -247,7 +247,6 @@ export default class Selector {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resetAreaOffset() {
 | 
			
		||||
    // console.log('offset:', offset);
 | 
			
		||||
    const offset = this.data.getSelectedRect();
 | 
			
		||||
    const coffset = this.data.getClipboardRect();
 | 
			
		||||
    setAllAreaOffset.call(this, offset);
 | 
			
		||||
@ -307,14 +306,13 @@ export default class Selector {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  reset() {
 | 
			
		||||
    // console.log('::::', this.data);
 | 
			
		||||
    const { eri, eci } = this.data.selector.range;
 | 
			
		||||
    this.setEnd(eri, eci);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  showAutofill(ri, ci) {
 | 
			
		||||
    if (ri === -1 && ci === -1) return;
 | 
			
		||||
    // console.log('ri:', ri, ', ci:', ci);
 | 
			
		||||
 | 
			
		||||
    // const [sri, sci] = this.sIndexes;
 | 
			
		||||
    // const [eri, eci] = this.eIndexes;
 | 
			
		||||
    const { sri, sci, eri, eci } = this.range;
 | 
			
		||||
@ -327,41 +325,39 @@ export default class Selector {
 | 
			
		||||
    const ecn = eci - ci;
 | 
			
		||||
    if (scn > 0) {
 | 
			
		||||
      // left
 | 
			
		||||
      // console.log('left');
 | 
			
		||||
 | 
			
		||||
      this.arange = new CellRange(sri, nci, eri, sci - 1);
 | 
			
		||||
      // this.saIndexes = [sri, nci];
 | 
			
		||||
      // this.eaIndexes = [eri, sci - 1];
 | 
			
		||||
      // data.calRangeIndexes2(
 | 
			
		||||
    } else if (srn > 0) {
 | 
			
		||||
      // top
 | 
			
		||||
      // console.log('top');
 | 
			
		||||
 | 
			
		||||
      // nri = sri;
 | 
			
		||||
      this.arange = new CellRange(nri, sci, sri - 1, eci);
 | 
			
		||||
      // this.saIndexes = [nri, sci];
 | 
			
		||||
      // this.eaIndexes = [sri - 1, eci];
 | 
			
		||||
    } else if (ecn < 0) {
 | 
			
		||||
      // right
 | 
			
		||||
      // console.log('right');
 | 
			
		||||
 | 
			
		||||
      // nci = eci;
 | 
			
		||||
      this.arange = new CellRange(sri, eci + 1, eri, nci);
 | 
			
		||||
      // this.saIndexes = [sri, eci + 1];
 | 
			
		||||
      // this.eaIndexes = [eri, nci];
 | 
			
		||||
    } else if (ern < 0) {
 | 
			
		||||
      // bottom
 | 
			
		||||
      // console.log('bottom');
 | 
			
		||||
 | 
			
		||||
      // nri = eri;
 | 
			
		||||
      this.arange = new CellRange(eri + 1, sci, nri, eci);
 | 
			
		||||
      // this.saIndexes = [eri + 1, sci];
 | 
			
		||||
      // this.eaIndexes = [nri, eci];
 | 
			
		||||
    } else {
 | 
			
		||||
      // console.log('else:');
 | 
			
		||||
      this.arange = null;
 | 
			
		||||
      // this.saIndexes = null;
 | 
			
		||||
      // this.eaIndexes = null;
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (this.arange !== null) {
 | 
			
		||||
      // console.log(this.saIndexes, ':', this.eaIndexes);
 | 
			
		||||
      const offset = this.data.getRect(this.arange);
 | 
			
		||||
      offset.width += 2;
 | 
			
		||||
      offset.height += 2;
 | 
			
		||||
@ -1,44 +1,25 @@
 | 
			
		||||
/* global window */
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { formulas } from '../core/formula';
 | 
			
		||||
import ContextMenu from './contextmenu';
 | 
			
		||||
import Editor from './editor';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bind, bindTouch, createEventEmitter, mouseMoveUp } from './event';
 | 
			
		||||
import { xtoast } from './message';
 | 
			
		||||
import ModalValidation from './modal_validation';
 | 
			
		||||
import Print from './print';
 | 
			
		||||
import { bind, mouseMoveUp, bindTouch, createEventEmitter } from './event';
 | 
			
		||||
import Resizer from './resizer';
 | 
			
		||||
import Scrollbar from './scrollbar';
 | 
			
		||||
import Selector from './selector';
 | 
			
		||||
import SortFilter from './sort_filter';
 | 
			
		||||
import Editor from './editor';
 | 
			
		||||
import Print from './print';
 | 
			
		||||
import ContextMenu from './contextmenu';
 | 
			
		||||
import Table from './table';
 | 
			
		||||
import Toolbar from './toolbar/index';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @desc throttle fn
 | 
			
		||||
 * @param func function
 | 
			
		||||
 * @param wait Delay in milliseconds
 | 
			
		||||
 */
 | 
			
		||||
function throttle(func, wait) {
 | 
			
		||||
  let timeout;
 | 
			
		||||
  return (...arg) => {
 | 
			
		||||
    const that = this;
 | 
			
		||||
    const args = arg;
 | 
			
		||||
    if (!timeout) {
 | 
			
		||||
      timeout = setTimeout(() => {
 | 
			
		||||
        timeout = null;
 | 
			
		||||
        func.apply(that, args);
 | 
			
		||||
      }, wait);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
import ModalValidation from './modal_validation';
 | 
			
		||||
import SortFilter from './sort_filter';
 | 
			
		||||
import { xtoast } from './message';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { formulas } from '../core/formula';
 | 
			
		||||
import { throttle } from '../core/helper';
 | 
			
		||||
 | 
			
		||||
function scrollbarMove() {
 | 
			
		||||
  const { data, verticalScrollbar, horizontalScrollbar } = this;
 | 
			
		||||
  const { l, t, left, top, width, height } = data.getSelectedRect();
 | 
			
		||||
  const tableOffset = this.getTableOffset();
 | 
			
		||||
  // console.log(',l:', l, ', left:', left, ', tOffset.left:', tableOffset.width);
 | 
			
		||||
 | 
			
		||||
  if (Math.abs(left) + width > tableOffset.width) {
 | 
			
		||||
    horizontalScrollbar.move({ left: l + width - tableOffset.width });
 | 
			
		||||
  } else {
 | 
			
		||||
@ -47,7 +28,7 @@ function scrollbarMove() {
 | 
			
		||||
      horizontalScrollbar.move({ left: l - 1 - fsw });
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // console.log('top:', top, ', height:', height, ', tof.height:', tableOffset.height);
 | 
			
		||||
 | 
			
		||||
  if (Math.abs(top) + height > tableOffset.height) {
 | 
			
		||||
    verticalScrollbar.move({ top: t + height - tableOffset.height - 1 });
 | 
			
		||||
  } else {
 | 
			
		||||
@ -85,7 +66,7 @@ function selectorMove(multiple, direction) {
 | 
			
		||||
  if (multiple) {
 | 
			
		||||
    [ri, ci] = selector.moveIndexes;
 | 
			
		||||
  }
 | 
			
		||||
  // console.log('selector.move:', ri, ci);
 | 
			
		||||
 | 
			
		||||
  if (direction === 'left') {
 | 
			
		||||
    if (ci > 0) ci -= 1;
 | 
			
		||||
  } else if (direction === 'right') {
 | 
			
		||||
@ -114,7 +95,6 @@ function selectorMove(multiple, direction) {
 | 
			
		||||
 | 
			
		||||
// private methods
 | 
			
		||||
function overlayerMousemove(evt) {
 | 
			
		||||
  // console.log('x:', evt.offsetX, ', y:', evt.offsetY);
 | 
			
		||||
  if (evt.buttons !== 0) return;
 | 
			
		||||
  if (evt.target.className === `${cssPrefix}-resizer-hover`) return;
 | 
			
		||||
  const { offsetX, offsetY } = evt;
 | 
			
		||||
@ -164,7 +144,6 @@ function overlayerMousescroll(evt) {
 | 
			
		||||
  const { verticalScrollbar, horizontalScrollbar, data } = this;
 | 
			
		||||
  const { top } = verticalScrollbar.scroll();
 | 
			
		||||
  const { left } = horizontalScrollbar.scroll();
 | 
			
		||||
  // console.log('evt:::', evt.wheelDelta, evt.detail * 40);
 | 
			
		||||
 | 
			
		||||
  const { rows, cols } = data;
 | 
			
		||||
 | 
			
		||||
@ -179,7 +158,7 @@ function overlayerMousescroll(evt) {
 | 
			
		||||
    } while (v <= 0);
 | 
			
		||||
    return v;
 | 
			
		||||
  };
 | 
			
		||||
  // console.log('deltaX', deltaX, 'evt.detail', evt.detail);
 | 
			
		||||
 | 
			
		||||
  // if (evt.detail) deltaY = evt.detail * 40;
 | 
			
		||||
  const moveY = (vertical) => {
 | 
			
		||||
    if (vertical > 0) {
 | 
			
		||||
@ -220,7 +199,7 @@ function overlayerMousescroll(evt) {
 | 
			
		||||
  const tempY = Math.abs(deltaY);
 | 
			
		||||
  const tempX = Math.abs(deltaX);
 | 
			
		||||
  const temp = Math.max(tempY, tempX);
 | 
			
		||||
  // console.log('event:', evt);
 | 
			
		||||
 | 
			
		||||
  // detail for windows/mac firefox vertical scroll
 | 
			
		||||
  if (/Firefox/i.test(window.navigator.userAgent)) throttle(moveY(evt.detail), 50);
 | 
			
		||||
  if (temp === tempX) throttle(moveX(deltaX), 50);
 | 
			
		||||
@ -243,7 +222,7 @@ function verticalScrollbarSet() {
 | 
			
		||||
  const { data, verticalScrollbar } = this;
 | 
			
		||||
  const { height } = this.getTableOffset();
 | 
			
		||||
  const erth = data.exceptRowTotalHeight(0, -1);
 | 
			
		||||
  // console.log('erth:', erth);
 | 
			
		||||
 | 
			
		||||
  verticalScrollbar.set(height, data.rows.totalHeight() - erth);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -349,8 +328,6 @@ function toolbarChangePaintformatPaste() {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function overlayerMousedown(evt) {
 | 
			
		||||
  // console.log(':::::overlayer.mousedown:', evt.detail, evt.button, evt.buttons, evt.shiftKey);
 | 
			
		||||
  // console.log('evt.target.className:', evt.target.className);
 | 
			
		||||
  const { selector, data, table, sortFilter } = this;
 | 
			
		||||
  const { offsetX, offsetY } = evt;
 | 
			
		||||
  const isAutofillEl = evt.target.className === `${cssPrefix}-selector-corner`;
 | 
			
		||||
@ -369,9 +346,7 @@ function overlayerMousedown(evt) {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // console.log('ri:', ri, ', ci:', ci);
 | 
			
		||||
  if (!evt.shiftKey) {
 | 
			
		||||
    // console.log('selectorSetStart:::');
 | 
			
		||||
    if (isAutofillEl) {
 | 
			
		||||
      selector.showAutofill(ri, ci);
 | 
			
		||||
    } else {
 | 
			
		||||
@ -382,7 +357,6 @@ function overlayerMousedown(evt) {
 | 
			
		||||
    mouseMoveUp(
 | 
			
		||||
      window,
 | 
			
		||||
      (e) => {
 | 
			
		||||
        // console.log('mouseMoveUp::::');
 | 
			
		||||
        ({ ri, ci } = data.getCellRectByXY(e.offsetX, e.offsetY));
 | 
			
		||||
        if (isAutofillEl) {
 | 
			
		||||
          selector.showAutofill(ri, ci);
 | 
			
		||||
@ -404,7 +378,6 @@ function overlayerMousedown(evt) {
 | 
			
		||||
 | 
			
		||||
  if (!isAutofillEl && evt.buttons === 1) {
 | 
			
		||||
    if (evt.shiftKey) {
 | 
			
		||||
      // console.log('shiftKey::::');
 | 
			
		||||
      selectorSet.call(this, true, ri, ci);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@ -415,7 +388,7 @@ function editorSetOffset() {
 | 
			
		||||
  const sOffset = data.getSelectedRect();
 | 
			
		||||
  const tOffset = this.getTableOffset();
 | 
			
		||||
  let sPosition = 'top';
 | 
			
		||||
  // console.log('sOffset:', sOffset, ':', tOffset);
 | 
			
		||||
 | 
			
		||||
  if (sOffset.top > tOffset.height / 2) {
 | 
			
		||||
    sPosition = 'bottom';
 | 
			
		||||
  }
 | 
			
		||||
@ -564,7 +537,6 @@ function toolbarChange(type, value) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function sortFilterChange(ci, order, operator, value) {
 | 
			
		||||
  // console.log('sort:', sortDesc, operator, value);
 | 
			
		||||
  this.data.setAutoFilter(ci, order, operator, value);
 | 
			
		||||
  sheetReset.call(this);
 | 
			
		||||
}
 | 
			
		||||
@ -669,7 +641,6 @@ function sheetInitEvents() {
 | 
			
		||||
  };
 | 
			
		||||
  // contextmenu
 | 
			
		||||
  contextMenu.itemClick = (type) => {
 | 
			
		||||
    // console.log('type:', type);
 | 
			
		||||
    if (type === 'validation') {
 | 
			
		||||
      modalValidation.setValue(this.data.getSelectedValidation());
 | 
			
		||||
    } else if (type === 'copy') {
 | 
			
		||||
@ -714,7 +685,7 @@ function sheetInitEvents() {
 | 
			
		||||
    if (!this.focusing) return;
 | 
			
		||||
    const keyCode = evt.keyCode || evt.which;
 | 
			
		||||
    const { key, ctrlKey, shiftKey, metaKey } = evt;
 | 
			
		||||
    // console.log('keydown.evt: ', keyCode);
 | 
			
		||||
 | 
			
		||||
    if (ctrlKey || metaKey) {
 | 
			
		||||
      // const { sIndexes, eIndexes } = selector;
 | 
			
		||||
      // let what = 'all';
 | 
			
		||||
@ -789,7 +760,6 @@ function sheetInitEvents() {
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
    } else {
 | 
			
		||||
      // console.log('evt.keyCode:', evt.keyCode);
 | 
			
		||||
      switch (keyCode) {
 | 
			
		||||
        case 32:
 | 
			
		||||
          if (shiftKey) {
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import Button from './button';
 | 
			
		||||
import { bindClickoutside, unbindClickoutside } from './event';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import Button from './button';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bindClickoutside, unbindClickoutside } from './event';
 | 
			
		||||
 | 
			
		||||
function buildMenu(clsName) {
 | 
			
		||||
  return h('div', `${cssPrefix}-item ${clsName}`);
 | 
			
		||||
@ -51,7 +51,6 @@ export default class SortFilter {
 | 
			
		||||
        ),
 | 
			
		||||
      )
 | 
			
		||||
      .hide();
 | 
			
		||||
    // this.setFilters(['test1', 'test2', 'text3']);
 | 
			
		||||
    this.ci = null;
 | 
			
		||||
    this.sortDesc = null;
 | 
			
		||||
    this.values = null;
 | 
			
		||||
@ -69,7 +68,6 @@ export default class SortFilter {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  itemClick(it) {
 | 
			
		||||
    // console.log('it:', it);
 | 
			
		||||
    this.sort = it;
 | 
			
		||||
    const { sortAscEl, sortDescEl } = this;
 | 
			
		||||
    sortAscEl.checked(it === 'asc');
 | 
			
		||||
@ -77,7 +75,6 @@ export default class SortFilter {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  filterClick(index, it) {
 | 
			
		||||
    // console.log('index:', index, it);
 | 
			
		||||
    const { filterbEl, filterValues, values } = this;
 | 
			
		||||
    const children = filterbEl.children();
 | 
			
		||||
    if (it === 'all') {
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bindClickoutside, unbindClickoutside } from './event';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
function inputMovePrev(evt) {
 | 
			
		||||
  evt.preventDefault();
 | 
			
		||||
@ -1,11 +1,12 @@
 | 
			
		||||
import { Draw, DrawBox, npx, thinLineWidth } from '../canvas';
 | 
			
		||||
import { stringAt } from '../core/alphabet';
 | 
			
		||||
import _cell from '../core/cell';
 | 
			
		||||
import { getFontSizePxByPt } from '../core/font';
 | 
			
		||||
import { formatm } from '../core/format';
 | 
			
		||||
import _cell from '../core/cell';
 | 
			
		||||
import { formulam } from '../core/formula';
 | 
			
		||||
import { formatm } from '../core/format';
 | 
			
		||||
 | 
			
		||||
import { Draw, DrawBox, thinLineWidth, npx } from '../canvas';
 | 
			
		||||
import DataProxy from '../core/data_proxy';
 | 
			
		||||
 | 
			
		||||
// gobal var
 | 
			
		||||
const cellPaddingWidth = 5;
 | 
			
		||||
const tableFixedHeaderCleanStyle = { fillStyle: '#f4f5f8' };
 | 
			
		||||
const tableGridStyle = {
 | 
			
		||||
@ -33,7 +34,7 @@ function renderCellBorders(bboxes, translateFunc) {
 | 
			
		||||
  const { draw } = this;
 | 
			
		||||
  if (bboxes) {
 | 
			
		||||
    const rset = new Set();
 | 
			
		||||
    // console.log('bboxes:', bboxes);
 | 
			
		||||
 | 
			
		||||
    bboxes.forEach(({ ri, ci, box }) => {
 | 
			
		||||
      if (!rset.has(ri)) {
 | 
			
		||||
        rset.add(ri);
 | 
			
		||||
@ -77,12 +78,11 @@ export function renderCell(draw, data, rindex, cindex, yoffset = 0) {
 | 
			
		||||
      cellText = cell.text || '';
 | 
			
		||||
    }
 | 
			
		||||
    if (style.format) {
 | 
			
		||||
      // console.log(data.formatm, '>>', cell.format);
 | 
			
		||||
      cellText = formatm[style.format].render(cellText);
 | 
			
		||||
    }
 | 
			
		||||
    const font = Object.assign({}, style.font);
 | 
			
		||||
    font.size = getFontSizePxByPt(font.size);
 | 
			
		||||
    // console.log('style:', style);
 | 
			
		||||
 | 
			
		||||
    draw.text(
 | 
			
		||||
      cellText,
 | 
			
		||||
      dbox,
 | 
			
		||||
@ -99,7 +99,6 @@ export function renderCell(draw, data, rindex, cindex, yoffset = 0) {
 | 
			
		||||
    // error
 | 
			
		||||
    const error = data.validations.getError(rindex, cindex);
 | 
			
		||||
    if (error) {
 | 
			
		||||
      // console.log('error:', rindex, cindex, error);
 | 
			
		||||
      draw.error(dbox);
 | 
			
		||||
    }
 | 
			
		||||
    if (frozen) {
 | 
			
		||||
@ -199,7 +198,7 @@ function renderFixedHeaders(type, viewRange, w, h, tx, ty) {
 | 
			
		||||
  if (type === 'all' || type === 'top') draw.fillRect(ntx, 0, sumWidth, h);
 | 
			
		||||
 | 
			
		||||
  const { sri, sci, eri, eci } = data.selector.range;
 | 
			
		||||
  // console.log(data.selectIndexes);
 | 
			
		||||
 | 
			
		||||
  // draw text
 | 
			
		||||
  // text font, align...
 | 
			
		||||
  draw.attr(tableFixedHeaderStyle());
 | 
			
		||||
@ -262,15 +261,14 @@ function renderContentGrid({ sri, sci, eri, eci, w, h }, fw, fh, tx, ty) {
 | 
			
		||||
  draw.attr(tableGridStyle).translate(fw + tx, fh + ty);
 | 
			
		||||
  // const sumWidth = cols.sumWidth(sci, eci + 1);
 | 
			
		||||
  // const sumHeight = rows.sumHeight(sri, eri + 1);
 | 
			
		||||
  // console.log('sumWidth:', sumWidth);
 | 
			
		||||
 | 
			
		||||
  // draw.clearRect(0, 0, w, h);
 | 
			
		||||
  if (!settings.showGrid) {
 | 
			
		||||
    draw.restore();
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  // console.log('rowStart:', rowStart, ', rowLen:', rowLen);
 | 
			
		||||
 | 
			
		||||
  data.rowEach(sri, eri, (i, y, ch) => {
 | 
			
		||||
    // console.log('y:', y);
 | 
			
		||||
    if (i !== sri) draw.line([0, y], [w, y]);
 | 
			
		||||
    if (i === eri) draw.line([0, y + ch], [w, y + ch]);
 | 
			
		||||
  });
 | 
			
		||||
@ -293,10 +291,12 @@ function renderFreezeHighlightLine(fw, fh, ftw, fth) {
 | 
			
		||||
 | 
			
		||||
/** end */
 | 
			
		||||
class Table {
 | 
			
		||||
  constructor(el, data) {
 | 
			
		||||
    this.el = el;
 | 
			
		||||
    this.draw = new Draw(el, data.viewWidth(), data.viewHeight());
 | 
			
		||||
    this.data = data;
 | 
			
		||||
  constructor(
 | 
			
		||||
    public el: HTMLElement,
 | 
			
		||||
    public data: DataProxy,
 | 
			
		||||
    public draw?: Draw,
 | 
			
		||||
  ) {
 | 
			
		||||
    this.draw = !draw ? new Draw(el, data.viewWidth(), data.viewHeight()) : draw;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  resetData(data) {
 | 
			
		||||
@ -1,18 +1,17 @@
 | 
			
		||||
/* global window */
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import DropdownAlign from './dropdown_align';
 | 
			
		||||
import DropdownBorder from './dropdown_border';
 | 
			
		||||
import DropdownColor from './dropdown_color';
 | 
			
		||||
import { h, HComponent } from './element';
 | 
			
		||||
import { bind } from './event';
 | 
			
		||||
import tooltip from './tooltip';
 | 
			
		||||
import DropdownFont from './dropdown_font';
 | 
			
		||||
import DropdownFontSize from './dropdown_fontsize';
 | 
			
		||||
import DropdownFormat from './dropdown_format';
 | 
			
		||||
import DropdownFormula from './dropdown_formula';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bind } from './event';
 | 
			
		||||
import DropdownColor from './dropdown_color';
 | 
			
		||||
import DropdownAlign from './dropdown_align';
 | 
			
		||||
import DropdownBorder from './dropdown_border';
 | 
			
		||||
import Dropdown from './dropdown';
 | 
			
		||||
import Icon from './icon';
 | 
			
		||||
import tooltip from './tooltip';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
 | 
			
		||||
function buildIcon(name) {
 | 
			
		||||
  return new Icon(name);
 | 
			
		||||
@ -63,6 +62,7 @@ function toggleChange(type) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class DropdownMore extends Dropdown {
 | 
			
		||||
  moreBtns: HComponent;
 | 
			
		||||
  constructor() {
 | 
			
		||||
    const icon = new Icon('ellipsis');
 | 
			
		||||
    const moreBtns = h('div', `${cssPrefix}-toolbar-more`);
 | 
			
		||||
@ -115,7 +115,6 @@ export default class Toolbar {
 | 
			
		||||
    this.change = () => {};
 | 
			
		||||
    this.widthFn = widthFn;
 | 
			
		||||
    const style = data.defaultStyle();
 | 
			
		||||
    // console.log('data:', data);
 | 
			
		||||
    this.ddFormat = new DropdownFormat();
 | 
			
		||||
    this.ddFont = new DropdownFont();
 | 
			
		||||
    this.ddFormula = new DropdownFormula();
 | 
			
		||||
@ -211,13 +210,10 @@ export default class Toolbar {
 | 
			
		||||
    const { data } = this;
 | 
			
		||||
    const style = data.getSelectedCellStyle();
 | 
			
		||||
    const cell = data.getSelectedCell();
 | 
			
		||||
    // console.log('canUndo:', data.canUndo());
 | 
			
		||||
    this.undoEl.disabled(!data.canUndo());
 | 
			
		||||
    this.redoEl.disabled(!data.canRedo());
 | 
			
		||||
    this.mergeEl.active(data.canUnmerge()).disabled(!data.selector.multiple());
 | 
			
		||||
    this.autofilterEl.active(!data.canAutofilter());
 | 
			
		||||
    // this.mergeEl.disabled();
 | 
			
		||||
    // console.log('selectedCell:', style, cell);
 | 
			
		||||
    const { font } = style;
 | 
			
		||||
    this.ddFont.setTitle(font.name);
 | 
			
		||||
    this.ddFontSize.setTitle(font.size);
 | 
			
		||||
@ -230,7 +226,6 @@ export default class Toolbar {
 | 
			
		||||
    this.ddAlign.setTitle(style.align);
 | 
			
		||||
    this.ddVAlign.setTitle(style.valign);
 | 
			
		||||
    this.textwrapEl.active(style.textwrap);
 | 
			
		||||
    // console.log('freeze is Active:', data.freezeIsActive());
 | 
			
		||||
    this.freezeEl.active(data.freezeIsActive());
 | 
			
		||||
    if (cell) {
 | 
			
		||||
      if (cell.format) {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownAlign from '../dropdown_align';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownAlign from '../dropdown_align';
 | 
			
		||||
 | 
			
		||||
export default class Align extends DropdownItem {
 | 
			
		||||
  constructor(value) {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownBorder from '../dropdown_border';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownBorder from '../dropdown_border';
 | 
			
		||||
 | 
			
		||||
export default class Border extends DropdownItem {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownColor from '../dropdown_color';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownColor from '../dropdown_color';
 | 
			
		||||
 | 
			
		||||
export default class FillColor extends DropdownItem {
 | 
			
		||||
  constructor(color) {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownFont from '../dropdown_font';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownFont from '../dropdown_font';
 | 
			
		||||
 | 
			
		||||
export default class Font extends DropdownItem {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownFontsize from '../dropdown_fontsize';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownFontsize from '../dropdown_fontsize';
 | 
			
		||||
 | 
			
		||||
export default class Format extends DropdownItem {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownFormat from '../dropdown_format';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownFormat from '../dropdown_format';
 | 
			
		||||
 | 
			
		||||
export default class Format extends DropdownItem {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownFormula from '../dropdown_formula';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownFormula from '../dropdown_formula';
 | 
			
		||||
 | 
			
		||||
export default class Format extends DropdownItem {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import Icon from '../icon';
 | 
			
		||||
import Item from './item';
 | 
			
		||||
import Icon from '../icon';
 | 
			
		||||
 | 
			
		||||
export default class IconItem extends Item {
 | 
			
		||||
  element() {
 | 
			
		||||
@ -1,32 +1,33 @@
 | 
			
		||||
/* global window */
 | 
			
		||||
 | 
			
		||||
import { cssPrefix } from '../../config';
 | 
			
		||||
import { h } from '../element';
 | 
			
		||||
import { bind } from '../event';
 | 
			
		||||
import Align from './align';
 | 
			
		||||
import Valign from './valign';
 | 
			
		||||
import Autofilter from './autofilter';
 | 
			
		||||
import Bold from './bold';
 | 
			
		||||
import Italic from './italic';
 | 
			
		||||
import Strike from './strike';
 | 
			
		||||
import Underline from './underline';
 | 
			
		||||
import Border from './border';
 | 
			
		||||
import Clearformat from './clearformat';
 | 
			
		||||
import Paintformat from './paintformat';
 | 
			
		||||
import TextColor from './text_color';
 | 
			
		||||
import FillColor from './fill_color';
 | 
			
		||||
import Font from './font';
 | 
			
		||||
import FontSize from './font_size';
 | 
			
		||||
import Font from './font';
 | 
			
		||||
import Format from './format';
 | 
			
		||||
import Formula from './formula';
 | 
			
		||||
import Freeze from './freeze';
 | 
			
		||||
import Italic from './italic';
 | 
			
		||||
import Item from './item';
 | 
			
		||||
import Merge from './merge';
 | 
			
		||||
import More from './more';
 | 
			
		||||
import Paintformat from './paintformat';
 | 
			
		||||
import Print from './print';
 | 
			
		||||
import Redo from './redo';
 | 
			
		||||
import Strike from './strike';
 | 
			
		||||
import TextColor from './text_color';
 | 
			
		||||
import Textwrap from './textwrap';
 | 
			
		||||
import Underline from './underline';
 | 
			
		||||
import Undo from './undo';
 | 
			
		||||
import Valign from './valign';
 | 
			
		||||
import Print from './print';
 | 
			
		||||
import Textwrap from './textwrap';
 | 
			
		||||
import More from './more';
 | 
			
		||||
import Item from './item';
 | 
			
		||||
 | 
			
		||||
import { h } from '../element';
 | 
			
		||||
import { cssPrefix } from '../../config';
 | 
			
		||||
import { bind } from '../event';
 | 
			
		||||
 | 
			
		||||
function buildDivider() {
 | 
			
		||||
  return h('div', `${cssPrefix}-toolbar-divider`);
 | 
			
		||||
@ -207,13 +208,13 @@ export default class Toolbar {
 | 
			
		||||
    if (this.isHide) return;
 | 
			
		||||
    const { data } = this;
 | 
			
		||||
    const style = data.getSelectedCellStyle();
 | 
			
		||||
    // console.log('canUndo:', data.canUndo());
 | 
			
		||||
 | 
			
		||||
    this.undoEl.setState(!data.canUndo());
 | 
			
		||||
    this.redoEl.setState(!data.canRedo());
 | 
			
		||||
    this.mergeEl.setState(data.canUnmerge(), !data.selector.multiple());
 | 
			
		||||
    this.autofilterEl.setState(!data.canAutofilter());
 | 
			
		||||
    // this.mergeEl.disabled();
 | 
			
		||||
    // console.log('selectedCell:', style, cell);
 | 
			
		||||
 | 
			
		||||
    const { font, format } = style;
 | 
			
		||||
    this.formatEl.setState(format);
 | 
			
		||||
    this.fontEl.setState(font.name);
 | 
			
		||||
@ -227,7 +228,7 @@ export default class Toolbar {
 | 
			
		||||
    this.alignEl.setState(style.align);
 | 
			
		||||
    this.valignEl.setState(style.valign);
 | 
			
		||||
    this.textwrapEl.setState(style.textwrap);
 | 
			
		||||
    // console.log('freeze is Active:', data.freezeIsActive());
 | 
			
		||||
 | 
			
		||||
    this.freezeEl.setState(data.freezeIsActive());
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { cssPrefix } from '../../config';
 | 
			
		||||
import { t } from '../../locale/locale';
 | 
			
		||||
import { h } from '../element';
 | 
			
		||||
import tooltip from '../tooltip';
 | 
			
		||||
import { h } from '../element';
 | 
			
		||||
import { t } from '../../locale/locale';
 | 
			
		||||
 | 
			
		||||
export default class Item {
 | 
			
		||||
  // tooltip
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
import { cssPrefix } from '../../config';
 | 
			
		||||
import Dropdown from '../dropdown';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
 | 
			
		||||
import { cssPrefix } from '../../config';
 | 
			
		||||
import { h } from '../element';
 | 
			
		||||
import Icon from '../icon';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
 | 
			
		||||
class DropdownMore extends Dropdown {
 | 
			
		||||
  constructor() {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownColor from '../dropdown_color';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownColor from '../dropdown_color';
 | 
			
		||||
 | 
			
		||||
export default class TextColor extends DropdownItem {
 | 
			
		||||
  constructor(color) {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import Icon from '../icon';
 | 
			
		||||
import Item from './item';
 | 
			
		||||
import Icon from '../icon';
 | 
			
		||||
 | 
			
		||||
export default class ToggleItem extends Item {
 | 
			
		||||
  element() {
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import DropdownAlign from '../dropdown_align';
 | 
			
		||||
import DropdownItem from './dropdown_item';
 | 
			
		||||
import DropdownAlign from '../dropdown_align';
 | 
			
		||||
 | 
			
		||||
export default class Valign extends DropdownItem {
 | 
			
		||||
  constructor(value) {
 | 
			
		||||
@ -1,9 +1,8 @@
 | 
			
		||||
/* global document */
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { h } from './element';
 | 
			
		||||
import { bind } from './event';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
export default function tooltip(html, target) {
 | 
			
		||||
export default function tooltip(html: string, target) {
 | 
			
		||||
  if (target.classList.contains('active')) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
@ -11,7 +10,6 @@ export default function tooltip(html, target) {
 | 
			
		||||
  const el = h('div', `${cssPrefix}-tooltip`).html(html).show();
 | 
			
		||||
  document.body.appendChild(el.el);
 | 
			
		||||
  const elBox = el.box();
 | 
			
		||||
  // console.log('elBox:', elBox);
 | 
			
		||||
  el.css('left', `${left + width / 2 - elBox.width / 2}px`).css('top', `${top + height + 2}px`);
 | 
			
		||||
 | 
			
		||||
  bind(target, 'mouseleave', () => {
 | 
			
		||||
@ -0,0 +1,63 @@
 | 
			
		||||
import React, { useState } from 'react';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { tf } from '../locale/locale';
 | 
			
		||||
import { Icon } from './Icon';
 | 
			
		||||
 | 
			
		||||
// this.el = h('div', `${cssPrefix}-bottombar`).children(
 | 
			
		||||
//   this.contextMenu.el,
 | 
			
		||||
//   (this.menuEl = h('ul', `${cssPrefix}-menu`).child(
 | 
			
		||||
//     h('li', '').children(
 | 
			
		||||
//       new Icon('add').on('click', () => {
 | 
			
		||||
//         addFunc();
 | 
			
		||||
//       }),
 | 
			
		||||
//       h('span', '').child(this.moreEl),
 | 
			
		||||
//     ),
 | 
			
		||||
//   )),
 | 
			
		||||
// );
 | 
			
		||||
 | 
			
		||||
// this.el = h('div', `${cssPrefix}-contextmenu`)
 | 
			
		||||
//   .css('width', '160px')
 | 
			
		||||
//   .children(...buildMenu.call(this))
 | 
			
		||||
//   .hide();
 | 
			
		||||
// this.itemClick = () => {};
 | 
			
		||||
 | 
			
		||||
const menuItems = [
 | 
			
		||||
  { key: 'delete', title: tf('contextmenu.deleteSheet') },
 | 
			
		||||
  { key: 'rename', title: tf('contextmenu.renameSheet') },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
// return h('div', `${cssPrefix}-item`)
 | 
			
		||||
//   .child(item.title())
 | 
			
		||||
//   .on('click', () => {
 | 
			
		||||
//     this.itemClick(item.key);
 | 
			
		||||
//     this.hide();
 | 
			
		||||
//   });
 | 
			
		||||
 | 
			
		||||
export const ContextMenu = () => {
 | 
			
		||||
  const [visible, setVisible] = useState(false);
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={`${cssPrefix}-contextmenu`} style={{ width: '160px' }}>
 | 
			
		||||
      {visible ? menuItems.map((item) => <div key={item.key}>{item.title()}</div>) : null}
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const Bottombar = () => {
 | 
			
		||||
  const addSheet = () => {};
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={`${cssPrefix}-bottombar`}>
 | 
			
		||||
      <ContextMenu />
 | 
			
		||||
      <ul className={`${cssPrefix}-menu`}>
 | 
			
		||||
        <li>
 | 
			
		||||
          <Icon name="add" onClick={addSheet} />
 | 
			
		||||
          <Icon name="ellipsis" onClick={() => {}} />
 | 
			
		||||
        </li>
 | 
			
		||||
        <li className="active">sheet1</li>
 | 
			
		||||
        <li>sheet2</li>
 | 
			
		||||
        <li>sheet3</li>
 | 
			
		||||
        <li>sheet4</li>
 | 
			
		||||
      </ul>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,33 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
// super('div', `${cssPrefix}-dropdown ${placement}`);
 | 
			
		||||
// this.title = title;
 | 
			
		||||
// this.change = () => {};
 | 
			
		||||
// this.headerClick = () => {};
 | 
			
		||||
// if (typeof title === 'string') {
 | 
			
		||||
//   this.title = h('div', `${cssPrefix}-dropdown-title`).child(title);
 | 
			
		||||
// } else if (showArrow) {
 | 
			
		||||
//   this.title.addClass('arrow-left');
 | 
			
		||||
// }
 | 
			
		||||
// this.contentEl = h('div', `${cssPrefix}-dropdown-content`).css('width', width).hide();
 | 
			
		||||
 | 
			
		||||
// this.setContentChildren(...children);
 | 
			
		||||
 | 
			
		||||
// this.headerEl = h('div', `${cssPrefix}-dropdown-header`);
 | 
			
		||||
// this.headerEl
 | 
			
		||||
//   .on('click', () => {
 | 
			
		||||
//     if (this.contentEl.css('display') !== 'block') {
 | 
			
		||||
//       this.show();
 | 
			
		||||
//     } else {
 | 
			
		||||
//       this.hide();
 | 
			
		||||
//     }
 | 
			
		||||
//   })
 | 
			
		||||
//   .children(
 | 
			
		||||
//     this.title,
 | 
			
		||||
//     showArrow ? h('div', `${cssPrefix}-icon arrow-right`).child(h('div', `${cssPrefix}-icon-img arrow-down`)) : '',
 | 
			
		||||
//   );
 | 
			
		||||
// this.children(this.headerEl, this.contentEl);
 | 
			
		||||
 | 
			
		||||
export const Dropdown = () => {
 | 
			
		||||
  return <div></div>;
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,29 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
// class DropdownMore extends Dropdown {
 | 
			
		||||
//   constructor(click) {
 | 
			
		||||
//     const icon = new Icon('ellipsis');
 | 
			
		||||
//     super(icon, 'auto', false, 'top-left');
 | 
			
		||||
//     this.contentClick = click;
 | 
			
		||||
//   }
 | 
			
		||||
 | 
			
		||||
//   reset(items) {
 | 
			
		||||
//     const eles = items.map((it, i) =>
 | 
			
		||||
//       h('div', `${cssPrefix}-item`)
 | 
			
		||||
//         .css('width', '150px')
 | 
			
		||||
//         .css('font-weight', 'normal')
 | 
			
		||||
//         .on('click', () => {
 | 
			
		||||
//           this.contentClick(i);
 | 
			
		||||
//           this.hide();
 | 
			
		||||
//         })
 | 
			
		||||
//         .child(it),
 | 
			
		||||
//     );
 | 
			
		||||
//     this.setContentChildren(...eles);
 | 
			
		||||
//   }
 | 
			
		||||
 | 
			
		||||
//   setTitle() {}
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
export const DropdownMore = () => {
 | 
			
		||||
  return <div>Dropdown</div>;
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,25 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
// import { HComponent, h } from './element';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
 | 
			
		||||
// export default class Icon extends HComponent {
 | 
			
		||||
//   constructor(name) {
 | 
			
		||||
//     super('div', `${cssPrefix}-icon`);
 | 
			
		||||
//     this.iconNameEl = h('div', ``);
 | 
			
		||||
//     this.child(this.iconNameEl);
 | 
			
		||||
//   }
 | 
			
		||||
 | 
			
		||||
// FIXME setName Icon
 | 
			
		||||
//   setName(name) {
 | 
			
		||||
//     this.iconNameEl.className(`${cssPrefix}-icon-img ${name}`);
 | 
			
		||||
//   }
 | 
			
		||||
// }
 | 
			
		||||
 | 
			
		||||
export const Icon = ({ name, onClick }: { name: string; onClick: () => void }) => {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={`${cssPrefix}-icon`} onClick={onClick}>
 | 
			
		||||
      <div className={`${cssPrefix}-icon-img ${name}`} />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,5 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
export const Print = () => {
 | 
			
		||||
  return <div>Print</div>;
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,43 @@
 | 
			
		||||
import React, { createContext, useContext, useEffect, useState } from 'react';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { Bottombar } from './Bottombar';
 | 
			
		||||
import { Toolbar } from './Toolbar';
 | 
			
		||||
import { Table } from './Table';
 | 
			
		||||
import { Print } from './Print';
 | 
			
		||||
import { Options } from '..';
 | 
			
		||||
import DataProxy from '../core/data_proxy';
 | 
			
		||||
 | 
			
		||||
const SheetContext = createContext<DataProxy>(null);
 | 
			
		||||
 | 
			
		||||
export const useSheetData = () => {
 | 
			
		||||
  return useContext(SheetContext);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const SheetRoot = ({ options }: { options: Options }) => {
 | 
			
		||||
  const [data, setData] = useState<DataProxy>(null);
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    setData(new DataProxy('sheet1', options));
 | 
			
		||||
  }, [options]);
 | 
			
		||||
 | 
			
		||||
  if (!data) {
 | 
			
		||||
    return null;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <SheetContext.Provider value={data}>
 | 
			
		||||
      <div
 | 
			
		||||
        className={`${cssPrefix}`}
 | 
			
		||||
        onContextMenu={(e) => {
 | 
			
		||||
          e.preventDefault();
 | 
			
		||||
          e.stopPropagation();
 | 
			
		||||
        }}
 | 
			
		||||
      >
 | 
			
		||||
        <Toolbar />
 | 
			
		||||
        <Table />
 | 
			
		||||
        {/* <Print /> */}
 | 
			
		||||
      </div>
 | 
			
		||||
      <Bottombar />
 | 
			
		||||
    </SheetContext.Provider>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,22 @@
 | 
			
		||||
import React, { useEffect, useRef } from 'react';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { useSheetData } from './SheetRoot';
 | 
			
		||||
import { Draw } from '../canvas';
 | 
			
		||||
import CanvasTable from '../component/table';
 | 
			
		||||
 | 
			
		||||
export const Table = () => {
 | 
			
		||||
  const data = useSheetData();
 | 
			
		||||
  const ref = useRef();
 | 
			
		||||
 | 
			
		||||
  useEffect(() => {
 | 
			
		||||
    const draw = new Draw(ref.current, data.viewWidth(), data.viewHeight());
 | 
			
		||||
    const canvasTable = new CanvasTable(ref.current, data, draw);
 | 
			
		||||
    canvasTable.render();
 | 
			
		||||
  }, [data, ref]);
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={`${cssPrefix}-sheet`}>
 | 
			
		||||
      <canvas ref={ref} className={`${cssPrefix}-table`} />
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -0,0 +1,39 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
import { cssPrefix } from '../config';
 | 
			
		||||
import { Icon } from './Icon';
 | 
			
		||||
 | 
			
		||||
const btns = [
 | 
			
		||||
  'undo',
 | 
			
		||||
  'redo',
 | 
			
		||||
  'print',
 | 
			
		||||
  'paintformat',
 | 
			
		||||
  'clearformat',
 | 
			
		||||
  'divider',
 | 
			
		||||
  'bold',
 | 
			
		||||
  'italic',
 | 
			
		||||
  'underline',
 | 
			
		||||
  'strike',
 | 
			
		||||
  'divider',
 | 
			
		||||
  'merge',
 | 
			
		||||
  'textwrap',
 | 
			
		||||
  'freeze',
 | 
			
		||||
  'autofilter',
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const Toolbar = () => {
 | 
			
		||||
  return (
 | 
			
		||||
    <div className={`${cssPrefix}-toolbar`}>
 | 
			
		||||
      <div className={`${cssPrefix}-toolbar-btns`}>
 | 
			
		||||
        {btns.map((btn, i) =>
 | 
			
		||||
          btn === 'divider' ? (
 | 
			
		||||
            <div key={btn + i} className={`${cssPrefix}-toolbar-divider`} />
 | 
			
		||||
          ) : (
 | 
			
		||||
            <div key={btn} className={`${cssPrefix}-toolbar-btn`}>
 | 
			
		||||
              <Icon name={btn} onClick={() => {}} />
 | 
			
		||||
            </div>
 | 
			
		||||
          ),
 | 
			
		||||
        )}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
  );
 | 
			
		||||
};
 | 
			
		||||
@ -1,4 +1,3 @@
 | 
			
		||||
/* global window */
 | 
			
		||||
export const cssPrefix = 'x-spreadsheet';
 | 
			
		||||
export const dpr = window.devicePixelRatio || 1;
 | 
			
		||||
export default {
 | 
			
		||||
@ -1,28 +0,0 @@
 | 
			
		||||
// font.js
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {number} fontsizePX px for fontSize
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {number} fontsizePT pt for fontSize
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {object} BaseFont
 | 
			
		||||
 * @property {string} key inner key
 | 
			
		||||
 * @property {string} title title for display
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {object} FontSize
 | 
			
		||||
 * @property {fontsizePT} pt
 | 
			
		||||
 * @property {fontsizePX} px
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
// alphabet.js
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {string} tagA1 A1 tag for XY-tag (0, 0)
 | 
			
		||||
 * @example "A1"
 | 
			
		||||
 */
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {[number, number]} tagXY
 | 
			
		||||
 * @example [0, 0]
 | 
			
		||||
 */
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import './_.prototypes';
 | 
			
		||||
export type TagA1 = string;
 | 
			
		||||
export type TagXY = [number, number];
 | 
			
		||||
 | 
			
		||||
const alphabets = [
 | 
			
		||||
  'A',
 | 
			
		||||
@ -36,13 +37,13 @@ const alphabets = [
 | 
			
		||||
 * @param {number} index
 | 
			
		||||
 * @returns {string}
 | 
			
		||||
 */
 | 
			
		||||
export function stringAt(index) {
 | 
			
		||||
export function stringAt(index: number): string {
 | 
			
		||||
  let str = '';
 | 
			
		||||
  let cindex = index;
 | 
			
		||||
  while (cindex >= alphabets.length) {
 | 
			
		||||
    cindex /= alphabets.length;
 | 
			
		||||
    cindex -= 1;
 | 
			
		||||
    str += alphabets[parseInt(cindex, 10) % alphabets.length];
 | 
			
		||||
    str += alphabets[parseInt(String(cindex), 10) % alphabets.length];
 | 
			
		||||
  }
 | 
			
		||||
  const last = index % alphabets.length;
 | 
			
		||||
  str += alphabets[last];
 | 
			
		||||
@ -55,20 +56,19 @@ export function stringAt(index) {
 | 
			
		||||
 * @param {string} str "AA" in A1-tag "AA1"
 | 
			
		||||
 * @returns {number}
 | 
			
		||||
 */
 | 
			
		||||
export function indexAt(str) {
 | 
			
		||||
export function indexAt(str: TagA1) {
 | 
			
		||||
  let ret = 0;
 | 
			
		||||
  for (let i = 0; i !== str.length; ++i) ret = 26 * ret + str.charCodeAt(i) - 64;
 | 
			
		||||
  return ret - 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// B10 => x,y
 | 
			
		||||
/** translate A1-tag to XY-tag
 | 
			
		||||
 * @date 2019-10-10
 | 
			
		||||
 * @export
 | 
			
		||||
 * @param {tagA1} src
 | 
			
		||||
 * @returns {tagXY}
 | 
			
		||||
 * @param {TagA1} src
 | 
			
		||||
 * @returns {TagXY}
 | 
			
		||||
 */
 | 
			
		||||
export function expr2xy(src) {
 | 
			
		||||
export function expr2xy(src: TagA1): TagXY {
 | 
			
		||||
  let x = '';
 | 
			
		||||
  let y = '';
 | 
			
		||||
  for (let i = 0; i < src.length; i += 1) {
 | 
			
		||||
@ -87,21 +87,21 @@ export function expr2xy(src) {
 | 
			
		||||
 * @export
 | 
			
		||||
 * @param {number} x
 | 
			
		||||
 * @param {number} y
 | 
			
		||||
 * @returns {tagA1}
 | 
			
		||||
 * @returns {TagA1}
 | 
			
		||||
 */
 | 
			
		||||
export function xy2expr(x, y) {
 | 
			
		||||
export function xy2expr(x: number, y: number): TagA1 {
 | 
			
		||||
  return `${stringAt(x)}${y + 1}`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** translate A1-tag src by (xn, yn)
 | 
			
		||||
 * @date 2019-10-10
 | 
			
		||||
 * @export
 | 
			
		||||
 * @param {tagA1} src
 | 
			
		||||
 * @param {TagA1} src
 | 
			
		||||
 * @param {number} xn
 | 
			
		||||
 * @param {number} yn
 | 
			
		||||
 * @returns {tagA1}
 | 
			
		||||
 * @returns {TagA1}
 | 
			
		||||
 */
 | 
			
		||||
export function expr2expr(src, xn, yn, condition = () => true) {
 | 
			
		||||
export function expr2expr(src: TagA1, xn: number, yn: number, condition = (a, b) => true): TagA1 {
 | 
			
		||||
  if (xn === 0 && yn === 0) return src;
 | 
			
		||||
  const [x, y] = expr2xy(src);
 | 
			
		||||
  if (!condition(x, y)) return src;
 | 
			
		||||
@ -1,27 +1,39 @@
 | 
			
		||||
import { CellRange } from './cell_range';
 | 
			
		||||
 | 
			
		||||
// operator: all|eq|neq|gt|gte|lt|lte|in|be
 | 
			
		||||
// value:
 | 
			
		||||
//   in => []
 | 
			
		||||
//   be => [min, max]
 | 
			
		||||
 | 
			
		||||
export const enum FilterOperator {
 | 
			
		||||
  ALL = 'all',
 | 
			
		||||
  IN = 'in',
 | 
			
		||||
  EQ = 'eq',
 | 
			
		||||
  NEQ = 'neq',
 | 
			
		||||
  GT = 'gt',
 | 
			
		||||
  GTE = 'gte',
 | 
			
		||||
  LT = 'lt',
 | 
			
		||||
  LTE = 'lte',
 | 
			
		||||
  BE = 'be',
 | 
			
		||||
  NBE = 'nbe',
 | 
			
		||||
}
 | 
			
		||||
class Filter {
 | 
			
		||||
  constructor(ci, operator, value) {
 | 
			
		||||
    this.ci = ci;
 | 
			
		||||
  constructor(
 | 
			
		||||
    public ci: unknown,
 | 
			
		||||
    public operator: FilterOperator,
 | 
			
		||||
    public value: unknown[],
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  set(operator: FilterOperator, value) {
 | 
			
		||||
    this.operator = operator;
 | 
			
		||||
    this.value = value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  set(operator, value) {
 | 
			
		||||
    this.operator = operator;
 | 
			
		||||
    this.value = value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  includes(v) {
 | 
			
		||||
  includes(v: unknown[]) {
 | 
			
		||||
    const { operator, value } = this;
 | 
			
		||||
    if (operator === 'all') {
 | 
			
		||||
    if (operator === FilterOperator.ALL) {
 | 
			
		||||
      return true;
 | 
			
		||||
    }
 | 
			
		||||
    if (operator === 'in') {
 | 
			
		||||
    if (operator === FilterOperator.IN) {
 | 
			
		||||
      return value.includes(v);
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
@ -29,7 +41,7 @@ class Filter {
 | 
			
		||||
 | 
			
		||||
  vlength() {
 | 
			
		||||
    const { operator, value } = this;
 | 
			
		||||
    if (operator === 'in') {
 | 
			
		||||
    if (operator === FilterOperator.IN) {
 | 
			
		||||
      return value.length;
 | 
			
		||||
    }
 | 
			
		||||
    return 0;
 | 
			
		||||
@ -42,10 +54,10 @@ class Filter {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Sort {
 | 
			
		||||
  constructor(ci, order) {
 | 
			
		||||
    this.ci = ci;
 | 
			
		||||
    this.order = order;
 | 
			
		||||
  }
 | 
			
		||||
  constructor(
 | 
			
		||||
    public ci: unknown,
 | 
			
		||||
    public order: 'asc' | 'desc',
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  asc() {
 | 
			
		||||
    return this.order === 'asc';
 | 
			
		||||
@ -57,6 +69,9 @@ class Sort {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class AutoFilter {
 | 
			
		||||
  ref: string | null;
 | 
			
		||||
  filters: Filter[];
 | 
			
		||||
  sort: Sort | null;
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.ref = null;
 | 
			
		||||
    this.filters = [];
 | 
			
		||||
@ -30,7 +30,6 @@ const infixExprToSuffixExpr = (src) => {
 | 
			
		||||
      } else if (c === '-' && /[+\-*/,(]/.test(oldc)) {
 | 
			
		||||
        subStrs.push(c);
 | 
			
		||||
      } else {
 | 
			
		||||
        // console.log('subStrs:', subStrs.join(''), stack);
 | 
			
		||||
        if (c !== '(' && subStrs.length > 0) {
 | 
			
		||||
          stack.push(subStrs.join(''));
 | 
			
		||||
        }
 | 
			
		||||
@ -41,7 +40,7 @@ const infixExprToSuffixExpr = (src) => {
 | 
			
		||||
            try {
 | 
			
		||||
              const [ex, ey] = expr2xy(stack.pop());
 | 
			
		||||
              const [sx, sy] = expr2xy(stack.pop());
 | 
			
		||||
              // console.log('::', sx, sy, ex, ey);
 | 
			
		||||
 | 
			
		||||
              let rangelen = 0;
 | 
			
		||||
              for (let x = sx; x <= ex; x += 1) {
 | 
			
		||||
                for (let y = sy; y <= ey; y += 1) {
 | 
			
		||||
@ -51,7 +50,7 @@ const infixExprToSuffixExpr = (src) => {
 | 
			
		||||
              }
 | 
			
		||||
              stack.push([c1, rangelen]);
 | 
			
		||||
            } catch (e) {
 | 
			
		||||
              // console.log(e);
 | 
			
		||||
              console.error(e);
 | 
			
		||||
            }
 | 
			
		||||
          } else if (fnArgType === 1 || fnArgType === 3) {
 | 
			
		||||
            if (fnArgType === 3) stack.push(fnArgOperator);
 | 
			
		||||
@ -59,7 +58,6 @@ const infixExprToSuffixExpr = (src) => {
 | 
			
		||||
            stack.push([c1, fnArgsLen]);
 | 
			
		||||
            fnArgsLen = 1;
 | 
			
		||||
          } else {
 | 
			
		||||
            // console.log('c1:', c1, fnArgType, stack, operatorStack);
 | 
			
		||||
            while (c1 !== '(') {
 | 
			
		||||
              stack.push(c1);
 | 
			
		||||
              if (operatorStack.length <= 0) break;
 | 
			
		||||
@ -88,7 +86,7 @@ const infixExprToSuffixExpr = (src) => {
 | 
			
		||||
          operatorStack.push(subStrs.join(''));
 | 
			
		||||
        } else {
 | 
			
		||||
          // priority: */ > +-
 | 
			
		||||
          // console.log('xxxx:', operatorStack, c, stack);
 | 
			
		||||
 | 
			
		||||
          if (operatorStack.length > 0 && (c === '+' || c === '-')) {
 | 
			
		||||
            let top = operatorStack[operatorStack.length - 1];
 | 
			
		||||
            if (top !== '(') stack.push(operatorStack.pop());
 | 
			
		||||
@ -143,9 +141,8 @@ const evalSubExpr = (subExpr, cellRender) => {
 | 
			
		||||
// cellRender: (x, y) => {}
 | 
			
		||||
const evalSuffixExpr = (srcStack, formulaMap, cellRender, cellList) => {
 | 
			
		||||
  const stack = [];
 | 
			
		||||
  // console.log(':::::formulaMap:', formulaMap);
 | 
			
		||||
 | 
			
		||||
  for (let i = 0; i < srcStack.length; i += 1) {
 | 
			
		||||
    // console.log(':::>>>', srcStack[i]);
 | 
			
		||||
    const expr = srcStack[i];
 | 
			
		||||
    const fc = expr[0];
 | 
			
		||||
    if (expr === '+') {
 | 
			
		||||
@ -199,7 +196,6 @@ const evalSuffixExpr = (srcStack, formulaMap, cellRender, cellList) => {
 | 
			
		||||
      stack.push(evalSubExpr(expr, cellRender));
 | 
			
		||||
      cellList.pop();
 | 
			
		||||
    }
 | 
			
		||||
    // console.log('stack:', stack);
 | 
			
		||||
  }
 | 
			
		||||
  return stack[0];
 | 
			
		||||
};
 | 
			
		||||
@ -1,16 +1,16 @@
 | 
			
		||||
import { expr2xy, xy2expr } from './alphabet';
 | 
			
		||||
import { xy2expr, expr2xy } from './alphabet';
 | 
			
		||||
 | 
			
		||||
class CellRange {
 | 
			
		||||
  constructor(sri, sci, eri, eci, w = 0, h = 0) {
 | 
			
		||||
    this.sri = sri;
 | 
			
		||||
    this.sci = sci;
 | 
			
		||||
    this.eri = eri;
 | 
			
		||||
    this.eci = eci;
 | 
			
		||||
    this.w = w;
 | 
			
		||||
    this.h = h;
 | 
			
		||||
  }
 | 
			
		||||
  constructor(
 | 
			
		||||
    public sri: number,
 | 
			
		||||
    public sci: number,
 | 
			
		||||
    public eri: number,
 | 
			
		||||
    public eci: number,
 | 
			
		||||
    public w = 0,
 | 
			
		||||
    public h = 0,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  set(sri, sci, eri, eci) {
 | 
			
		||||
  set(sri: number, sci: number, eri: number, eci: number) {
 | 
			
		||||
    this.sri = sri;
 | 
			
		||||
    this.sci = sci;
 | 
			
		||||
    this.eri = eri;
 | 
			
		||||
@ -23,18 +23,20 @@ class CellRange {
 | 
			
		||||
 | 
			
		||||
  // cell-index: ri, ci
 | 
			
		||||
  // cell-ref: A10
 | 
			
		||||
  includes(...args) {
 | 
			
		||||
  includes(a: string, b: undefined): boolean;
 | 
			
		||||
  includes(a: number, b: number): boolean;
 | 
			
		||||
  includes(a: string | number, b: number | undefined): boolean {
 | 
			
		||||
    let [ri, ci] = [0, 0];
 | 
			
		||||
    if (args.length === 1) {
 | 
			
		||||
      [ci, ri] = expr2xy(args[0]);
 | 
			
		||||
    } else if (args.length === 2) {
 | 
			
		||||
      [ri, ci] = args;
 | 
			
		||||
    if (typeof a === 'string') {
 | 
			
		||||
      [ci, ri] = expr2xy(a);
 | 
			
		||||
    } else if (typeof a === 'number') {
 | 
			
		||||
      [ri, ci] = [a, b];
 | 
			
		||||
    }
 | 
			
		||||
    const { sri, sci, eri, eci } = this;
 | 
			
		||||
    return sri <= ri && ri <= eri && sci <= ci && ci <= eci;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  each(cb, rowFilter = () => true) {
 | 
			
		||||
  each(cb, rowFilter = (i: number) => true) {
 | 
			
		||||
    const { sri, sci, eri, eci } = this;
 | 
			
		||||
    for (let i = sri; i <= eri; i += 1) {
 | 
			
		||||
      if (rowFilter(i)) {
 | 
			
		||||
@ -45,27 +47,27 @@ class CellRange {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  contains(other) {
 | 
			
		||||
  contains(other: CellRange) {
 | 
			
		||||
    return this.sri <= other.sri && this.sci <= other.sci && this.eri >= other.eri && this.eci >= other.eci;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // within
 | 
			
		||||
  within(other) {
 | 
			
		||||
  within(other: CellRange) {
 | 
			
		||||
    return this.sri >= other.sri && this.sci >= other.sci && this.eri <= other.eri && this.eci <= other.eci;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // disjoint
 | 
			
		||||
  disjoint(other) {
 | 
			
		||||
  disjoint(other: CellRange) {
 | 
			
		||||
    return this.sri > other.eri || this.sci > other.eci || other.sri > this.eri || other.sci > this.eci;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // intersects
 | 
			
		||||
  intersects(other) {
 | 
			
		||||
  intersects(other: CellRange) {
 | 
			
		||||
    return this.sri <= other.eri && this.sci <= other.eci && other.sri <= this.eri && other.sci <= this.eci;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // union
 | 
			
		||||
  union(other) {
 | 
			
		||||
  union(other: CellRange) {
 | 
			
		||||
    const { sri, sci, eri, eci } = this;
 | 
			
		||||
    return new CellRange(
 | 
			
		||||
      other.sri < sri ? other.sri : sri,
 | 
			
		||||
@ -80,7 +82,7 @@ class CellRange {
 | 
			
		||||
 | 
			
		||||
  // Returns Array<CellRange> that represents that part of this that does not intersect with other
 | 
			
		||||
  // difference
 | 
			
		||||
  difference(other) {
 | 
			
		||||
  difference(other: CellRange) {
 | 
			
		||||
    const ret = [];
 | 
			
		||||
    const addRet = (sri, sci, eri, eci) => {
 | 
			
		||||
      ret.push(new CellRange(sri, sci, eri, eci));
 | 
			
		||||
@ -171,11 +173,11 @@ class CellRange {
 | 
			
		||||
  }
 | 
			
		||||
  */
 | 
			
		||||
 | 
			
		||||
  equals(other) {
 | 
			
		||||
  equals(other: CellRange) {
 | 
			
		||||
    return this.eri === other.eri && this.eci === other.eci && this.sri === other.sri && this.sci === other.sci;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static valueOf(ref) {
 | 
			
		||||
  static valueOf(ref: string) {
 | 
			
		||||
    // B1:B8, B1 => 1 x 1 cell range
 | 
			
		||||
    const refs = ref.split(':');
 | 
			
		||||
    const [sci, sri] = expr2xy(refs[0]);
 | 
			
		||||
@ -1,16 +1,20 @@
 | 
			
		||||
import CellRange from './cell_range';
 | 
			
		||||
 | 
			
		||||
export default class Clipboard {
 | 
			
		||||
  range: CellRange;
 | 
			
		||||
  state: 'clear' | 'cut' | 'copy';
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.range = null; // CellRange
 | 
			
		||||
    this.state = 'clear';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  copy(cellRange) {
 | 
			
		||||
  copy(cellRange: CellRange) {
 | 
			
		||||
    this.range = cellRange;
 | 
			
		||||
    this.state = 'copy';
 | 
			
		||||
    return this;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  cut(cellRange) {
 | 
			
		||||
  cut(cellRange: CellRange) {
 | 
			
		||||
    this.range = cellRange;
 | 
			
		||||
    this.state = 'cut';
 | 
			
		||||
    return this;
 | 
			
		||||
@ -1,6 +1,12 @@
 | 
			
		||||
import helper from './helper';
 | 
			
		||||
 | 
			
		||||
class Cols {
 | 
			
		||||
  _: {};
 | 
			
		||||
  len: number;
 | 
			
		||||
  width: number;
 | 
			
		||||
  indexWidth: number;
 | 
			
		||||
  minWidth: number;
 | 
			
		||||
 | 
			
		||||
  constructor({ len, width, indexWidth, minWidth }) {
 | 
			
		||||
    this._ = {};
 | 
			
		||||
    this.len = len;
 | 
			
		||||
@ -1,18 +1,16 @@
 | 
			
		||||
/* global document */
 | 
			
		||||
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import { expr2xy, xy2expr } from './alphabet';
 | 
			
		||||
import AutoFilter from './auto_filter';
 | 
			
		||||
import { CellRange } from './cell_range';
 | 
			
		||||
import Clipboard from './clipboard';
 | 
			
		||||
import { Cols } from './col';
 | 
			
		||||
import helper from './helper';
 | 
			
		||||
import History from './history';
 | 
			
		||||
import { Merges } from './merge';
 | 
			
		||||
import { Rows } from './row';
 | 
			
		||||
import Scroll from './scroll';
 | 
			
		||||
import Selector from './selector';
 | 
			
		||||
import Scroll from './scroll';
 | 
			
		||||
import History from './history';
 | 
			
		||||
import Clipboard from './clipboard';
 | 
			
		||||
import AutoFilter from './auto_filter';
 | 
			
		||||
import { Merges } from './merge';
 | 
			
		||||
import helper from './helper';
 | 
			
		||||
import { Rows } from './row';
 | 
			
		||||
import { Cols } from './col';
 | 
			
		||||
import { Validations } from './validation';
 | 
			
		||||
import { CellRange } from './cell_range';
 | 
			
		||||
import { expr2xy, xy2expr } from './alphabet';
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
 | 
			
		||||
// private methods
 | 
			
		||||
/*
 | 
			
		||||
@ -109,9 +107,7 @@ const defaultSettings = {
 | 
			
		||||
const toolbarHeight = 41;
 | 
			
		||||
const bottombarHeight = 41;
 | 
			
		||||
 | 
			
		||||
// src: cellRange
 | 
			
		||||
// dst: cellRange
 | 
			
		||||
function canPaste(src, dst, error = () => {}) {
 | 
			
		||||
function canPaste(src: CellRange, dst: CellRange, error = (e) => {}) {
 | 
			
		||||
  const { merges } = this;
 | 
			
		||||
  const cellRange = dst.clone();
 | 
			
		||||
  const [srn, scn] = src.size();
 | 
			
		||||
@ -137,7 +133,6 @@ function copyPaste(srcCellRange, dstCellRange, what, autofill = false) {
 | 
			
		||||
  }
 | 
			
		||||
  rows.copyPaste(srcCellRange, dstCellRange, what, autofill, (ri, ci, cell) => {
 | 
			
		||||
    if (cell && cell.merge) {
 | 
			
		||||
      // console.log('cell:', ri, ci, cell);
 | 
			
		||||
      const [rn, cn] = cell.merge;
 | 
			
		||||
      if (rn <= 0 && cn <= 0) return;
 | 
			
		||||
      merges.add(new CellRange(ri, ci, ri + rn, ci + cn));
 | 
			
		||||
@ -152,8 +147,15 @@ function cutPaste(srcCellRange, dstCellRange) {
 | 
			
		||||
  clipboard.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BorderStyles {
 | 
			
		||||
  top?: string[];
 | 
			
		||||
  bottom?: string[];
 | 
			
		||||
  left?: string[];
 | 
			
		||||
  right?: string[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// bss: { top, bottom, left, right }
 | 
			
		||||
function setStyleBorder(ri, ci, bss) {
 | 
			
		||||
function setStyleBorder(ri, ci, bss: BorderStyles) {
 | 
			
		||||
  const { styles, rows } = this;
 | 
			
		||||
  const cell = rows.getCellOrNew(ri, ci);
 | 
			
		||||
  let cstyle = {};
 | 
			
		||||
@ -225,7 +227,7 @@ function setStyleBorders({ mode, style, color }) {
 | 
			
		||||
        }
 | 
			
		||||
        const mrl = rn > 0 && ri + rn === eri;
 | 
			
		||||
        const mcl = cn > 0 && ci + cn === eci;
 | 
			
		||||
        let bss = {};
 | 
			
		||||
        let bss: BorderStyles = {};
 | 
			
		||||
        if (mode === 'all') {
 | 
			
		||||
          bss = {
 | 
			
		||||
            bottom: [style, color],
 | 
			
		||||
@ -280,7 +282,6 @@ function setStyleBorders({ mode, style, color }) {
 | 
			
		||||
function getCellRowByY(y, scrollOffsety) {
 | 
			
		||||
  const { rows } = this;
 | 
			
		||||
  const fsh = this.freezeTotalHeight();
 | 
			
		||||
  // console.log('y:', y, ', fsh:', fsh);
 | 
			
		||||
  let inits = rows.height;
 | 
			
		||||
  if (fsh + rows.height < y) inits -= scrollOffsety;
 | 
			
		||||
 | 
			
		||||
@ -298,7 +299,6 @@ function getCellRowByY(y, scrollOffsety) {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  top -= height;
 | 
			
		||||
  // console.log('ri:', ri, ', top:', top, ', height:', height);
 | 
			
		||||
 | 
			
		||||
  if (top <= 0) {
 | 
			
		||||
    return { ri: -1, top: 0, height };
 | 
			
		||||
@ -320,6 +320,33 @@ function getCellColByX(x, scrollOffsetx) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class DataProxy {
 | 
			
		||||
  clipboard: Clipboard;
 | 
			
		||||
  selector: Selector;
 | 
			
		||||
  // FIXME settings type
 | 
			
		||||
  settings: {
 | 
			
		||||
    style?: any;
 | 
			
		||||
    view?: any;
 | 
			
		||||
    row?: any;
 | 
			
		||||
    col?: any;
 | 
			
		||||
    showToolbar?: any;
 | 
			
		||||
    showBottomBar?: any;
 | 
			
		||||
  };
 | 
			
		||||
  name: any;
 | 
			
		||||
  freeze: number[];
 | 
			
		||||
  styles: any[];
 | 
			
		||||
  merges: Merges;
 | 
			
		||||
  rows: Rows;
 | 
			
		||||
  cols: Cols;
 | 
			
		||||
  validations: Validations;
 | 
			
		||||
  hyperlinks: {};
 | 
			
		||||
  comments: {};
 | 
			
		||||
  scroll: Scroll;
 | 
			
		||||
  history: History;
 | 
			
		||||
  autoFilter: AutoFilter;
 | 
			
		||||
  change: (a?) => void;
 | 
			
		||||
  exceptRowSet: Set<unknown>;
 | 
			
		||||
  sortedRowMap: Map<any, any>;
 | 
			
		||||
  unsortedRowMap: Map<any, any>;
 | 
			
		||||
  constructor(name, settings) {
 | 
			
		||||
    this.settings = helper.merge(defaultSettings, settings || {});
 | 
			
		||||
    // save data begin
 | 
			
		||||
@ -347,7 +374,6 @@ export default class DataProxy {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  addValidation(mode, ref, validator) {
 | 
			
		||||
    // console.log('mode:', mode, ', ref:', ref, ', validator:', validator);
 | 
			
		||||
    this.changeData(() => {
 | 
			
		||||
      this.validations.add(mode, ref, validator);
 | 
			
		||||
    });
 | 
			
		||||
@ -369,7 +395,7 @@ export default class DataProxy {
 | 
			
		||||
  getSelectedValidation() {
 | 
			
		||||
    const { ri, ci, range } = this.selector;
 | 
			
		||||
    const v = this.validations.get(ri, ci);
 | 
			
		||||
    const ret = { ref: range.toString() };
 | 
			
		||||
    const ret: any = { ref: range.toString() };
 | 
			
		||||
    if (v !== null) {
 | 
			
		||||
      ret.mode = v.mode;
 | 
			
		||||
      ret.validator = v.validator;
 | 
			
		||||
@ -402,7 +428,7 @@ export default class DataProxy {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  copyToSystemClipboard(evt) {
 | 
			
		||||
    let copyText = [];
 | 
			
		||||
    let copyText: string | any[] = [];
 | 
			
		||||
    const { sri, eri, sci, eci } = this.selector.range;
 | 
			
		||||
 | 
			
		||||
    for (let ri = sri; ri <= eri; ri += 1) {
 | 
			
		||||
@ -428,12 +454,15 @@ export default class DataProxy {
 | 
			
		||||
    // this need https protocol
 | 
			
		||||
    /* global navigator */
 | 
			
		||||
    if (navigator.clipboard) {
 | 
			
		||||
      navigator.clipboard.writeText(copyText).then(
 | 
			
		||||
        () => {},
 | 
			
		||||
        (err) => {
 | 
			
		||||
          console.log('text copy to the system clipboard error  ', copyText, err);
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
      navigator.clipboard
 | 
			
		||||
        .writeText(copyText)
 | 
			
		||||
        .then(
 | 
			
		||||
          () => {},
 | 
			
		||||
          (err) => {
 | 
			
		||||
            console.log('text copy to the system clipboard error  ', copyText, err);
 | 
			
		||||
          },
 | 
			
		||||
        )
 | 
			
		||||
        .catch(console.error);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -443,7 +472,6 @@ export default class DataProxy {
 | 
			
		||||
 | 
			
		||||
  // what: all | text | format
 | 
			
		||||
  paste(what = 'all', error = () => {}) {
 | 
			
		||||
    // console.log('sIndexes:', sIndexes);
 | 
			
		||||
    const { clipboard, selector } = this;
 | 
			
		||||
    if (clipboard.isClear()) return false;
 | 
			
		||||
    if (!canPaste.call(this, clipboard.range, selector.range, error)) return false;
 | 
			
		||||
@ -460,20 +488,23 @@ export default class DataProxy {
 | 
			
		||||
 | 
			
		||||
  pasteFromSystemClipboard(resetSheet, eventTrigger) {
 | 
			
		||||
    const { selector } = this;
 | 
			
		||||
    navigator.clipboard.readText().then((content) => {
 | 
			
		||||
      const contentToPaste = this.parseClipboardContent(content);
 | 
			
		||||
      let startRow = selector.ri;
 | 
			
		||||
      contentToPaste.forEach((row) => {
 | 
			
		||||
        let startColumn = selector.ci;
 | 
			
		||||
        row.forEach((cellContent) => {
 | 
			
		||||
          this.setCellText(startRow, startColumn, cellContent, 'input');
 | 
			
		||||
          startColumn += 1;
 | 
			
		||||
    navigator.clipboard
 | 
			
		||||
      .readText()
 | 
			
		||||
      .then((content) => {
 | 
			
		||||
        const contentToPaste = this.parseClipboardContent(content);
 | 
			
		||||
        let startRow = selector.ri;
 | 
			
		||||
        contentToPaste.forEach((row) => {
 | 
			
		||||
          let startColumn = selector.ci;
 | 
			
		||||
          row.forEach((cellContent) => {
 | 
			
		||||
            this.setCellText(startRow, startColumn, cellContent, 'input');
 | 
			
		||||
            startColumn += 1;
 | 
			
		||||
          });
 | 
			
		||||
          startRow += 1;
 | 
			
		||||
        });
 | 
			
		||||
        startRow += 1;
 | 
			
		||||
      });
 | 
			
		||||
      resetSheet();
 | 
			
		||||
      eventTrigger(this.rows.getData());
 | 
			
		||||
    });
 | 
			
		||||
        resetSheet();
 | 
			
		||||
        eventTrigger(this.rows.getData());
 | 
			
		||||
      })
 | 
			
		||||
      .catch(console.error);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  parseClipboardContent(clipboardContent) {
 | 
			
		||||
@ -533,14 +564,14 @@ export default class DataProxy {
 | 
			
		||||
    else [sci, eci] = [nci, cci];
 | 
			
		||||
    selector.range = merges.union(new CellRange(sri, sci, eri, eci));
 | 
			
		||||
    selector.range = merges.union(selector.range);
 | 
			
		||||
    // console.log('selector.range:', selector.range);
 | 
			
		||||
 | 
			
		||||
    return selector.range;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  calSelectedRangeByStart(ri, ci) {
 | 
			
		||||
    const { selector, rows, cols, merges } = this;
 | 
			
		||||
    let cellRange = merges.getFirstIncludes(ri, ci);
 | 
			
		||||
    // console.log('cellRange:', cellRange, ri, ci, merges);
 | 
			
		||||
 | 
			
		||||
    if (cellRange === null) {
 | 
			
		||||
      cellRange = new CellRange(ri, ci, ri, ci);
 | 
			
		||||
      if (ri === -1) {
 | 
			
		||||
@ -565,7 +596,6 @@ export default class DataProxy {
 | 
			
		||||
      } else if (property === 'border') {
 | 
			
		||||
        setStyleBorders.call(this, value);
 | 
			
		||||
      } else if (property === 'formula') {
 | 
			
		||||
        // console.log('>>>', selector.multiple());
 | 
			
		||||
        const { ri, ci, range } = selector;
 | 
			
		||||
        if (selector.multiple()) {
 | 
			
		||||
          const [rn, cn] = selector.size();
 | 
			
		||||
@ -586,7 +616,8 @@ export default class DataProxy {
 | 
			
		||||
      } else {
 | 
			
		||||
        selector.range.each((ri, ci) => {
 | 
			
		||||
          const cell = rows.getCellOrNew(ri, ci);
 | 
			
		||||
          let cstyle = {};
 | 
			
		||||
          // FIXME cstyle type
 | 
			
		||||
          let cstyle: any = {};
 | 
			
		||||
          if (cell.style !== undefined) {
 | 
			
		||||
            cstyle = helper.cloneDeep(styles[cell.style]);
 | 
			
		||||
          }
 | 
			
		||||
@ -641,7 +672,6 @@ export default class DataProxy {
 | 
			
		||||
        if (vIndex >= 0) {
 | 
			
		||||
          filter.value.splice(vIndex, 1, text);
 | 
			
		||||
        }
 | 
			
		||||
        // console.log('filter:', filter, oldCell);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // this.resetAutoFilter();
 | 
			
		||||
@ -660,7 +690,7 @@ export default class DataProxy {
 | 
			
		||||
    const { left, top, width, height } = this.getSelectedRect();
 | 
			
		||||
    const x1 = x - this.cols.indexWidth;
 | 
			
		||||
    const y1 = y - this.rows.height;
 | 
			
		||||
    // console.log('x:', x, ',y:', y, 'left:', left, 'top:', top);
 | 
			
		||||
 | 
			
		||||
    return x1 > left && x1 < left + width && y1 > top && y1 < top + height;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -679,7 +709,7 @@ export default class DataProxy {
 | 
			
		||||
  getRect(cellRange) {
 | 
			
		||||
    const { scroll, rows, cols, exceptRowSet } = this;
 | 
			
		||||
    const { sri, sci, eri, eci } = cellRange;
 | 
			
		||||
    // console.log('sri:', sri, ',sci:', sci, ', eri:', eri, ', eci:', eci);
 | 
			
		||||
 | 
			
		||||
    // no selector
 | 
			
		||||
    if (sri < 0 && sci < 0) {
 | 
			
		||||
      return {
 | 
			
		||||
@ -694,7 +724,7 @@ export default class DataProxy {
 | 
			
		||||
    const top = rows.sumHeight(0, sri, exceptRowSet);
 | 
			
		||||
    const height = rows.sumHeight(sri, eri + 1, exceptRowSet);
 | 
			
		||||
    const width = cols.sumWidth(sci, eci + 1);
 | 
			
		||||
    // console.log('sri:', sri, ', sci:', sci, ', eri:', eri, ', eci:', eci);
 | 
			
		||||
 | 
			
		||||
    let left0 = left - scroll.x;
 | 
			
		||||
    let top0 = top - scroll.y;
 | 
			
		||||
    const fsh = this.freezeTotalHeight();
 | 
			
		||||
@ -768,7 +798,7 @@ export default class DataProxy {
 | 
			
		||||
    const { selector, rows } = this;
 | 
			
		||||
    if (this.isSingleSelected()) return;
 | 
			
		||||
    const [rn, cn] = selector.size();
 | 
			
		||||
    // console.log('merge:', rn, cn);
 | 
			
		||||
 | 
			
		||||
    if (rn > 1 || cn > 1) {
 | 
			
		||||
      const { sri, sci } = selector.range;
 | 
			
		||||
      this.changeData(() => {
 | 
			
		||||
@ -777,7 +807,7 @@ export default class DataProxy {
 | 
			
		||||
        this.merges.add(selector.range);
 | 
			
		||||
        // delete merge cells
 | 
			
		||||
        this.rows.deleteCells(selector.range);
 | 
			
		||||
        // console.log('cell:', cell, this.d);
 | 
			
		||||
 | 
			
		||||
        this.rows.setCell(sri, sci, cell);
 | 
			
		||||
      });
 | 
			
		||||
    }
 | 
			
		||||
@ -826,7 +856,7 @@ export default class DataProxy {
 | 
			
		||||
    const fary = Array.from(fset);
 | 
			
		||||
    const oldAry = Array.from(fset);
 | 
			
		||||
    if (sort) {
 | 
			
		||||
      fary.sort((a, b) => {
 | 
			
		||||
      fary.sort((a: number, b: number) => {
 | 
			
		||||
        if (sort.order === 'asc') return a - b;
 | 
			
		||||
        if (sort.order === 'desc') return b - a;
 | 
			
		||||
        return 0;
 | 
			
		||||
@ -905,9 +935,8 @@ export default class DataProxy {
 | 
			
		||||
          }
 | 
			
		||||
        });
 | 
			
		||||
      }
 | 
			
		||||
      // console.log('type:', type, ', si:', si, ', size:', size);
 | 
			
		||||
 | 
			
		||||
      merges.shift(type, si, -size, (ri, ci, rn, cn) => {
 | 
			
		||||
        // console.log('ri:', ri, ', ci:', ci, ', rn:', rn, ', cn:', cn);
 | 
			
		||||
        const cell = rows.getCell(ri, ci);
 | 
			
		||||
        cell.merge[0] += rn;
 | 
			
		||||
        cell.merge[1] += cn;
 | 
			
		||||
@ -922,7 +951,7 @@ export default class DataProxy {
 | 
			
		||||
    const { scroll, freeze, cols } = this;
 | 
			
		||||
    const [, fci] = freeze;
 | 
			
		||||
    const [ci, left, width] = helper.rangeReduceIf(fci, cols.len, 0, 0, x, (i) => cols.getWidth(i));
 | 
			
		||||
    // console.log('fci:', fci, ', ci:', ci);
 | 
			
		||||
 | 
			
		||||
    let x1 = left;
 | 
			
		||||
    if (x > 0) x1 += width;
 | 
			
		||||
    if (scroll.x !== x1) {
 | 
			
		||||
@ -938,7 +967,7 @@ export default class DataProxy {
 | 
			
		||||
    const [ri, top, height] = helper.rangeReduceIf(fri, rows.len, 0, 0, y, (i) => rows.getHeight(i));
 | 
			
		||||
    let y1 = top;
 | 
			
		||||
    if (y > 0) y1 += height;
 | 
			
		||||
    // console.log('ri:', ri, ' ,y:', y1);
 | 
			
		||||
 | 
			
		||||
    if (scroll.y !== y1) {
 | 
			
		||||
      scroll.ri = y > 0 ? ri : 0;
 | 
			
		||||
      scroll.y = y1;
 | 
			
		||||
@ -956,7 +985,7 @@ export default class DataProxy {
 | 
			
		||||
    if (cell !== null) {
 | 
			
		||||
      if (cell.merge) {
 | 
			
		||||
        const [rn, cn] = cell.merge;
 | 
			
		||||
        // console.log('cell.merge:', cell.merge);
 | 
			
		||||
 | 
			
		||||
        if (rn > 0) {
 | 
			
		||||
          for (let i = 1; i <= rn; i += 1) {
 | 
			
		||||
            height += rows.getHeight(ri + i);
 | 
			
		||||
@ -969,7 +998,7 @@ export default class DataProxy {
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // console.log('data:', this.d);
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      left,
 | 
			
		||||
      top,
 | 
			
		||||
@ -1098,7 +1127,7 @@ export default class DataProxy {
 | 
			
		||||
 | 
			
		||||
  viewRange() {
 | 
			
		||||
    const { scroll, rows, cols, freeze, exceptRowSet } = this;
 | 
			
		||||
    // console.log('scroll:', scroll, ', freeze:', freeze)
 | 
			
		||||
 | 
			
		||||
    let { ri, ci } = scroll;
 | 
			
		||||
    if (ri <= 0) [ri] = freeze;
 | 
			
		||||
    if (ci <= 0) [, ci] = freeze;
 | 
			
		||||
@ -1117,7 +1146,7 @@ export default class DataProxy {
 | 
			
		||||
      eci = j;
 | 
			
		||||
      if (x > this.viewWidth()) break;
 | 
			
		||||
    }
 | 
			
		||||
    // console.log(ri, ci, eri, eci, x, y);
 | 
			
		||||
 | 
			
		||||
    return new CellRange(ri, ci, eri, eci, x, y);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1157,7 +1186,7 @@ export default class DataProxy {
 | 
			
		||||
        offset += 1;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // console.log('min:', min, ', max:', max, ', scroll:', scroll);
 | 
			
		||||
 | 
			
		||||
    for (let i = min + offset; i <= max + offset; i += 1) {
 | 
			
		||||
      if (frset.has(i)) {
 | 
			
		||||
        offset += 1;
 | 
			
		||||
@ -1191,7 +1220,7 @@ export default class DataProxy {
 | 
			
		||||
 | 
			
		||||
  addStyle(nstyle) {
 | 
			
		||||
    const { styles } = this;
 | 
			
		||||
    // console.log('old.styles:', styles, nstyle);
 | 
			
		||||
 | 
			
		||||
    for (let i = 0; i < styles.length; i += 1) {
 | 
			
		||||
      const style = styles[i];
 | 
			
		||||
      if (helper.equals(style, nstyle)) return i;
 | 
			
		||||
@ -1,10 +1,7 @@
 | 
			
		||||
// docs
 | 
			
		||||
import './_.prototypes';
 | 
			
		||||
 | 
			
		||||
/** default font list
 | 
			
		||||
 * @type {BaseFont[]}
 | 
			
		||||
 */
 | 
			
		||||
const baseFonts = [
 | 
			
		||||
const baseFonts: BaseFont[] = [
 | 
			
		||||
  { key: 'Arial', title: 'Arial' },
 | 
			
		||||
  { key: 'Helvetica', title: 'Helvetica' },
 | 
			
		||||
  { key: 'Source Sans Pro', title: 'Source Sans Pro' },
 | 
			
		||||
@ -14,10 +11,20 @@ const baseFonts = [
 | 
			
		||||
  { key: 'Lato', title: 'Lato' },
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/** default fontSize list
 | 
			
		||||
 * @type {FontSize[]}
 | 
			
		||||
 */
 | 
			
		||||
const fontSizes = [
 | 
			
		||||
export interface FontSize {
 | 
			
		||||
  pt: number;
 | 
			
		||||
  px: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BaseFont {
 | 
			
		||||
  key: string;
 | 
			
		||||
  title: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export type FontsizePX = number;
 | 
			
		||||
export type FontsizePT = number;
 | 
			
		||||
 | 
			
		||||
const fontSizes: FontSize[] = [
 | 
			
		||||
  { pt: 7.5, px: 10 },
 | 
			
		||||
  { pt: 8, px: 11 },
 | 
			
		||||
  { pt: 9, px: 12 },
 | 
			
		||||
@ -41,10 +48,10 @@ const fontSizes = [
 | 
			
		||||
 | 
			
		||||
/** map pt to px
 | 
			
		||||
 * @date 2019-10-10
 | 
			
		||||
 * @param {fontsizePT} pt
 | 
			
		||||
 * @returns {fontsizePX}
 | 
			
		||||
 * @param {FontsizePT} pt
 | 
			
		||||
 * @returns {FontsizePX}
 | 
			
		||||
 */
 | 
			
		||||
function getFontSizePxByPt(pt) {
 | 
			
		||||
function getFontSizePxByPt(pt: FontsizePT): FontsizePX {
 | 
			
		||||
  for (let i = 0; i < fontSizes.length; i += 1) {
 | 
			
		||||
    const fontSize = fontSizes[i];
 | 
			
		||||
    if (fontSize.pt === pt) {
 | 
			
		||||
@ -59,7 +66,7 @@ function getFontSizePxByPt(pt) {
 | 
			
		||||
 * @param {BaseFont[]} [ary=[]]
 | 
			
		||||
 * @returns {object}
 | 
			
		||||
 */
 | 
			
		||||
function fonts(ary = []) {
 | 
			
		||||
function fonts(ary: BaseFont[] = []) {
 | 
			
		||||
  const map = {};
 | 
			
		||||
  baseFonts.concat(ary).forEach((f) => {
 | 
			
		||||
    map[f.key] = f;
 | 
			
		||||
@ -1,20 +1,13 @@
 | 
			
		||||
/**
 | 
			
		||||
  formula:
 | 
			
		||||
    key
 | 
			
		||||
    title
 | 
			
		||||
    render
 | 
			
		||||
*/
 | 
			
		||||
/**
 | 
			
		||||
 * @typedef {object} Formula
 | 
			
		||||
 * @property {string} key
 | 
			
		||||
 * @property {function} title
 | 
			
		||||
 * @property {function} render
 | 
			
		||||
 */
 | 
			
		||||
import { tf } from '../locale/locale';
 | 
			
		||||
import { numberCalc } from './helper';
 | 
			
		||||
 | 
			
		||||
/** @type {Formula[]} */
 | 
			
		||||
const baseFormulas = [
 | 
			
		||||
export interface Formula {
 | 
			
		||||
  key: string;
 | 
			
		||||
  title: Function;
 | 
			
		||||
  render: Function;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const baseFormulas: Formula[] = [
 | 
			
		||||
  {
 | 
			
		||||
    key: 'SUM',
 | 
			
		||||
    title: tf('formula.sum'),
 | 
			
		||||
@ -1,5 +1,4 @@
 | 
			
		||||
/* eslint-disable no-param-reassign */
 | 
			
		||||
function cloneDeep(obj) {
 | 
			
		||||
function cloneDeep(obj: any) {
 | 
			
		||||
  return JSON.parse(JSON.stringify(obj));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -7,7 +6,7 @@ const mergeDeep = (object = {}, ...sources) => {
 | 
			
		||||
  sources.forEach((source) => {
 | 
			
		||||
    Object.keys(source).forEach((key) => {
 | 
			
		||||
      const v = source[key];
 | 
			
		||||
      // console.log('k:', key, ', v:', source[key], typeof v, v instanceof Object);
 | 
			
		||||
 | 
			
		||||
      if (typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean') {
 | 
			
		||||
        object[key] = v;
 | 
			
		||||
      } else if (typeof v !== 'function' && !Array.isArray(v) && v instanceof Object) {
 | 
			
		||||
@ -18,7 +17,7 @@ const mergeDeep = (object = {}, ...sources) => {
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  // console.log('::', object);
 | 
			
		||||
 | 
			
		||||
  return object;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -48,7 +47,7 @@ function equals(obj1, obj2) {
 | 
			
		||||
  objOrAry: obejct or Array
 | 
			
		||||
  cb: (value, index | key) => { return value }
 | 
			
		||||
*/
 | 
			
		||||
const sum = (objOrAry, cb = (value) => value) => {
 | 
			
		||||
const sum = (objOrAry, cb = (value, key: number | string) => value) => {
 | 
			
		||||
  let total = 0;
 | 
			
		||||
  let size = 0;
 | 
			
		||||
  Object.keys(objOrAry).forEach((key) => {
 | 
			
		||||
@ -144,4 +143,21 @@ export default {
 | 
			
		||||
  rangeReduceIf,
 | 
			
		||||
  deleteProperty,
 | 
			
		||||
  numberCalc,
 | 
			
		||||
};
 | 
			
		||||
}; /**
 | 
			
		||||
 * @desc throttle fn
 | 
			
		||||
 * @param func function
 | 
			
		||||
 * @param wait Delay in milliseconds
 | 
			
		||||
 */
 | 
			
		||||
export function throttle(func: Function, wait: number) {
 | 
			
		||||
  let timeout: ReturnType<typeof setTimeout>;
 | 
			
		||||
  return (...arg: any) => {
 | 
			
		||||
    const that = this;
 | 
			
		||||
    const args = arg;
 | 
			
		||||
    if (!timeout) {
 | 
			
		||||
      timeout = setTimeout(() => {
 | 
			
		||||
        timeout = null;
 | 
			
		||||
        func.apply(that, args);
 | 
			
		||||
      }, wait);
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
// import helper from '../helper';
 | 
			
		||||
 | 
			
		||||
export default class History {
 | 
			
		||||
  undoItems: any[];
 | 
			
		||||
  redoItems: any[];
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.undoItems = [];
 | 
			
		||||
    this.redoItems = [];
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
import { CellRange } from './cell_range';
 | 
			
		||||
 | 
			
		||||
class Merges {
 | 
			
		||||
  _: any[];
 | 
			
		||||
  constructor(d = []) {
 | 
			
		||||
    this._ = d;
 | 
			
		||||
  }
 | 
			
		||||
@ -31,7 +32,6 @@ class Merges {
 | 
			
		||||
    for (let i = 0; i < this._.length; i += 1) {
 | 
			
		||||
      const it = this._[i];
 | 
			
		||||
      if (it.intersects(cellRange)) {
 | 
			
		||||
        // console.log('intersects');
 | 
			
		||||
        return true;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@ -1,7 +1,10 @@
 | 
			
		||||
import { expr2expr } from './alphabet';
 | 
			
		||||
import helper from './helper';
 | 
			
		||||
import { expr2expr } from './alphabet';
 | 
			
		||||
 | 
			
		||||
class Rows {
 | 
			
		||||
  len: number;
 | 
			
		||||
  height: number;
 | 
			
		||||
  _: {};
 | 
			
		||||
  constructor({ len, height }) {
 | 
			
		||||
    this._ = {};
 | 
			
		||||
    this.len = len;
 | 
			
		||||
@ -49,7 +52,7 @@ class Rows {
 | 
			
		||||
    row.style = style;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sumHeight(min, max, exceptSet) {
 | 
			
		||||
  sumHeight(min, max, exceptSet?) {
 | 
			
		||||
    return helper.rangeSum(min, max, (i) => {
 | 
			
		||||
      if (exceptSet && exceptSet.has(i)) return 0;
 | 
			
		||||
      return this.getHeight(i);
 | 
			
		||||
@ -110,7 +113,7 @@ class Rows {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // what: all | format | text
 | 
			
		||||
  copyPaste(srcCellRange, dstCellRange, what, autofill = false, cb = () => {}) {
 | 
			
		||||
  copyPaste(srcCellRange, dstCellRange, what, autofill = false, cb = (nri, nci, ncell) => {}) {
 | 
			
		||||
    const { sri, sci, eri, eci } = srcCellRange;
 | 
			
		||||
    const dsri = dstCellRange.sri;
 | 
			
		||||
    const dsci = dstCellRange.sci;
 | 
			
		||||
@ -118,7 +121,6 @@ class Rows {
 | 
			
		||||
    const deci = dstCellRange.eci;
 | 
			
		||||
    const [rn, cn] = srcCellRange.size();
 | 
			
		||||
    const [drn, dcn] = dstCellRange.size();
 | 
			
		||||
    // console.log(srcIndexes, dstIndexes);
 | 
			
		||||
    let isAdd = true;
 | 
			
		||||
    let dn = 0;
 | 
			
		||||
    if (deri < sri || deci < sci) {
 | 
			
		||||
@ -160,7 +162,6 @@ class Rows {
 | 
			
		||||
                    (rn <= 1 && cn <= 1)
 | 
			
		||||
                  ) {
 | 
			
		||||
                    const result = /[\\.\d]+$/.exec(text);
 | 
			
		||||
                    // console.log('result:', result);
 | 
			
		||||
                    if (result !== null) {
 | 
			
		||||
                      const index = Number(result[0]) + n - 1;
 | 
			
		||||
                      ncell.text = text.substring(0, result.index) + index;
 | 
			
		||||
@ -1,8 +0,0 @@
 | 
			
		||||
export default class Scroll {
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.x = 0; // left
 | 
			
		||||
    this.y = 0; // top
 | 
			
		||||
    this.ri = 0; // cell row-index
 | 
			
		||||
    this.ci = 0; // cell col-index
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,7 @@
 | 
			
		||||
export default class Scroll {
 | 
			
		||||
  x = 0; // left
 | 
			
		||||
  y = 0; // top
 | 
			
		||||
  ri = 0; // cell row-index
 | 
			
		||||
  ci = 0; // cell col-index
 | 
			
		||||
  constructor() {}
 | 
			
		||||
}
 | 
			
		||||
@ -1,6 +1,9 @@
 | 
			
		||||
import { CellRange } from './cell_range';
 | 
			
		||||
 | 
			
		||||
export default class Selector {
 | 
			
		||||
  range: CellRange;
 | 
			
		||||
  ri: number;
 | 
			
		||||
  ci: number;
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.range = new CellRange(0, 0, 0, 0);
 | 
			
		||||
    this.ri = 0;
 | 
			
		||||
@ -11,7 +14,7 @@ export default class Selector {
 | 
			
		||||
    return this.range.multiple();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  setIndexes(ri, ci) {
 | 
			
		||||
  setIndexes(ri: number, ci: number) {
 | 
			
		||||
    this.ri = ri;
 | 
			
		||||
    this.ci = ci;
 | 
			
		||||
  }
 | 
			
		||||
@ -1,14 +1,14 @@
 | 
			
		||||
import { CellRange } from './cell_range';
 | 
			
		||||
import Validator from './validator';
 | 
			
		||||
import { CellRange } from './cell_range';
 | 
			
		||||
 | 
			
		||||
class Validation {
 | 
			
		||||
  constructor(mode, refs, validator) {
 | 
			
		||||
    this.refs = refs;
 | 
			
		||||
    this.mode = mode; // cell
 | 
			
		||||
    this.validator = validator;
 | 
			
		||||
  }
 | 
			
		||||
  constructor(
 | 
			
		||||
    public mode,
 | 
			
		||||
    public refs: string[],
 | 
			
		||||
    public validator,
 | 
			
		||||
  ) {}
 | 
			
		||||
 | 
			
		||||
  includes(ri, ci) {
 | 
			
		||||
  includes(ri: number, ci: number) {
 | 
			
		||||
    const { refs } = this;
 | 
			
		||||
    for (let i = 0; i < refs.length; i += 1) {
 | 
			
		||||
      const cr = CellRange.valueOf(refs[i]);
 | 
			
		||||
@ -17,12 +17,12 @@ class Validation {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  addRef(ref) {
 | 
			
		||||
  addRef(ref: string) {
 | 
			
		||||
    this.remove(CellRange.valueOf(ref));
 | 
			
		||||
    this.refs.push(ref);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  remove(cellRange) {
 | 
			
		||||
  remove(cellRange: CellRange) {
 | 
			
		||||
    const nrefs = [];
 | 
			
		||||
    this.refs.forEach((it) => {
 | 
			
		||||
      const cr = CellRange.valueOf(it);
 | 
			
		||||
@ -54,17 +54,18 @@ class Validation {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
class Validations {
 | 
			
		||||
  _: any[];
 | 
			
		||||
  errors: Map<any, any>;
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this._ = [];
 | 
			
		||||
    // ri_ci: errMessage
 | 
			
		||||
    this.errors = new Map();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getError(ri, ci) {
 | 
			
		||||
  getError(ri: number, ci: number) {
 | 
			
		||||
    return this.errors.get(`${ri}_${ci}`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  validate(ri, ci, text) {
 | 
			
		||||
  validate(ri: number, ci: number, text: string) {
 | 
			
		||||
    const v = this.get(ri, ci);
 | 
			
		||||
    const key = `${ri}_${ci}`;
 | 
			
		||||
    const { errors } = this;
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
import { t } from '../locale/locale';
 | 
			
		||||
import { FilterOperator } from './auto_filter';
 | 
			
		||||
import helper from './helper';
 | 
			
		||||
 | 
			
		||||
const rules = {
 | 
			
		||||
@ -9,19 +10,22 @@ const rules = {
 | 
			
		||||
function returnMessage(flag, key, ...arg) {
 | 
			
		||||
  let message = '';
 | 
			
		||||
  if (!flag) {
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    message = t(`validation.${key}`, ...arg);
 | 
			
		||||
  }
 | 
			
		||||
  return [flag, message];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class Validator {
 | 
			
		||||
  message: string;
 | 
			
		||||
  // operator: b|nb|eq|neq|lt|lte|gt|gte
 | 
			
		||||
  // type: date|number|list|phone|email
 | 
			
		||||
  constructor(type, required, value, operator) {
 | 
			
		||||
    this.required = required;
 | 
			
		||||
    this.value = value;
 | 
			
		||||
    this.type = type;
 | 
			
		||||
    this.operator = operator;
 | 
			
		||||
  constructor(
 | 
			
		||||
    public type,
 | 
			
		||||
    public required,
 | 
			
		||||
    public value,
 | 
			
		||||
    public operator: FilterOperator,
 | 
			
		||||
  ) {
 | 
			
		||||
    this.message = '';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -1,32 +1,32 @@
 | 
			
		||||
@css-prefix: x-spreadsheet;
 | 
			
		||||
// color
 | 
			
		||||
@red-color: #db2828;
 | 
			
		||||
@red-color: #DB2828;
 | 
			
		||||
@red-hover-color: #d01919;
 | 
			
		||||
@orange-color: #f2711c;
 | 
			
		||||
@orange-color: #F2711C;
 | 
			
		||||
@orange-hover-color: #f26202;
 | 
			
		||||
@yellow-color: #fbbd08;
 | 
			
		||||
@yellow-color: #FBBD08;
 | 
			
		||||
@yellow-hover-color: #eaae00;
 | 
			
		||||
@olive-color: #b5cc18;
 | 
			
		||||
@olive-color: #B5CC18;
 | 
			
		||||
@olive-hover-color: #a7bd0d;
 | 
			
		||||
@green-color: #21ba45;
 | 
			
		||||
@green-color: #21BA45;
 | 
			
		||||
@green-hover-color: #16ab39;
 | 
			
		||||
@teal-color: #00b5ad;
 | 
			
		||||
@teal-color: #00B5AD;
 | 
			
		||||
@teal-hover-color: #009c95;
 | 
			
		||||
@blue-color: #2185d0;
 | 
			
		||||
@blue-color: #2185D0;
 | 
			
		||||
@blue-hover-color: #1678c2;
 | 
			
		||||
@violet-color: #6435c9;
 | 
			
		||||
@violet-color: #6435C9;
 | 
			
		||||
@violet-hover-color: #5829bb;
 | 
			
		||||
@purple-color: #a333c8;
 | 
			
		||||
@purple-color: #A333C8;
 | 
			
		||||
@purple-hover-color: #9627ba;
 | 
			
		||||
@pink-color: #e03997;
 | 
			
		||||
@pink-color: #E03997;
 | 
			
		||||
@pink-hover-color: #e61a8d;
 | 
			
		||||
@brown-color: #a5673f;
 | 
			
		||||
@brown-color: #A5673F;
 | 
			
		||||
@brown-hover-color: #975b33;
 | 
			
		||||
@grey-color: #767676;
 | 
			
		||||
@grey-hover-color: #838383;
 | 
			
		||||
@dark-color: #343a40;
 | 
			
		||||
@dark-hover-color: darken(@dark-color, 10%);
 | 
			
		||||
@black-color: #1b1c1d;
 | 
			
		||||
@black-color: #1B1C1D;
 | 
			
		||||
@black-hover-color: #27292a;
 | 
			
		||||
 | 
			
		||||
// base
 | 
			
		||||
@ -37,7 +37,7 @@
 | 
			
		||||
@border: 1px solid @border-color;
 | 
			
		||||
@input-border: @border;
 | 
			
		||||
@input-padding: 0.5em 0.75em;
 | 
			
		||||
@input-box-shadow: inset 0 1px 2px hsla(0, 0%, 4%, 0.06);
 | 
			
		||||
@input-box-shadow: inset 0 1px 2px hsla(0,0%,4%,.06);
 | 
			
		||||
@border-radius: 2px;
 | 
			
		||||
@form-field-height: 30px;
 | 
			
		||||
@primary-color: @blue-color;
 | 
			
		||||
@ -47,8 +47,7 @@
 | 
			
		||||
.type-primary() {
 | 
			
		||||
  color: #fff;
 | 
			
		||||
  background-color: @primary-color;
 | 
			
		||||
  &:hover,
 | 
			
		||||
  &.active {
 | 
			
		||||
  &:hover, &.active {
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    background-color: @primary-hover-color;
 | 
			
		||||
  }
 | 
			
		||||
@ -69,13 +68,7 @@ body {
 | 
			
		||||
  -webkit-font-smoothing: antialiased;
 | 
			
		||||
 | 
			
		||||
  textarea {
 | 
			
		||||
    font:
 | 
			
		||||
      400 13px Arial,
 | 
			
		||||
      'Lato',
 | 
			
		||||
      'Source Sans Pro',
 | 
			
		||||
      Roboto,
 | 
			
		||||
      Helvetica,
 | 
			
		||||
      sans-serif;
 | 
			
		||||
    font: 400 13px Arial, 'Lato', 'Source Sans Pro', Roboto, Helvetica, sans-serif;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -97,21 +90,22 @@ body {
 | 
			
		||||
  border-radius: 1px;
 | 
			
		||||
  background: rgba(0, 0, 0, 1);
 | 
			
		||||
  font-size: 12px;
 | 
			
		||||
  z-index: 201;
 | 
			
		||||
  // z-index 这个现在是混乱的
 | 
			
		||||
  z-index: 1201;
 | 
			
		||||
 | 
			
		||||
  &:before {
 | 
			
		||||
    pointer-events: none;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: calc(50% - 4px);
 | 
			
		||||
    top: -4px;
 | 
			
		||||
    content: '';
 | 
			
		||||
    content: "";
 | 
			
		||||
    width: 8px;
 | 
			
		||||
    height: 8px;
 | 
			
		||||
    background: inherit;
 | 
			
		||||
    -webkit-transform: rotate(45deg);
 | 
			
		||||
    transform: rotate(45deg);
 | 
			
		||||
    z-index: 1;
 | 
			
		||||
    box-shadow: 1px 1px 3px -1px rgba(0, 0, 0, 0.3);
 | 
			
		||||
    box-shadow: 1px 1px 3px -1px rgba(0, 0, 0, .3);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -169,7 +163,7 @@ body {
 | 
			
		||||
      text-align: center;
 | 
			
		||||
 | 
			
		||||
      .@{css-prefix}-icon-img {
 | 
			
		||||
        opacity: 0.8;
 | 
			
		||||
        opacity: .8;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &:hover {
 | 
			
		||||
@ -191,7 +185,9 @@ body {
 | 
			
		||||
      left: 0;
 | 
			
		||||
      top: -3px;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-dropdown {
 | 
			
		||||
@ -201,7 +197,7 @@ body {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    z-index: 200;
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
 | 
			
		||||
    box-shadow: 1px 2px 5px 2px rgba(51,51,51,.15);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &.bottom-left {
 | 
			
		||||
@ -232,6 +228,7 @@ body {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  .@{css-prefix}-dropdown-title {
 | 
			
		||||
    padding: 0 5px;
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
@ -256,7 +253,7 @@ body {
 | 
			
		||||
  z-index: 11;
 | 
			
		||||
 | 
			
		||||
  .@{css-prefix}-resizer-hover {
 | 
			
		||||
    background-color: rgba(75, 137, 255, 0.25);
 | 
			
		||||
    background-color: rgba(75, 137, 255, .25);
 | 
			
		||||
  }
 | 
			
		||||
  .@{css-prefix}-resizer-line {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
@ -325,8 +322,7 @@ body {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-editor,
 | 
			
		||||
.@{css-prefix}-selector {
 | 
			
		||||
.@{css-prefix}-editor, .@{css-prefix}-selector {
 | 
			
		||||
  box-sizing: content-box;
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
@ -345,17 +341,16 @@ body {
 | 
			
		||||
    input {
 | 
			
		||||
      padding: 0;
 | 
			
		||||
      width: 0;
 | 
			
		||||
      border: none !important;
 | 
			
		||||
      border: none!important;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .@{css-prefix}-selector-area {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    border: 2px solid rgb(75, 137, 255);
 | 
			
		||||
    background: rgba(75, 137, 255, 0.1);
 | 
			
		||||
    background: rgba(75, 137, 255, .1);
 | 
			
		||||
    z-index: 5;
 | 
			
		||||
  }
 | 
			
		||||
  .@{css-prefix}-selector-clipboard,
 | 
			
		||||
  .@{css-prefix}-selector-autofill {
 | 
			
		||||
  .@{css-prefix}-selector-clipboard, .@{css-prefix}-selector-autofill {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    background: transparent;
 | 
			
		||||
    z-index: 100;
 | 
			
		||||
@ -364,7 +359,7 @@ body {
 | 
			
		||||
    border: 2px dashed rgb(75, 137, 255);
 | 
			
		||||
  }
 | 
			
		||||
  .@{css-prefix}-selector-autofill {
 | 
			
		||||
    border: 1px dashed rgba(0, 0, 0, 0.45); // #606060; // rgba(0, 0, 0, .2);
 | 
			
		||||
    border: 1px dashed rgba(0, 0, 0, .45); // #606060; // rgba(0, 0, 0, .2);
 | 
			
		||||
  }
 | 
			
		||||
  .@{css-prefix}-selector-corner {
 | 
			
		||||
    pointer-events: auto;
 | 
			
		||||
@ -397,13 +392,7 @@ body {
 | 
			
		||||
      resize: none;
 | 
			
		||||
      text-align: start;
 | 
			
		||||
      overflow-y: hidden;
 | 
			
		||||
      font:
 | 
			
		||||
        400 13px Arial,
 | 
			
		||||
        'Lato',
 | 
			
		||||
        'Source Sans Pro',
 | 
			
		||||
        Roboto,
 | 
			
		||||
        Helvetica,
 | 
			
		||||
        sans-serif;
 | 
			
		||||
      font: 400 13px Arial, 'Lato', 'Source Sans Pro', Roboto, Helvetica, sans-serif;
 | 
			
		||||
      color: inherit;
 | 
			
		||||
      white-space: normal;
 | 
			
		||||
      word-wrap: break-word;
 | 
			
		||||
@ -427,7 +416,7 @@ body {
 | 
			
		||||
  border: 1px solid transparent;
 | 
			
		||||
  outline: none;
 | 
			
		||||
  height: 26px;
 | 
			
		||||
  color: rgba(0, 0, 0, 0.9);
 | 
			
		||||
  color: rgba(0, 0, 0, .9);
 | 
			
		||||
  line-height: 26px;
 | 
			
		||||
  list-style: none;
 | 
			
		||||
  padding: 2px 10px;
 | 
			
		||||
@ -440,13 +429,12 @@ body {
 | 
			
		||||
    opacity: 0.5;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &:hover,
 | 
			
		||||
  &.active {
 | 
			
		||||
    background: rgba(0, 0, 0, 0.05);
 | 
			
		||||
  &:hover, &.active {
 | 
			
		||||
    background: rgba(0, 0, 0, .05);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // &.active {
 | 
			
		||||
  ////   background: #89aef53d;
 | 
			
		||||
    ////   background: #89aef53d;
 | 
			
		||||
  // }
 | 
			
		||||
 | 
			
		||||
  &.divider {
 | 
			
		||||
@ -454,12 +442,12 @@ body {
 | 
			
		||||
    padding: 0;
 | 
			
		||||
    margin: 5px 0;
 | 
			
		||||
    border: none;
 | 
			
		||||
    border-bottom: 1px solid rgba(0, 0, 0, 0.1);
 | 
			
		||||
    border-bottom: 1px solid rgba(0, 0, 0, .1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .label {
 | 
			
		||||
    float: right;
 | 
			
		||||
    opacity: 0.65;
 | 
			
		||||
    opacity: .65;
 | 
			
		||||
    font-size: 1em;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -467,7 +455,7 @@ body {
 | 
			
		||||
.x-spreadsheet-item,
 | 
			
		||||
.x-spreadsheet-header {
 | 
			
		||||
  &.state {
 | 
			
		||||
    padding-left: 35px !important;
 | 
			
		||||
    padding-left: 35px!important;
 | 
			
		||||
    position: relative;
 | 
			
		||||
 | 
			
		||||
    &:before {
 | 
			
		||||
@ -501,6 +489,7 @@ body {
 | 
			
		||||
    // transform: rotate(45deg);
 | 
			
		||||
    // -webkit-transform: rotate(45deg);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-checkbox {
 | 
			
		||||
@ -516,7 +505,7 @@ body {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    opacity: 0 !important;
 | 
			
		||||
    opacity: 0!important;
 | 
			
		||||
    outline: 0;
 | 
			
		||||
    z-index: -1;
 | 
			
		||||
  }
 | 
			
		||||
@ -544,7 +533,7 @@ body {
 | 
			
		||||
  margin: 10px;
 | 
			
		||||
 | 
			
		||||
  .@{css-prefix}-header {
 | 
			
		||||
    padding: 0.5em 0.75em;
 | 
			
		||||
    padding: .5em .75em;
 | 
			
		||||
    background: #f8f8f9;
 | 
			
		||||
    border-bottom: 1px solid #e9e9e9;
 | 
			
		||||
    border-left: 1px solid transparent;
 | 
			
		||||
@ -566,8 +555,7 @@ body {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-toolbar,
 | 
			
		||||
.@{css-prefix}-bottombar {
 | 
			
		||||
.@{css-prefix}-toolbar, .@{css-prefix}-bottombar {
 | 
			
		||||
  height: 40px;
 | 
			
		||||
  padding: 0 30px;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
@ -598,7 +586,7 @@ body {
 | 
			
		||||
.@{css-prefix}-menu > li {
 | 
			
		||||
  float: left;
 | 
			
		||||
  line-height: 1.25em;
 | 
			
		||||
  padding: 0.785em 1em;
 | 
			
		||||
  padding: .785em 1em;
 | 
			
		||||
  margin: 0;
 | 
			
		||||
  vertical-align: middle;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
@ -606,12 +594,12 @@ body {
 | 
			
		||||
  color: #80868b;
 | 
			
		||||
  white-space: nowrap;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  transition: all 0.3s;
 | 
			
		||||
  transition: all .3s;
 | 
			
		||||
  font-weight: bold;
 | 
			
		||||
 | 
			
		||||
  &.active {
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    color: rgba(0, 0, 0, 0.65);
 | 
			
		||||
    color: rgba(0, 0, 0, .65);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .@{css-prefix}-icon {
 | 
			
		||||
@ -619,7 +607,7 @@ body {
 | 
			
		||||
 | 
			
		||||
    .@{css-prefix}-icon-img {
 | 
			
		||||
      &:hover {
 | 
			
		||||
        opacity: 0.85;
 | 
			
		||||
        opacity: .85;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@ -661,9 +649,8 @@ body {
 | 
			
		||||
      opacity: 0.5;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &:hover,
 | 
			
		||||
    &.active {
 | 
			
		||||
      background: rgba(0, 0, 0, 0.08);
 | 
			
		||||
    &:hover, &.active {
 | 
			
		||||
      background: rgba(0, 0, 0, .08);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -727,6 +714,7 @@ body {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-canvas-card-wraper {
 | 
			
		||||
  margin: 40px 20px;
 | 
			
		||||
}
 | 
			
		||||
@ -735,14 +723,11 @@ body {
 | 
			
		||||
  margin: auto;
 | 
			
		||||
  page-break-before: auto;
 | 
			
		||||
  page-break-after: always;
 | 
			
		||||
  box-shadow:
 | 
			
		||||
    0 8px 10px 1px rgba(0, 0, 0, 0.14),
 | 
			
		||||
    0 3px 14px 3px rgba(0, 0, 0, 0.12),
 | 
			
		||||
    0 4px 5px 0 rgba(0, 0, 0, 0.2);
 | 
			
		||||
  box-shadow: 0 8px 10px 1px rgba(0,0,0,0.14), 0 3px 14px 3px rgba(0,0,0,0.12), 0 4px 5px 0 rgba(0,0,0,0.20);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-calendar {
 | 
			
		||||
  color: rgba(0, 0, 0, 0.65);
 | 
			
		||||
  color: rgba(0,0,0,.65);
 | 
			
		||||
  background: #ffffff;
 | 
			
		||||
  user-select: none;
 | 
			
		||||
 | 
			
		||||
@ -768,7 +753,7 @@ body {
 | 
			
		||||
        border-radius: 2px;
 | 
			
		||||
      }
 | 
			
		||||
      a:hover {
 | 
			
		||||
        background: rgba(0, 0, 0, 0.08);
 | 
			
		||||
        background: rgba(0,0,0,.08);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@ -777,8 +762,7 @@ body {
 | 
			
		||||
    border-collapse: collapse;
 | 
			
		||||
    border-spacing: 0;
 | 
			
		||||
 | 
			
		||||
    th,
 | 
			
		||||
    td {
 | 
			
		||||
    th, td {
 | 
			
		||||
      width: 100%/7;
 | 
			
		||||
      min-width: 32px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
@ -794,10 +778,9 @@ body {
 | 
			
		||||
        background: #ecf6fd;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &.active,
 | 
			
		||||
      &.active:hover {
 | 
			
		||||
      &.active, &.active:hover {
 | 
			
		||||
        background: #ecf6fd;
 | 
			
		||||
        color: #2185d0;
 | 
			
		||||
        color: #2185D0;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      &.disabled {
 | 
			
		||||
@ -809,7 +792,7 @@ body {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-datepicker {
 | 
			
		||||
  box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);
 | 
			
		||||
  box-shadow: 2px 2px 5px rgba(0,0,0,.2);
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  top: calc(100% + 5px);
 | 
			
		||||
@ -835,11 +818,11 @@ body {
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  font-size: 1em;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
  padding: 0.75em 1em;
 | 
			
		||||
  color: rgba(0, 0, 0, 0.6);
 | 
			
		||||
  background: #e0e1e2;
 | 
			
		||||
  padding: .75em 1em;
 | 
			
		||||
  color: rgba(0,0,0,.6);
 | 
			
		||||
  background: #E0E1E2;
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  font-family: 'Lato', 'proxima-nova', 'Helvetica Neue', Arial, sans-serif;
 | 
			
		||||
  font-family: "Lato","proxima-nova","Helvetica Neue",Arial,sans-serif;
 | 
			
		||||
  //box-shadow: 0px 1px 2px -1px rgba(255,255,255,0.5) inset, 0px -2px 0px 0px rgba(0,0,0,0.1) inset;
 | 
			
		||||
  //box-shadow: 0 0 0 0 rgba(0,0,0,.5) inset;
 | 
			
		||||
  outline: none;
 | 
			
		||||
@ -848,10 +831,9 @@ body {
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  transition: all 0.1s linear;
 | 
			
		||||
 | 
			
		||||
  &.active,
 | 
			
		||||
  &:hover {
 | 
			
		||||
    background-color: #c0c1c2;
 | 
			
		||||
    color: rgba(0, 0, 0, 0.8);
 | 
			
		||||
  &.active, &:hover {
 | 
			
		||||
    background-color: #C0C1C2;
 | 
			
		||||
    color: rgba(0,0,0,.8);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &.primary {
 | 
			
		||||
@ -865,7 +847,7 @@ body {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  font-weight: 400;
 | 
			
		||||
  display: inline-flex;
 | 
			
		||||
  color: rgba(0, 0, 0, 0.87);
 | 
			
		||||
  color: rgba(0,0,0,.87);
 | 
			
		||||
 | 
			
		||||
  input {
 | 
			
		||||
    z-index: 1;
 | 
			
		||||
@ -873,7 +855,7 @@ body {
 | 
			
		||||
    max-width: 100%;
 | 
			
		||||
    flex: 1 0 auto;
 | 
			
		||||
    outline: 0;
 | 
			
		||||
    -webkit-tap-highlight-color: rgba(255, 255, 255, 0);
 | 
			
		||||
    -webkit-tap-highlight-color: rgba(255,255,255,0);
 | 
			
		||||
    text-align: left;
 | 
			
		||||
    line-height: @form-field-height;
 | 
			
		||||
    height: @form-field-height;
 | 
			
		||||
@ -881,14 +863,12 @@ body {
 | 
			
		||||
    background: #fff;
 | 
			
		||||
    border: 1px solid #e9e9e9;
 | 
			
		||||
    border-radius: 3px;
 | 
			
		||||
    transition:
 | 
			
		||||
      box-shadow 0.1s ease,
 | 
			
		||||
      border-color 0.1s ease;
 | 
			
		||||
    box-shadow: inset 0 1px 2px hsla(0, 0%, 4%, 0.06);
 | 
			
		||||
    transition: box-shadow .1s ease,border-color .1s ease;
 | 
			
		||||
    box-shadow: inset 0 1px 2px hsla(0,0%,4%,.06);
 | 
			
		||||
 | 
			
		||||
    &:focus {
 | 
			
		||||
      border-color: rgb(75, 137, 255);
 | 
			
		||||
      box-shadow: inset 0 1px 2px rgba(75, 137, 255, 0.2);
 | 
			
		||||
      box-shadow: inset 0 1px 2px rgba(75, 137, 255, .2);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -900,9 +880,9 @@ body {
 | 
			
		||||
  border: @input-border;
 | 
			
		||||
  border-radius: 2px;
 | 
			
		||||
  cursor: pointer;
 | 
			
		||||
  color: rgba(0, 0, 0, 0.87);
 | 
			
		||||
  color: rgba(0,0,0,.87);
 | 
			
		||||
  user-select: none;
 | 
			
		||||
  box-shadow: inset 0 1px 2px hsla(0, 0%, 4%, 0.06);
 | 
			
		||||
  box-shadow: inset 0 1px 2px hsla(0,0%,4%,.06);
 | 
			
		||||
 | 
			
		||||
  .input-text {
 | 
			
		||||
    text-overflow: ellipsis;
 | 
			
		||||
@ -938,15 +918,14 @@ body {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  &.error {
 | 
			
		||||
    .@{css-prefix}-form-select,
 | 
			
		||||
    input {
 | 
			
		||||
    .@{css-prefix}-form-select, input {
 | 
			
		||||
      border-color: #f04134;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  .tip {
 | 
			
		||||
    color: #f04134;
 | 
			
		||||
    font-size: 0.9em;
 | 
			
		||||
    font-size: .9em;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
// form end
 | 
			
		||||
@ -980,7 +959,7 @@ form fieldset {
 | 
			
		||||
 | 
			
		||||
  label {
 | 
			
		||||
    display: block;
 | 
			
		||||
    margin-bottom: 0.5em;
 | 
			
		||||
    margin-bottom: .5em;
 | 
			
		||||
    font-size: 1em;
 | 
			
		||||
    color: #666;
 | 
			
		||||
  }
 | 
			
		||||
@ -991,44 +970,42 @@ form fieldset {
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    border: none;
 | 
			
		||||
    border-bottom: 2px solid #ddd;
 | 
			
		||||
    padding: 0.5em 0.85em;
 | 
			
		||||
    padding: .5em .85em;
 | 
			
		||||
    border-radius: 2px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-modal,
 | 
			
		||||
.@{css-prefix}-toast {
 | 
			
		||||
.@{css-prefix}-modal, .@{css-prefix}-toast {
 | 
			
		||||
  font-size: 13px;
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  z-index: 1001;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  line-height: @line-height;
 | 
			
		||||
  min-width: 360px;
 | 
			
		||||
  color: rgba(0, 0, 0, 0.87);
 | 
			
		||||
  color: rgba(0,0,0,.87);
 | 
			
		||||
  font-family: 'Lato', 'Source Sans Pro', Roboto, Helvetica, Arial, sans-serif;
 | 
			
		||||
  border-radius: 4px;
 | 
			
		||||
  border: 1px solid rgba(0, 0, 0, 0.1);
 | 
			
		||||
  border: 1px solid rgba(0,0,0,.1);
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  background-clip: padding-box;
 | 
			
		||||
  box-shadow: rgba(0, 0, 0, 0.2) 0px 2px 8px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-toast {
 | 
			
		||||
  background-color: rgba(255, 255, 255, 0.85);
 | 
			
		||||
  background-color: rgba(255,255,255,.85);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-modal-header,
 | 
			
		||||
.@{css-prefix}-toast-header {
 | 
			
		||||
.@{css-prefix}-modal-header, .@{css-prefix}-toast-header {
 | 
			
		||||
  font-weight: 600;
 | 
			
		||||
  background-clip: padding-box;
 | 
			
		||||
  background-color: rgba(255, 255, 255, 0.85);
 | 
			
		||||
  border-bottom: 1px solid rgba(0, 0, 0, 0.05);
 | 
			
		||||
  background-color: rgba(255,255,255,.85);
 | 
			
		||||
  border-bottom: 1px solid rgba(0,0,0,.05);
 | 
			
		||||
  border-radius: 4px 4px 0 0;
 | 
			
		||||
 | 
			
		||||
  .@{css-prefix}-icon {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    right: 0.8em;
 | 
			
		||||
    top: 0.65em;
 | 
			
		||||
    right: .8em;
 | 
			
		||||
    top: .65em;
 | 
			
		||||
    border-radius: 18px;
 | 
			
		||||
 | 
			
		||||
    &:hover {
 | 
			
		||||
@ -1044,7 +1021,7 @@ form fieldset {
 | 
			
		||||
 | 
			
		||||
.@{css-prefix}-modal-header {
 | 
			
		||||
  border-bottom: @border-style;
 | 
			
		||||
  background: rgba(0, 0, 0, 0.08);
 | 
			
		||||
  background: rgba(0, 0, 0, .08);
 | 
			
		||||
  font-size: 1.0785em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1052,7 +1029,7 @@ form fieldset {
 | 
			
		||||
.@{css-prefix}-modal-content,
 | 
			
		||||
.@{css-prefix}-toast-header,
 | 
			
		||||
.@{css-prefix}-toast-content {
 | 
			
		||||
  padding: 0.75em 1em;
 | 
			
		||||
  padding: .75em 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@media screen and (min-width: 320px) and (max-width: 480px) {
 | 
			
		||||
 | 
			
		||||
@ -1,12 +1,19 @@
 | 
			
		||||
import React from 'react';
 | 
			
		||||
 | 
			
		||||
import { createRoot, Root } from 'react-dom/client';
 | 
			
		||||
 | 
			
		||||
import Bottombar from './component/bottombar';
 | 
			
		||||
import { h, HComponent } from './component/element';
 | 
			
		||||
import Sheet from './component/sheet';
 | 
			
		||||
import { Bottombar as RBottombar } from './components/Bottombar';
 | 
			
		||||
import { cssPrefix } from './config';
 | 
			
		||||
import DataProxy from './core/data_proxy';
 | 
			
		||||
import { locale } from './locale/locale';
 | 
			
		||||
 | 
			
		||||
import './index.less';
 | 
			
		||||
 | 
			
		||||
import { SheetRoot } from './components/SheetRoot';
 | 
			
		||||
 | 
			
		||||
export type CELL_SELECTED = 'cell-selected';
 | 
			
		||||
export type CELLS_SELECTED = 'cells-selected';
 | 
			
		||||
export type CELL_EDITED = 'cell-edited';
 | 
			
		||||
@ -148,11 +155,11 @@ class Spreadsheet {
 | 
			
		||||
  sheet: any;
 | 
			
		||||
  data: DataProxy;
 | 
			
		||||
  rootEl: HComponent;
 | 
			
		||||
  root: Root;
 | 
			
		||||
  constructor(selectors: string | HTMLElement, options: Options = {}) {
 | 
			
		||||
    this.options = { showBottomBar: true, ...options };
 | 
			
		||||
    this.sheetIndex = 1;
 | 
			
		||||
    this.datas = [];
 | 
			
		||||
 | 
			
		||||
    if (typeof selectors === 'string') {
 | 
			
		||||
      this.targetEl = document.querySelector(selectors) as HTMLElement;
 | 
			
		||||
    } else {
 | 
			
		||||
@ -179,17 +186,32 @@ class Spreadsheet {
 | 
			
		||||
        )
 | 
			
		||||
      : null;
 | 
			
		||||
    this.data = this.addSheet();
 | 
			
		||||
    this.rootEl = h('div', `${cssPrefix}`).on('contextmenu', (evt) => evt.preventDefault());
 | 
			
		||||
    // create canvas element
 | 
			
		||||
    this.targetEl.appendChild(this.rootEl.el);
 | 
			
		||||
    this.sheet = new Sheet(this.rootEl, this.data);
 | 
			
		||||
    if (this.bottombar !== null) {
 | 
			
		||||
      this.rootEl.child(this.bottombar.el);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.root = createRoot(this.targetEl);
 | 
			
		||||
    this.root.render(<SheetRoot options={this.options} />);
 | 
			
		||||
 | 
			
		||||
    // this.rootEl = h('div', `${cssPrefix}`).on('contextmenu', (evt: Event) => {
 | 
			
		||||
    //   evt.preventDefault();
 | 
			
		||||
    //   evt.stopPropagation();
 | 
			
		||||
    // });
 | 
			
		||||
    // // create canvas element
 | 
			
		||||
    // console.log('🚀 ~ file: index.ts:183 ~ Spreadsheet ~ constructor ~ rootEl:', this.rootEl);
 | 
			
		||||
    // this.targetEl.appendChild(this.rootEl.el);
 | 
			
		||||
    // console.log('🚀 ~ file: index.ts:183 ~ Spreadsheet ~ constructor ~ this.targetEl:', this.targetEl);
 | 
			
		||||
    // this.sheet = new Sheet(this.rootEl, this.data);
 | 
			
		||||
    // if (this.bottombar !== null) {
 | 
			
		||||
    //   // this.rootEl.child(this.bottombar.el);
 | 
			
		||||
    //   const bottomDiv = document.createElement('div');
 | 
			
		||||
    //   this.targetEl.appendChild(bottomDiv);
 | 
			
		||||
    //   const bottomRoot = createRoot(bottomDiv);
 | 
			
		||||
    //   bottomRoot.render(<RBottombar />);
 | 
			
		||||
    //   console.log('🚀 ~ file: index.tsx:191 ~ Spreadsheet ~ constructor ~ bottombar:', this.bottombar);
 | 
			
		||||
    // }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  dispose() {
 | 
			
		||||
    this.targetEl.removeChild(this.rootEl.el);
 | 
			
		||||
    // this.targetEl.removeChild(this.rootEl.el);
 | 
			
		||||
    this.root.unmount();
 | 
			
		||||
    console.debug('x-sheet is diposed');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -200,7 +222,6 @@ class Spreadsheet {
 | 
			
		||||
      this.sheet.trigger('change', ...args);
 | 
			
		||||
    };
 | 
			
		||||
    this.datas.push(d);
 | 
			
		||||
    // console.log('d:', n, d, this.datas);
 | 
			
		||||
    if (this.bottombar !== null) {
 | 
			
		||||
      this.bottombar.addItem(n, active, this.options);
 | 
			
		||||
    }
 | 
			
		||||
@ -231,7 +252,7 @@ class Spreadsheet {
 | 
			
		||||
        const nd = this.addSheet(it.name, i === 0);
 | 
			
		||||
        nd.setData(it);
 | 
			
		||||
        if (i === 0) {
 | 
			
		||||
          this.sheet.resetData(nd);
 | 
			
		||||
          // this.sheet.resetData(nd);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@ -39,7 +39,10 @@ function translate(key, messages) {
 | 
			
		||||
 | 
			
		||||
function t(key) {
 | 
			
		||||
  let v = translate(key, $messages);
 | 
			
		||||
  // FIXME
 | 
			
		||||
  // @ts-ignore
 | 
			
		||||
  if (!v && window && window.x_spreadsheet && window.x_spreadsheet.$messages) {
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    v = translate(key, window.x_spreadsheet.$messages);
 | 
			
		||||
  }
 | 
			
		||||
  return v || '';
 | 
			
		||||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue
	
	Block a user