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,7 +189,8 @@ 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 = `
|
@ -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(
|
||||
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,7 +488,9 @@ export default class DataProxy {
|
||||
|
||||
pasteFromSystemClipboard(resetSheet, eventTrigger) {
|
||||
const { selector } = this;
|
||||
navigator.clipboard.readText().then((content) => {
|
||||
navigator.clipboard
|
||||
.readText()
|
||||
.then((content) => {
|
||||
const contentToPaste = this.parseClipboardContent(content);
|
||||
let startRow = selector.ri;
|
||||
contentToPaste.forEach((row) => {
|
||||
@ -473,7 +503,8 @@ export default class DataProxy {
|
||||
});
|
||||
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,9 +429,8 @@ body {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&.active {
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
&:hover, &.active {
|
||||
background: rgba(0, 0, 0, .05);
|
||||
}
|
||||
|
||||
// &.active {
|
||||
@ -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