refactor: @hera/plugin-core (#1081)

Reviewed-on: daoyoucloud/tachybase#1081
This commit is contained in:
sealday 2024-05-30 17:01:02 +08:00
parent 7092559ea0
commit 8fdd5d4fe9
221 changed files with 1407 additions and 1303 deletions

View File

@ -1,38 +1,34 @@
import React, { ComponentType, ReactElement } from 'react';
import { define, observable } from '@tachybase/schema';
import { APIClientOptions, getSubAppName } from '@tachybase/sdk';
import { i18n as i18next } from 'i18next';
import get from 'lodash/get';
import merge from 'lodash/merge';
import set from 'lodash/set';
import React, { ComponentType, FC, ReactElement } from 'react';
import { get, merge, set } from 'lodash';
import { createRoot } from 'react-dom/client';
import { I18nextProvider } from 'react-i18next';
import { Link, NavLink, Navigate } from 'react-router-dom';
import { Link, Navigate, NavLink } from 'react-router-dom';
import { APIClient, APIClientProvider } from '../api-client';
import { CSSVariableProvider } from '../css-variable';
import { CollectionField } from '../data-source/collection-field/CollectionField';
import { DataSourceApplicationProvider } from '../data-source/components/DataSourceApplicationProvider';
import { DataBlockProvider } from '../data-source/data-block/DataBlockProvider';
import { DataSourceManager, type DataSourceManagerOptions } from '../data-source/data-source/DataSourceManager';
import { AntdAppProvider, GlobalThemeProvider } from '../global-theme';
import { i18n } from '../i18n';
import { AppSchemaComponentProvider } from './AppSchemaComponentProvider';
import { AppComponent, BlankComponent, defaultAppComponents } from './components';
import type { Plugin } from './Plugin';
import { PluginManager, PluginType } from './PluginManager';
import { PluginSettingOptions, PluginSettingsManager } from './PluginSettingsManager';
import { ComponentTypeAndString, RouterManager, RouterOptions } from './RouterManager';
import { WebSocketClient, WebSocketClientOptions } from './WebSocketClient';
import { AppComponent, BlankComponent, defaultAppComponents } from './components';
import { SchemaInitializer, SchemaInitializerManager } from './schema-initializer';
import * as schemaInitializerComponents from './schema-initializer/components';
import { SchemaSettings, SchemaSettingsManager } from './schema-settings';
import { compose, normalizeContainer } from './utils';
import { defineGlobalDeps } from './utils/globalDeps';
import { getRequireJs } from './utils/requirejs';
import { CollectionField } from '../data-source/collection-field/CollectionField';
import { DataSourceApplicationProvider } from '../data-source/components/DataSourceApplicationProvider';
import { DataBlockProvider } from '../data-source/data-block/DataBlockProvider';
import { DataSourceManager, type DataSourceManagerOptions } from '../data-source/data-source/DataSourceManager';
import { AppSchemaComponentProvider } from './AppSchemaComponentProvider';
import type { Plugin } from './Plugin';
import type { RequireJS } from './utils/requirejs';
import { getRequireJs, type RequireJS } from './utils/requirejs';
import { WebSocketClient, WebSocketClientOptions } from './WebSocketClient';
declare global {
interface Window {
@ -319,7 +315,7 @@ export class Application {
}
getRootComponent() {
const Root: FC = () => <AppComponent app={this} />;
const Root = () => <AppComponent app={this} />;
return Root;
}

View File

@ -1,14 +1,6 @@
import React from 'react';
import * as tachybaseComponents from '@tachybase/components';
import * as tachybaseEvaluators from '@tachybase/evaluators/client';
import * as formilyCore from '@tachybase/schema';
import * as formilyJsonSchema from '@tachybase/schema';
import * as formilyPath from '@tachybase/schema';
import * as formilyReact from '@tachybase/schema';
import * as formilyJsonReactive from '@tachybase/schema';
import * as formilyReactiveReact from '@tachybase/schema';
import * as formilyShared from '@tachybase/schema';
import * as formilyValidator from '@tachybase/schema';
import * as tachybaseSchema from '@tachybase/schema';
import * as tachybaseSDK from '@tachybase/sdk';
import * as tachybaseClientUtils from '@tachybase/utils/client';
@ -60,22 +52,9 @@ export function defineGlobalDeps(requirejs: RequireJS) {
requirejs.define('i18next', () => i18next);
requirejs.define('react-i18next', () => reactI18next);
// formily
requirejs.define('@formily/core', () => formilyCore);
requirejs.define('@formily/react', () => formilyReact);
requirejs.define('@formily/shared', () => formilyShared);
requirejs.define('@formily/json-schema', () => formilyJsonSchema);
requirejs.define('@formily/reactive', () => formilyJsonReactive);
requirejs.define('@formily/path', () => formilyPath);
requirejs.define('@formily/validator', () => formilyValidator);
requirejs.define('@formily/reactive-react', () => formilyReactiveReact);
// tachybase
requirejs.define('@tachybase/utils', () => tachybaseClientUtils);
requirejs.define('@tachybase/utils/client', () => tachybaseClientUtils);
requirejs.define('@tachybase/client', () => tachybaseClient);
requirejs.define('@tachybase/client/client', () => tachybaseClient);
requirejs.define('@tachybase/evaluators', () => tachybaseEvaluators);
requirejs.define('@tachybase/evaluators/client', () => tachybaseEvaluators);
requirejs.define('@tachybase/sdk', () => tachybaseSDK);
requirejs.define('@tachybase/schema', () => tachybaseSchema);
@ -94,5 +73,4 @@ export function defineGlobalDeps(requirejs: RequireJS) {
requirejs.define('lodash', () => lodash);
requirejs.define('ahooks', () => ahooks);
requirejs.define('@emotion/css', () => emotionCss);
requirejs.define('dayjs', () => dayjs);
}

View File

@ -2,7 +2,7 @@ import { ChangeEvent, useCallback, useEffect } from 'react';
import { Field, Form, untracked, useField, useFieldSchema, useForm } from '@tachybase/schema';
import { isURL, parse } from '@tachybase/utils/client';
import { App, message } from 'antd';
import { App } from 'antd';
import _ from 'lodash';
import get from 'lodash/get';
import omit from 'lodash/omit';
@ -13,7 +13,6 @@ import { useReactToPrint } from 'react-to-print';
import {
AssociationFilter,
useCollectionRecord,
useDataLoadingMode,
useDataSourceHeaders,
useFormActiveFields,
useFormBlockContext,
@ -193,15 +192,12 @@ export const useCreateActionProps = () => {
const actionSchema = useFieldSchema();
const actionField = useField();
const compile = useCompile();
const { modal } = App.useApp();
const { modal, message } = App.useApp();
const { t } = useTranslation();
const { updateAssociationValues } = useFormBlockContext();
const collectValues = useCollectValuesToSubmit();
const action = record.isNew ? actionField.componentProps.saveMode || 'create' : 'update';
const filterKeys = actionField.componentProps.filterKeys?.checked || [];
const dataLoadingMode = useDataLoadingMode();
console.log('dataLoadingMode', dataLoadingMode);
return {
async onClick() {
@ -271,6 +267,7 @@ export const useAssociationCreateActionProps = () => {
const { setVisible, fieldSchema } = useActionContext();
const actionSchema = useFieldSchema();
const actionField = useField();
const { message } = App.useApp();
const { fields, getField, getTreeParentField, name } = useCollection_deprecated();
const compile = useCompile();
const filterByTk = useFilterByTk();
@ -510,7 +507,7 @@ export const useCustomizeUpdateActionProps = () => {
const navigate = useNavigate();
const compile = useCompile();
const form = useForm();
const { modal } = App.useApp();
const { modal, message } = App.useApp();
const variables = useVariables();
const localVariables = useLocalVariables({ currentForm: form });
const { name, getField } = useCollection_deprecated();
@ -605,7 +602,7 @@ export const useCustomizeRequestActionProps = () => {
const currentUser = currentUserContext?.data?.data;
const actionField = useField();
const { setVisible } = useActionContext();
const { modal } = App.useApp();
const { modal, message } = App.useApp();
const { getActiveFieldsName } = useFormActiveFields() || {};
return {
@ -694,7 +691,7 @@ export const useUpdateActionProps = () => {
const compile = useCompile();
const actionField = useField();
const { updateAssociationValues } = useFormBlockContext();
const { modal } = App.useApp();
const { modal, message } = App.useApp();
const data = useParamsFromRecord();
const variables = useVariables();
const localVariables = useLocalVariables({ currentForm: form });

View File

@ -1,6 +1,6 @@
import React, { createContext, useContext, useMemo, useState } from 'react';
import { Checkbox, message, Table } from 'antd';
import { App, Checkbox, Table } from 'antd';
import { omit } from 'lodash';
import { useTranslation } from 'react-i18next';
@ -42,12 +42,12 @@ export const SettingCenterProvider = (props) => {
export const SettingsCenterConfigure = () => {
const app = useApp();
const { message } = App.useApp();
const { styles } = useStyles();
const record = useRecord();
const api = useAPIClient();
const compile = useCompile();
const settings = app.pluginSettingsManager.getList(false);
console.log(settings);
const allAclSnippets = app.pluginSettingsManager.getAclSnippets();
const [snippets, setSnippets] = useState<string[]>([]);
const allChecked = useMemo(

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react';
import { Checkbox, message, Table } from 'antd';
import { App, Checkbox, Table } from 'antd';
import { uniq } from 'lodash';
import { useTranslation } from 'react-i18next';
@ -45,6 +45,7 @@ export const MenuConfigure = () => {
const { styles } = useStyles();
const record = useRecord();
const api = useAPIClient();
const { message } = App.useApp();
const { items } = useMenuItems();
const { t } = useTranslation();
const allUids = findUids(items);

View File

@ -1,6 +1,6 @@
import React, { createContext, useContext, useState } from 'react';
import { message } from 'antd';
import { App } from 'antd';
import { useTranslation } from 'react-i18next';
import { useAPIClient } from '../../../api-client';
@ -21,6 +21,7 @@ export const PermissionProvider = (props) => {
const api = useAPIClient();
const record = useRecord();
const { t } = useTranslation();
const { message } = App.useApp();
const { snippets } = record;
snippets?.forEach((key) => {
record[key] = true;

View File

@ -1,7 +1,7 @@
import React, { FC, useState } from 'react';
import { ClockCircleOutlined, DeleteOutlined, ReadOutlined, ReloadOutlined, SettingOutlined } from '@ant-design/icons';
import { App, Card, Divider, message, Popconfirm, Space, Switch, Typography } from 'antd';
import { App, Card, Divider, Popconfirm, Space, Switch, Typography } from 'antd';
import classnames from 'classnames';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
@ -22,7 +22,7 @@ export const SwitchAction = (props: IPluginData) => {
const { name, enabled, builtIn, error, isCompatible } = props;
const api = useAPIClient();
const { t } = useTranslation();
const { modal } = App.useApp();
const { modal, message } = App.useApp();
return (
<Switch
aria-label="enable"
@ -70,7 +70,7 @@ function PluginInfo(props: IPluginInfo) {
const navigate = useNavigate();
const { t } = useTranslation();
const api = useAPIClient();
const { modal } = App.useApp();
const { modal, message } = App.useApp();
const [showUploadForm, setShowUploadForm] = useState(false);
const reload = () => window.location.reload();
const title = displayName || name || packageName;

View File

@ -1,7 +1,7 @@
import React from 'react';
import { ISchema, uid, useForm } from '@tachybase/schema';
import { Card, message } from 'antd';
import { App, Card } from 'antd';
import { cloneDeep } from 'lodash';
import { useTranslation } from 'react-i18next';
@ -38,6 +38,7 @@ const useSystemSettingsValues = (options) => {
const useSaveSystemSettingsValues = () => {
const { setVisible } = useActionContext();
const form = useForm();
const { message } = App.useApp();
const { mutate, data } = useSystemSettings();
const api = useAPIClient();
const { t } = useTranslation();

View File

@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { useForm } from '@tachybase/schema';
import { DeleteOutlined, ExclamationCircleFilled } from '@ant-design/icons';
import { Button, message } from 'antd';
import { App, Button } from 'antd';
import { createStyles } from 'antd-style';
import { useTranslation } from 'react-i18next';
@ -75,6 +75,7 @@ export const useBulkDestroyAction = () => {
const { resource } = useResourceContext();
const ctx = useActionContext();
const { t } = useTranslation();
const { message } = App.useApp();
const form = useForm();
const { cascade } = form?.values || {};
return {

View File

@ -1,7 +1,7 @@
import { useCallback, useEffect, useMemo } from 'react';
import { useField, useForm } from '@tachybase/schema';
import { message } from 'antd';
import { App } from 'antd';
import _ from 'lodash';
import cloneDeep from 'lodash/cloneDeep';
import omit from 'lodash/omit';
@ -431,8 +431,8 @@ export const useCreateActionWithoutRefresh = (actionCallback?: (values: any) =>
export const useUpdateViewAction = (actionCallback?: (filterByTk: string, values: any) => void) => {
const form = useForm();
const ctx = useActionContext();
// const { refresh } = useResourceActionContext();
const { message } = App.useApp();
const { t } = useTranslation();
const { resource, targetKey } = useResourceContext();
const { [targetKey]: filterByTk } = useRecord();
return {
@ -440,8 +440,7 @@ export const useUpdateViewAction = (actionCallback?: (filterByTk: string, values
await form.submit();
const res = await resource.update({ filterByTk, values: form.values });
actionCallback?.(filterByTk, res?.data?.data);
// refresh();
message.success('保存成功');
message.success(t('Save successfully.'));
},
};
};
@ -503,6 +502,7 @@ export const useDestroyAction = (actionCallback?: (key: string) => void) => {
export const useBulkDestroyAction = (actionCallback?: (keys: string[]) => void) => {
const { state, setState, refresh } = useResourceActionContext();
const { resource } = useResourceContext();
const { message } = App.useApp();
const { t } = useTranslation();
return {
async run() {

View File

@ -1,7 +1,9 @@
import React from 'react';
import { observer, RecursionField, useField, useFieldSchema } from '@tachybase/schema';
import { Drawer } from 'antd';
import classNames from 'classnames';
import React from 'react';
import { OpenSize } from './';
import { useStyles } from './Action.Drawer.style';
import { useActionContext } from './hooks';
@ -16,7 +18,7 @@ const openSizeWidthMap = new Map<OpenSize, string>([
export const ActionDrawer: ComposedActionDrawer = observer(
(props) => {
const { footerNodeName = 'Action.Drawer.Footer', ...others } = props;
const { visible, setVisible, openSize = 'middle', drawerProps, modalProps } = useActionContext();
const { visible, setVisible, openSize = 'middle', drawerProps } = useActionContext();
const schema = useFieldSchema();
const field = useField();
const { componentCls, hashId } = useStyles();

View File

@ -8,9 +8,7 @@ import { useActionContext } from './hooks';
export const ActionContext = createContext<ActionContextProps>({});
ActionContext.displayName = 'ActionContext';
export const ActionContextProvider: React.FC<ActionContextProps & { value?: ActionContextProps; children: any }> = (
props,
) => {
export const ActionContextProvider = (props: ActionContextProps & { value?: ActionContextProps; children: any }) => {
const contextProps = useActionContext();
return (
<ActionContext.Provider value={{ ...contextProps, ...props, ...props?.value }}>

View File

@ -1,7 +1,9 @@
import { useFieldSchema, useForm } from '@tachybase/schema';
import { App } from 'antd';
import { useContext } from 'react';
import { useFieldSchema, useForm } from '@tachybase/schema';
import { App } from 'antd';
import { useTranslation } from 'react-i18next';
import { useIsDetailBlock } from '../../../block-provider/FormBlockProvider';
import { ActionContext } from './context';

View File

@ -1,4 +1,4 @@
import React, { useEffect, useMemo, useState } from 'react';
import React, { useEffect, useState } from 'react';
import {
connect,
mapProps,
@ -12,7 +12,7 @@ import {
} from '@tachybase/schema';
import { LoadingOutlined, PlusOutlined } from '@ant-design/icons';
import { message, Space } from 'antd';
import { App, Space } from 'antd';
import { isFunction } from 'mathjs';
import { useTranslation } from 'react-i18next';
@ -53,6 +53,7 @@ export const filterAnalyses = (filters): any[] => {
const InternalAssociationSelect = observer(
(props: AssociationSelectProps) => {
const { objectValue = true } = props;
const { message } = App.useApp();
const field: any = useField();
const fieldSchema = useFieldSchema();
const service = useServiceOptions(props);

View File

@ -2,7 +2,7 @@ import React from 'react';
import { TreeSelect } from '@tachybase/components';
import { Field, ISchema, onFieldChange, Schema, useField, useFieldSchema } from '@tachybase/schema';
import { message } from 'antd';
import { App } from 'antd';
import { saveAs } from 'file-saver';
import { useTranslation } from 'react-i18next';
@ -250,6 +250,7 @@ export const MenuDesigner = () => {
const field = useField();
const fieldSchema = useFieldSchema();
const api = useAPIClient();
const { message } = App.useApp();
const { dn, refresh } = useDesignable();
const { t } = useTranslation();
const menuSchema = findMenuSchema(fieldSchema);

View File

@ -10,10 +10,7 @@ import {
useFieldSchema,
} from '@tachybase/schema';
import { message } from 'antd';
import cloneDeep from 'lodash/cloneDeep';
import get from 'lodash/get';
import set from 'lodash/set';
import { cloneDeep, get, set } from 'lodash';
import { useTranslation } from 'react-i18next';
import { APIClient, useAPIClient } from '../../api-client';
@ -185,7 +182,6 @@ export class Designable {
});
}
onSuccess?.(res?.data?.data);
message.success(t('Saved successfully'), 0.2);
});
this.on('patch', async ({ schema }) => {
this.refresh();
@ -199,7 +195,6 @@ export class Designable {
...schema,
},
});
message.success(t('Saved successfully'), 0.2);
});
this.on('batchPatch', async ({ schemas }) => {
this.refresh();
@ -208,7 +203,6 @@ export class Designable {
method: 'post',
data: schemas,
});
message.success(t('Saved successfully'), 0.2);
});
this.on('remove', async ({ removed }) => {
let schemas = [];
@ -230,7 +224,6 @@ export class Designable {
data: schemas,
});
}
message.success(t('Saved successfully'), 0.2);
});
}

View File

@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { ISchema, useField, useFieldSchema, useForm } from '@tachybase/schema';
import { message } from 'antd';
import { App } from 'antd';
import { saveAs } from 'file-saver';
import { SchemaComponent, useActionContext, useAPIClient, useDesignable, useProps, useRecord } from '../..';
@ -11,6 +11,7 @@ import { useGetAriaLabelOfSchemaInitializer } from '../hooks/useGetAriaLabelOfSc
export const TabPaneInitializers = (props?: any) => {
const { designable, insertBeforeEnd } = useDesignable();
const fieldSchema = useFieldSchema();
const { message } = App.useApp();
const { isCreate, isBulkEdit, options } = props;
const { gridInitializer } = options;
const { getAriaLabel } = useGetAriaLabelOfSchemaInitializer();

View File

@ -1,17 +1,20 @@
import React, { useCallback } from 'react';
import { ArrayBase } from '@tachybase/components';
import { useForm } from '@tachybase/schema';
import { message } from 'antd';
import React, { useCallback } from 'react';
import { App } from 'antd';
import LRUCache from 'lru-cache';
import { useTranslation } from 'react-i18next';
import { getAssociationPath } from '../../block-provider/hooks';
import { useCollectionManager_deprecated } from '../../collection-manager';
import { useCompile } from '../../schema-component';
import { TreeNode } from './TreeLabel';
import { systemKeys } from './hooks/useCollectionState';
import LRUCache from 'lru-cache';
import { TreeNode } from './TreeLabel';
export const useSyncFromForm = (fieldSchema, collection?, callBack?) => {
const { getCollectionJoinField, getCollectionFields } = useCollectionManager_deprecated();
const { message } = App.useApp();
const array = ArrayBase.useArray();
const index = ArrayBase.useIndex();
const record = ArrayBase.useRecord();

View File

@ -1,7 +1,7 @@
import React, { useEffect, useRef, useState } from 'react';
import { useForm } from '@tachybase/schema';
import { Button, Input, message } from 'antd';
import { App, Button, Input } from 'antd';
import { createStyles } from 'antd-style';
import { useTranslation } from 'react-i18next';
@ -17,6 +17,7 @@ const useStyles = createStyles(({ css }) => {
});
export default function VerificationCode({ targetFieldName = 'phone', actionType, value, onChange }) {
const { message } = App.useApp();
const { t } = useTranslation();
const { styles } = useStyles();
const api = useAPIClient();

View File

@ -1,6 +1,8 @@
import React, { useEffect, useRef } from 'react';
import { connect, mapProps } from '@tachybase/schema';
import { Button } from 'antd';
import React, { useRef, useEffect } from 'react';
import SignaturePad from './SignaturePad';
export const SignatureInput = connect(

View File

@ -1,4 +1,5 @@
import * as React from 'react';
import SigPad, { Options, PointGroup, ToSVGOptions } from 'signature_pad';
import { debounce } from 'throttle-debounce';

View File

@ -1,5 +1,7 @@
import React, { useCallback, useRef } from 'react';
import classnames from 'classnames';
import { callHideEvent } from './registerEvent';
function ContextMenuItem({ children, onClick, disabled, preventClose, attributes, className }) {

View File

@ -1,6 +1,8 @@
import React, { useRef, useCallback } from 'react';
import React, { useCallback, useRef } from 'react';
import classnames from 'classnames';
import { callShowEvent, callHideEvent } from './registerEvent';
import { callHideEvent, callShowEvent } from './registerEvent';
function ContextMenuTrigger({ children, id, disableWhileShiftPressed, attributes, disable, className }) {
const menuTrigger = useRef(null);

View File

@ -95,7 +95,9 @@
.zoom-enter-active {
opacity: 1;
transform: scale(1);
transition: opacity 200ms, transform 200ms;
transition:
opacity 200ms,
transform 200ms;
transform-origin: top left;
}
.zoom-exit {
@ -106,7 +108,9 @@
.zoom-exit-active {
opacity: 0;
transform: scale(0.8);
transition: opacity 200ms, transform 200ms;
transition:
opacity 200ms,
transform 200ms;
transform-origin: top left;
}
// zoom in animation start
@ -119,7 +123,9 @@
.toTopLeft-enter-active {
opacity: 1;
transform: translate(0px, 0px);
transition: opacity 200ms, transform 200ms;
transition:
opacity 200ms,
transform 200ms;
}
.toTopLeft-exit {
opacity: 1;
@ -128,7 +134,9 @@
.toTopLeft-exit-active {
opacity: 0;
transform: translate(10px, 10px);
transition: opacity 200ms, transform 200ms;
transition:
opacity 200ms,
transform 200ms;
}
// to top left animation start
@ -140,7 +148,9 @@
.rightToLeft-enter-active {
opacity: 1;
transform: translateX(0px);
transition: opacity 200ms, transform 200ms;
transition:
opacity 200ms,
transform 200ms;
}
.rightToLeft-exit {
opacity: 1;
@ -149,7 +159,9 @@
.rightToLeft-exit-active {
opacity: 0;
transform: translateX(10px);
transition: opacity 200ms, transform 200ms;
transition:
opacity 200ms,
transform 200ms;
}
// right to left animation start
@ -161,7 +173,9 @@
.pop-enter-active {
opacity: 1;
transform: scale(1);
transition: opacity 200ms, transform 200ms;
transition:
opacity 200ms,
transform 200ms;
}
.pop-exit {
opacity: 1;
@ -170,7 +184,9 @@
.pop-exit-active {
opacity: 0;
transform: scale(0.8);
transition: opacity 200ms, transform 200ms;
transition:
opacity 200ms,
transform 200ms;
}
// right to left animation start

View File

@ -1,5 +1,7 @@
import React, { useCallback, useState, useRef } from 'react';
import React, { useCallback, useRef, useState } from 'react';
import classnames from 'classnames';
import ContextMenuItem from './contextMenuItem';
function Submenu({ children, title, attributes, className }) {

View File

@ -1,6 +1,8 @@
import { SchemaComponent } from '@tachybase/client';
import React from 'react';
import { SchemaComponent } from '@tachybase/client';
import { ErrorBoundary } from 'react-error-boundary';
import { ErrorBoundaryFallBack } from './ErrorBoundary';
export const CustomAssociatedField = (props) => {

View File

@ -1,10 +1,12 @@
import { SchemaComponent, SchemaSettings, useApp, useDesignable, usePlugin } from '@tachybase/client';
import React from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from '../../locale';
import { useField, useFieldSchema } from '@tachybase/schema';
import { SchemaComponent, SchemaSettings, useApp, useDesignable, usePlugin } from '@tachybase/client';
import { Field } from '@tachybase/database';
import { useField, useFieldSchema } from '@tachybase/schema';
import { ErrorBoundary } from 'react-error-boundary';
import { useCustomComponent } from '../../hooks/useCustomComponent';
import { useTranslation } from '../../locale';
import { CustomComponentType } from './custom-components';
import { ErrorBoundaryFallBack } from './ErrorBoundary';

View File

@ -1,6 +1,8 @@
import { SchemaComponent } from '@tachybase/client';
import React from 'react';
import { SchemaComponent } from '@tachybase/client';
import { ErrorBoundary } from 'react-error-boundary';
import { ErrorBoundaryFallBack } from './ErrorBoundary';
export const CustomField = (props) => {

View File

@ -1,4 +1,5 @@
import React from 'react';
import { useTranslation } from '../../locale';
export const ErrorBoundaryFallBack = () => {

View File

@ -1,5 +1,5 @@
import { ReactFC } from '@tachybase/schema';
import { ComponentType, MemoExoticComponent } from 'react';
import { ReactFC } from '@tachybase/schema';
export interface CustomFunctionComponent<P = {}> extends React.FunctionComponent<P> {
__componentType: CustomComponentType;

View File

@ -1,6 +1,8 @@
import { connect, mapProps } from '@tachybase/schema';
import { Button } from 'antd';
import React, { useRef, useState } from 'react';
import { connect, mapProps } from '@tachybase/schema';
import { Button } from 'antd';
import ModalFullScreen from '../modal-full-screen/ModalFullScreen';
import Sheet, { SheetRef } from './Sheet';

View File

@ -1,5 +1,4 @@
import _ from 'lodash';
import { ISchema, RecursionField, connect, observer, useField, useFieldSchema, useForm } from '@tachybase/schema';
import React, { useCallback, useEffect, useState } from 'react';
import {
ActionContextProvider,
CollectionProvider_deprecated,
@ -8,7 +7,9 @@ import {
useDesignable,
useRequest,
} from '@tachybase/client';
import React, { useCallback, useEffect, useState } from 'react';
import { connect, ISchema, observer, RecursionField, useField, useFieldSchema, useForm } from '@tachybase/schema';
import _ from 'lodash';
const viewerSchema: ISchema = {
type: 'void',

View File

@ -1,18 +1,18 @@
import { css } from '@tachybase/client';
import { ArrayCollapse } from '@tachybase/components';
import { Form } from '@tachybase/schema';
import { observer, useField, useFieldSchema } from '@tachybase/schema';
import React, { useMemo } from 'react';
import {
FormBlockContext,
RecordProvider,
SchemaComponent,
getShouldChange,
useCollectionManager_deprecated,
__UNSAFE__VariablesContextType,
__UNSAFE__DynamicComponentProps,
__UNSAFE__VariableOption,
__UNSAFE__VariablesContextType,
css,
FormBlockContext,
getShouldChange,
RecordProvider,
SchemaComponent,
useCollectionManager_deprecated,
} from '@tachybase/client';
import React, { useMemo } from 'react';
import { ArrayCollapse } from '@tachybase/components';
import { Form, observer, useField, useFieldSchema } from '@tachybase/schema';
import { FilterContext } from './context';
import { VariableInput } from './VariableInput';

View File

@ -1,6 +1,5 @@
import { ObjectField } from '@tachybase/schema';
import { Schema } from '@tachybase/schema';
import { createContext } from 'react';
import { ObjectField, Schema } from '@tachybase/schema';
export interface FilterContextProps {
field?: ObjectField & { collectionName?: string };

View File

@ -1,5 +1,6 @@
import React from 'react';
import { css } from '@tachybase/client';
import { Button } from 'antd';
export const ModalHeader = (props) => {

View File

@ -1,7 +1,9 @@
import React from 'react';
import { css } from '@tachybase/client';
import { Button, Tooltip } from 'antd';
import { MobileOutlined } from '@ant-design/icons';
import { Button, Tooltip } from 'antd';
import { useTranslation } from '../../locale';
export const MobileLink = () => {

View File

@ -1,7 +1,8 @@
import { uid } from '@tachybase/schema';
import { css, useAPIClient, useApp } from '@tachybase/client';
import { Button, Dropdown } from 'antd';
import React, { useEffect, useState } from 'react';
import { css, useAPIClient, useApp } from '@tachybase/client';
import { uid } from '@tachybase/schema';
import { Button, Dropdown } from 'antd';
import _ from 'lodash';
const OnlineUserManger = () => {

View File

@ -1,9 +1,5 @@
import { DrawBox } from './DrawBox';
import { npxLine } from './utils';
import { drawFontLine } from './utils';
import { npx } from './utils';
import { thinLineWidth } from './utils';
import { dpr } from './utils';
import { dpr, drawFontLine, npx, npxLine, thinLineWidth } from './utils';
interface Attr {
align?: 'left' | 'center' | 'right';

View File

@ -1,24 +1,22 @@
import { h } from './element';
import Icon from './icon';
import { cssPrefix } from '../config';
import DropdownColor from './dropdown_color';
import DropdownLineType from './dropdown_linetype';
import { cssPrefix } from '../config';
import { h } from './element';
import Icon from './icon';
function buildTable(...trs) {
return h('table', '').child(
h('tbody', '').children(...trs),
);
return h('table', '').child(h('tbody', '').children(...trs));
}
function buildTd(iconName) {
return h('td', '').child(
h('div', `${cssPrefix}-border-palette-cell`).child(
new Icon(`border-${iconName}`),
).on('click', () => {
this.mode = iconName;
const { mode, style, color } = this;
this.change({ mode, style, color });
}),
h('div', `${cssPrefix}-border-palette-cell`)
.child(new Icon(`border-${iconName}`))
.on('click', () => {
this.mode = iconName;
const { mode, style, color } = this;
this.change({ mode, style, color });
}),
);
}
@ -42,11 +40,9 @@ export default class BorderPalette {
h('td', `${cssPrefix}-border-palette-left`).child(
buildTable(
h('tr', '').children(
...['all', 'inside', 'horizontal', 'vertical', 'outside'].map(it => buildTd.call(this, it)),
),
h('tr', '').children(
...['left', 'top', 'right', 'bottom', 'none'].map(it => buildTd.call(this, it)),
...['all', 'inside', 'horizontal', 'vertical', 'outside'].map((it) => buildTd.call(this, it)),
),
h('tr', '').children(...['left', 'top', 'right', 'bottom', 'none'].map((it) => buildTd.call(this, it))),
),
),
h('td', `${cssPrefix}-border-palette-right`).children(

View File

@ -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) {

View File

@ -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

View File

@ -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);
@ -37,28 +37,23 @@ export default class Calendar {
this.headerLeftEl = h('div', 'calendar-header-left');
this.bodyEl = h('tbody', '');
this.buildAll();
this.el = h('div', 'x-spreadsheet-calendar')
.children(
h('div', 'calendar-header').children(
this.headerLeftEl,
h('div', 'calendar-header-right').children(
h('a', 'calendar-prev')
.on('click.stop', () => this.prev())
.child(new Icon('chevron-left')),
h('a', 'calendar-next')
.on('click.stop', () => this.next())
.child(new Icon('chevron-right')),
),
this.el = h('div', 'x-spreadsheet-calendar').children(
h('div', 'calendar-header').children(
this.headerLeftEl,
h('div', 'calendar-header-right').children(
h('a', 'calendar-prev')
.on('click.stop', () => this.prev())
.child(new Icon('chevron-left')),
h('a', 'calendar-next')
.on('click.stop', () => this.next())
.child(new Icon('chevron-right')),
),
h('table', 'calendar-body').children(
h('thead', '').child(
h('tr', '').children(
...t('calendar.weeks').map(week => h('th', 'cell').child(week)),
),
),
this.bodyEl,
),
);
),
h('table', 'calendar-body').children(
h('thead', '').child(h('tr', '').children(...t('calendar.weeks').map((week) => h('th', 'cell').child(week)))),
this.bodyEl,
),
);
this.selectChange = () => {};
}

View File

@ -1,7 +1,18 @@
import { h } from './element';
import { cssPrefix } from '../config';
import { h } from './element';
const themeColorPlaceHolders = ['#ffffff', '#000100', '#e7e5e6', '#445569', '#5b9cd6', '#ed7d31', '#a5a5a5', '#ffc001', '#4371c6', '#71ae47'];
const themeColorPlaceHolders = [
'#ffffff',
'#000100',
'#e7e5e6',
'#445569',
'#5b9cd6',
'#ed7d31',
'#a5a5a5',
'#ffc001',
'#4371c6',
'#71ae47',
];
const themeColors = [
['#f2f2f2', '#7f7f7f', '#d0cecf', '#d5dce4', '#deeaf6', '#fce5d5', '#ededed', '#fff2cd', '#d9e2f3', '#e3efd9'],
@ -11,7 +22,18 @@ const themeColors = [
['#7f7f7f', '#0c0c0c', '#171516', '#222a35', '#1f4e7a', '#843c0a', '#525252', '#7e6000', '#203864', '#365624'],
];
const standardColors = ['#c00000', '#fe0000', '#fdc101', '#ffff01', '#93d051', '#00b04e', '#01b0f1', '#0170c1', '#012060', '#7030a0'];
const standardColors = [
'#c00000',
'#fe0000',
'#fdc101',
'#ffff01',
'#93d051',
'#00b04e',
'#01b0f1',
'#0170c1',
'#012060',
'#7030a0',
];
function buildTd(bgcolor) {
return h('td', '').child(
@ -28,14 +50,12 @@ export default class ColorPalette {
const table = h('table', '').children(
h('tbody', '').children(
h('tr', `${cssPrefix}-theme-color-placeholders`).children(
...themeColorPlaceHolders.map(color => buildTd.call(this, color)),
...themeColorPlaceHolders.map((color) => buildTd.call(this, color)),
),
...themeColors.map(it => h('tr', `${cssPrefix}-theme-colors`).children(
...it.map(color => buildTd.call(this, color)),
)),
h('tr', `${cssPrefix}-standard-colors`).children(
...standardColors.map(color => buildTd.call(this, color)),
...themeColors.map((it) =>
h('tr', `${cssPrefix}-theme-colors`).children(...it.map((color) => buildTd.call(this, color))),
),
h('tr', `${cssPrefix}-standard-colors`).children(...standardColors.map((color) => buildTd.call(this, color))),
),
);
this.el.child(table);

View File

@ -1,7 +1,7 @@
import { h } from './element';
import { bindClickoutside, unbindClickoutside } from './event';
import { cssPrefix } from '../config';
import { tf } from '../locale/locale';
import { h } from './element';
import { bindClickoutside, unbindClickoutside } from './event';
const menuItems = [
{ key: 'copy', title: tf('contextmenu.copy'), label: 'Ctrl+C' },
@ -36,14 +36,11 @@ function buildMenuItem(item) {
this.itemClick(item.key);
this.hide();
})
.children(
item.title(),
h('div', 'label').child(item.label || ''),
);
.children(item.title(), h('div', 'label').child(item.label || ''));
}
function buildMenu() {
return menuItems.map(it => buildMenuItem.call(this, it));
return menuItems.map((it) => buildMenuItem.call(this, it));
}
export default class ContextMenu {

View File

@ -1,13 +1,11 @@
import { cssPrefix } from '../config';
import Calendar from './calendar';
import { h } from './element';
import { cssPrefix } from '../config';
export default class Datepicker {
constructor() {
this.calendar = new Calendar(new Date());
this.el = h('div', `${cssPrefix}-datepicker`).child(
this.calendar.el,
).hide();
this.el = h('div', `${cssPrefix}-datepicker`).child(this.calendar.el).hide();
}
setValue(date) {

View File

@ -1,6 +1,6 @@
import { HComponent, h } from './element';
import { bindClickoutside, unbindClickoutside } from './event';
import { cssPrefix } from '../config';
import { h, HComponent } from './element';
import { bindClickoutside, unbindClickoutside } from './event';
export default class Dropdown extends HComponent {
constructor(title, width, showArrow, placement, ...children) {

View File

@ -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));
@ -10,11 +10,12 @@ function buildItemWithIcon(iconName) {
export default class DropdownAlign extends Dropdown {
constructor(aligns, align) {
const icon = new Icon(`align-${align}`);
const naligns = aligns.map(it => buildItemWithIcon(`align-${it}`)
.on('click', () => {
const naligns = aligns.map((it) =>
buildItemWithIcon(`align-${it}`).on('click', () => {
this.setTitle(it);
this.change(it);
}));
}),
);
super(icon, 'auto', true, 'bottom-left', ...naligns);
}

View File

@ -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() {

View File

@ -1,12 +1,10 @@
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) {
const icon = new Icon(iconName)
.css('height', '16px')
.css('border-bottom', `3px solid ${color}`);
const icon = new Icon(iconName).css('height', '16px').css('border-bottom', `3px solid ${color}`);
const colorPalette = new ColorPalette();
colorPalette.change = (v) => {
this.setTitle(v);

View File

@ -1,16 +1,18 @@
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() {
const nfonts = baseFonts.map(it => h('div', `${cssPrefix}-item`)
.on('click', () => {
this.setTitle(it.title);
this.change(it);
})
.child(it.title));
const nfonts = baseFonts.map((it) =>
h('div', `${cssPrefix}-item`)
.on('click', () => {
this.setTitle(it.title);
this.change(it);
})
.child(it.title),
);
super(baseFonts[0].title, '160px', true, 'bottom-left', ...nfonts);
}
}

View File

@ -1,16 +1,18 @@
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() {
const nfontSizes = fontSizes.map(it => h('div', `${cssPrefix}-item`)
.on('click', () => {
this.setTitle(`${it.pt}`);
this.change(it);
})
.child(`${it.pt}`));
const nfontSizes = fontSizes.map((it) =>
h('div', `${cssPrefix}-item`)
.on('click', () => {
this.setTitle(`${it.pt}`);
this.change(it);
})
.child(`${it.pt}`),
);
super('10', '60px', true, 'bottom-left', ...nfontSizes);
}
}

View File

@ -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() {
@ -13,11 +13,10 @@ export default class DropdownFormat extends Dropdown {
if (it.key === 'divider') {
item.addClass('divider');
} else {
item.child(it.title())
.on('click', () => {
this.setTitle(it.title());
this.change(it);
});
item.child(it.title()).on('click', () => {
this.setTitle(it.title());
this.change(it);
});
if (it.label) item.child(h('div', 'label').html(it.label));
}
return item;

View File

@ -1,17 +1,19 @@
import Dropdown from './dropdown';
import Icon from './icon';
import { h } from './element';
import { baseFormulas } from '../core/formula';
import { cssPrefix } from '../config';
import { baseFormulas } from '../core/formula';
import Dropdown from './dropdown';
import { h } from './element';
import Icon from './icon';
export default class DropdownFormula extends Dropdown {
constructor() {
const nformulas = baseFormulas.map(it => h('div', `${cssPrefix}-item`)
.on('click', () => {
this.hide();
this.change(it);
})
.child(it.key));
const nformulas = baseFormulas.map((it) =>
h('div', `${cssPrefix}-item`)
.on('click', () => {
this.hide();
this.change(it);
})
.child(it.key),
);
super(new Icon('formula'), '180px', true, 'bottom-left', ...nformulas);
}
}

View File

@ -1,14 +1,29 @@
import { cssPrefix } from '../config';
import Dropdown from './dropdown';
import { h } from './element';
import Icon from './icon';
import { cssPrefix } from '../config';
const lineTypes = [
['thin', '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="1" style="user-select: none;"><line x1="0" y1="0.5" x2="50" y2="0.5" stroke-width="1" stroke="black" style="user-select: none;"></line></svg>'],
['medium', '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="2" style="user-select: none;"><line x1="0" y1="1.0" x2="50" y2="1.0" stroke-width="2" stroke="black" style="user-select: none;"></line></svg>'],
['thick', '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="3" style="user-select: none;"><line x1="0" y1="1.5" x2="50" y2="1.5" stroke-width="3" stroke="black" style="user-select: none;"></line></svg>'],
['dashed', '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="1" style="user-select: none;"><line x1="0" y1="0.5" x2="50" y2="0.5" stroke-width="1" stroke="black" stroke-dasharray="2" style="user-select: none;"></line></svg>'],
['dotted', '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="1" style="user-select: none;"><line x1="0" y1="0.5" x2="50" y2="0.5" stroke-width="1" stroke="black" stroke-dasharray="1" style="user-select: none;"></line></svg>'],
[
'thin',
'<svg xmlns="http://www.w3.org/2000/svg" width="50" height="1" style="user-select: none;"><line x1="0" y1="0.5" x2="50" y2="0.5" stroke-width="1" stroke="black" style="user-select: none;"></line></svg>',
],
[
'medium',
'<svg xmlns="http://www.w3.org/2000/svg" width="50" height="2" style="user-select: none;"><line x1="0" y1="1.0" x2="50" y2="1.0" stroke-width="2" stroke="black" style="user-select: none;"></line></svg>',
],
[
'thick',
'<svg xmlns="http://www.w3.org/2000/svg" width="50" height="3" style="user-select: none;"><line x1="0" y1="1.5" x2="50" y2="1.5" stroke-width="3" stroke="black" style="user-select: none;"></line></svg>',
],
[
'dashed',
'<svg xmlns="http://www.w3.org/2000/svg" width="50" height="1" style="user-select: none;"><line x1="0" y1="0.5" x2="50" y2="0.5" stroke-width="1" stroke="black" stroke-dasharray="2" style="user-select: none;"></line></svg>',
],
[
'dotted',
'<svg xmlns="http://www.w3.org/2000/svg" width="50" height="1" style="user-select: none;"><line x1="0" y1="0.5" x2="50" y2="0.5" stroke-width="1" stroke="black" stroke-dasharray="1" style="user-select: none;"></line></svg>',
],
// ['double', '<svg xmlns="http://www.w3.org/2000/svg" width="50" height="3" style="user-select: none;"><line x1="0" y1="0.5" x2="50" y2="0.5" stroke-width="1" stroke="black" style="user-select: none;"></line><line x1="0" y1="2.5" x2="50" y2="2.5" stroke-width="1" stroke="black" style="user-select: none;"></line></svg>'],
];
@ -16,17 +31,17 @@ export default class DropdownLineType extends Dropdown {
constructor(type) {
const icon = new Icon('line-type');
let beforei = 0;
const lineTypeEls = lineTypes.map((it, iti) => h('div', `${cssPrefix}-item state ${type === it[0] ? 'checked' : ''}`)
.on('click', () => {
lineTypeEls[beforei].toggle('checked');
lineTypeEls[iti].toggle('checked');
beforei = iti;
this.hide();
this.change(it);
})
.child(
h('div', `${cssPrefix}-line-type`).html(it[1]),
));
const lineTypeEls = lineTypes.map((it, iti) =>
h('div', `${cssPrefix}-item state ${type === it[0] ? 'checked' : ''}`)
.on('click', () => {
lineTypeEls[beforei].toggle('checked');
lineTypeEls[iti].toggle('checked');
beforei = iti;
this.hide();
this.change(it);
})
.child(h('div', `${cssPrefix}-line-type`).html(it[1])),
);
super(icon, 'auto', false, 'bottom-left', ...lineTypeEls);
}

View File

@ -1,18 +1,17 @@
//* global window */
import { cssPrefix } from '../config';
import Datepicker from './datepicker';
import { h } from './element';
import Suggest from './suggest';
import Datepicker from './datepicker';
import { cssPrefix } from '../config';
// import { mouseMoveUp } from '../event';
function resetTextareaSize() {
const { inputText } = this;
if (!/^\s*$/.test(inputText)) {
const {
textlineEl, textEl, areaOffset,
} = this;
const { textlineEl, textEl, areaOffset } = this;
const txts = inputText.split('\n');
const maxTxtSize = Math.max(...txts.map(it => it.length));
const maxTxtSize = Math.max(...txts.map((it) => it.length));
const tlOffset = textlineEl.offset();
const fontWidth = tlOffset.width / inputText.length;
const tlineWidth = (maxTxtSize + 1) * fontWidth + 5;
@ -23,7 +22,7 @@ function resetTextareaSize() {
if (tlineWidth > maxWidth) {
twidth = maxWidth;
h1 += parseInt(tlineWidth / maxWidth, 10);
h1 += (tlineWidth % maxWidth) > 0 ? 1 : 0;
h1 += tlineWidth % maxWidth > 0 ? 1 : 0;
}
textEl.css('width', `${twidth}px`);
}
@ -61,7 +60,7 @@ function inputEventHandler(evt) {
const { suggest, textlineEl, validator } = this;
const { cell } = this;
if (cell !== null) {
if (('editable' in cell && cell.editable === true) || (cell.editable === undefined)) {
if (('editable' in cell && cell.editable === true) || cell.editable === undefined) {
this.inputText = v;
if (validator) {
if (validator.type === 'list') {
@ -174,18 +173,17 @@ export default class Editor {
});
this.areaEl = h('div', `${cssPrefix}-editor-area`)
.children(
this.textEl = h('textarea', '')
.on('input', evt => inputEventHandler.call(this, evt))
(this.textEl = h('textarea', '')
.on('input', (evt) => inputEventHandler.call(this, evt))
.on('paste.stop', () => {})
.on('keydown', evt => keydownEventHandler.call(this, evt)),
this.textlineEl = h('div', 'textline'),
.on('keydown', (evt) => keydownEventHandler.call(this, evt))),
(this.textlineEl = h('div', 'textline')),
this.suggest.el,
this.datepicker.el,
)
.on('mousemove.stop', () => {})
.on('mousedown.stop', () => {});
this.el = h('div', `${cssPrefix}-editor`)
.child(this.areaEl).hide();
this.el = h('div', `${cssPrefix}-editor`).child(this.areaEl).hide();
this.suggest.bindInputEvents(this.textEl);
this.areaOffset = null;
@ -217,14 +215,10 @@ export default class Editor {
}
setOffset(offset, suggestPosition = 'top') {
const {
textEl, areaEl, suggest, freeze, el,
} = this;
const { textEl, areaEl, suggest, freeze, el } = this;
if (offset) {
this.areaOffset = offset;
const {
left, top, width, height, l, t,
} = 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

View File

@ -1,4 +1,5 @@
import _ from 'lodash';
class Element {
el: HTMLElement;
private _data: Record<string, any>;

View File

@ -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})?$)/,
@ -18,8 +18,7 @@ export default class FormField {
this.tip = h('div', 'tip').child('tip').hide();
this.input = input;
this.input.vchange = () => this.validate();
this.el = h('div', `${cssPrefix}-form-field`)
.children(this.label, input.el, this.tip);
this.el = h('div', `${cssPrefix}-form-field`).children(this.label, input.el, this.tip);
}
isShow() {
@ -44,9 +43,7 @@ export default class FormField {
}
validate() {
const {
input, rule, tip, el,
} = this;
const { input, rule, tip, el } = this;
const v = input.val();
if (rule.required) {
if (/^\s*$/.test(v)) {

View File

@ -1,12 +1,13 @@
import { h } from './element';
import { cssPrefix } from '../config';
import { h } from './element';
export default class FormInput {
constructor(width, hint) {
this.vchange = () => {};
this.el = h('div', `${cssPrefix}-form-input`);
this.input = h('input', '').css('width', width)
.on('input', evt => this.vchange(evt))
this.input = h('input', '')
.css('width', width)
.on('input', (evt) => this.vchange(evt))
.attr('placeholder', hint);
this.el.child(this.input);
}

View File

@ -1,22 +1,26 @@
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 = () => {}) {
constructor(key, items, width, getTitle = (it) => it, change = () => {}) {
this.key = key;
this.getTitle = getTitle;
this.vchange = () => {};
this.el = h('div', `${cssPrefix}-form-select`);
this.suggest = new Suggest(items.map(it => ({ key: it, title: this.getTitle(it) })), (it) => {
this.itemClick(it.key);
change(it.key);
this.vchange(it.key);
}, width, this.el);
this.el.children(
this.itemEl = h('div', 'input-text').html(this.getTitle(key)),
this.suggest.el,
).on('click', () => this.show());
this.suggest = new Suggest(
items.map((it) => ({ key: it, title: this.getTitle(it) })),
(it) => {
this.itemClick(it.key);
change(it.key);
this.vchange(it.key);
},
width,
this.el,
);
this.el
.children((this.itemEl = h('div', 'input-text').html(this.getTitle(key))), this.suggest.el)
.on('click', () => this.show());
}
show() {

View File

@ -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) {

View File

@ -1,7 +1,7 @@
/* 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`);

View File

@ -1,20 +1,23 @@
/* global document */
/* global window */
import { h } from './element';
import Icon from './icon';
import { cssPrefix } from '../config';
import { h } from './element';
import { bind, unbind } from './event';
import Icon from './icon';
export default class Modal {
constructor(title, content, width = '600px') {
this.title = title;
this.el = h('div', `${cssPrefix}-modal`).css('width', width).children(
h('div', `${cssPrefix}-modal-header`).children(
new Icon('close').on('click.stop', () => this.hide()),
this.title,
),
h('div', `${cssPrefix}-modal-content`).children(...content),
).hide();
this.el = h('div', `${cssPrefix}-modal`)
.css('width', width)
.children(
h('div', `${cssPrefix}-modal-header`).children(
new Icon('close').on('click.stop', () => this.hide()),
this.title,
),
h('div', `${cssPrefix}-modal-content`).children(...content),
)
.hide();
}
show() {

View File

@ -1,35 +1,39 @@
import Modal from './modal';
import { cssPrefix } from '../config';
import { t } from '../locale/locale';
import Button from './button';
import { h } from './element';
import FormField from './form_field';
import FormInput from './form_input';
import FormSelect from './form_select';
import FormField from './form_field';
import Button from './button';
import { t } from '../locale/locale';
import { h } from './element';
import { cssPrefix } from '../config';
import Modal from './modal';
const fieldLabelWidth = 100;
export default class ModalValidation extends Modal {
constructor() {
const mf = new FormField(
new FormSelect('cell',
new FormSelect(
'cell',
['cell'], // cell|row|column
'100%',
it => t(`dataValidation.modeType.${it}`)),
(it) => t(`dataValidation.modeType.${it}`),
),
{ required: true },
`${t('dataValidation.range')}:`,
fieldLabelWidth,
);
const rf = new FormField(
new FormInput('120px', 'E3 or E3:F12'),
{ required: true, pattern: /^([A-Z]{1,2}[1-9]\d*)(:[A-Z]{1,2}[1-9]\d*)?$/ },
);
const rf = new FormField(new FormInput('120px', 'E3 or E3:F12'), {
required: true,
pattern: /^([A-Z]{1,2}[1-9]\d*)(:[A-Z]{1,2}[1-9]\d*)?$/,
});
const cf = new FormField(
new FormSelect('list',
new FormSelect(
'list',
['list', 'number', 'date', 'phone', 'email'],
'100%',
it => t(`dataValidation.type.${it}`),
it => this.criteriaSelected(it)),
(it) => t(`dataValidation.type.${it}`),
(it) => this.criteriaSelected(it),
),
{ required: true },
`${t('dataValidation.criteria')}:`,
fieldLabelWidth,
@ -37,45 +41,25 @@ export default class ModalValidation extends Modal {
// operator
const of = new FormField(
new FormSelect('be',
new FormSelect(
'be',
['be', 'nbe', 'eq', 'neq', 'lt', 'lte', 'gt', 'gte'],
'160px',
it => t(`dataValidation.operator.${it}`),
it => this.criteriaOperatorSelected(it)),
(it) => t(`dataValidation.operator.${it}`),
(it) => this.criteriaOperatorSelected(it),
),
{ required: true },
).hide();
// min, max
const minvf = new FormField(
new FormInput('70px', '10'),
{ required: true },
).hide();
const maxvf = new FormField(
new FormInput('70px', '100'),
{ required: true, type: 'number' },
).hide();
const minvf = new FormField(new FormInput('70px', '10'), { required: true }).hide();
const maxvf = new FormField(new FormInput('70px', '100'), { required: true, type: 'number' }).hide();
// value
const svf = new FormField(
new FormInput('120px', 'a,b,c'),
{ required: true },
);
const vf = new FormField(
new FormInput('70px', '10'),
{ required: true, type: 'number' },
).hide();
const svf = new FormField(new FormInput('120px', 'a,b,c'), { required: true });
const vf = new FormField(new FormInput('70px', '10'), { required: true, type: 'number' }).hide();
super(t('contextmenu.validation'), [
h('div', `${cssPrefix}-form-fields`).children(
mf.el,
rf.el,
),
h('div', `${cssPrefix}-form-fields`).children(
cf.el,
of.el,
minvf.el,
maxvf.el,
vf.el,
svf.el,
),
h('div', `${cssPrefix}-form-fields`).children(mf.el, rf.el),
h('div', `${cssPrefix}-form-fields`).children(cf.el, of.el, minvf.el, maxvf.el, vf.el, svf.el),
h('div', `${cssPrefix}-buttons`).children(
new Button('cancel').on('click', () => this.btnClick('cancel')),
new Button('remove').on('click', () => this.btnClick('remove')),
@ -101,9 +85,7 @@ export default class ModalValidation extends Modal {
}
criteriaSelected(it) {
const {
of, minvf, maxvf, vf, svf,
} = this;
const { of, minvf, maxvf, vf, svf } = this;
if (it === 'date' || it === 'number') {
of.show();
minvf.rule.type = it;
@ -134,9 +116,7 @@ export default class ModalValidation extends Modal {
criteriaOperatorSelected(it) {
if (!it) return;
const {
minvf, maxvf, vf,
} = this;
const { minvf, maxvf, vf } = this;
if (it === 'be' || it === 'nbe') {
minvf.show();
maxvf.show();
@ -186,12 +166,12 @@ export default class ModalValidation extends Modal {
}
}
// console.log(mode, ref, type, operator, value);
this.change('save',
mode,
ref,
{
type, operator, required: false, value,
});
this.change('save', mode, ref, {
type,
operator,
required: false,
value,
});
this.hide();
}
}
@ -199,15 +179,9 @@ export default class ModalValidation extends Modal {
// validation: { mode, ref, validator }
setValue(v) {
if (v) {
const {
mf, rf, cf, of, svf, vf, minvf, maxvf,
} = this;
const {
mode, ref, validator,
} = v;
const {
type, operator, value,
} = validator || { type: 'list' };
const { mf, rf, cf, of, svf, vf, minvf, maxvf } = this;
const { mode, ref, validator } = v;
const { type, operator, value } = validator || { type: 'list' };
mf.val(mode || 'cell');
rf.val(ref);
cf.val(type);

View File

@ -1,10 +1,10 @@
/* global window document */
import { h } from './element';
import { cssPrefix } from '../config';
import Button from './button';
import { Draw } from '../canvas';
import { renderCell } from './table';
import { cssPrefix } from '../config';
import { t } from '../locale/locale';
import Button from './button';
import { h } from './element';
import { renderCell } from './table';
// resolution: 72 => 595 x 842
// 150 => 1240 x 1754

View File

@ -1,20 +1,24 @@
/* 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) {
this.moving = false;
this.vertical = vertical;
this.el = h('div', `${cssPrefix}-resizer ${vertical ? 'vertical' : 'horizontal'}`).children(
this.unhideHoverEl = h('div', `${cssPrefix}-resizer-hover`)
.on('dblclick.stop', evt => this.mousedblclickHandler(evt))
.css('position', 'absolute').hide(),
this.hoverEl = h('div', `${cssPrefix}-resizer-hover`)
.on('mousedown.stop', evt => this.mousedownHandler(evt)),
this.lineEl = h('div', `${cssPrefix}-resizer-line`).hide(),
).hide();
this.el = h('div', `${cssPrefix}-resizer ${vertical ? 'vertical' : 'horizontal'}`)
.children(
(this.unhideHoverEl = h('div', `${cssPrefix}-resizer-hover`)
.on('dblclick.stop', (evt) => this.mousedblclickHandler(evt))
.css('position', 'absolute')
.hide()),
(this.hoverEl = h('div', `${cssPrefix}-resizer-hover`).on('mousedown.stop', (evt) =>
this.mousedownHandler(evt),
)),
(this.lineEl = h('div', `${cssPrefix}-resizer-line`).hide()),
)
.hide();
// cell rect
this.cRect = null;
this.finishedFn = null;
@ -34,15 +38,10 @@ export default class Resizer {
// rect : {top, left, width, height}
// line : {width, height}
show(rect, line) {
const {
moving, vertical, hoverEl, lineEl, el,
unhideHoverEl,
} = this;
const { moving, vertical, hoverEl, lineEl, el, unhideHoverEl } = this;
if (moving) return;
this.cRect = rect;
const {
left, top, width, height,
} = rect;
const { left, top, width, height } = rect;
el.offset({
left: vertical ? left + width - 5 : left,
top: vertical ? top : top + height - 5,
@ -64,10 +63,12 @@ export default class Resizer {
}
hide() {
this.el.offset({
left: 0,
top: 0,
}).hide();
this.el
.offset({
left: 0,
top: 0,
})
.hide();
this.hideUnhide();
}
@ -77,38 +78,40 @@ export default class Resizer {
mousedownHandler(evt) {
let startEvt = evt;
const {
el, lineEl, cRect, vertical, minDistance,
} = this;
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) {
el.css('left', `${cRect.left + distance}px`);
}
} else {
distance += e.movementY;
if (distance > minDistance) {
el.css('top', `${cRect.top + distance}px`);
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) {
el.css('left', `${cRect.left + distance}px`);
}
} else {
distance += e.movementY;
if (distance > minDistance) {
el.css('top', `${cRect.top + distance}px`);
}
}
startEvt = e;
}
startEvt = e;
}
}, () => {
startEvt = null;
lineEl.hide();
this.moving = false;
this.hide();
if (this.finishedFn) {
if (distance < minDistance) distance = minDistance;
this.finishedFn(cRect, distance);
}
});
},
() => {
startEvt = null;
lineEl.hide();
this.moving = false;
this.hide();
if (this.finishedFn) {
if (distance < minDistance) distance = minDistance;
this.finishedFn(cRect, distance);
}
},
);
}
}

View File

@ -1,5 +1,5 @@
import { h, HComponent } from './element';
import { cssPrefix } from '../config';
import { h, HComponent } from './element';
export default class Scrollbar {
private el: HComponent;

View File

@ -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;
@ -11,8 +11,7 @@ class SelectorElement {
this.autoFocus = autoFocus;
this.inputChange = () => {};
this.cornerEl = h('div', `${cssPrefix}-selector-corner`);
this.areaEl = h('div', `${cssPrefix}-selector-area`)
.child(this.cornerEl).hide();
this.areaEl = h('div', `${cssPrefix}-selector-area`).child(this.cornerEl).hide();
this.clipboardEl = h('div', `${cssPrefix}-selector-clipboard`).hide();
this.autofillEl = h('div', `${cssPrefix}-selector-autofill`).hide();
this.el = h('div', `${cssPrefix}-selector`)
@ -20,12 +19,11 @@ class SelectorElement {
.children(this.areaEl, this.clipboardEl, this.autofillEl)
.hide();
if (useHideInput) {
this.hideInput = h('input', '')
.on('compositionend', (evt) => {
this.inputChange(evt.target.value);
});
this.el.child(this.hideInputDiv = h('div', 'hide-input').child(this.hideInput));
this.el.child(this.hideInputDiv = h('div', 'hide-input').child(this.hideInput));
this.hideInput = h('input', '').on('compositionend', (evt) => {
this.inputChange(evt.target.value);
});
this.el.child((this.hideInputDiv = h('div', 'hide-input').child(this.hideInput)));
this.el.child((this.hideInputDiv = h('div', 'hide-input').child(this.hideInput)));
}
startZIndex += 1;
}
@ -41,9 +39,7 @@ class SelectorElement {
}
setAreaOffset(v) {
const {
left, top, width, height,
} = v;
const { left, top, width, height } = v;
const of = {
width: width - selectorHeightBorderWidth + 0.8,
height: height - selectorHeightBorderWidth + 0.8,
@ -62,9 +58,7 @@ class SelectorElement {
}
setClipboardOffset(v) {
const {
left, top, width, height,
} = v;
const { left, top, width, height } = v;
this.clipboardEl.offset({
left,
top,
@ -74,15 +68,15 @@ class SelectorElement {
}
showAutofill(v) {
const {
left, top, width, height,
} = v;
this.autofillEl.offset({
width: width - selectorHeightBorderWidth,
height: height - selectorHeightBorderWidth,
left,
top,
}).show();
const { left, top, width, height } = v;
this.autofillEl
.offset({
width: width - selectorHeightBorderWidth,
height: height - selectorHeightBorderWidth,
left,
top,
})
.show();
}
hideAutofill() {
@ -100,9 +94,7 @@ class SelectorElement {
function calBRAreaOffset(offset) {
const { data } = this;
const {
left, top, width, height, scroll, l, t,
} = offset;
const { left, top, width, height, scroll, l, t } = offset;
const ftwidth = data.freezeTotalWidth();
const ftheight = data.freezeTotalHeight();
let left0 = left - ftwidth;
@ -119,28 +111,30 @@ function calBRAreaOffset(offset) {
function calTAreaOffset(offset) {
const { data } = this;
const {
left, width, height, l, t, scroll,
} = offset;
const { left, width, height, l, t, scroll } = offset;
const ftwidth = data.freezeTotalWidth();
let left0 = left - ftwidth;
if (ftwidth > l) left0 -= scroll.x;
return {
left: left0, top: t, width, height,
left: left0,
top: t,
width,
height,
};
}
function calLAreaOffset(offset) {
const { data } = this;
const {
top, width, height, l, t, scroll,
} = 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, top: top0, width, height,
left: l,
top: top0,
width,
height,
};
}
@ -216,13 +210,7 @@ export default class Selector {
this.indexes = null;
this.range = null;
this.arange = null;
this.el = h('div', `${cssPrefix}-selectors`)
.children(
this.tl.el,
this.t.el,
this.l.el,
this.br.el,
).hide();
this.el = h('div', `${cssPrefix}-selectors`).children(this.tl.el, this.t.el, this.l.el, this.br.el).hide();
// for performance
this.lastri = -1;
@ -242,9 +230,7 @@ export default class Selector {
}
resetOffset() {
const {
data, tl, t, l, br,
} = this;
const { data, tl, t, l, br } = this;
const freezeHeight = data.freezeTotalHeight();
const freezeWidth = data.freezeTotalWidth();
if (freezeHeight > 0 || freezeWidth > 0) {
@ -331,9 +317,7 @@ export default class Selector {
// console.log('ri:', ri, ', ci:', ci);
// const [sri, sci] = this.sIndexes;
// const [eri, eci] = this.eIndexes;
const {
sri, sci, eri, eci,
} = this.range;
const { sri, sci, eri, eci } = this.range;
const [nri, nci] = [ri, ci];
// const rn = eri - sri;
// const cn = eci - sci;
@ -381,9 +365,7 @@ export default class Selector {
const offset = this.data.getRect(this.arange);
offset.width += 2;
offset.height += 2;
const {
br, l, t, tl,
} = this;
const { br, l, t, tl } = this;
br.showAutofill(calBRAreaOffset.call(this, offset));
l.showAutofill(calLAreaOffset.call(this, offset));
t.showAutofill(calTAreaOffset.call(this, offset));

View File

@ -1,19 +1,19 @@
/* 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, mouseMoveUp, bindTouch, createEventEmitter } from './event';
import { bind, bindTouch, createEventEmitter, mouseMoveUp } from './event';
import { xtoast } from './message';
import ModalValidation from './modal_validation';
import Print from './print';
import Resizer from './resizer';
import Scrollbar from './scrollbar';
import Selector from './selector';
import Editor from './editor';
import Print from './print';
import ContextMenu from './contextmenu';
import SortFilter from './sort_filter';
import Table from './table';
import Toolbar from './toolbar/index';
import ModalValidation from './modal_validation';
import SortFilter from './sort_filter';
import { xtoast } from './message';
import { cssPrefix } from '../config';
import { formulas } from '../core/formula';
/**
* @desc throttle fn

View File

@ -1,15 +1,16 @@
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}`);
}
function buildSortItem(it) {
return buildMenu('state').child(t(`sort.${it}`))
return buildMenu('state')
.child(t(`sort.${it}`))
.on('click.stop', () => this.itemClick(it));
}
@ -20,9 +21,11 @@ function buildFilterBody(items) {
itemKeys.forEach((it, index) => {
const cnt = items[it];
const active = filterValues.includes(it) ? 'checked' : '';
filterbEl.child(h('div', `${cssPrefix}-item state ${active}`)
.on('click.stop', () => this.filterClick(index, it))
.children(it === '' ? t('filter.empty') : it, h('div', 'label').html(`(${cnt})`)));
filterbEl.child(
h('div', `${cssPrefix}-item state ${active}`)
.on('click.stop', () => this.filterClick(index, it))
.children(it === '' ? t('filter.empty') : it, h('div', 'label').html(`(${cnt})`)),
);
});
}
@ -36,19 +39,18 @@ export default class SortFilter {
constructor() {
this.filterbEl = h('div', `${cssPrefix}-body`);
this.filterhEl = h('div', `${cssPrefix}-header state`).on('click.stop', () => this.filterClick(0, 'all'));
this.el = h('div', `${cssPrefix}-sort-filter`).children(
this.sortAscEl = buildSortItem.call(this, 'asc'),
this.sortDescEl = buildSortItem.call(this, 'desc'),
buildMenu('divider'),
h('div', `${cssPrefix}-filter`).children(
this.filterhEl,
this.filterbEl,
),
h('div', `${cssPrefix}-buttons`).children(
new Button('cancel').on('click', () => this.btnClick('cancel')),
new Button('ok', 'primary').on('click', () => this.btnClick('ok')),
),
).hide();
this.el = h('div', `${cssPrefix}-sort-filter`)
.children(
(this.sortAscEl = buildSortItem.call(this, 'asc')),
(this.sortDescEl = buildSortItem.call(this, 'desc')),
buildMenu('divider'),
h('div', `${cssPrefix}-filter`).children(this.filterhEl, this.filterbEl),
h('div', `${cssPrefix}-buttons`).children(
new Button('cancel').on('click', () => this.btnClick('cancel')),
new Button('ok', 'primary').on('click', () => this.btnClick('ok')),
),
)
.hide();
// this.setFilters(['test1', 'test2', 'text3']);
this.ci = null;
this.sortDesc = null;
@ -81,17 +83,20 @@ export default class SortFilter {
if (it === 'all') {
if (children.length === filterValues.length) {
this.filterValues = [];
children.forEach(i => h(i).checked(false));
children.forEach((i) => h(i).checked(false));
} else {
this.filterValues = Array.from(values);
children.forEach(i => h(i).checked(true));
children.forEach((i) => h(i).checked(true));
}
} else {
const checked = h(children[index]).toggle('checked');
if (checked) {
filterValues.push(it);
} else {
filterValues.splice(filterValues.findIndex(i => i === it), 1);
filterValues.splice(
filterValues.findIndex((i) => i === it),
1,
);
}
}
resetFilterHeader.call(this);

View File

@ -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();
@ -77,8 +77,7 @@ export default class Suggest {
}
setOffset(v) {
this.el.cssRemoveKeys('top', 'bottom')
.offset(v);
this.el.cssRemoveKeys('top', 'bottom').offset(v);
}
hide() {
@ -97,7 +96,7 @@ export default class Suggest {
search(word) {
let { items } = this;
if (!/^\s*$/.test(word)) {
items = items.filter(it => (it.key || it).startsWith(word.toUpperCase()));
items = items.filter((it) => (it.key || it).startsWith(word.toUpperCase()));
}
items = items.map((it) => {
let { title } = it;
@ -125,11 +124,15 @@ export default class Suggest {
}
const { el } = this;
// items[0].toggle();
el.html('').children(...items).show();
bindClickoutside(el.parent(), () => { this.hide(); });
el.html('')
.children(...items)
.show();
bindClickoutside(el.parent(), () => {
this.hide();
});
}
bindInputEvents(input) {
input.on('keydown', evt => inputKeydownHandler.call(this, evt));
input.on('keydown', (evt) => inputKeydownHandler.call(this, evt));
}
}

View File

@ -1,10 +1,10 @@
import { Draw, DrawBox, npx, thinLineWidth } from '../canvas';
import { stringAt } from '../core/alphabet';
import { getFontSizePxByPt } from '../core/font';
import _cell from '../core/cell';
import { formulam } from '../core/formula';
import { getFontSizePxByPt } from '../core/font';
import { formatm } from '../core/format';
import { formulam } from '../core/formula';
import { Draw, DrawBox, thinLineWidth, npx } from '../canvas';
// gobal var
const cellPaddingWidth = 5;
const tableFixedHeaderCleanStyle = { fillStyle: '#f4f5f8' };

View File

@ -1,18 +1,18 @@
/* global window */
import { h } from './element';
import { bind } from './event';
import tooltip from './tooltip';
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 DropdownFont from './dropdown_font';
import DropdownFontSize from './dropdown_fontsize';
import DropdownFormat from './dropdown_format';
import DropdownFormula from './dropdown_formula';
import DropdownColor from './dropdown_color';
import DropdownAlign from './dropdown_align';
import DropdownBorder from './dropdown_border';
import Dropdown from './dropdown';
import { h } from './element';
import { bind } from './event';
import Icon from './icon';
import { cssPrefix } from '../config';
import { t } from '../locale/locale';
import tooltip from './tooltip';
function buildIcon(name) {
return new Icon(name);
@ -37,18 +37,17 @@ function buildButtonWithIcon(tooltipdata, iconName, change = () => {}) {
}
function bindDropdownChange() {
this.ddFormat.change = it => this.change('format', it.key);
this.ddFont.change = it => this.change('font-name', it.key);
this.ddFormula.change = it => this.change('formula', it.key);
this.ddFontSize.change = it => this.change('font-size', it.pt);
this.ddTextColor.change = it => this.change('color', it);
this.ddFillColor.change = it => this.change('bgcolor', it);
this.ddAlign.change = it => this.change('align', it);
this.ddVAlign.change = it => this.change('valign', it);
this.ddBorder.change = it => this.change('border', it);
this.ddFormat.change = (it) => this.change('format', it.key);
this.ddFont.change = (it) => this.change('font-name', it.key);
this.ddFormula.change = (it) => this.change('formula', it.key);
this.ddFontSize.change = (it) => this.change('font-size', it.pt);
this.ddTextColor.change = (it) => this.change('color', it);
this.ddFillColor.change = (it) => this.change('bgcolor', it);
this.ddAlign.change = (it) => this.change('align', it);
this.ddVAlign.change = (it) => this.change('valign', it);
this.ddBorder.change = (it) => this.change('border', it);
}
function toggleChange(type) {
let elName = type;
const types = type.split('-');
@ -82,9 +81,7 @@ function initBtns2() {
}
function moreResize() {
const {
el, btns, moreEl, ddMore, btns2,
} = this;
const { el, btns, moreEl, ddMore, btns2 } = this;
const { moreBtns, contentEl } = ddMore;
el.css('width', `${this.widthFn() - 60}px`);
const elBox = el.box();
@ -130,38 +127,58 @@ export default class Toolbar {
this.ddBorder = new DropdownBorder();
this.ddMore = new DropdownMore();
this.btnChildren = [
this.undoEl = buildButtonWithIcon(`${t('toolbar.undo')} (Ctrl+Z)`, 'undo', () => this.change('undo')),
this.redoEl = buildButtonWithIcon(`${t('toolbar.undo')} (Ctrl+Y)`, 'redo', () => this.change('redo')),
(this.undoEl = buildButtonWithIcon(`${t('toolbar.undo')} (Ctrl+Z)`, 'undo', () => this.change('undo'))),
(this.redoEl = buildButtonWithIcon(`${t('toolbar.undo')} (Ctrl+Y)`, 'redo', () => this.change('redo'))),
// this.printEl = buildButtonWithIcon('Print (Ctrl+P)', 'print', () => this.change('print')),
this.paintformatEl = buildButtonWithIcon(`${t('toolbar.paintformat')}`, 'paintformat', () => toggleChange.call(this, 'paintformat')),
this.clearformatEl = buildButtonWithIcon(`${t('toolbar.clearformat')}`, 'clearformat', () => this.change('clearformat')),
(this.paintformatEl = buildButtonWithIcon(`${t('toolbar.paintformat')}`, 'paintformat', () =>
toggleChange.call(this, 'paintformat'),
)),
(this.clearformatEl = buildButtonWithIcon(`${t('toolbar.clearformat')}`, 'clearformat', () =>
this.change('clearformat'),
)),
buildDivider(),
buildButton(`${t('toolbar.format')}`).child(this.ddFormat.el),
buildDivider(),
buildButton(`${t('toolbar.font')}`).child(this.ddFont.el),
buildButton(`${t('toolbar.fontSize')}`).child(this.ddFontSize.el),
buildDivider(),
this.fontBoldEl = buildButtonWithIcon(`${t('toolbar.fontBold')} (Ctrl+B)`, 'bold', () => toggleChange.call(this, 'font-bold')),
this.fontItalicEl = buildButtonWithIcon(`${t('toolbar.fontItalic')} (Ctrl+I)`, 'italic', () => toggleChange.call(this, 'font-italic')),
this.underlineEl = buildButtonWithIcon(`${t('toolbar.underline')} (Ctrl+U)`, 'underline', () => toggleChange.call(this, 'underline')),
this.strikeEl = buildButtonWithIcon(`${t('toolbar.strike')}`, 'strike', () => toggleChange.call(this, 'strike')),
(this.fontBoldEl = buildButtonWithIcon(`${t('toolbar.fontBold')} (Ctrl+B)`, 'bold', () =>
toggleChange.call(this, 'font-bold'),
)),
(this.fontItalicEl = buildButtonWithIcon(`${t('toolbar.fontItalic')} (Ctrl+I)`, 'italic', () =>
toggleChange.call(this, 'font-italic'),
)),
(this.underlineEl = buildButtonWithIcon(`${t('toolbar.underline')} (Ctrl+U)`, 'underline', () =>
toggleChange.call(this, 'underline'),
)),
(this.strikeEl = buildButtonWithIcon(`${t('toolbar.strike')}`, 'strike', () =>
toggleChange.call(this, 'strike'),
)),
buildButton(`${t('toolbar.textColor')}`).child(this.ddTextColor.el),
buildDivider(),
buildButton(`${t('toolbar.fillColor')}`).child(this.ddFillColor.el),
buildButton(`${t('toolbar.border')}`).child(this.ddBorder.el),
this.mergeEl = buildButtonWithIcon(`${t('toolbar.merge')}`, 'merge', () => toggleChange.call(this, 'merge')),
(this.mergeEl = buildButtonWithIcon(`${t('toolbar.merge')}`, 'merge', () => toggleChange.call(this, 'merge'))),
buildDivider(),
buildButton(`${t('toolbar.align')}`).child(this.ddAlign.el),
buildButton(`${t('toolbar.valign')}`).child(this.ddVAlign.el),
this.textwrapEl = buildButtonWithIcon(`${t('toolbar.textwrap')}`, 'textwrap', () => toggleChange.call(this, 'textwrap')),
(this.textwrapEl = buildButtonWithIcon(`${t('toolbar.textwrap')}`, 'textwrap', () =>
toggleChange.call(this, 'textwrap'),
)),
buildDivider(),
// this.linkEl = buildButtonWithIcon('Insert link', 'link'),
// this.chartEl = buildButtonWithIcon('Insert chart', 'chart'),
this.freezeEl = buildButtonWithIcon(`${t('toolbar.freeze')}`, 'freeze', () => toggleChange.call(this, 'freeze')),
this.autofilterEl = buildButtonWithIcon(`${t('toolbar.autofilter')}`, 'autofilter', () => toggleChange.call(this, 'autofilter')),
(this.freezeEl = buildButtonWithIcon(`${t('toolbar.freeze')}`, 'freeze', () =>
toggleChange.call(this, 'freeze'),
)),
(this.autofilterEl = buildButtonWithIcon(`${t('toolbar.autofilter')}`, 'autofilter', () =>
toggleChange.call(this, 'autofilter'),
)),
buildButton(`${t('toolbar.formula')}`).child(this.ddFormula.el),
// buildDivider(),
this.moreEl = buildButton(`${t('toolbar.more')}`).child(this.ddMore.el).hide(),
(this.moreEl = buildButton(`${t('toolbar.more')}`)
.child(this.ddMore.el)
.hide()),
];
this.el = h('div', `${cssPrefix}-toolbar`);
this.btns = h('div', `${cssPrefix}-toolbar-btns`).children(...this.btnChildren);
@ -197,8 +214,7 @@ export default class Toolbar {
// 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.mergeEl.active(data.canUnmerge()).disabled(!data.selector.multiple());
this.autofilterEl.active(!data.canAutofilter());
// this.mergeEl.disabled();
// console.log('selectedCell:', style, cell);

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownAlign from '../dropdown_align';
import DropdownItem from './dropdown_item';
export default class Align extends DropdownItem {
constructor(value) {

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownBorder from '../dropdown_border';
import DropdownItem from './dropdown_item';
export default class Border extends DropdownItem {
constructor() {

View File

@ -10,10 +10,8 @@ export default class DropdownItem extends Item {
element() {
const { tag } = this;
this.dd = this.dropdown();
this.dd.change = it => this.change(tag, this.getValue(it));
return super.element().child(
this.dd,
);
this.dd.change = (it) => this.change(tag, this.getValue(it));
return super.element().child(this.dd);
}
setState(v) {

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownColor from '../dropdown_color';
import DropdownItem from './dropdown_item';
export default class FillColor extends DropdownItem {
constructor(color) {

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownFont from '../dropdown_font';
import DropdownItem from './dropdown_item';
export default class Font extends DropdownItem {
constructor() {

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownFontsize from '../dropdown_fontsize';
import DropdownItem from './dropdown_item';
export default class Format extends DropdownItem {
constructor() {

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownFormat from '../dropdown_format';
import DropdownItem from './dropdown_item';
export default class Format extends DropdownItem {
constructor() {

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownFormula from '../dropdown_formula';
import DropdownItem from './dropdown_item';
export default class Format extends DropdownItem {
constructor() {

View File

@ -1,9 +1,10 @@
import Item from './item';
import Icon from '../icon';
import Item from './item';
export default class IconItem extends Item {
element() {
return super.element()
return super
.element()
.child(new Icon(this.tag))
.on('click', () => this.change(this.tag));
}

View File

@ -1,33 +1,32 @@
/* 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 FontSize from './font_size';
import Font from './font';
import FontSize from './font_size';
import Format from './format';
import Formula from './formula';
import Freeze from './freeze';
import Merge from './merge';
import Redo from './redo';
import Undo from './undo';
import Print from './print';
import Textwrap from './textwrap';
import More from './more';
import Italic from './italic';
import Item from './item';
import { h } from '../element';
import { cssPrefix } from '../../config';
import { bind } from '../event';
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';
function buildDivider() {
return h('div', `${cssPrefix}-toolbar-divider`);
@ -51,9 +50,7 @@ function initBtns2() {
}
function moreResize() {
const {
el, btns, moreEl, btns2,
} = this;
const { el, btns, moreEl, btns2 } = this;
const { moreBtns, contentEl } = moreEl.dd;
el.css('width', `${this.widthFn()}px`);
const elBox = el.box();
@ -112,47 +109,34 @@ export default class Toolbar {
const style = data.defaultStyle();
this.items = [
[
this.undoEl = new Undo(),
this.redoEl = new Redo(),
(this.undoEl = new Undo()),
(this.redoEl = new Redo()),
new Print(),
this.paintformatEl = new Paintformat(),
this.clearformatEl = new Clearformat(),
(this.paintformatEl = new Paintformat()),
(this.clearformatEl = new Clearformat()),
],
buildDivider(),
[
this.formatEl = new Format(),
],
[(this.formatEl = new Format())],
buildDivider(),
[(this.fontEl = new Font()), (this.fontSizeEl = new FontSize())],
buildDivider(),
[
this.fontEl = new Font(),
this.fontSizeEl = new FontSize(),
(this.boldEl = new Bold()),
(this.italicEl = new Italic()),
(this.underlineEl = new Underline()),
(this.strikeEl = new Strike()),
(this.textColorEl = new TextColor(style.color)),
],
buildDivider(),
[
this.boldEl = new Bold(),
this.italicEl = new Italic(),
this.underlineEl = new Underline(),
this.strikeEl = new Strike(),
this.textColorEl = new TextColor(style.color),
],
[(this.fillColorEl = new FillColor(style.bgcolor)), (this.borderEl = new Border()), (this.mergeEl = new Merge())],
buildDivider(),
[
this.fillColorEl = new FillColor(style.bgcolor),
this.borderEl = new Border(),
this.mergeEl = new Merge(),
(this.alignEl = new Align(style.align)),
(this.valignEl = new Valign(style.valign)),
(this.textwrapEl = new Textwrap()),
],
buildDivider(),
[
this.alignEl = new Align(style.align),
this.valignEl = new Valign(style.valign),
this.textwrapEl = new Textwrap(),
],
buildDivider(),
[
this.freezeEl = new Freeze(),
this.autofilterEl = new Autofilter(),
this.formulaEl = new Formula(),
],
[(this.freezeEl = new Freeze()), (this.autofilterEl = new Autofilter()), (this.formulaEl = new Formula())],
];
const { extendToolbar = {} } = data.settings;
@ -169,7 +153,7 @@ export default class Toolbar {
this.items.push(btns);
}
this.items.push([this.moreEl = new More()]);
this.items.push([(this.moreEl = new More())]);
this.el = h('div', `${cssPrefix}-toolbar`);
this.btns = h('div', `${cssPrefix}-toolbar-btns`);

View File

@ -1,7 +1,7 @@
import { cssPrefix } from '../../config';
import tooltip from '../tooltip';
import { h } from '../element';
import { t } from '../../locale/locale';
import { h } from '../element';
import tooltip from '../tooltip';
export default class Item {
// tooltip
@ -9,7 +9,7 @@ export default class Item {
// shortcut: shortcut key
constructor(tag, shortcut, value) {
this.tip = '';
if (tag) this.tip = t(`toolbar.${tag.replace(/-[a-z]/g, c => c[1].toUpperCase())}`);
if (tag) this.tip = t(`toolbar.${tag.replace(/-[a-z]/g, (c) => c[1].toUpperCase())}`);
if (shortcut) this.tip += ` (${shortcut})`;
this.tag = tag;
this.shortcut = shortcut;

View File

@ -1,9 +1,8 @@
import Dropdown from '../dropdown';
import DropdownItem from './dropdown_item';
import { cssPrefix } from '../../config';
import Dropdown from '../dropdown';
import { h } from '../element';
import Icon from '../icon';
import DropdownItem from './dropdown_item';
class DropdownMore extends Dropdown {
constructor() {

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownColor from '../dropdown_color';
import DropdownItem from './dropdown_item';
export default class TextColor extends DropdownItem {
constructor(color) {

View File

@ -1,10 +1,11 @@
import Item from './item';
import Icon from '../icon';
import Item from './item';
export default class ToggleItem extends Item {
element() {
const { tag } = this;
return super.element()
return super
.element()
.child(new Icon(tag))
.on('click', () => this.click());
}

View File

@ -1,5 +1,5 @@
import DropdownItem from './dropdown_item';
import DropdownAlign from '../dropdown_align';
import DropdownItem from './dropdown_item';
export default class Valign extends DropdownItem {
constructor(value) {

View File

@ -1,21 +1,18 @@
/* global document */
import { cssPrefix } from '../config';
import { h } from './element';
import { bind } from './event';
import { cssPrefix } from '../config';
export default function tooltip(html, target) {
if (target.classList.contains('active')) {
return;
}
const {
left, top, width, height,
} = target.getBoundingClientRect();
const { left, top, width, height } = target.getBoundingClientRect();
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`);
el.css('left', `${left + width / 2 - elBox.width / 2}px`).css('top', `${top + height + 2}px`);
bind(target, 'mouseleave', () => {
if (document.body.contains(el.el)) {

View File

@ -1,6 +1,33 @@
import './_.prototypes';
const alphabets = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
const alphabets = [
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
];
/** index number 2 letters
* @example stringAt(26) ==> 'AA'
@ -30,11 +57,10 @@ export function stringAt(index) {
*/
export function indexAt(str) {
let ret = 0;
for(let i = 0; i !== str.length; ++i) ret = 26 * ret + str.charCodeAt(i) - 64;
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

View File

@ -1,4 +1,5 @@
import { CellRange } from './cell_range';
// operator: all|eq|neq|gt|gte|lt|lte|in|be
// value:
// in => []
@ -65,7 +66,7 @@ export default class AutoFilter {
setData({ ref, filters, sort }) {
if (ref != null) {
this.ref = ref;
this.filters = filters.map(it => new Filter(it.ci, it.operator, it.value));
this.filters = filters.map((it) => new Filter(it.ci, it.operator, it.value));
if (sort) {
this.sort = new Sort(sort.ci, sort.order);
}
@ -75,7 +76,7 @@ export default class AutoFilter {
getData() {
if (this.active()) {
const { ref, filters, sort } = this;
return { ref, filters: filters.map(it => it.getData()), sort };
return { ref, filters: filters.map((it) => it.getData()), sort };
}
return {};
}

View File

@ -171,15 +171,15 @@ const evalSuffixExpr = (srcStack, formulaMap, cellRender, cellList) => {
if (!Number.isNaN(left)) left = Number(left);
let ret = false;
if (fc === '=') {
ret = (left === top);
ret = left === top;
} else if (expr === '>') {
ret = (left > top);
ret = left > top;
} else if (expr === '>=') {
ret = (left >= top);
ret = left >= top;
} else if (expr === '<') {
ret = (left < top);
ret = left < top;
} else if (expr === '<=') {
ret = (left <= top);
ret = left <= top;
}
stack.push(ret);
} else if (Array.isArray(expr)) {
@ -221,6 +221,4 @@ const cellRender = (src, formulaMap, getCellText, cellList = []) => {
export default {
render: cellRender,
};
export {
infixExprToSuffixExpr,
};
export { infixExprToSuffixExpr };

View File

@ -1,4 +1,4 @@
import { xy2expr, expr2xy } from './alphabet';
import { expr2xy, xy2expr } from './alphabet';
class CellRange {
constructor(sri, sci, eri, eci, w = 0, h = 0) {
@ -30,16 +30,12 @@ class CellRange {
} else if (args.length === 2) {
[ri, ci] = args;
}
const {
sri, sci, eri, eci,
} = this;
const { sri, sci, eri, eci } = this;
return sri <= ri && ri <= eri && sci <= ci && ci <= eci;
}
each(cb, rowFilter = () => true) {
const {
sri, sci, eri, eci,
} = this;
const { sri, sci, eri, eci } = this;
for (let i = sri; i <= eri; i += 1) {
if (rowFilter(i)) {
for (let j = sci; j <= eci; j += 1) {
@ -50,41 +46,27 @@ class CellRange {
}
contains(other) {
return this.sri <= other.sri
&& this.sci <= other.sci
&& this.eri >= other.eri
&& this.eci >= other.eci;
return this.sri <= other.sri && this.sci <= other.sci && this.eri >= other.eri && this.eci >= other.eci;
}
// within
within(other) {
return this.sri >= other.sri
&& this.sci >= other.sci
&& this.eri <= other.eri
&& this.eci <= other.eci;
return this.sri >= other.sri && this.sci >= other.sci && this.eri <= other.eri && this.eci <= other.eci;
}
// disjoint
disjoint(other) {
return this.sri > other.eri
|| this.sci > other.eci
|| other.sri > this.eri
|| other.sci > this.eci;
return this.sri > other.eri || this.sci > other.eci || other.sri > this.eri || other.sci > this.eci;
}
// intersects
intersects(other) {
return this.sri <= other.eri
&& this.sci <= other.eci
&& other.sri <= this.eri
&& other.sci <= this.eci;
return this.sri <= other.eri && this.sci <= other.eci && other.sri <= this.eri && other.sci <= this.eci;
}
// union
union(other) {
const {
sri, sci, eri, eci,
} = this;
const { sri, sci, eri, eci } = this;
return new CellRange(
other.sri < sri ? other.sri : sri,
other.sci < sci ? other.sci : sci,
@ -103,9 +85,7 @@ class CellRange {
const addRet = (sri, sci, eri, eci) => {
ret.push(new CellRange(sri, sci, eri, eci));
};
const {
sri, sci, eri, eci,
} = this;
const { sri, sci, eri, eci } = this;
const dsr = other.sri - sri;
const dsc = other.sci - sci;
const der = eri - other.eri;
@ -168,16 +148,11 @@ class CellRange {
}
size() {
return [
this.eri - this.sri + 1,
this.eci - this.sci + 1,
];
return [this.eri - this.sri + 1, this.eci - this.sci + 1];
}
toString() {
const {
sri, sci, eri, eci,
} = this;
const { sri, sci, eri, eci } = this;
let ref = xy2expr(sci, sri);
if (this.multiple()) {
ref = `${ref}:${xy2expr(eci, eri)}`;
@ -186,9 +161,7 @@ class CellRange {
}
clone() {
const {
sri, sci, eri, eci, w, h,
} = this;
const { sri, sci, eri, eci, w, h } = this;
return new CellRange(sri, sci, eri, eci, w, h);
}
@ -199,10 +172,7 @@ class CellRange {
*/
equals(other) {
return this.eri === other.eri
&& this.eci === other.eci
&& this.sri === other.sri
&& this.sci === other.sci;
return this.eri === other.eri && this.eci === other.eci && this.sri === other.sri && this.sci === other.sci;
}
static valueOf(ref) {
@ -219,6 +189,4 @@ class CellRange {
export default CellRange;
export {
CellRange,
};
export { CellRange };

View File

@ -1,9 +1,7 @@
import helper from './helper';
class Cols {
constructor({
len, width, indexWidth, minWidth,
}) {
constructor({ len, width, indexWidth, minWidth }) {
this._ = {};
this.len = len;
this.width = width;
@ -70,7 +68,7 @@ class Cols {
}
sumWidth(min, max) {
return helper.rangeSum(min, max, i => this.getWidth(i));
return helper.rangeSum(min, max, (i) => this.getWidth(i));
}
totalWidth() {
@ -79,6 +77,4 @@ class Cols {
}
export default {};
export {
Cols,
};
export { Cols };

View File

@ -1,18 +1,18 @@
/* global document */
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';
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 { Validations } from './validation';
// private methods
/*
@ -148,9 +148,7 @@ function copyPaste(srcCellRange, dstCellRange, what, autofill = false) {
function cutPaste(srcCellRange, dstCellRange) {
const { clipboard, rows, merges } = this;
rows.cutPaste(srcCellRange, dstCellRange);
merges.move(srcCellRange,
dstCellRange.sri - srcCellRange.sri,
dstCellRange.sci - srcCellRange.sci);
merges.move(srcCellRange, dstCellRange.sri - srcCellRange.sri, dstCellRange.sci - srcCellRange.sci);
clipboard.clear();
}
@ -168,9 +166,7 @@ function setStyleBorder(ri, ci, bss) {
function setStyleBorders({ mode, style, color }) {
const { styles, selector, rows } = this;
const {
sri, sci, eri, eci,
} = selector.range;
const { sri, sci, eri, eci } = selector.range;
const multiple = !this.isSingleSelected();
if (!multiple) {
if (mode === 'inside' || mode === 'horizontal' || mode === 'vertical') {
@ -179,7 +175,10 @@ function setStyleBorders({ mode, style, color }) {
}
if (mode === 'outside' && !multiple) {
setStyleBorder.call(this, sri, sci, {
top: [style, color], bottom: [style, color], left: [style, color], right: [style, color],
top: [style, color],
bottom: [style, color],
left: [style, color],
right: [style, color],
});
} else if (mode === 'none') {
selector.range.each((ri, ci) => {
@ -193,8 +192,13 @@ function setStyleBorders({ mode, style, color }) {
cell.style = this.addStyle(ns);
}
});
} else if (mode === 'all' || mode === 'inside' || mode === 'outside'
|| mode === 'horizontal' || mode === 'vertical') {
} else if (
mode === 'all' ||
mode === 'inside' ||
mode === 'outside' ||
mode === 'horizontal' ||
mode === 'vertical'
) {
const merges = [];
for (let ri = sri; ri <= eri; ri += 1) {
for (let ci = sci; ci <= eci; ci += 1) {
@ -210,7 +214,7 @@ function setStyleBorders({ mode, style, color }) {
}
}
}
mergeIndexes.forEach(it => merges.splice(it, 1));
mergeIndexes.forEach((it) => merges.splice(it, 1));
if (ci > eci) break;
// jump merges -- end
const cell = rows.getCell(ri, ci);
@ -308,14 +312,7 @@ function getCellColByX(x, scrollOffsetx) {
const fsw = this.freezeTotalWidth();
let inits = cols.indexWidth;
if (fsw + cols.indexWidth < x) inits -= scrollOffsetx;
const [ci, left, width] = helper.rangeReduceIf(
0,
cols.len,
inits,
cols.indexWidth,
x,
i => cols.getWidth(i),
);
const [ci, left, width] = helper.rangeReduceIf(0, cols.len, inits, cols.indexWidth, x, (i) => cols.getWidth(i));
if (left <= 0) {
return { ci: -1, left: 0, width: cols.indexWidth };
}
@ -406,9 +403,7 @@ export default class DataProxy {
copyToSystemClipboard(evt) {
let copyText = [];
const {
sri, eri, sci, eci,
} = this.selector.range;
const { sri, eri, sci, eci } = this.selector.range;
for (let ri = sri; ri <= eri; ri += 1) {
const row = [];
@ -420,7 +415,7 @@ export default class DataProxy {
}
// Adding \n and why not adding \r\n is to support online office and client MS office and WPS
copyText = copyText.map(row => row.join('\t')).join('\n');
copyText = copyText.map((row) => row.join('\t')).join('\n');
// why used this
// cuz http protocol will be blocked request clipboard by browser
@ -433,9 +428,12 @@ export default class DataProxy {
// this need https protocol
/* global navigator */
if (navigator.clipboard) {
navigator.clipboard.writeText(copyText).then(() => {}, (err) => {
console.log('text copy to the system clipboard error ', copyText, err);
});
navigator.clipboard.writeText(copyText).then(
() => {},
(err) => {
console.log('text copy to the system clipboard error ', copyText, err);
},
);
}
}
@ -496,8 +494,8 @@ export default class DataProxy {
pasteFromText(txt) {
let lines = [];
if (/\r\n/.test(txt)) lines = txt.split('\r\n').map(it => it.replace(/"/g, '').split('\t'));
else lines = txt.split('\n').map(it => it.replace(/"/g, '').split('\t'));
if (/\r\n/.test(txt)) lines = txt.split('\r\n').map((it) => it.replace(/"/g, '').split('\t'));
else lines = txt.split('\n').map((it) => it.replace(/"/g, '').split('\t'));
if (lines.length) {
const { rows, selector } = this;
@ -522,12 +520,8 @@ export default class DataProxy {
}
calSelectedRangeByEnd(ri, ci) {
const {
selector, rows, cols, merges,
} = this;
let {
sri, sci, eri, eci,
} = selector.range;
const { selector, rows, cols, merges } = this;
let { sri, sci, eri, eci } = selector.range;
const cri = selector.ri;
const cci = selector.ci;
let [nri, nci] = [ri, ci];
@ -537,18 +531,14 @@ export default class DataProxy {
else [sri, eri] = [nri, cri];
if (nci > cci) [sci, eci] = [cci, nci];
else [sci, eci] = [nci, cci];
selector.range = merges.union(new CellRange(
sri, sci, eri, eci,
));
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;
const { selector, rows, cols, merges } = this;
let cellRange = merges.getFirstIncludes(ri, ci);
// console.log('cellRange:', cellRange, ri, ci, merges);
if (cellRange === null) {
@ -579,9 +569,7 @@ export default class DataProxy {
const { ri, ci, range } = selector;
if (selector.multiple()) {
const [rn, cn] = selector.size();
const {
sri, sci, eri, eci,
} = range;
const { sri, sci, eri, eci } = range;
if (rn > 1) {
for (let i = sci; i <= eci; i += 1) {
const cell = rows.getCellOrNew(eri + 1, i);
@ -605,16 +593,25 @@ export default class DataProxy {
if (property === 'format') {
cstyle.format = value;
cell.style = this.addStyle(cstyle);
} else if (property === 'font-bold' || property === 'font-italic'
|| property === 'font-name' || property === 'font-size') {
} else if (
property === 'font-bold' ||
property === 'font-italic' ||
property === 'font-name' ||
property === 'font-size'
) {
const nfont = {};
nfont[property.split('-')[1]] = value;
cstyle.font = Object.assign(cstyle.font || {}, nfont);
cell.style = this.addStyle(cstyle);
} else if (property === 'strike' || property === 'textwrap'
|| property === 'underline'
|| property === 'align' || property === 'valign'
|| property === 'color' || property === 'bgcolor') {
} else if (
property === 'strike' ||
property === 'textwrap' ||
property === 'underline' ||
property === 'align' ||
property === 'valign' ||
property === 'color' ||
property === 'bgcolor'
) {
cstyle[property] = value;
cell.style = this.addStyle(cstyle);
} else {
@ -640,7 +637,7 @@ export default class DataProxy {
if (autoFilter.active()) {
const filter = autoFilter.getFilter(ci);
if (filter) {
const vIndex = filter.value.findIndex(v => v === oldText);
const vIndex = filter.value.findIndex((v) => v === oldText);
if (vIndex >= 0) {
filter.value.splice(vIndex, 1, text);
}
@ -660,14 +657,11 @@ export default class DataProxy {
}
xyInSelectedRect(x, y) {
const {
left, top, width, height,
} = this.getSelectedRect();
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);
return x1 > left && x1 < left + width && y1 > top && y1 < top + height;
}
getSelectedRect() {
@ -683,17 +677,17 @@ export default class DataProxy {
}
getRect(cellRange) {
const {
scroll, rows, cols, exceptRowSet,
} = this;
const {
sri, sci, eri, eci,
} = 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 {
left: 0, l: 0, top: 0, t: 0, scroll,
left: 0,
l: 0,
top: 0,
t: 0,
scroll,
};
}
const left = cols.sumWidth(0, sci);
@ -723,9 +717,7 @@ export default class DataProxy {
}
getCellRectByXY(x, y) {
const {
scroll, merges, rows, cols,
} = this;
const { scroll, merges, rows, cols } = this;
let { ri, top, height } = getCellRowByY.call(this, y, scroll.y);
let { ci, left, width } = getCellColByX.call(this, x, scroll.x);
if (ci === -1) {
@ -739,20 +731,21 @@ export default class DataProxy {
if (merge) {
ri = merge.sri;
ci = merge.sci;
({
left, top, width, height,
} = this.cellRect(ri, ci));
({ left, top, width, height } = this.cellRect(ri, ci));
}
}
return {
ri, ci, left, top, width, height,
ri,
ci,
left,
top,
width,
height,
};
}
isSingleSelected() {
const {
sri, sci, eri, eci,
} = this.selector.range;
const { sri, sci, eri, eci } = this.selector.range;
const cell = this.getCell(sri, sci);
if (cell && cell.merge) {
const [rn, cn] = cell.merge;
@ -762,9 +755,7 @@ export default class DataProxy {
}
canUnmerge() {
const {
sri, sci, eri, eci,
} = this.selector.range;
const { sri, sci, eri, eci } = this.selector.range;
const cell = this.getCell(sri, sci);
if (cell && cell.merge) {
const [rn, cn] = cell.merge;
@ -872,13 +863,15 @@ export default class DataProxy {
rows.insertColumn(sci, n);
si = sci;
cols.len += n;
Object.keys(cols._).reverse().forEach((colIndex) => {
const col = parseInt(colIndex, 10);
if (col >= sci) {
cols._[col + n] = cols._[col];
delete cols._[col];
}
});
Object.keys(cols._)
.reverse()
.forEach((colIndex) => {
const col = parseInt(colIndex, 10);
if (col >= sci) {
cols._[col + n] = cols._[col];
delete cols._[col];
}
});
}
merges.shift(type, si, n, (ri, ci, rn, cn) => {
const cell = rows.getCell(ri, ci);
@ -891,13 +884,9 @@ export default class DataProxy {
// type: row | column
delete(type) {
this.changeData(() => {
const {
rows, merges, selector, cols,
} = this;
const { rows, merges, selector, cols } = this;
const { range } = selector;
const {
sri, sci, eri, eci,
} = selector.range;
const { sri, sci, eri, eci } = selector.range;
const [rsize, csize] = selector.range.size();
let si = sri;
let size = rsize;
@ -907,7 +896,7 @@ export default class DataProxy {
rows.deleteColumn(sci, eci);
si = range.sci;
size = csize;
cols.len -= (eci - sci + 1);
cols.len -= eci - sci + 1;
Object.keys(cols._).forEach((colIndex) => {
const col = parseInt(colIndex, 10);
if (col >= sci) {
@ -932,9 +921,7 @@ export default class DataProxy {
scrollx(x, cb) {
const { scroll, freeze, cols } = this;
const [, fci] = freeze;
const [
ci, left, width,
] = helper.rangeReduceIf(fci, cols.len, 0, 0, x, i => cols.getWidth(i));
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;
@ -948,9 +935,7 @@ export default class DataProxy {
scrolly(y, cb) {
const { scroll, freeze, rows } = this;
const [fri] = freeze;
const [
ri, top, height,
] = helper.rangeReduceIf(fri, rows.len, 0, 0, y, i => rows.getHeight(i));
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);
@ -986,7 +971,11 @@ export default class DataProxy {
}
// console.log('data:', this.d);
return {
left, top, width, height, cell,
left,
top,
width,
height,
cell,
};
}
@ -996,7 +985,7 @@ export default class DataProxy {
getCellTextOrDefault(ri, ci) {
const cell = this.getCell(ri, ci);
return (cell && cell.text) ? cell.text : '';
return cell && cell.text ? cell.text : '';
}
getCellStyle(ri, ci) {
@ -1010,7 +999,7 @@ export default class DataProxy {
getCellStyleOrDefault(ri, ci) {
const { styles, rows } = this;
const cell = rows.getCell(ri, ci);
const cellStyle = (cell && cell.style !== undefined) ? styles[cell.style] : {};
const cellStyle = cell && cell.style !== undefined ? styles[cell.style] : {};
return helper.merge(this.defaultStyle(), cellStyle);
}
@ -1108,9 +1097,7 @@ export default class DataProxy {
}
viewRange() {
const {
scroll, rows, cols, freeze, exceptRowSet,
} = this;
const { scroll, rows, cols, freeze, exceptRowSet } = this;
// console.log('scroll:', scroll, ', freeze:', freeze)
let { ri, ci } = scroll;
if (ri <= 0) [ri] = freeze;
@ -1135,16 +1122,13 @@ export default class DataProxy {
}
eachMergesInView(viewRange, cb) {
this.merges.filterIntersects(viewRange)
.forEach(it => cb(it));
this.merges.filterIntersects(viewRange).forEach((it) => cb(it));
}
hideRowsOrCols() {
const { rows, cols, selector } = this;
const [rlen, clen] = selector.size();
const {
sri, sci, eri, eci,
} = selector.range;
const { sri, sci, eri, eci } = selector.range;
if (rlen === rows.len) {
for (let ci = sci; ci <= eci; ci += 1) {
cols.setHide(ci, true);
@ -1224,8 +1208,7 @@ export default class DataProxy {
setData(d) {
Object.keys(d).forEach((property) => {
if (property === 'merges' || property === 'rows'
|| property === 'cols' || property === 'validations') {
if (property === 'merges' || property === 'rows' || property === 'cols' || property === 'validations') {
this[property].setData(d[property]);
} else if (property === 'freeze') {
const [x, y] = expr2xy(d[property]);
@ -1240,9 +1223,7 @@ export default class DataProxy {
}
getData() {
const {
name, freeze, styles, merges, rows, cols, validations, autoFilter,
} = this;
const { name, freeze, styles, merges, rows, cols, validations, autoFilter } = this;
return {
name,
freeze: xy2expr(freeze[1], freeze[0]),

View File

@ -68,9 +68,4 @@ function fonts(ary = []) {
}
export default {};
export {
fontSizes,
fonts,
baseFonts,
getFontSizePxByPt,
};
export { fontSizes, fonts, baseFonts, getFontSizePxByPt };

View File

@ -1,6 +1,6 @@
import { tf } from '../locale/locale';
const formatStringRender = v => v;
const formatStringRender = (v) => v;
const formatNumberRender = (v) => {
// match "-12.1" or "12" or "12.1"
@ -37,28 +37,28 @@ const baseFormats = [
title: tf('format.percent'),
type: 'number',
label: '10.12%',
render: v => `${v}%`,
render: (v) => `${v}%`,
},
{
key: 'rmb',
title: tf('format.rmb'),
type: 'number',
label: '¥10.00',
render: v => `${formatNumberRender(v)}`,
render: (v) => `${formatNumberRender(v)}`,
},
{
key: 'usd',
title: tf('format.usd'),
type: 'number',
label: '$10.00',
render: v => `$${formatNumberRender(v)}`,
render: (v) => `$${formatNumberRender(v)}`,
},
{
key: 'eur',
title: tf('format.eur'),
type: 'number',
label: '€10.00',
render: v => `${formatNumberRender(v)}`,
render: (v) => `${formatNumberRender(v)}`,
},
{
key: 'date',
@ -102,9 +102,5 @@ baseFormats.forEach((f) => {
formatm[f.key] = f;
});
export default {
};
export {
formatm,
baseFormats,
};
export default {};
export { formatm, baseFormats };

View File

@ -18,22 +18,22 @@ const baseFormulas = [
{
key: 'SUM',
title: tf('formula.sum'),
render: ary => ary.reduce((a, b) => numberCalc('+', a, b), 0),
render: (ary) => ary.reduce((a, b) => numberCalc('+', a, b), 0),
},
{
key: 'AVERAGE',
title: tf('formula.average'),
render: ary => ary.reduce((a, b) => Number(a) + Number(b), 0) / ary.length,
render: (ary) => ary.reduce((a, b) => Number(a) + Number(b), 0) / ary.length,
},
{
key: 'MAX',
title: tf('formula.max'),
render: ary => Math.max(...ary.map(v => Number(v))),
render: (ary) => Math.max(...ary.map((v) => Number(v))),
},
{
key: 'MIN',
title: tf('formula.min'),
render: ary => Math.min(...ary.map(v => Number(v))),
render: (ary) => Math.min(...ary.map((v) => Number(v))),
},
{
key: 'IF',
@ -43,17 +43,17 @@ const baseFormulas = [
{
key: 'AND',
title: tf('formula.and'),
render: ary => ary.every(it => it),
render: (ary) => ary.every((it) => it),
},
{
key: 'OR',
title: tf('formula.or'),
render: ary => ary.some(it => it),
render: (ary) => ary.some((it) => it),
},
{
key: 'CONCAT',
title: tf('formula.concat'),
render: ary => ary.join(''),
render: (ary) => ary.join(''),
},
/* support: 1 + A1 + B2 * 3
{
@ -88,11 +88,6 @@ baseFormulas.forEach((f) => {
formulam[f.key] = f;
});
export default {
};
export default {};
export {
formulam,
formulas,
baseFormulas,
};
export { formulam, formulas, baseFormulas };

View File

@ -48,7 +48,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) => value) => {
let total = 0;
let size = 0;
Object.keys(objOrAry).forEach((key) => {

View File

@ -10,7 +10,7 @@ class Merges {
}
deleteWithin(cr) {
this._ = this._.filter(it => !it.within(cr));
this._ = this._.filter((it) => !it.within(cr));
}
getFirstIncludes(ri, ci) {
@ -24,7 +24,7 @@ class Merges {
}
filterIntersects(cellRange) {
return new Merges(this._.filter(it => it.intersects(cellRange)));
return new Merges(this._.filter((it) => it.intersects(cellRange)));
}
intersects(cellRange) {
@ -56,9 +56,7 @@ class Merges {
// type: row | column
shift(type, index, n, cbWithin) {
this._.forEach((cellRange) => {
const {
sri, sci, eri, eci,
} = cellRange;
const { sri, sci, eri, eci } = cellRange;
const range = cellRange;
if (type === 'row') {
if (sri >= index) {
@ -93,16 +91,14 @@ class Merges {
}
setData(merges) {
this._ = merges.map(merge => CellRange.valueOf(merge));
this._ = merges.map((merge) => CellRange.valueOf(merge));
return this;
}
getData() {
return this._.map(merge => merge.toString());
return this._.map((merge) => merge.toString());
}
}
export default {};
export {
Merges,
};
export { Merges };

View File

@ -1,5 +1,5 @@
import helper from './helper';
import { expr2expr } from './alphabet';
import helper from './helper';
class Rows {
constructor({ len, height }) {
@ -111,9 +111,7 @@ class Rows {
// what: all | format | text
copyPaste(srcCellRange, dstCellRange, what, autofill = false, cb = () => {}) {
const {
sri, sci, eri, eci,
} = srcCellRange;
const { sri, sci, eri, eci } = srcCellRange;
const dsri = dstCellRange.sri;
const dsci = dstCellRange.sci;
const deri = dstCellRange.eri;
@ -140,7 +138,7 @@ class Rows {
// ncell.text
if (autofill && ncell && ncell.text && ncell.text.length > 0) {
const { text } = ncell;
let n = (jj - dsci) + (ii - dsri) + 2;
let n = jj - dsci + (ii - dsri) + 2;
if (!isAdd) {
n -= dn + 1;
}
@ -156,9 +154,11 @@ class Rows {
if (/^\d+$/.test(word)) return word;
return expr2expr(word, xn, yn);
});
} else if ((rn <= 1 && cn > 1 && (dsri > eri || deri < sri))
|| (cn <= 1 && rn > 1 && (dsci > eci || deci < sci))
|| (rn <= 1 && cn <= 1)) {
} else if (
(rn <= 1 && cn > 1 && (dsri > eri || deri < sri)) ||
(cn <= 1 && rn > 1 && (dsci > eci || deci < sci)) ||
(rn <= 1 && cn <= 1)
) {
const result = /[\\.\d]+$/.exec(text);
// console.log('result:', result);
if (result !== null) {
@ -215,7 +215,7 @@ class Rows {
nri += n;
this.eachCells(ri, (ci, cell) => {
if (cell.text && cell.text[0] === '=') {
cell.text = cell.text.replace(/[a-zA-Z]{1,3}\d+/g, word => expr2expr(word, 0, n, (x, y) => y >= sri));
cell.text = cell.text.replace(/[a-zA-Z]{1,3}\d+/g, (word) => expr2expr(word, 0, n, (x, y) => y >= sri));
}
});
}
@ -236,7 +236,7 @@ class Rows {
ndata[nri - n] = row;
this.eachCells(ri, (ci, cell) => {
if (cell.text && cell.text[0] === '=') {
cell.text = cell.text.replace(/[a-zA-Z]{1,3}\d+/g, word => expr2expr(word, 0, -n, (x, y) => y > eri));
cell.text = cell.text.replace(/[a-zA-Z]{1,3}\d+/g, (word) => expr2expr(word, 0, -n, (x, y) => y > eri));
}
});
}
@ -253,7 +253,7 @@ class Rows {
if (nci >= sci) {
nci += n;
if (cell.text && cell.text[0] === '=') {
cell.text = cell.text.replace(/[a-zA-Z]{1,3}\d+/g, word => expr2expr(word, n, 0, x => x >= sci));
cell.text = cell.text.replace(/[a-zA-Z]{1,3}\d+/g, (word) => expr2expr(word, n, 0, (x) => x >= sci));
}
}
rndata[nci] = cell;
@ -273,7 +273,7 @@ class Rows {
} else if (nci > eci) {
rndata[nci - n] = cell;
if (cell.text && cell.text[0] === '=') {
cell.text = cell.text.replace(/[a-zA-Z]{1,3}\d+/g, word => expr2expr(word, -n, 0, x => x > eci));
cell.text = cell.text.replace(/[a-zA-Z]{1,3}\d+/g, (word) => expr2expr(word, -n, 0, (x) => x > eci));
}
}
});
@ -351,6 +351,4 @@ class Rows {
}
export default {};
export {
Rows,
};
export { Rows };

Some files were not shown because too many files have changed in this diff Show More