Full Code of myliang/xspreadsheet for AI

master 3075e5007eaa cached
60 files
204.8 KB
62.2k tokens
476 symbols
1 requests
Download .txt
Showing preview only (220K chars total). Download the full file or copy to clipboard to get everything.
Repository: myliang/xspreadsheet
Branch: master
Commit: 3075e5007eaa
Files: 60
Total size: 204.8 KB

Directory structure:
gitextract_n0gowviz/

├── .gitignore
├── LICENSE
├── README.md
├── docs/
│   ├── index.html
│   └── xspreadsheet.js
├── index.html
├── package.json
├── src/
│   ├── core/
│   │   ├── alphabet.d.ts
│   │   ├── alphabet.ts
│   │   ├── cell.d.ts
│   │   ├── cell.ts
│   │   ├── font.d.ts
│   │   ├── font.ts
│   │   ├── format.d.ts
│   │   ├── format.ts
│   │   ├── formula.d.ts
│   │   ├── formula.ts
│   │   ├── index.d.ts
│   │   ├── index.ts
│   │   ├── select.d.ts
│   │   └── select.ts
│   ├── local/
│   │   ├── base/
│   │   │   ├── colorPanel.d.ts
│   │   │   ├── colorPanel.ts
│   │   │   ├── dropdown.d.ts
│   │   │   ├── dropdown.ts
│   │   │   ├── element.d.ts
│   │   │   ├── element.ts
│   │   │   ├── icon.d.ts
│   │   │   ├── icon.ts
│   │   │   ├── item.d.ts
│   │   │   ├── item.ts
│   │   │   ├── menu.d.ts
│   │   │   ├── menu.ts
│   │   │   ├── suggest.d.ts
│   │   │   └── suggest.ts
│   │   ├── contextmenu.d.ts
│   │   ├── contextmenu.ts
│   │   ├── editor.d.ts
│   │   ├── editor.ts
│   │   ├── editorbar.d.ts
│   │   ├── editorbar.ts
│   │   ├── event.d.ts
│   │   ├── event.ts
│   │   ├── index.d.ts
│   │   ├── index.ts
│   │   ├── resizer.d.ts
│   │   ├── resizer.ts
│   │   ├── selector.d.ts
│   │   ├── selector.ts
│   │   ├── table.d.ts
│   │   ├── table.ts
│   │   ├── toolbar.d.ts
│   │   └── toolbar.ts
│   ├── main.d.ts
│   ├── main.ts
│   └── style/
│       └── index.less
├── tsconfig.json
├── tslint.json
├── webpack.config.dev.js
└── webpack.config.js

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
node_modules/
.vscode/

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 myliang

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# XSpreadsheet

[![npm package](https://img.shields.io/npm/v/xspreadsheet.svg)](https://www.npmjs.org/package/xspreadsheet)
[![NPM downloads](http://img.shields.io/npm/dm/xspreadsheet.svg)](https://npmjs.org/package/xspreadsheet)

> a javascript spreadsheet for web

<p align="center">
  <a href="https://github.com/myliang/xspreadsheet">
    <img width="100%" src="/docs/demo.png?raw=true">
  </a>
</p>

## Install
```shell
npm install typescript --save-dev
npm install awesome-typescript-loader --save-dev
npm install xspreadsheet --save-dev
```

## Quick Start

``` javascript
import xspreadsheet from 'xspreadsheet'

const x = xspreadsheet(document.getElementById('#id'))
x.change = (data) => {
  console.log('data:', data)
}

// edit
// data is param in the change method
xspreadsheet(document.getElementById('#id'), {d: data})
```

### in tsconfig.json
```
{
  "compilerOptions": {
    ....
    "types": ["xspreadsheet"],
    ....
  }
}

```

## Browser Support
Modern browsers and Internet Explorer 9+(no test).

## LICENSE
MIT


================================================
FILE: docs/index.html
================================================
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="xspreadsheet.css"></link>
    <script type="text/javascript" src="xspreadsheet.js"></script>
    <script type="text/javascript">
      window.onload = function () {
        xspreadsheet(document.getElementById('wrapper')).change(function (data) {
          console.log('data:', data)
        })
      }
    </script> 
    <title>XSpreadsheet Demo</title>
  </head>
  <body>
    <div id="wrapper"></div>
  </body>
</html>


================================================
FILE: docs/xspreadsheet.js
================================================
!function(e){var t={};function s(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,s),n.l=!0,n.exports}s.m=e,s.c=t,s.d=function(e,t,i){s.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:i})},s.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},s.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return s.d(t,"a",t),t},s.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},s.p="",s(s.s=30)}([function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(1);class n{constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,this.el=document.createElement(e)}data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e=>{for(let t of i){if(console.log("::::::::::",t),"left"===t&&0!==e.button)return;if("right"===t&&2!==e.button)return;"stop"===t&&e.stopPropagation()}t(e)}),this}onClickOutside(e){return this._clickOutside=e,this}parent(){return this.el.parentNode}class(e){return this.el.className=e,this}attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttribute(e,t),this)}removeAttr(e){return this.el.removeAttribute(e),this}offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=this.el;return{top:e,left:t,height:s,width:i}}clearStyle(){return this.el.style="",this}styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))this.style(t,e[t]);return this}style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.el.style.setProperty(e,t),this)}contains(e){return this.el.contains(e)}removeStyle(e){this.el.style.removeProperty(e)}children(e){for(let t of e)this.child(t);return this}child(e){return"string"==typeof e?this.el.appendChild(document.createTextNode(e)):e instanceof n?this.el.appendChild(e.el):e instanceof HTMLElement&&this.el.appendChild(e),this}html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}val(e){return void 0===e?this.el.value:(this.el.value=e,this)}clone(){return this.el.cloneNode()}isHide(){return"none"===this.style("display")}toggle(){this.isHide()?this.show():this.hide()}disabled(){return this.addClass("disabled"),this}able(){return this.removeClass("disabled"),this}active(e=!0){return e?this.addClass("active"):this.deactive(),this}deactive(){return this.removeClass("active")}isActive(){return this.hasClass("active")}addClass(e){return this.el.className=this.el.className.split(" ").concat(e).join(" "),this}removeClass(e){return this.el.className=this.el.className.split(" ").filter(t=>t!==e).join(" "),this}hasClass(e){return-1!==this.el.className.indexOf(e)}show(e=!1){return e?this.removeStyle("display"):this.style("display","block"),this._clickOutside&&(this.data("_outsidehandler",e=>{if(this.contains(e.target))return!1;this.hide(),i.unbind("click",this.data("_outsidehandler")),this._clickOutside&&this._clickOutside()}),setTimeout(()=>{i.bind("click",this.data("_outsidehandler"))},0)),this}hide(){return this.style("display","none"),this._clickOutside&&i.unbind("click",this.data("_outsidehandler")),this}}t.Element=n,t.h=function(e="div"){return new n(e)}},function(e,t,s){"use strict";function i(e,t,s=window){s.addEventListener(e,t)}function n(e,t,s=window){s.removeEventListener(e,t)}Object.defineProperty(t,"__esModule",{value:!0}),t.bind=i,t.unbind=n,t.mouseMoveUp=function(e,t){i("mousemove",e);const s=i=>{n("mousemove",e),n("mouseup",s),t(i)};i("mouseup",s)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0);class n extends i.Element{constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}}t.Menu=n,t.buildMenu=function(e="vertical"){return new n(e)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0);class n extends i.Element{constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i.h().class(`spreadsheet-icon-img ${e}`))}replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}}t.Icon=n,t.buildIcon=function(e){return new n(e)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(3);class r extends i.Element{constructor(){super(),this.iconEl=null,this.class("spreadsheet-item")}static build(){return new r}icon(e){return this.child(this.iconEl=n.buildIcon(e)),this}replaceIcon(e){this.iconEl&&this.iconEl.replace(e)}}t.Item=r,t.buildItem=function(){return new r}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.defaultCell={font:"Microsoft YaHei",format:"normal",fontSize:14,bold:!1,italic:!1,underline:!1,color:"#333",backgroundColor:"#fff",align:"left",valign:"middle",wordWrap:!1,invisible:!1,rowspan:1,colspan:1,text:""},t.getStyleFromCell=function(e){const t={};return e&&(e.font&&(t["font-family"]=e.font),e.fontSize&&(t["font-size"]=`${e.fontSize}px`),e.bold&&(t["font-weight"]="bold"),e.italic&&(t["font-style"]="italic"),e.underline&&(t["text-decoration"]="underline"),e.color&&(t.color=e.color),e.backgroundColor&&(t["background-color"]=e.backgroundColor),e.align&&(t["text-align"]=e.align),e.valign&&(t["vertical-align"]=e.valign),e.invisible&&(t.display="none"),e.wordWrap&&(t["word-wrap"]="break-word",t["white-space"]="normal")),t}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=["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"];t.alphabet=function(e){const[t,s]=[parseInt(e/i.length+""),e%i.length];return t>0?`${i[t-1]}${i[s]}`:i[s]},t.alphabetIndex=function(e){let t=0;for(let s=0;s<e.length;s++){let n=e.charCodeAt(s)-65;t+=s*i.length+n}return t}},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const alphabet_1=__webpack_require__(6);exports.formulaFilterKey=((e,t)=>{if("="===e[0]){const s=e.substring(1,e.indexOf("("));for(let i of exports.formulas)if(i.key.toLowerCase()===s.toLowerCase())return t(i,e.substring(e.indexOf("(")+1,e.lastIndexOf(")")))}return e}),exports.formulaRender=((e,t)=>exports.formulaFilterKey(e,(e,s)=>e.render(formulaParamToArray(s,t))+"")),exports.formulaReplaceParam=((e,t,s)=>exports.formulaFilterKey(e,(e,i)=>{const n=e=>{if(/^[0-9\-\+\*\/()\s]+$/.test(e.trim()))return e;const i=/\d+/.exec(e);if(i){let n=e.substring(0,i.index).trim(),r=parseInt(e.substring(i.index).trim());return`${alphabet_1.alphabet(alphabet_1.alphabetIndex(n)+s)}${r+t}`}return e};return i=-1!==i.indexOf(":")?i.split(":").map(n).join(":"):i.split(",").map(n).join(","),`=${e.key}(${i})`}));const formulaParamToArray=(param,renderCell)=>{let paramValues=[];try{if(-1!==param.indexOf(":")){const[e,t]=param.split(":"),s=/\d+/.exec(e),i=/\d+/.exec(t);if(s&&i){let n=e.substring(0,s.index).trim(),r=parseInt(e.substring(s.index).trim()),o=t.substring(0,i.index).trim(),l=parseInt(t.substring(i.index).trim());if(o===n)for(let e=r;e<=l;e++)paramValues.push(renderCell(e-1,alphabet_1.alphabetIndex(n)));else for(let e=alphabet_1.alphabetIndex(n);e<=alphabet_1.alphabetIndex(o);e++)paramValues.push(renderCell(r-1,e))}}else paramValues=param.split(",").map(p=>{if(/^[0-9\-\+\*\/()\s]+$/.test(p.trim()))try{return eval(p)}catch(e){return 0}const idx=/\d+/.exec(p);if(idx){const e=p.substring(0,idx.index).trim(),t=p.substring(idx.index).trim();return renderCell(parseInt(t)-1,alphabet_1.alphabetIndex(e))}return 0})}catch(e){console.log("warning:",e)}return paramValues};exports.formulas=[{key:"SUM",title:"求和",render:e=>e.reduce((e,t)=>Number(e)+Number(t),0)},{key:"AVERAGE",title:"平均值",render:e=>e.reduce((e,t)=>Number(e)+Number(t),0)/e.length},{key:"MAX",title:"最大值",render:e=>Math.max(...e.map(e=>Number(e)))},{key:"MIN",title:"最小值",render:e=>Math.min(...e.map(e=>Number(e)))}]},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.formatRenderHtml=((e,s)=>{for(let i=0;i<t.formats.length;i++)if(t.formats[i].key===e)return t.formats[i].render(s||"");return s||""});const i=e=>{if(/^(-?\d*.?\d*)$/.test(e)){const t=(e=Number(e).toFixed(2).toString()).split(".");return t[0]=t[0].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1,"),t.join(".")}return e},n=e=>e;t.formats=[{key:"normal",title:"Normal",render:n},{key:"text",title:"Text",render:n},{key:"number",title:"Number",label:"1,000.12",render:i},{key:"percent",title:"Percent",label:"10.12%",render:e=>`${i(e)}%`},{key:"RMB",title:"RMB",label:"¥10.00",render:e=>`¥${i(e)}`},{key:"USD",title:"USD",label:"$10.00",render:e=>`$${i(e)}`}]},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0);t.Editorbar=class{constructor(){this.value=null,this.change=(e=>{}),this.el=i.h().class("spreadsheet-editor-bar").children([i.h().class("spreadsheet-formula-bar").children([this.label=i.h().class("spreadsheet-formula-label"),this.textarea=i.h("textarea").on("input",e=>this.input(e))])])}set(e,t){this.label.html(e),this.setValue(t)}setValue(e){this.value=e,this.textarea.val(e&&e.text||"")}input(e){const t=e.target.value;this.value?this.value.text=t:this.value={text:t},this.change(this.value)}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=[["#c00000","#ff0000","#ffc003","#ffff00","#91d051","#00af50","#00b0f0","#0070c0","#002060","#70309f"],["#ffffff","#000000","#e7e6e6","#44546a","#4472c4","#ed7d31","#a5a5a5","#ffc003","#5b9bd5","#70ad47"],["#f4f5f8","#848484","#d0cece","#d6dce4","#d9e2f2","#fae5d5","#ededed","#fff2cc","#deebf6","#e2efd9"],["#d8d8d8","#595959","#afabab","#adb9ca","#b4c6e7","#f7cbac","#dbdbdb","#fee598","#bdd7ee","#c5e0b3"],["#bfbfbf","#3f3f3f","#757070","#8496b0","#8eaad8","#f4b183","#c9c9c9","#ffd964","#9dc2e5","#a8d08d"],["#a5a5a5","#262626","#3a3838","#333f4f","#2f5496","#c55b11","#7b7b7b","#bf9001","#2e75b5","#538135"],["#7e7e7e","#0c0c0c","#171616","#232a35","#1e3864","#833d0b","#525252","#7e6000","#1f4e79","#375623"]];class r extends i.Element{constructor(e){super(),this.class("spreadsheet-color-panel").child(i.h("table").child(i.h("tbody").children(n.map(t=>i.h("tr").children(t.map(t=>i.h("td").child(i.h().class("color-cell").on("click",e.bind(null,t)).style("background-color",t))))))))}}t.ColorPanel=r,t.buildColorPanel=function(e){return new r(e)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(3);class r extends i.Element{constructor(e,t,s){super(),this.class("spreadsheet-dropdown spreadsheet-item"),this.content=i.h().class("spreadsheet-dropdown-content").children(s).onClickOutside(()=>this.deactive()).on("click",e=>this.toggleHandler(e)).style("width",t).hide(),this.child(i.h().class("spreadsheet-dropdown-header").children([this.title="string"==typeof e?i.h().class("spreadsheet-dropdown-title").child(e):e,i.h().class("spreadsheet-dropdown-icon").on("click",e=>this.toggleHandler(e)).child(n.buildIcon("arrow-down"))])).child(this.content)}toggleHandler(e){this.content.isHide()?(this.content.show(),this.active()):(this.content.hide(),this.deactive())}}t.Dropdown=r,t.buildDropdown=function(e,t,s){return new r(e,t,s)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(4),r=s(3),o=s(11),l=s(2),h=s(10);t.Toolbar=class{constructor(e){this.ss=e,this.target=null,this.currentCell=null,this.change=((e,t)=>{}),this.redo=(()=>!1),this.undo=(()=>!1),this.defaultCell=e.data.cell,this.el=i.h().class("spreadsheet-toolbar").child(l.buildMenu("horizontal").children([this.elUndo=this.buildUndo(),this.elRedo=this.buildRedo(),this.elPaintformat=this.buildPaintformat(),this.elClearformat=this.buildClearformat(),this.elFormat=this.buildFormats(),this.buildSeparator(),this.elFont=this.buildFonts(),this.elFontSize=this.buildFontSizes(),this.buildSeparator(),this.elFontWeight=this.buildFontWeight(),this.elFontStyle=this.buildFontStyle(),this.elTextDecoration=this.buildTextDecoration(),this.elColor=this.buildColor(),this.buildSeparator(),this.elBackgroundColor=this.buildBackgroundColor(),this.elMerge=this.buildMerge(),this.buildSeparator(),this.elAlign=this.buildAligns(),this.elValign=this.buildValigns(),this.elWordWrap=this.buildWordWrap()]))}set(e,t){this.target=e,this.setCell(t)}setCell(e){this.currentCell=e,this.setCellStyle()}setCellStyle(){const{target:e,currentCell:t,defaultCell:s,ss:i}=this;e&&(this.elFormat.title.html(i.getFormat(null!==t&&t.format||s.format).title),this.elFont.title.html(i.getFont(null!==t&&t.font||s.font).title),this.elFontSize.title.html((null!==t&&t.fontSize||s.fontSize)+""),this.elFontWeight.active(null!==t&&void 0!==t.bold&&t.bold!==s.bold),this.elFontStyle.active(null!==t&&void 0!==t.italic&&t.italic!==s.italic),this.elTextDecoration.active(null!==t&&void 0!==t.underline&&t.underline!==s.underline),this.elColor.title.style("border-bottom-color",null!==t&&t.color||s.color),this.elBackgroundColor.title.style("border-bottom-color",null!==t&&t.backgroundColor||s.backgroundColor),this.elAlign.title.replace(`align-${null!==t&&t.align||s.align}`),this.elValign.title.replace(`valign-${null!==t&&t.valign||s.valign}`),this.elWordWrap.active(null!==t&&void 0!==t.wordWrap&&t.wordWrap!==s.wordWrap),null!==t&&t.rowspan&&t.rowspan>1||null!==t&&t.colspan&&t.colspan>1?this.elMerge.active(!0):this.elMerge.active(!1))}setRedoAble(e){e?this.elRedo.able():this.elRedo.disabled()}setUndoAble(e){e?this.elUndo.able():this.elUndo.disabled()}buildSeparator(){return i.h().class("spreadsheet-item-separator")}buildAligns(){const e=r.buildIcon(`align-${this.defaultCell.align}`),t=t=>{e.replace(`align-${t}`),this.change("align",t)};return o.buildDropdown(e,"60px",[l.buildMenu().children(["left","center","right"].map(e=>n.buildItem().child(r.buildIcon(`align-${e}`).style("text-align","center")).on("click",t.bind(null,e))))])}buildValigns(){const e=r.buildIcon(`valign-${this.defaultCell.valign}`),t=t=>{e.replace(`valign-${t}`),this.change("valign",t)};return o.buildDropdown(e,"60px",[l.buildMenu().children(["top","middle","bottom"].map(e=>n.buildItem().child(r.buildIcon(`valign-${e}`).style("text-align","center")).on("click",t.bind(null,e))))])}buildWordWrap(){return a("textwrap",e=>this.change("wordWrap",e))}buildFontWeight(){return a("bold",e=>this.change("bold",e))}buildFontStyle(){return a("italic",e=>this.change("italic",e))}buildTextDecoration(){return a("underline",e=>this.change("underline",e))}buildMerge(){return a("merge",e=>this.change("merge",e))}buildColor(){return o.buildDropdown(r.buildIcon("text-color").styles({"border-bottom":`3px solid ${this.defaultCell.color}`,"margin-top":"2px",height:"16px"}),"auto",[h.buildColorPanel(e=>{this.elColor.title.style("border-bottom-color",e),this.change("color",e)})])}buildBackgroundColor(){return o.buildDropdown(r.buildIcon("cell-color").styles({"border-bottom":`3px solid ${this.defaultCell.backgroundColor}`,"margin-top":"2px",height:"16px"}),"auto",[h.buildColorPanel(e=>{this.elBackgroundColor.title.style("border-bottom-color",e),this.change("backgroundColor",e)})])}buildUndo(){return n.buildItem().child(r.buildIcon("undo")).on("click",e=>{this.undo()?this.elUndo.able():this.elUndo.disabled()}).disabled()}buildRedo(){return n.buildItem().child(r.buildIcon("redo")).on("click",e=>{this.redo()?this.elRedo.able():this.elRedo.disabled()}).disabled()}buildPaintformat(){return a("paintformat",e=>{this.change("paintformat",!0),this.elPaintformat.deactive()})}buildClearformat(){return a("clearformat",e=>{this.change("clearformat",!0),this.elClearformat.deactive()})}buildFormats(){const e=e=>{this.elFormat.title.html(this.ss.getFormat(e.key).title),this.change("format",e.key)};return o.buildDropdown(this.ss.getFormat(this.defaultCell.format).title,"250px",[l.buildMenu().children(this.ss.formats.map(t=>n.buildItem().children([t.title,i.h().class("label").child(t.label||"")]).on("click",e.bind(null,t))))])}buildFonts(){const e=e=>{this.elFont.title.html(e.title),this.change("font",e.key)};return o.buildDropdown(this.ss.getFont(this.defaultCell.font).title,"170px",[l.buildMenu().children(this.ss.fonts.map(t=>n.buildItem().child(t.title).on("click",e.bind(null,t))))])}buildFontSizes(){const e=e=>{this.elFontSize.title.html(`${e}`),this.change("fontSize",e)};return o.buildDropdown(this.defaultCell.fontSize+"","70px",[l.buildMenu().children([6,8,10,12,14,16,18,20,22,24,30,36].map(t=>n.buildItem().child(`${t}`).on("click",e.bind(null,t))))])}};const a=(e,t)=>{const s=n.buildItem().child(r.buildIcon(e));return s.on("click",e=>{let i=s.isActive();i?s.deactive():s.active(),t(!i)}),s}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(4),r=s(2);t.ContextMenu=class{constructor(e){this.table=e,this.el=i.h().class("spreadsheet-contextmenu").style("width","160px").on("click",e=>this.el.hide()).children([r.buildMenu().children([n.buildItem().on("click",t=>e.copy()).children(["copy",i.h().class("label").html("ctrl + c")]),n.buildItem().on("click",t=>e.cut()).children(["cut",i.h().class("label").html("ctrl + x")]),n.buildItem().on("click",t=>e.paste()).children(["paste",i.h().class("label").html("ctrl + v")])])]).onClickOutside(()=>{}).hide()}set(e){const{offsetLeft:t,offsetTop:s}=e.target,i=this.el.el.getBoundingClientRect(),{clientWidth:n,clientHeight:r}=document.documentElement;let o=s+e.offsetY,l=t+e.offsetX;e.clientY>r/1.5&&(o-=i.height),e.clientX>n/1.5&&(l-=i.width),this.el.style("left",`${l}px`).style("top",`${o}px`).show()}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(1);t.Resizer=class{constructor(e,t){this.vertical=e,this.change=t,this.moving=!1,this.index=0,this.el=i.h().class("spreadsheet-resizer-wrapper").children([this.resizer=i.h().class(`spreadsheet-resizer ${e?"vertical":"horizontal"}`).on("mousedown",e=>this.mousedown(e)),this.resizerLine=i.h().class(`spreadsheet-resizer-line ${e?"vertical":"horizontal"}`).hide()])}set(e,t,s){if(this.moving)return;this.index=t;const{vertical:i}=this,{offsetLeft:n,offsetTop:r,offsetHeight:o,offsetWidth:l,parentNode:h}=e;this.resizer.styles({left:`${i?n+l-5-s:n}px`,top:`${i?r:r+o-5+24-s}px`,width:`${i?5:l}px`,height:`${i?o:5}px`}),this.resizerLine.styles({left:`${i?n+l-s:n}px`,top:`${i?r:r+o+24-s}px`,width:`${i?0:h.parentNode.parentNode.parentNode.parentNode.nextSibling.offsetWidth-15}px`,height:`${i?h.parentNode.parentNode.parentNode.nextSibling.offsetHeight+h.offsetHeight:0}px`})}mousedown(e){let t=e,s=0;this.resizerLine.show(),n.mouseMoveUp(e=>{if(this.moving=!0,null!==t&&1===e.buttons){if(this.vertical){const i=e.x-t.x;s+=i,this.resizer.style("left",`${this.resizer.offset().left+i}px`),this.resizerLine.style("left",`${this.resizerLine.offset().left+i}px`)}else{const i=e.y-t.y;s+=i,this.resizer.style("top",`${this.resizer.offset().top+i}px`),this.resizerLine.style("top",`${this.resizerLine.offset().top+i}px`)}t=e}},e=>{this.change(this.index,s),t=null,this.resizerLine.hide(),s=0,this.moving=!1})}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(1);t.Selector=class{constructor(e,t){this.ss=e,this.table=t,this._offset={left:0,top:0,width:0,height:0},this.change=(()=>{}),this.changeCopy=((e,t,s,i,n,r)=>{}),this.topEl=i.h().class("top-border"),this.rightEl=i.h().class("right-border"),this.bottomEl=i.h().class("bottom-border"),this.leftEl=i.h().class("left-border"),this.areaEl=i.h().class("area-border"),this.cornerEl=i.h().class("corner").on("mousedown",e=>this.cornerMousedown(e)),this.copyEl=i.h().class("copy-border"),this.el=i.h().class("spreadsheet-borders").children([this.topEl,this.rightEl,this.bottomEl,this.leftEl,this.areaEl,this.cornerEl,this.copyEl.hide()]).hide()}mousedown(e){if(1===e.detail&&"cell"===e.target.getAttribute("type")){if(e.shiftKey)return this.endTarget=e.target,void this.setOffset();this.setCurrentTarget(e.target),n.mouseMoveUp(e=>{1===e.buttons&&"cell"===e.target.getAttribute("type")&&(this.endTarget=e.target,this.setOffset())},e=>{this.change()}),this.el.show()}}setCurrentTarget(e){Object.assign(this,{startTarget:e,endTarget:e}),this.setOffset()}cornerMousedown(e){const{select:t}=this.ss;if(null===t)return;const[s,i]=t.stop,[r,o]=t.start;let l=null;n.mouseMoveUp(e=>{const n=e.target.getAttribute("row-index"),h=e.target.getAttribute("col-index");if(n&&h){this.copyEl.show();let e=s-n,a=i-h,d=r-n,c=o-h;const{left:p,top:u,height:f,width:b}=this._offset;if(e<0)this.copyEl.styles({left:`${p-1}px`,top:`${u-1}px`,width:`${b-1}px`,height:`${this.rowsHeight(s-t.rowLen()+1,s+Math.abs(e))-1}px`}),l=["bottom",s+1,o,s+Math.abs(e),i];else if(a<0)this.copyEl.styles({left:`${p-1}px`,top:`${u-1}px`,width:`${this.colsWidth(i-t.colLen()+1,i+Math.abs(a))-1}px`,height:`${f-1}px`}),l=["right",r,i+1,s,i+Math.abs(a)];else if(d>0){const e=this.rowsHeight(r-d,r-1);this.copyEl.styles({left:`${p-1}px`,top:`${u-e-1}px`,width:`${b-1}px`,height:`${e-1}px`}),l=["top",r-d,o,r-1,i]}else if(c>0){const e=this.colsWidth(o-c,o-1);this.copyEl.styles({left:`${p-e-1}px`,top:`${u-1}px`,width:`${e-1}px`,height:`${f-1}px`}),l=["left",r,o-c,s,o-1]}else this.copyEl.styles({left:`${p-1}px`,top:`${u-1}px`,width:`${b-1}px`,height:`${f-1}px`}),l=null}},e=>{if(this.copyEl.hide(),null!==l){const[t,s,i,n,r]=l;this.changeCopy(e,t,s,i,n,r)}})}reload(){this.setOffset()}setOffset(){if(void 0===this.startTarget)return;let{select:e}=this.ss;if(e){const[t,s]=e.start,[i,n]=e.stop;r(t,i,this.table.firsttds,e=>{e.deactive()}),r(s,n,this.table.ths,e=>{e.deactive()})}e=this.ss.buildSelect(this.startTarget,this.endTarget);const[t,s]=e.start,[i,n]=e.stop,o=this.rowsHeight(t,i,e=>e.active()),l=this.colsWidth(s,n,e=>e.active()),h=this.table.td(t,s);if(h){const{left:e,top:t}=h.offset();this._offset={left:e,top:t,width:l,height:o},this.topEl.styles({left:`${e-1}px`,top:`${t-1}px`,width:`${l+1}px`,height:"2px"}),this.rightEl.styles({left:`${e+l-1}px`,top:`${t-1}px`,width:"2px",height:`${o}px`}),this.bottomEl.styles({left:`${e-1}px`,top:`${t+o-1}px`,width:`${l}px`,height:"2px"}),this.leftEl.styles({left:`${e-1}px`,top:`${t-1}px`,width:"2px",height:`${o}px`}),this.areaEl.styles({left:`${e}px`,top:`${t}px`,width:`${l-2}px`,height:`${o-2}px`}),this.cornerEl.styles({left:`${e+l-5}px`,top:`${t+o-5}px`})}}rowsHeight(e,t,s=(e=>{})){let i=0;return r(e,t,this.table.firsttds,e=>{s(e),i+=parseInt(e.offset().height)}),i/=2}colsWidth(e,t,s=(e=>{})){let i=0;return r(e,t,this.table.ths,e=>{s(e),i+=parseInt(e.offset().width)}),i}};const r=(e,t,s,n)=>{for(let r=e;r<=t;r++){const e=s[r+""];e&&(e instanceof i.Element?n(e):e.forEach(e=>n(e)))}};t.DashedSelector=class{constructor(){this.el=i.h().class("spreadsheet-borders dashed").hide()}set(e){if(e._offset){const{left:t,top:s,width:i,height:n}=e._offset;this.el.style("left",`${t-2}px`).style("top",`${s-2}px`).style("width",`${i}px`).style("height",`${n}px`).show()}}hide(){this.el.hide()}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(4),r=s(2),o=s(1);t.Suggest=class extends i.Element{constructor(e,t){super(),this.list=e,this.width=t,this.filterList=[],this.currentIndex=0,this.target=null,this.evtTarget=null,this.itemClick=(e=>{}),this.class("spreadsheet-suggest").hide()}documentHandler(e){if(this.el.contains(e.target))return!1;this.hideAndRemoveEvents()}documentKeydownHandler(e){if(console.log("keyCode: ",e),!(this.filterList.length<=0&&"textarea"!==e.target.type)){switch(e.keyCode){case 37:e.returnValue=!1;break;case 38:this.filterList[this.currentIndex].deactive(),this.currentIndex--,this.currentIndex<0&&(this.currentIndex=this.filterList.length-1),this.filterList[this.currentIndex].active(),e.returnValue=!1,e.stopPropagation();break;case 39:e.returnValue=!1;break;case 40:this.filterList[this.currentIndex].deactive(),this.currentIndex++,this.currentIndex>this.filterList.length-1&&(this.currentIndex=0),this.filterList[this.currentIndex].active(),e.returnValue=!1;break;case 13:this.filterList[this.currentIndex].el.click(),e.returnValue=!1}e.stopPropagation()}}hideAndRemoveEvents(){this.hide(),this.removeEvents()}removeEvents(){null!==this.evtTarget&&(o.unbind("click",this.data("_outsidehandler"),this.evtTarget.el),o.unbind("keydown",this.data("_keydownhandler"),this.evtTarget.el))}clickItemHandler(e){this.itemClick(e),this.hideAndRemoveEvents()}search(e,t,s){this.removeEvents(),this.target=e,this.evtTarget=t;const{left:l,top:h,width:a,height:d}=e.offset();this.styles({left:`${l}px`,top:`${h+d+2}px`,width:`${this.width}px`});let c=this.list;/^\s*$/.test(s)||(c=this.list.filter(e=>e[0].startsWith(s.toUpperCase()))),c=c.map(e=>{const t=n.buildItem().on("click",t=>this.clickItemHandler(e)).child(e[0]);return e[1]&&t.child(i.h().class("label").html(e[1])),t}),this.filterList=c,this.currentIndex=0,c.length<=0?c=[n.buildItem().child("No Result")]:(c[0].active(),this.data("_outsidehandler",e=>{this.documentHandler(e)}),this.data("_keydownhandler",e=>this.documentKeydownHandler(e)),setTimeout(()=>{null!==this.evtTarget&&(o.bind("click",this.data("_outsidehandler"),this.evtTarget.el),o.bind("keydown",this.data("_keydownhandler"),this.evtTarget.el))},0)),this.html(""),this.child(r.buildMenu().children(c)).show()}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(16),r=s(5);t.Editor=class{constructor(e,t){this.defaultRowHeight=e,this.formulas=t,this.target=null,this.value=null,this.change=(e=>{});const s=t.map(e=>[e.key,e.title]);this.el=i.h().children([this.editor=i.h().class("spreadsheet-editor").children([this.textarea=i.h("textarea").on("keydown",e=>this.inputKeydown(e)).on("input",e=>this.inputChange(e)),this.textline=i.h().styles({visibility:"hidden",overflow:"hidden",position:"fixed",top:"0",left:"0"})]),this.suggest=new n.Suggest(s,180)]).hide(),this.el.on("keydown",e=>{13!==e.keyCode&&9!==e.keyCode&&e.stopPropagation()}),this.suggest.itemClick=(e=>{const t=`=${e[0]}()`;this.value&&(this.value.text=t),this.textarea.val(t),this.textline.html(t),this.setTextareaRange(t.length-1)})}onChange(e){this.change=e}set(e,t){this.target=e;const s=this.setValue(t);this.el.show(),this.setTextareaRange(s.length),this.reload()}setValue(e){if(this.setStyle(e),e){this.value=e;const t=e.text||"";return this.textarea.val(t),this.textline.html(t),t}return""}setStyle(e){let t={width:this.textarea.style("width"),height:this.textarea.style("height")};this.textarea.styles(Object.assign(t,r.getStyleFromCell(e)),!0)}clear(){this.el.hide(),this.target=null,this.value=null,this.textarea.val(""),this.textline.html("")}setTextareaRange(e){setTimeout(()=>{this.textarea.el.setSelectionRange(e,e),this.textarea.el.focus()},10)}inputKeydown(e){13===e.keyCode&&e.preventDefault()}inputChange(e){const t=e.target.value;this.value?this.value.text=t:this.value={text:t},this.change(this.value),this.autocomplete(t),this.textline.html(t),this.reload()}autocomplete(e){if("="===e[0])if(e.includes("("))this.suggest.hide();else{const t=e.substring(1);console.log(":::;search word:",t),this.suggest.search(this.editor,this.textarea,t)}else this.suggest.hide()}reload(){if(this.target){const{offsetTop:e,offsetLeft:t,offsetWidth:s,offsetHeight:i}=this.target;this.editor.styles({left:`${t-1}px`,top:`${e-1}px`}),this.textarea.styles({width:`${s-8}px`,height:`${i-2}px`});let n=this.textline.offset().width+16;if(this.value)if(this.value.wordWrap){const e=(parseInt(n/s+"")+(n%s>0?1:0))*this.defaultRowHeight;e>i&&this.textarea.style("height",`${e}px`)}else{const e=document.documentElement.clientWidth-t-24;if(n>s){if(n>e){const t=(parseInt(n/e+"")+(n%e>0?1:0))*this.defaultRowHeight;t>i?this.textarea.style("height",`${t}px`):this.textarea.style("height",`${i}px`),n=e}this.textarea.style("width",`${n}px`)}}this.el.show()}}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(17),r=s(15),o=s(14),l=s(13),h=s(5),a=s(8),d=s(7),c=s(1);t.Table=class{constructor(e,t){this.options=t,this.cols={},this.firsttds={},this.tds={},this.ths={},this.formulaCellIndexs=new Set,this.fixedLeftBody=null,this.editor=null,this.rowResizer=null,this.colResizer=null,this.contextmenu=null,this.state=null,this.currentIndexs=null,this.focusing=!1,this.change=(()=>{}),this.editorChange=(e=>{}),this.clickCell=((e,t,s)=>{}),this.ss=e,this.ss.change=(e=>{this.change(e)}),"read"!==t.mode&&(this.editor=new n.Editor(e.defaultRowHeight(),e.formulas),this.editor.change=(e=>this.editorChange(e))),"design"===t.mode&&(this.rowResizer=new o.Resizer(!1,(e,t)=>this.changeRowResizer(e,t)),this.colResizer=new o.Resizer(!0,(e,t)=>this.changeColResizer(e,t)),this.contextmenu=new l.ContextMenu(this)),this.selector=new r.Selector(this.ss,this),this.selector.change=(()=>this.selectorChange()),this.selector.changeCopy=((e,t,s,i,n,r)=>{this.selectorChangeCopy(e,t,s,i,n,r)}),this.dashedSelector=new r.DashedSelector,this.el=i.h().class("spreadsheet-table").children([this.colResizer&&this.colResizer.el||"",this.rowResizer&&this.rowResizer.el||"",this.buildFixedLeft(),this.header=this.buildHeader(),this.body=this.buildBody()]).on("contextmenu",e=>{e.returnValue=!1,e.preventDefault()}),c.bind("resize",e=>{this.header.style("width",`${this.options.width()}px`),this.body.style("width",`${this.options.width()}px`),"read"!==this.options.mode&&this.body.style("height",`${this.options.height()}px`)}),c.bind("click",e=>{this.focusing=this.el.parent().contains(e.target)}),c.bind("keydown",e=>{if(this.focusing&&this.focusing)if(e.ctrlKey&&"textarea"!==e.target.type&&"read"!==this.options.mode)67===e.keyCode&&(this.copy(),e.returnValue=!1),88===e.keyCode&&(this.cut(),e.returnValue=!1),86===e.keyCode&&(this.paste(),e.returnValue=!1);else{switch(e.keyCode){case 37:this.moveLeft(),e.returnValue=!1;break;case 38:this.moveUp(),e.returnValue=!1;break;case 39:this.moveRight(),e.returnValue=!1;break;case 40:this.moveDown(),e.returnValue=!1;break;case 9:this.moveRight(),e.returnValue=!1;break;case 13:this.moveDown(),e.returnValue=!1}"read"!==this.options.mode&&(e.keyCode>=65&&e.keyCode<=90||e.keyCode>=48&&e.keyCode<=57||e.keyCode>=96&&e.keyCode<=105||187==e.keyCode)&&"textarea"!==e.target.type&&this.ss.cellText(e.key,(e,t,s)=>{if(this.editor){const i=this.td(e,t);i.html(this.renderCell(e,t,s)),this.editor.set(i.el,this.ss.currentCell())}})}})}reload(){this.firsttds={},this.el.html(""),this.el.children([this.colResizer&&this.colResizer.el||"",this.rowResizer&&this.rowResizer.el||"",this.buildFixedLeft(),this.header=this.buildHeader(),this.body=this.buildBody()])}moveLeft(){this.currentIndexs&&this.currentIndexs[1]>0&&(this.currentIndexs[1]-=1,this.moveSelector("left"))}moveUp(){this.currentIndexs&&this.currentIndexs[0]>0&&(this.currentIndexs[0]-=1,this.moveSelector("up"))}moveDown(){this.currentIndexs&&this.currentIndexs[0]<this.ss.rows("read"===this.options.mode).length&&(this.currentIndexs[0]+=1,this.moveSelector("down"))}moveRight(){this.currentIndexs&&this.currentIndexs[1]<this.ss.cols().length&&(this.currentIndexs[1]+=1,this.moveSelector("right"))}moveSelector(e){if(this.currentIndexs){const[t,s]=this.currentIndexs,i=this.td(t,s);if(i){this.selector.setCurrentTarget(i.el);const n=this.options.width(),r=this.options.height(),{left:o,top:l,width:h,height:a}=i.offset(),d=o+h-n;d>0&&"right"===e&&(this.body.el.scrollLeft=d+15),"left"===e&&this.body.el.scrollLeft+60>o&&(this.body.el.scrollLeft-=this.body.el.scrollLeft+60-o),"up"===e&&this.body.el.scrollTop>l&&(this.body.el.scrollTop-=this.body.el.scrollTop-l),"down"===e&&l+a-r>0&&(this.body.el.scrollTop=l+a-r+15),this.mousedownCell(t,s)}}}setValueWithText(e){this.currentIndexs&&this.ss.cellText(e.text,(e,t,s)=>{this.td(e,t).html(this.renderCell(e,t,s))}),this.editor&&this.editor.setValue(e)}setTdWithCell(e,t,s,i=!0){this.setTdStyles(e,t,s),this.setRowHeight(e,t,i),this.td(e,t).html(this.renderCell(e,t,s))}setCellAttr(e,t){this.ss.cellAttr(e,t,(s,i,n)=>{this.setTdWithCell(s,i,n,"wordWrap"===e&&t)}),this.editor&&this.editor.setStyle(this.ss.currentCell())}undo(){return this.ss.undo((e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t,s)})}redo(){return this.ss.redo((e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t,s)})}setTdStylesAndAttrsAndText(e,t,s){let i=this.td(e,t);this.setTdStyles(e,t,s),this.setTdAttrs(e,t,s),i.html(this.renderCell(e,t,s))}copy(){this.ss.copy(),this.dashedSelector.set(this.selector),this.state="copy"}cut(){this.ss.cut(),this.dashedSelector.set(this.selector),this.state="cut"}copyformat(){this.ss.copy(),this.dashedSelector.set(this.selector),this.state="copyformat"}paste(){null!==this.state&&this.ss.select&&(this.ss.paste((e,t,s)=>{let i=this.td(e,t);this.setTdStyles(e,t,s),this.setTdAttrs(e,t,s),"cut"!==this.state&&"copy"!==this.state||i.html(this.renderCell(e,t,s))},this.state,(e,t,s)=>{let i=this.td(e,t);this.setTdStyles(e,t,s),this.setTdAttrs(e,t,s),i.html("")}),this.selector.reload()),"copyformat"===this.state?this.state=null:"cut"===this.state?this.state=null:this.state,this.dashedSelector.hide()}clearformat(){this.ss.clearformat((e,t,s)=>{this.td(e,t).removeAttr("rowspan").removeAttr("colspan").styles({},!0).show(!0)})}merge(){this.ss.merge((e,t,s)=>{this.setTdAttrs(e,t,s).show(!0)},(e,t,s)=>{this.setTdAttrs(e,t,s).show(!0)},(e,t,s)=>{let i=this.td(e,t);s.invisible?i.hide():i.show(!0)})}insert(e,t){this.ss.insert(e,t,(e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t,s)})}td(e,t){return this.tds[`${e}_${t}`]}selectorChange(){"copyformat"===this.state&&this.paste()}selectorChangeCopy(e,t,s,i,n,r){this.ss.batchPaste(t,s,i,n,r,e.ctrlKey,(e,t,s)=>{this.setTdStyles(e,t,s),this.setTdAttrs(e,t,s),this.td(e,t).html(this.renderCell(e,t,s))})}renderCell(e,t,s){if(s){const i=`${e}_${t}`;return s.text&&"="===s.text[0]?this.formulaCellIndexs.add(i):(this.formulaCellIndexs.has(i)&&this.formulaCellIndexs.delete(i),this.reRenderFormulaCells()),a.formatRenderHtml(s.format,this._renderCell(s))}return""}_renderCell(e){if(e){let t=e.text||"";return d.formulaRender(t,(e,t)=>this._renderCell(this.ss.getCell(e,t)))}return""}reRenderFormulaCells(){this.formulaCellIndexs.forEach(e=>{let t=e.split("_");const s=parseInt(t[0]),i=parseInt(t[1]),n=this.renderCell(s,i,this.ss.getCell(s,i));this.td(s,i).html(n)})}setRowHeight(e,t,s){if(!1===s)return;this.ss.cols();const i=this.td(e,t);let n=i.offset().height;console.log("h:",n);const r=i.attr("rowspan");if(r)for(let t=1;t<parseInt(r);t++){let s=this.firsttds[e+t+""];s&&(n-=parseInt(s[0].attr("height")||0)+1)}this.changeRowHeight(e,n-1)}setTdStyles(e,t,s){return this.td(e,t).styles(h.getStyleFromCell(s),!0)}setTdAttrs(e,t,s){return this.td(e,t).attr("rowspan",s.rowspan||1).attr("colspan",s.colspan||1)}changeRowHeight(e,t){if(t<=this.ss.defaultRowHeight())return;this.ss.row(e,t);const s=this.firsttds[e+""];s&&s.forEach(e=>e.attr("height",t)),this.selector.reload(),this.editor&&this.editor.reload()}changeRowResizer(e,t){const s=this.ss.row(e).height+t;this.changeRowHeight(e,s)}changeColResizer(e,t){const s=this.ss.col(e).width+t;if(s<=50)return;this.ss.col(e,s);const i=this.cols[e+""];i&&i.forEach(e=>e.attr("width",s)),this.selector.reload(),this.editor&&this.editor.reload()}buildColGroup(e){const t=this.ss.cols();return i.h("colgroup").children([i.h("col").attr("width","60"),...t.map((e,t)=>{let s=i.h("col").attr("width",e.width);return this.cols[t+""]=this.cols[t+""]||[],this.cols[t+""].push(s),s}),i.h("col").attr("width",e)])}buildFixedLeft(){const e=this.ss.rows("read"===this.options.mode);return i.h().class("spreadsheet-fixed").style("width","60px").children([i.h().class("spreadsheet-fixed-header").child(i.h("table").child(i.h("thead").child(i.h("tr").child(i.h("th").child("-"))))),this.fixedLeftBody=i.h().class("spreadsheet-fixed-body").style("height",`${"read"===this.options.mode?"auto":this.options.height()-18}px`).children([i.h("table").child(i.h("tbody").children(e.map((e,t)=>{let s=i.h("td").attr("height",`${e.height}`).child(`${t+1}`).on("mouseover",e=>this.rowResizer&&this.rowResizer.set(e.target,t,this.body.el.scrollTop));return this.firsttdsPush(t,s),i.h("tr").child(s)})))])])}buildHeader(){const e=this.ss.cols(),t=i.h("thead").child(i.h("tr").children([i.h("th"),...e.map((e,t)=>{let s=i.h("th").child(e.title).on("mouseover",e=>{console.log(e),this.colResizer&&this.colResizer.set(e.target,t,this.body.el.scrollLeft)});return this.ths[t+""]=s,s}),i.h("th")]));return i.h().class("spreadsheet-header").style("width",`${this.options.width()}px`).children([i.h("table").children([this.buildColGroup(15),t])])}mousedownCell(e,t){if(this.editor){const e=this.editor.value;if(this.currentIndexs&&this.editor.target&&e){const t=this.ss.cellText(e.text,(e,t,s)=>{this.td(e,t).html(this.renderCell(e,t,s))});t&&t.wordWrap&&this.setRowHeight(this.currentIndexs[0],this.currentIndexs[1],!0)}this.editor.clear()}this.currentIndexs=[e,t];const s=this.ss.currentCell([e,t]);this.clickCell(e,t,s)}editCell(e,t){const s=this.td(e,t);this.editor&&this.editor.set(s.el,this.ss.currentCell())}buildBody(){const e=this.ss.rows("read"===this.options.mode),t=this.ss.cols(),s=(e,t,s)=>{const{select:i}=this.ss;2===s.button&&(console.log(":::evt:",s),this.contextmenu&&this.contextmenu.set(s),i&&i.contains(e,t))||(this.selector.mousedown(s),this.mousedownCell(e,t),this.focusing=!0)},n=(e,t)=>{this.editCell(e,t)},r=i.h("tbody").children(e.map((e,r)=>{let o=i.h("td").attr("height",`${e.height}`).child(`${r+1}`);return this.firsttdsPush(r,o),i.h("tr").children([o,...t.map((e,t)=>{let o=this.ss.getCell(r,t),l=i.h("td").child(this.renderCell(r,t,o)).attr("type","cell").attr("row-index",r+"").attr("col-index",t+"").attr("rowspan",o&&o.rowspan||1).attr("colspan",o&&o.colspan||1).styles(h.getStyleFromCell(o),!0).on("mousedown",e=>s(r,t,e)).on("dblclick",n.bind(null,r,t));return this.tds[`${r}_${t}`]=l,l}),i.h("td")])}));return i.h().class("spreadsheet-body").on("scroll",e=>{this.header.el.scrollLeft=e.target.scrollLeft,this.fixedLeftBody&&(this.fixedLeftBody.el.scrollTop=e.target.scrollTop)}).style("height",`${"read"===this.options.mode?"auto":this.options.height()}px`).style("width",`${this.options.width()}px`).children([i.h("table").children([this.buildColGroup(0),r]),this.editor&&this.editor.el||"",this.selector.el,this.contextmenu&&this.contextmenu.el||"",this.dashedSelector.el])}addRow(e=1){}firsttdsPush(e,t){this.firsttds[`${e}`]=this.firsttds[`${e}`]||[],this.firsttds[`${e}`].push(t)}}},function(e,t){e.exports=function(e){var t="undefined"!=typeof window&&window.location;if(!t)throw new Error("fixUrls requires window.location");if(!e||"string"!=typeof e)return e;var s=t.protocol+"//"+t.host,i=s+t.pathname.replace(/\/[^\/]*$/,"/");return e.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi,function(e,t){var n,r=t.trim().replace(/^"(.*)"$/,function(e,t){return t}).replace(/^'(.*)'$/,function(e,t){return t});return/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/|\s*$)/i.test(r)?e:(n=0===r.indexOf("//")?r:0===r.indexOf("/")?s+r:i+r.replace(/^\.\//,""),"url("+JSON.stringify(n)+")")})}},function(e,t,s){var i,n,r={},o=(i=function(){return window&&document&&document.all&&!window.atob},function(){return void 0===n&&(n=i.apply(this,arguments)),n}),l=function(e){var t={};return function(e){if("function"==typeof e)return e();if(void 0===t[e]){var s=function(e){return document.querySelector(e)}.call(this,e);if(window.HTMLIFrameElement&&s instanceof window.HTMLIFrameElement)try{s=s.contentDocument.head}catch(e){s=null}t[e]=s}return t[e]}}(),h=null,a=0,d=[],c=s(19);function p(e,t){for(var s=0;s<e.length;s++){var i=e[s],n=r[i.id];if(n){n.refs++;for(var o=0;o<n.parts.length;o++)n.parts[o](i.parts[o]);for(;o<i.parts.length;o++)n.parts.push(x(i.parts[o],t))}else{var l=[];for(o=0;o<i.parts.length;o++)l.push(x(i.parts[o],t));r[i.id]={id:i.id,refs:1,parts:l}}}}function u(e,t){for(var s=[],i={},n=0;n<e.length;n++){var r=e[n],o=t.base?r[0]+t.base:r[0],l={css:r[1],media:r[2],sourceMap:r[3]};i[o]?i[o].parts.push(l):s.push(i[o]={id:o,parts:[l]})}return s}function f(e,t){var s=l(e.insertInto);if(!s)throw new Error("Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid.");var i=d[d.length-1];if("top"===e.insertAt)i?i.nextSibling?s.insertBefore(t,i.nextSibling):s.appendChild(t):s.insertBefore(t,s.firstChild),d.push(t);else if("bottom"===e.insertAt)s.appendChild(t);else{if("object"!=typeof e.insertAt||!e.insertAt.before)throw new Error("[Style Loader]\n\n Invalid value for parameter 'insertAt' ('options.insertAt') found.\n Must be 'top', 'bottom', or Object.\n (https://github.com/webpack-contrib/style-loader#insertat)\n");var n=l(e.insertInto+" "+e.insertAt.before);s.insertBefore(t,n)}}function b(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e);var t=d.indexOf(e);t>=0&&d.splice(t,1)}function g(e){var t=document.createElement("style");return e.attrs.type="text/css",m(t,e.attrs),f(e,t),t}function m(e,t){Object.keys(t).forEach(function(s){e.setAttribute(s,t[s])})}function x(e,t){var s,i,n,r;if(t.transform&&e.css){if(!(r=t.transform(e.css)))return function(){};e.css=r}if(t.singleton){var o=a++;s=h||(h=g(t)),i=v.bind(null,s,o,!1),n=v.bind(null,s,o,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(s=function(e){var t=document.createElement("link");return e.attrs.type="text/css",e.attrs.rel="stylesheet",m(t,e.attrs),f(e,t),t}(t),i=function(e,t,s){var i=s.css,n=s.sourceMap,r=void 0===t.convertToAbsoluteUrls&&n;(t.convertToAbsoluteUrls||r)&&(i=c(i));n&&(i+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(n))))+" */");var o=new Blob([i],{type:"text/css"}),l=e.href;e.href=URL.createObjectURL(o),l&&URL.revokeObjectURL(l)}.bind(null,s,t),n=function(){b(s),s.href&&URL.revokeObjectURL(s.href)}):(s=g(t),i=function(e,t){var s=t.css,i=t.media;i&&e.setAttribute("media",i);if(e.styleSheet)e.styleSheet.cssText=s;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(s))}}.bind(null,s),n=function(){b(s)});return i(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;i(e=t)}else n()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=o()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var s=u(e,t);return p(s,t),function(e){for(var i=[],n=0;n<s.length;n++){var o=s[n];(l=r[o.id]).refs--,i.push(l)}e&&p(u(e,t),t);for(n=0;n<i.length;n++){var l;if(0===(l=i[n]).refs){for(var h=0;h<l.parts.length;h++)l.parts[h]();delete r[l.id]}}}};var y,w=(y=[],function(e,t){return y[e]=t,y.filter(Boolean).join("\n")});function v(e,t,s,i){var n=s?"":i.css;if(e.styleSheet)e.styleSheet.cssText=w(t,n);else{var r=document.createTextNode(n),o=e.childNodes;o[t]&&e.removeChild(o[t]),o.length?e.insertBefore(r,o[t]):e.appendChild(r)}}},function(e,t,s){e.exports=s.p+"13b240062f9cf9a7f4131b86a426f140.svg"},function(e,t){e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var s=function(e,t){var s=e[1]||"",i=e[3];if(!i)return s;if(t&&"function"==typeof btoa){var n=(o=i,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */"),r=i.sources.map(function(e){return"/*# sourceURL="+i.sourceRoot+e+" */"});return[s].concat(r).concat([n]).join("\n")}var o;return[s].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+s+"}":s}).join("")},t.i=function(e,s){"string"==typeof e&&(e=[[null,e,""]]);for(var i={},n=0;n<this.length;n++){var r=this[n][0];"number"==typeof r&&(i[r]=!0)}for(n=0;n<e.length;n++){var o=e[n];"number"==typeof o[0]&&i[o[0]]||(s&&!o[2]?o[2]=s:s&&(o[2]="("+o[2]+") and ("+s+")"),t.push(o))}},t}},function(e,t){e.exports=function(e){return"string"!=typeof e?e:(/^['"].*['"]$/.test(e)&&(e=e.slice(1,-1)),/["'() \t\n]/.test(e)?'"'+e.replace(/"/g,'\\"').replace(/\n/g,"\\n")+'"':e)}},function(e,t,s){var i=s(23);(e.exports=s(22)(!1)).push([e.i,"body {\n  margin: 0;\n}\n.spreadsheet {\n  font-size: 14px;\n  line-height: normal;\n  user-select: none;\n  -moz-user-select: none;\n  font-family: Roboto, Helvetica, Arial, sans-serif;\n  box-sizing: content-box;\n  background: #fff;\n}\n.spreadsheet .spreadsheet-table {\n  position: relative;\n  background: #fff;\n}\n.spreadsheet .spreadsheet-fixed {\n  position: absolute;\n  top: 0;\n  left: 0;\n  z-index: 10;\n  background: #fff;\n}\n.spreadsheet .spreadsheet-fixed .spreadsheet-fixed-body {\n  overflow: hidden;\n}\n.spreadsheet .spreadsheet-fixed .spreadsheet-fixed-header {\n  overflow: hidden;\n}\n.spreadsheet .spreadsheet-body {\n  overflow: scroll;\n  position: relative;\n}\n.spreadsheet .spreadsheet-header {\n  overflow: hidden;\n  width: 100%;\n}\n.spreadsheet .spreadsheet-header table,\n.spreadsheet .spreadsheet-body table,\n.spreadsheet .spreadsheet-fixed table {\n  table-layout: fixed;\n  text-align: left;\n  width: 100%;\n  border-collapse: separate;\n  border-spacing: 0;\n  color: #000;\n}\n.spreadsheet .spreadsheet-header table td,\n.spreadsheet .spreadsheet-body table td,\n.spreadsheet .spreadsheet-fixed table td,\n.spreadsheet .spreadsheet-header table th,\n.spreadsheet .spreadsheet-body table th,\n.spreadsheet .spreadsheet-fixed table th {\n  transition: background .1s ease,color .1s ease;\n  border-bottom: 1px solid #e0e2e4;\n  border-right: 1px solid #e0e2e4;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n  overflow: hidden;\n  padding: 0 4px;\n  line-height: 22px;\n}\n.spreadsheet .spreadsheet-header table td.active,\n.spreadsheet .spreadsheet-body table td.active,\n.spreadsheet .spreadsheet-fixed table td.active,\n.spreadsheet .spreadsheet-header table th.active,\n.spreadsheet .spreadsheet-body table th.active,\n.spreadsheet .spreadsheet-fixed table th.active {\n  background: rgba(75, 137, 255, 0.05) !important;\n}\n.spreadsheet .spreadsheet-header table th,\n.spreadsheet .spreadsheet-body table th,\n.spreadsheet .spreadsheet-fixed table th {\n  border-top: 1px solid #e0e2e4;\n  text-align: center;\n}\n.spreadsheet .spreadsheet-header table th,\n.spreadsheet .spreadsheet-body table th,\n.spreadsheet .spreadsheet-fixed table th,\n.spreadsheet .spreadsheet-header table td:first-child,\n.spreadsheet .spreadsheet-body table td:first-child,\n.spreadsheet .spreadsheet-fixed table td:first-child {\n  font-size: 12px;\n  background: #f4f5f8;\n  font-weight: normal;\n  color: #666;\n}\n.spreadsheet .spreadsheet-header table td:first-child,\n.spreadsheet .spreadsheet-body table td:first-child,\n.spreadsheet .spreadsheet-fixed table td:first-child,\n.spreadsheet .spreadsheet-header table th:first-child,\n.spreadsheet .spreadsheet-body table th:first-child,\n.spreadsheet .spreadsheet-fixed table th:first-child {\n  border-left: 1px solid #e0e2e4;\n  text-align: center;\n}\n.spreadsheet-editor {\n  position: absolute;\n  text-align: left;\n  border: 2px solid #4b89ff;\n  line-height: 0;\n  z-index: 10;\n}\n.spreadsheet-editor textarea {\n  box-sizing: content-box;\n  border: none;\n  padding: 0 3px;\n  outline-width: 0;\n  resize: none;\n  text-align: start;\n  overflow-y: hidden;\n  font-family: inherit;\n  font-size: inherit;\n  color: inherit;\n  white-space: normal;\n  word-wrap: break-word;\n  line-height: 22px;\n  margin: 0;\n}\n.spreadsheet-suggest,\n.spreadsheet-contextmenu {\n  position: absolute;\n  box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);\n  background: #fff;\n  z-index: 100;\n}\n.spreadsheet-resizer {\n  position: absolute;\n  z-index: 11;\n}\n.spreadsheet-resizer.horizontal {\n  cursor: row-resize;\n}\n.spreadsheet-resizer.vertical {\n  cursor: col-resize;\n}\n.spreadsheet-resizer-line {\n  position: absolute;\n  z-index: 100;\n}\n.spreadsheet-resizer-line.horizontal {\n  border-bottom: 2px dashed #4b89ff;\n}\n.spreadsheet-resizer-line.vertical {\n  border-right: 2px dashed #4b89ff;\n}\n.spreadsheet-borders {\n  box-sizing: content-box;\n}\n.spreadsheet-borders.dashed {\n  border: 2px dashed #4b89ff;\n  position: absolute;\n  background: rgba(75, 137, 255, 0.03);\n}\n.spreadsheet-borders .left-border,\n.spreadsheet-borders .right-border,\n.spreadsheet-borders .bottom-border,\n.spreadsheet-borders .top-border,\n.spreadsheet-borders .area-border {\n  position: absolute;\n  font-size: 0;\n  pointer-events: none;\n  background: #4b89ff;\n}\n.spreadsheet-borders .area-border {\n  background: rgba(75, 137, 255, 0.03);\n}\n.spreadsheet-borders .corner {\n  cursor: crosshair;\n  font-size: 0;\n  height: 5px;\n  width: 5px;\n  border: 2px solid #ffffff;\n  position: absolute;\n  bottom: -6px;\n  right: -6px;\n  background: #4b89ff;\n}\n.spreadsheet-borders .copy-border {\n  position: absolute;\n  pointer-events: none;\n  border: 1px dashed #4b89ff;\n  background: rgba(75, 137, 255, 0.03);\n}\n.spreadsheet-paint-border {\n  position: absolute;\n  pointer-events: none;\n  border: 1px dashed #4b89ff;\n  background: rgba(75, 137, 255, 0.03);\n}\n.spreadsheet-bars .spreadsheet-toolbar {\n  height: 40px;\n  text-align: left;\n  padding: 0 60px;\n  border-bottom: 1px solid #e0e2e4;\n  background: #f5f6f7;\n}\n.spreadsheet-bars .spreadsheet-toolbar > .spreadsheet-menu > .spreadsheet-item {\n  margin: 7px 1px 0;\n}\n.spreadsheet-bars .spreadsheet-editor-bar {\n  width: 100%;\n  height: 26px;\n  line-height: 26px;\n  position: relative;\n  background: #fff;\n  padding: 0;\n}\n.spreadsheet-formula-bar {\n  position: relative;\n  height: 100%;\n}\n.spreadsheet-formula-bar .spreadsheet-formula-label {\n  width: 60px;\n  height: 100%;\n  box-sizing: border-box;\n  display: inline-block;\n  text-align: center;\n  border-right: 1px solid #e0e2e4;\n  background-color: #fff;\n  font-size: 12px;\n  color: #777;\n  user-select: none;\n  float: left;\n  vertical-align: middle;\n}\n.spreadsheet-formula-bar textarea {\n  width: calc(100% - 60px);\n  height: 100%;\n  box-sizing: border-box;\n  font-family: inherit;\n  font-size: inherit;\n  padding: 4px 10px;\n  position: relative;\n  float: left;\n  resize: none;\n  overflow-y: hidden;\n  border: none;\n  outline-width: 0;\n  margin: 0;\n  line-height: 1.2rem;\n}\n.spreadsheet-formula-bar-resizer {\n  cursor: ns-resize;\n  height: 4px;\n  position: absolute;\n  width: 100%;\n  left: 0;\n  bottom: 0;\n}\n.spreadsheet-menu.vertical > .spreadsheet-item-separator {\n  background: #e0e2e4;\n  height: 1px;\n  margin: 5px 0;\n}\n.spreadsheet-menu.vertical > .spreadsheet-item {\n  padding: 2px 10px;\n  border-radius: 0;\n}\n.spreadsheet-menu.horizontal > .spreadsheet-item {\n  display: inline-block;\n}\n.spreadsheet-menu.horizontal > .spreadsheet-item-separator {\n  display: inline-block;\n  background: #e0e2e4;\n  width: 1px;\n  vertical-align: middle;\n  height: 18px;\n  margin: 0 3px;\n}\n.spreadsheet-menu > .spreadsheet-item {\n  border-radius: 2px;\n  user-select: none;\n  background: 0;\n  border: 1px solid transparent;\n  outline: none;\n  height: 24px;\n  color: rgba(0, 0, 0, 0.8);\n  line-height: 24px;\n  list-style: none;\n  cursor: default;\n}\n.spreadsheet-menu > .spreadsheet-item.disabled {\n  pointer-events: none;\n  opacity: 0.5;\n}\n.spreadsheet-menu > .spreadsheet-item:not(.separator):hover,\n.spreadsheet-menu > .spreadsheet-item.active {\n  background: rgba(0, 0, 0, 0.08);\n}\n.spreadsheet-menu > .spreadsheet-item:not(.separator):hover .spreadsheet-icon-img,\n.spreadsheet-menu > .spreadsheet-item.active .spreadsheet-icon-img {\n  opacity: 0.7;\n}\n.spreadsheet-menu > .spreadsheet-item:not(.separator):hover .spreadsheet-dropdown-icon,\n.spreadsheet-menu > .spreadsheet-item.active .spreadsheet-dropdown-icon {\n  background-color: rgba(0, 0, 0, 0.15);\n  opacity: 0.6;\n}\n.spreadsheet-menu > .spreadsheet-item > .label {\n  float: right;\n  opacity: .8;\n}\n.spreadsheet-dropdown {\n  position: relative;\n  display: inline-block;\n  width: auto!important;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-content {\n  position: absolute;\n  top: calc(100% + 5px);\n  left: 0;\n  z-index: 200;\n  background: #fff;\n  box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);\n  width: auto;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-header .spreadsheet-dropdown-title {\n  padding: 0 5px;\n  display: inline-block;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-header .spreadsheet-dropdown-icon {\n  display: inline-block;\n  vertical-align: top;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-header .spreadsheet-dropdown-icon .spreadsheet-icon {\n  width: 10px;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-header .spreadsheet-dropdown-icon .spreadsheet-icon .arrow-down {\n  left: -130px;\n}\n.spreadsheet-color-panel {\n  padding: 10px;\n  width: 100%;\n}\n.spreadsheet-color-panel table {\n  border-collapse: separate;\n  border-spacing: 0;\n  border: none;\n}\n.spreadsheet-color-panel table tr td {\n  padding: 0;\n  border: none;\n}\n.spreadsheet-color-panel .color-cell {\n  width: 20px;\n  height: 20px;\n  margin: 3px;\n}\n.spreadsheet-color-panel .color-cell:hover {\n  box-shadow: 0 0 2px rgba(0, 0, 0, 0.8);\n}\n.spreadsheet-icon {\n  height: 18px;\n  width: 18px;\n  margin: 0px 4px 3px 3px;\n  direction: ltr;\n  text-align: left;\n  user-select: none;\n  vertical-align: middle;\n  overflow: hidden;\n  position: relative;\n  display: inline-block;\n}\n.spreadsheet-icon-img {\n  background-image: url("+i(s(21))+");\n  position: absolute;\n  width: 262px;\n  height: 444px;\n  opacity: 0.55;\n}\n.spreadsheet-icon-img.undo {\n  left: 0;\n  top: 0;\n}\n.spreadsheet-icon-img.redo {\n  left: -18px;\n  top: 0;\n}\n.spreadsheet-icon-img.print {\n  left: -36px;\n  top: 0;\n}\n.spreadsheet-icon-img.paintformat {\n  left: -54px;\n  top: 0;\n}\n.spreadsheet-icon-img.clearformat {\n  left: -72px;\n  top: 0;\n}\n.spreadsheet-icon-img.bold {\n  left: -90px;\n  top: 0;\n}\n.spreadsheet-icon-img.italic {\n  left: -108px;\n  top: 0;\n}\n.spreadsheet-icon-img.underline {\n  left: -126px;\n  top: 0;\n}\n.spreadsheet-icon-img.strikethrough {\n  left: -144px;\n  top: 0;\n}\n.spreadsheet-icon-img.text-color {\n  left: -162px;\n  top: 0;\n}\n.spreadsheet-icon-img.cell-color {\n  left: -180px;\n  top: 0;\n}\n.spreadsheet-icon-img.merge {\n  left: -198px;\n  top: 0;\n}\n.spreadsheet-icon-img.align-left {\n  left: -216px;\n  top: 0;\n}\n.spreadsheet-icon-img.align-center {\n  left: -234px;\n  top: 0;\n}\n.spreadsheet-icon-img.align-right {\n  left: 0;\n  top: -18px;\n}\n.spreadsheet-icon-img.valign-top {\n  left: -18px;\n  top: -18px;\n}\n.spreadsheet-icon-img.valign-middle {\n  left: -36px;\n  top: -18px;\n}\n.spreadsheet-icon-img.valign-bottom {\n  left: -54px;\n  top: -18px;\n}\n.spreadsheet-icon-img.textwrap {\n  left: -72px;\n  top: -18px;\n}\n.spreadsheet-icon-img.autofilter {\n  left: -90px;\n  top: -18px;\n}\n.spreadsheet-icon-img.formula {\n  left: -108px;\n  top: -18px;\n}\n.spreadsheet-icon-img.arrow-down {\n  left: -126px;\n  top: -18px;\n}\n.spreadsheet-icon-img.arrow-right {\n  left: -144px;\n  top: -18px;\n}\n",""])},function(e,t,s){var i=s(24);"string"==typeof i&&(i=[[e.i,i,""]]);var n={hmr:!0,transform:void 0,insertInto:void 0};s(20)(i,n);i.locals&&(e.exports=i.locals)},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});t.Select=class{constructor(e,t,s){this.start=e,this.stop=t,this.canMerge=s}forEach(e){const[t,s]=this.start,[i,n]=this.stop;for(let r=t;r<=i;r++)for(let o=s;o<=n;o++)e(r,o,r-t,o-s,i-t+1,n-s+1)}rowIndex(e){return this.start[0]+e%this.rowLen()}colIndex(e){return this.start[1]+e%this.colLen()}rowLen(){return this.stop[0]-this.start[0]+1}colLen(){return this.stop[1]-this.start[1]+1}cellLen(){return this.rowLen()*this.colLen()}contains(e,t){const[s,i]=this.start,[n,r]=this.stop;return s<=e&&n>=e&&i<=t&&r>=t}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.fonts=[{key:"Microsoft YaHei",title:"微软雅黑"},{key:"STFangsong",title:"华文仿宋"},{key:"Comic Sans MS",title:"Comic Sans MS"},{key:"Arial",title:"Arial"},{key:"Courier New",title:"Courier New"},{key:"Verdana",title:"Verdana"}]},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(8),n=s(27),r=s(7),o=s(5),l=s(6),h=s(26);class a{constructor(e){this.type=e,this.values=[]}add(e,t,s){this.values.push([e,t,s])}}t.History=a;t.Spreadsheet=class{constructor(e={}){if(this.histories=[],this.histories2=[],this.currentCellIndexes=[0,0],this.select=null,this.copySelect=null,this.cutSelect=null,this.change=(()=>{}),this.formats=e.formats||i.formats,this.fonts=e.fonts||n.fonts,this.formulas=e.formulas||r.formulas,this.data={rowHeight:22,colWidth:100,cell:o.defaultCell},e.data){const{data:t}=e;for(let e of["rowHeight","colWidth","rows","cols","cells"])t[e]&&(this.data[e]=t[e]);Object.assign(this.data.cell,t.cell||{})}}buildSelect(e,t){const s=f(e),i=f(t);let n=s.row,r=s.col,o=i.row,l=i.col;n>o&&(n=i.row,o=s.row),r>l&&(r=i.col,l=s.col);let[a,d]=g((e,t)=>this.getCell(e,t),n,o,r,l),[c,p]=b((e,t)=>this.getCell(e,t),a,d,r,l);for(;;){const[e,t]=g((e,t)=>this.getCell(e,t),a,d,c,p);let[s,i]=b((e,t)=>this.getCell(e,t),a,d,c,p);if(a===e&&d===t&&c===s&&p===i)break;a=e,d=t,c=s,p=i}const u=this.getCell(a,c);let m=a+(u&&u.rowspan||1)-1===d&&c+(u&&u.colspan||1)-1===p;return this.select=new h.Select([a,c],[d,p],!m),this.select}defaultRowHeight(){return this.data.rowHeight||22}defaultColWidth(){return this.data.colWidth||100}copy(){this.copySelect=this.select}cut(){this.cutSelect=this.select}paste(e,t,s){let i=this.copySelect;if(this.cutSelect&&(i=this.cutSelect,this.cutSelect=null),i&&this.select){const n=new a("cells");"copyformat"===t?this.select.forEach((r,o,l,h,a,d)=>{if(i){const a=i.rowIndex(l),d=i.colIndex(h),[c,p]=this.copyCell(a,d,r,o,t,e,s);n.add([r,o],c,p)}}):i.forEach((i,r,o,l,h,a)=>{if(this.select){const h=this.select.start[0]+o,a=this.select.start[1]+l,[d,c]=this.copyCell(i,r,h,a,t,e,s);n.add([h,a],d,c)}}),this.histories.push(n),this.change(this.data)}}insert(e,t,s){if(this.select){const{cells:t}=this.data,[i,n]=this.select.start;if(!t)return;const r=new a("cells");if("row"===e){const e={};Object.keys(t).forEach(n=>{let o=parseInt(n),l=t[o];i<=o&&Object.keys(l).forEach(e=>{let t=parseInt(e);s(o,t,{}),r.add([o,t],l[t],void 0),s(o+1,t,l[t]||{}),r.add([o+1,t],this.getCell(o+1,t),l[t])}),e[i<=o?o+1:o]=t[o]}),this.data.cells=e}else"col"===e&&Object.keys(t).forEach(e=>{let i=parseInt(e),o=t[i],l={};Object.keys(o).forEach(e=>{let t=parseInt(e);n<=t&&(s(i,t,{}),r.add([i,t],o[t],void 0),s(i,t+1,o[t]||{}),r.add([i,t+1],this.getCell(i,t+1),o[t])),l[n<=t?t+1:t]=o[t]}),t[i]=l});this.histories.push(r)}}batchPaste(e,t,s,i,n,r,o){if(this.select){const e=new a("cells");for(let l=t;l<=i;l++)for(let i=s;i<=n;i++){const n=this.select.rowIndex(l-t),h=this.select.colIndex(i-s),[a,d]=this.copyCell(n,h,l,i,r?"seqCopy":"copy",o,()=>{});e.add([l,i],a,d)}this.histories.push(e),this.change(this.data)}}copyCell(e,t,s,i,n,o,l){const h=this.getCell(e,t),a=s-e,d=i-t;if(h){let c=this.getCell(s,i);const p=Object.assign({},h);if(h.merge){const[e,t]=h.merge;p.merge=[e+a,t+d]}if("cut"===n&&l(e,t,this.cell(e,t,{})),"copyformat"===n)c&&c.text&&(p.text=c.text);else{const o=p.text;o&&!/^\s*$/.test(o)&&(/^\d*$/.test(o)&&"seqCopy"===n?p.text=parseInt(o)+(s-e)+(i-t)+"":-1!==o.indexOf("=")&&(p.text=r.formulaReplaceParam(o,a,d)))}return o(s,i,this.cell(s,i,p)),[c,p]}return[null,null]}isRedo(){return this.histories2.length>0}redo(e){const{histories:t,histories2:s}=this;if(s.length>0){const i=s.pop();i&&(this.resetByHistory(i,e,"redo"),t.push(i),this.change(this.data))}return this.isRedo()}isUndo(){return this.histories.length>0}undo(e){const{histories:t,histories2:s}=this;if(t.length>0){const i=t.pop();i&&(this.resetByHistory(i,e,"undo"),s.push(i),this.change(this.data))}return this.isUndo()}resetByHistory(e,t,s){e.values.forEach(([i,n,r])=>{if("cells"===e.type){const e="undo"===s?n:r,o=this.getCell(i[0],i[1]);if(o)if(3===i.length){const s={};s[i[2]]=e,t(i[0],i[1],e?this.cell(i[0],i[1],s,!0):this.cell(i[0],i[1],p(o,i[2])))}else t(i[0],i[1],this.cell(i[0],i[1],e||{}));else if(3===i.length){if(e){const s={};s[i[2]]=e,t(i[0],i[1],this.cell(i[0],i[1],s))}}else t(i[0],i[1],this.cell(i[0],i[1],e||{}))}})}clearformat(e){const{select:t}=this;if(null!==t){const s=new a("cells");t.forEach((t,i,n,r,o,l)=>{let h=this.getCell(t,i);h&&(s.add([t,i],h,{text:h.text}),h=this.cell(t,i,{text:h.text}),e(t,i,h))}),this.histories.push(s),this.change(this.data)}}merge(e,t,s){const{select:i}=this;if(null!==i&&i.cellLen()>1){const n=new a("cells");let r=0,o=[0,0];i.forEach((l,h,a,d,c,u)=>{if(0==r++){o=[l,h];let s={};if(c>1&&(s.rowspan=c),u>1&&(s.colspan=u),i.canMerge){n.add([l,h,"rowspan"],void 0,c),n.add([l,h,"colspan"],void 0,u);let t=this.cell(l,h,s,!0);e(l,h,t)}else{const e=this.getCell(l,h);if(null!==e){n.add([l,h,"rowspan"],e.rowspan,void 0),n.add([l,h,"colspan"],e.colspan,void 0);let s=this.cell(l,h,p(e,"rowspan","colspan","merge"));t(l,h,s)}}}else{let e={invisible:i.canMerge};if(i.canMerge){n.add([l,h,"invisible"],void 0,i.canMerge),e.merge=o;let t=this.cell(l,h,e,!0);s(l,h,t)}else{const e=this.getCell(l,h);if(null!==e){n.add([l,h,"invisible"],e.invisible,void 0);let t=this.cell(l,h,p(e,"rowspan","colspan","merge","invisible"));s(l,h,t)}}}}),this.histories.push(n),i.canMerge=!i.canMerge,this.change(this.data)}}cellAttr(e,t,s){let i={};i[e]=t;const n=t===this.data.cell[e];if(null!==this.select){const r=new a("cells");this.select.forEach((o,l)=>{const h=this.getCell(o,l);r.add([o,l,e],null!==h?h[e]:void 0,t);let a=this.cell(o,l,n?p(h,e):i,!n);s(o,l,a)}),this.histories.push(r)}this.change(this.data)}cellText(e,t){if(this.currentCellIndexes){const s=new a("cells"),[i,n]=this.currentCellIndexes,r=this.getCell(i,n);s.add([i,n,"text"],null!==r?r.text:void 0,e);const o=this.cell(i,n,{text:e},!0);return t(i,n,o),this.histories.push(s),this.change(this.data),o}return null}currentCell(e){void 0!==e&&(this.currentCellIndexes=e);const[t,s]=this.currentCellIndexes;return this.getCell(t,s)}cell(e,t,s,i=!1){return this.data.cells=this.data.cells||{},this.data.cells[e]=this.data.cells[e]||{},this.data.cells[e][t]=this.data.cells[e][t]||{},i?Object.assign(this.data.cells[e][t],s):s&&(this.data.cells[e][t]=s),this.data.cells[e][t]}getCell(e,t){return this.data.cells&&this.data.cells[e]&&this.data.cells[e][t]?this.data.cells[e][t]:null}getFont(e){return this.fonts.filter(t=>t.key===e)[0]}getFormat(e){return this.formats.filter(t=>t.key===e)[0]}row(e,t){const{data:s}=this;if(void 0!==t){const i=new a("rows");s.rows=s.rows||{},s.rows[e]=s.rows[e]||{},s.rows[e].height=t,i.add([e],null,s.rows[e]),this.histories.push(i)}return Object.assign({height:s.rowHeight},s.rows?s.rows[e]:{})}rows(e){const{data:t}=this;let s;return e?(s=10,this.data.cells&&(s=d(this.data.cells)+2)):s=c(100,t.rows),u(s,e=>this.row(e))}col(e,t){const{data:s}=this;if(void 0!==t){const i=new a("cols");s.cols=s.cols||{},s.cols[e]=s.cols[e]||{},s.cols[e].width=t,i.add([e],null,s.cols[e]),this.histories.push(i)}const i={width:s.colWidth,title:l.alphabet(e)};if(s.cols&&s.cols[e])for(let t in s.cols[e]){const n=s.cols[e];n[t]&&(i[t]=n[t])}return i}cols(){const{data:e}=this;let t=c(52,e.cols);return u(t,e=>this.col(e))}};const d=function(e){return Math.max(...Object.keys(e).map(e=>parseInt(e)))},c=function(e,t){if(t){const s=d(t);if(s>e)return s}return e},p=function(e,...t){const s={};return e&&Object.keys(e).forEach(i=>{-1===t.indexOf(i)&&(s[i]=e[i])}),s},u=function(e,t){const s=[];for(let i=0;i<e;i++)s.push(t(i));return s},f=e=>{const{offsetTop:t,offsetLeft:s,offsetHeight:i,offsetWidth:n}=e;return{row:parseInt(e.getAttribute("row-index")),col:parseInt(e.getAttribute("col-index")),rowspan:parseInt(e.getAttribute("rowspan")),colspan:parseInt(e.getAttribute("colspan")),left:s,top:t,width:n,height:i}},b=(e,t,s,i,n)=>{let r=i,o=n;for(let n=t;n<=s;n++){let t=i,s=e(n,t);s&&s.merge&&(t+=s.merge[1]-t),t<r&&(r=t);const l=(s=e(n,t=o))?s.colspan:1;if(parseInt(l)>1)t+=parseInt(l);else if(s&&s.merge){const[i,n]=s.merge;t+=e(i,n).colspan+(n-t)}t-1>o&&(o=t-1)}return[r,o]},g=(e,t,s,i,n)=>{let r=t,o=s;for(let s=i;s<=n;s++){let i=t,n=e(i,s);n&&n.merge&&(i+=n.merge[0]-i),i<r&&(r=i);const l=(n=e(i=o,s))?n.rowspan:1;if(parseInt(l)>1)i+=parseInt(l);else if(n&&n.merge){const[t,s]=n.merge;i+=e(t,s).rowspan+(t-i)}i-1>o&&(o=i-1)}return[r,o]}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(28);s(25);const n=s(18),r=s(12),o=s(9),l=s(0);t.LocalSpreadsheet=class{constructor(e,t={}){this.refs={},this.toolbar=null,this.editorbar=null,this._change=(()=>{}),this.bindEl=e,this.options=Object.assign({mode:"design"},t),this.bindEl&&(this.bindEl.innerHTML=""),this.ss=new i.Spreadsheet(t),"design"===this.options.mode&&(this.editorbar=new o.Editorbar,this.editorbar.change=(e=>this.editorbarChange(e)),this.toolbar=new r.Toolbar(this.ss),this.toolbar.change=((e,t)=>this.toolbarChange(e,t)),this.toolbar.undo=(()=>this.table.undo()),this.toolbar.redo=(()=>this.table.redo())),this.table=new n.Table(this.ss,Object.assign({height:()=>this.options.height?this.options.height():document.documentElement.clientHeight-24-41-26,width:()=>this.bindEl.offsetWidth,mode:this.options.mode})),this.table.change=(e=>{this.toolbar&&this.toolbar.setRedoAble(this.ss.isRedo()),this.toolbar&&this.toolbar.setUndoAble(this.ss.isUndo()),this._change(e)}),this.table.editorChange=(e=>this.editorChange(e)),this.table.clickCell=((e,t,s)=>this.clickCell(e,t,s)),this.render()}loadData(e){return setTimeout(()=>{this.ss.data=e,this.table.reload()},1),this}change(e){return this._change=e,this}render(){this.bindEl.appendChild(l.h().class("spreadsheet").children([l.h().class("spreadsheet-bars").children([this.toolbar&&this.toolbar.el||"",this.editorbar&&this.editorbar.el||""]),this.table.el]).el)}toolbarChange(e,t){"merge"!==e?"clearformat"!==e?"paintformat"!==e?this.table.setCellAttr(e,t):this.table.copyformat():this.table.clearformat():this.table.merge()}editorbarChange(e){this.table.setValueWithText(e)}editorChange(e){this.editorbar&&this.editorbar.setValue(e)}clickCell(e,t,s){const i=this.ss.cols();this.editorbar&&this.editorbar.set(`${i[t].title}${e+1}`,s),this.toolbar&&this.toolbar.set(this.table.td(e,t),s)}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(29);function n(e,t){return new i.LocalSpreadsheet(e,t)}t.default=n,window.xspreadsheet=n}]);
//# sourceMappingURL=xspreadsheet.js.map

================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel="stylesheet" type="text/css" href="spreadsheet.css"></link>
    <script type="text/javascript" src="bundle.js"></script>
    <script type="text/javascript">
      window.onload = function () {
        var data = {"rowHeight":22,"colWidth":100,"rows":{"1":{"height":35},"3":{"height":40},"4":{"height":53},"5":{"height":57}},"cols":{"0":{"width":74,"title":null},"2":{"width":79,"title":null},"3":{"width":75,"title":null},"5":{"width":58,"title":null},"6":{"width":59,"title":null},"8":{"width":89,"title":null},"9":{"width":80,"title":null},"10":{"width":53,"title":null},"11":{"width":54,"title":null},"12":{"width":51,"title":null},"13":{"width":52,"title":null},"14":{"width":53,"title":null},"15":{"width":52,"title":null},"16":{"width":51,"title":null},"17":{"width":52,"title":null}},"cell":{"font":"Microsoft YaHei","format":"normal","fontSize":14,"bold":false,"italic":false,"underline":false,"color":"#333","backgroundColor":"#fff","align":"left","valign":"middle","wordWrap":false,"invisible":false,"rowspan":1,"colspan":1,"text":""},"cells":{"1":{"2":{"colspan":19,"text":"2019-2021年中期财政规划(高速公路)","bold":true,"fontSize":16,"align":"center"},"3":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"4":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"5":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"6":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"7":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"8":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"9":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"10":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"11":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"12":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"13":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"14":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"15":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"16":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"17":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"18":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"19":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"20":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"}},"3":{"0":{"rowspan":3,"text":"序号","align":"center"},"1":{"rowspan":3,"text":"单位名称","align":"center"},"2":{"colspan":2,"text":"项目所在地区","align":"center"},"3":{"invisible":true,"merge":[3,2],"align":"center"},"4":{"rowspan":3,"text":"项 目 名 称","align":"center"},"5":{"rowspan":3,"text":"项目所属集中连片特困地区","align":"center","wordWrap":true},"6":{"rowspan":3,"text":"项目所属革命老区","align":"center","wordWrap":true},"7":{"rowspan":3,"text":"贫困县类别(国贫、省贫、一般)","align":"center","wordWrap":true},"8":{"rowspan":3,"text":"线路性质","align":"center","wordWrap":true},"9":{"rowspan":3,"text":"建设性质","align":"center","wordWrap":true},"10":{"colspan":8,"text":"建设规模(公里)/(延米)","align":"center"},"11":{"invisible":true,"merge":[3,10],"align":"center"},"12":{"invisible":true,"merge":[3,10],"align":"center"},"13":{"invisible":true,"merge":[3,10],"align":"center"},"14":{"invisible":true,"merge":[3,10],"align":"center"},"15":{"invisible":true,"merge":[3,10],"align":"center"},"16":{"invisible":true,"merge":[3,10],"align":"center"},"17":{"invisible":true,"merge":[3,10],"align":"center"},"18":{"colspan":2,"text":"建设年限","align":"center"},"19":{"invisible":true,"merge":[3,18],"align":"center"}},"4":{"0":{"invisible":true,"merge":[3,0],"align":"center"},"1":{"invisible":true,"merge":[3,1],"align":"center"},"2":{"rowspan":2,"text":"市","align":"center"},"3":{"rowspan":2,"text":"县区","align":"center"},"4":{"invisible":true,"merge":[3,4],"align":"center"},"5":{"invisible":true,"merge":[3,5],"align":"center","wordWrap":true},"6":{"invisible":true,"merge":[3,6],"align":"center","wordWrap":true},"7":{"invisible":true,"merge":[3,7],"align":"center","wordWrap":true},"8":{"invisible":true,"merge":[3,8],"align":"center","wordWrap":true},"9":{"invisible":true,"merge":[3,9],"align":"center","wordWrap":true},"10":{"rowspan":2,"text":"合计","align":"center"},"11":{"rowspan":2,"text":"高速\n公路","align":"center","wordWrap":true},"12":{"rowspan":2,"text":"一级\n公路","align":"center","wordWrap":true},"13":{"rowspan":2,"text":"二级\n公路","align":"center","wordWrap":true},"14":{"rowspan":2,"text":"三级\n公路","align":"center","wordWrap":true},"15":{"rowspan":2,"text":"四级\n公路","align":"center","wordWrap":true},"16":{"rowspan":2,"text":"独立\n大桥","align":"center","wordWrap":true},"17":{"rowspan":2,"text":"独立\n隧道","align":"center","wordWrap":true},"18":{"rowspan":2,"text":"开工年","align":"center"},"19":{"rowspan":2,"text":"完工年","align":"center"}},"5":{"0":{"invisible":true,"merge":[3,0],"align":"center"},"1":{"invisible":true,"merge":[3,1],"align":"center"},"2":{"invisible":true,"merge":[4,2],"align":"center"},"3":{"invisible":true,"merge":[4,3],"align":"center"},"4":{"invisible":true,"merge":[3,4],"align":"center"},"5":{"invisible":true,"merge":[3,5],"align":"center","wordWrap":true},"6":{"invisible":true,"merge":[3,6],"align":"center","wordWrap":true},"7":{"invisible":true,"merge":[3,7],"align":"center","wordWrap":true},"8":{"invisible":true,"merge":[3,8],"align":"center","wordWrap":true},"9":{"invisible":true,"merge":[3,9],"align":"center","wordWrap":true},"10":{"invisible":true,"merge":[4,10],"align":"center"},"11":{"invisible":true,"merge":[4,11],"align":"center","wordWrap":true},"12":{"invisible":true,"merge":[4,12],"align":"center","wordWrap":true},"13":{"invisible":true,"merge":[4,13],"align":"center","wordWrap":true},"14":{"invisible":true,"merge":[4,14],"align":"center","wordWrap":true},"15":{"invisible":true,"merge":[4,15],"align":"center","wordWrap":true},"16":{"invisible":true,"merge":[4,16],"align":"center","wordWrap":true},"17":{"invisible":true,"merge":[4,17],"align":"center","wordWrap":true},"18":{"invisible":true,"merge":[4,18],"align":"center"},"19":{"invisible":true,"merge":[4,19],"align":"center"}}}};
        xspreadsheet(document.getElementById('wrapper'), {mode: 'design'}).loadData(data)
      }
    </script> 
    <title>TypeScript with VSCode</title>
  </head>
  <body>
      <div style="display: flex;">
        <div style="width: 300px; flex: 0 0 auto;">
          xxxxxx
        </div>
        <div style="flex: 1 1 auto;overflow: hidden;">
          <div id="wrapper"></div>  
        </div>
      </div>

  </body>
</html>


================================================
FILE: package.json
================================================
{
  "name": "xspreadsheet",
  "version": "1.0.4",
  "description": "a javascript spreadsheet",
  "author": "myliang <liangyuliang0335@126.com>",
  "private": false,
  "main": "src/main.ts",
  "types": "src/main.d.ts",
  "repository": {
    "type": "git",
    "url": "https://github.com/myliang/spreadsheet.git"
  },
  "scripts": {
    "dev": "webpack-dev-server --color --inline --hot --config webpack.config.dev.js --open",
    "build": "webpack --config webpack.config.js --progress --color"
  },
  "keywords": [
    "excel",
    "js",
    "component",
    "ui",
    "spreadsheet"
  ],
  "license": "MIT",
  "devDependencies": {
    "awesome-typescript-loader": "^5.2.0",
    "css-loader": "^0.28.11",
    "extract-text-webpack-plugin": "^4.0.0-beta.0",
    "file-loader": "^1.1.11",
    "less": "^3.0.1",
    "less-loader": "^4.1.0",
    "source-map-loader": "^0.2.3",
    "style-loader": "^0.20.3",
    "tslint-eslint-rules": "^5.2.0",
    "typescript": "^2.9.2",
    "webpack": "^4.5.0",
    "webpack-cli": "^2.0.14",
    "webpack-dev-server": "^3.1.3"
  }
}


================================================
FILE: src/core/alphabet.d.ts
================================================
export declare function alphabet(index: number): string;
export declare function alphabetIndex(key: string): number;


================================================
FILE: src/core/alphabet.ts
================================================
const _alphabet = ['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']
export function alphabet(index: number): string {
  const [a, b] = [parseInt(index / _alphabet.length + ''), index % _alphabet.length]
  // console.log('a: ', a, '; b: ', b)
  return a > 0 ? `${_alphabet[a - 1]}${_alphabet[b]}` : _alphabet[b]
}

export function alphabetIndex (key: string): number {
  let ret = 0;
  for (let i = 0; i < key.length; i++) {
    // console.log(key.charCodeAt(i), key[i])
    let cindex = key.charCodeAt(i) - 65;
    ret += i * _alphabet.length + cindex;
  }
  return ret;
}


================================================
FILE: src/core/cell.d.ts
================================================
export interface Cell {
    font?: string;
    format?: string;
    fontSize?: number;
    bold?: boolean;
    italic?: boolean;
    underline?: boolean;
    color?: string;
    backgroundColor?: string;
    align?: string;
    valign?: string;
    wordWrap?: boolean;
    visable?: boolean;
    rowspan?: number;
    colspan?: number;
    text?: string;
    merge?: [number, number];
    [key: string]: any;
}
export declare const defaultCell: Cell;
export declare function getStyleFromCell(cell: Cell | null): {
    [key: string]: string;
};


================================================
FILE: src/core/cell.ts
================================================
export interface Cell {
  font?: string;
  format?: string;
  fontSize?: number;
  bold?: boolean;
  italic?: boolean;
  underline?: boolean;
  color?: string;
  backgroundColor?: string;
  align?: string;
  valign?: string;
  wordWrap?: boolean;
  visable?: boolean;
  rowspan?: number;
  colspan?: number;
  text?: string;
  merge?: [number, number];
  [key: string]: any
}

export const defaultCell: Cell = {
  font: 'Microsoft YaHei',
  format: 'normal',
  fontSize: 14,
  bold: false,
  italic: false,
  underline: false,
  color: '#333',
  backgroundColor: '#fff',
  align: 'left',
  valign: 'middle',
  wordWrap: false,
  invisible: false,
  rowspan: 1,
  colspan: 1,
  text: '',

}

export function getStyleFromCell (cell: Cell | null): {[key: string]: string} {
  const map: {[key: string]: string} = {}
  if (cell) {
    if (cell.font) map['font-family'] = cell.font
    if (cell.fontSize) map['font-size'] = `${cell.fontSize}px`
    if (cell.bold) map['font-weight'] = 'bold'
    if (cell.italic) map['font-style'] = 'italic'
    if (cell.underline) map['text-decoration'] = 'underline'
    if (cell.color) map['color'] = cell.color
    if (cell.backgroundColor) map['background-color'] = cell.backgroundColor
    if (cell.align) map['text-align'] = cell.align
    if (cell.valign) map['vertical-align'] = cell.valign
    if (cell.invisible) {
      map['display'] = 'none'
    }
    if (cell.wordWrap) {
      map['word-wrap'] = 'break-word'
      map['white-space'] = 'normal'
    }
  }
  return map
}


================================================
FILE: src/core/font.d.ts
================================================
export interface Font {
    key: string;
    title: string;
}
export declare const fonts: Array<Font>;


================================================
FILE: src/core/font.ts
================================================
export interface Font {
  key: string;
  title: string;
}

export const fonts: Array<Font> = [
  {key: 'Microsoft YaHei', title: '微软雅黑'},
  {key: 'STFangsong', title: '华文仿宋'},
  {key: 'Comic Sans MS', title: 'Comic Sans MS'},
  {key: 'Arial', title: 'Arial'},
  {key: 'Courier New', title: 'Courier New'},
  {key: 'Verdana', title: 'Verdana'}
]

================================================
FILE: src/core/format.d.ts
================================================
export interface Format {
    key: string;
    title: string;
    label?: string;
    render(txt: string): string;
}
export declare const formatRenderHtml: (key: string | undefined, txt: string | undefined) => string;
export declare const formats: Array<Format>;


================================================
FILE: src/core/format.ts
================================================
export interface Format {
  key: string;
  title: string;
  label?: string;
  render(txt: string): string;
}
export const formatRenderHtml = (key: string | undefined, txt: string | undefined) => {
  for (let i = 0; i < formats.length; i++) {
    if (formats[i].key === key) {
      return formats[i].render(txt || '')
    }
  }
  return txt || ''
}

const formatNumberRender = (v: string) => {
  if (/^(-?\d*.?\d*)$/.test(v)) {
    v = Number(v).toFixed(2).toString()
    const parts = v.split('.')
    parts[0] = parts[0].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + ',')
    return parts.join('.')
  }
  return v
}

const formatRender = (v: string) => v

export const formats: Array<Format> = [
  {key: 'normal', title: 'Normal', render: formatRender},
  {key: 'text', title: 'Text', render: formatRender},
  {key: 'number', title: 'Number', label: '1,000.12', render: formatNumberRender},
  {key: 'percent', title: 'Percent', label: '10.12%', render: (v) => `${formatNumberRender(v)}%`},
  {key: 'RMB', title: 'RMB', label: '¥10.00', render: (v) => `¥${formatNumberRender(v)}`},
  {key: 'USD', title: 'USD', label: '$10.00', render: (v) => `$${formatNumberRender(v)}`}
]

================================================
FILE: src/core/formula.d.ts
================================================
export interface Formula {
    key: string;
    title: string;
    render(ary: Array<number>): number;
}
export declare const formulaFilterKey: (v: string, filter: (formula: Formula, param: string) => string) => string;
export declare const formulaRender: (v: string, renderCell: (rindex: number, cindex: number) => any) => string;
export declare const formulaReplaceParam: (param: string, rowDiff: number, colDiff: number) => string;
export declare const formulas: Array<Formula>;


================================================
FILE: src/core/formula.ts
================================================
import { alphabetIndex, alphabet } from "./alphabet";

export interface Formula {
  key: string;
  title: string;
  render(ary: Array<number>): number
}

export const formulaFilterKey = (v: string, filter: (formula: Formula, param: string) => string) => {
  if (v[0] === '=') {
    const fx = v.substring(1, v.indexOf('('))
    for (let formula of formulas) {
      if (formula.key.toLowerCase() === fx.toLowerCase()) {
        return filter(formula, v.substring(v.indexOf('(') + 1, v.lastIndexOf(')')))
      }
    }
  }
  return v
}

export const formulaRender = (v: string, renderCell: (rindex: number, cindex: number) => any) => {
  return formulaFilterKey(v, (fx, param) => {
    return fx.render(formulaParamToArray(param, renderCell)) + '';
  })
}

export const formulaReplaceParam = (param: string, rowDiff: number, colDiff: number): string => {
  return formulaFilterKey(param, (fx, params) => {
    const replaceFormula = (_v: string):string => {
      if (/^[0-9\-\+\*\/()\s]+$/.test(_v.trim())) {
        return _v
      }
      const idx = /\d+/.exec(_v)
      if (idx) {
        let vc = _v.substring(0, idx.index).trim()
        let vr = parseInt(_v.substring(idx.index).trim())
        return `${alphabet(alphabetIndex(vc) + colDiff)}${vr + rowDiff}`
      }
      return _v;
    }

    if (params.indexOf(':') !== -1) {
      params = params.split(':').map(replaceFormula).join(':')
    } else {
      params = params.split(',').map(replaceFormula).join(',')
    }
    return `=${fx.key}(${params})`
  })
}

const formulaParamToArray = (param: string, renderCell: (rindex: number, cindex: number) => any) => {
  let paramValues = []
  try {
    if (param.indexOf(':') !== -1) {
      const [min, max] = param.split(':');
      const idx = /\d+/.exec(min);
      const maxIdx = /\d+/.exec(max);
      if (idx && maxIdx) {
        // idx = idx.index;
        // maxIdx = maxIdx.index;
        let minC = min.substring(0, idx.index).trim()
        let minR = parseInt(min.substring(idx.index).trim())

        let maxC = max.substring(0, maxIdx.index).trim()
        let maxR = parseInt(max.substring(maxIdx.index).trim())
        // console.log(min, max, minR, maxR, minC, maxC)
        if (maxC === minC) {
          for (let i = minR; i <= maxR; i++) {
            // console.log('value:::', i-1, alphabetIndex(minC), renderCell(i - 1, alphabetIndex(minC)))
            paramValues.push(renderCell(i - 1, alphabetIndex(minC)))
          }
        } else {
          for (let i = alphabetIndex(minC); i <= alphabetIndex(maxC); i++) {
            paramValues.push(renderCell(minR - 1, i))
          }
        }
      }
    } else {
      paramValues = param.split(',').map(p => {
        // console.log(/^[0-9\-\+\*\/() ]+$/.test(p), p)
        if (/^[0-9\-\+\*\/()\s]+$/.test(p.trim())) {
          try {
            return eval(p)
          } catch (e) {
            return 0
          }
        }
        const idx = /\d+/.exec(p)
        if (idx) {
          const c = p.substring(0, idx.index).trim()
          const r = p.substring(idx.index).trim()
          return renderCell(parseInt(r) - 1, alphabetIndex(c))
        }
        return 0
      })
    }
  } catch (e) {
    console.log('warning:', e)
  }
  return paramValues;
}

export const formulas: Array<Formula> = [
  {key: 'SUM', title: '求和', render: (vv) => vv.reduce((a, b) => Number(a) + Number(b), 0)},
  {key: 'AVERAGE', title: '平均值', render: (vv) => vv.reduce((a, b) => Number(a) + Number(b), 0) / vv.length},
  {key: 'MAX', title: '最大值', render: (vv) => Math.max(...vv.map(v => Number(v)))},
  {key: 'MIN', title: '最小值', render: (vv) => Math.min(...vv.map(v => Number(v)))}
]

================================================
FILE: src/core/index.d.ts
================================================
import { Format } from './format';
import { Font } from './font';
import { Formula } from './formula';
import { Cell } from './cell';
import { Select } from './select';
export interface Row {
    height: number;
}
export interface Col {
    title: string;
    width: number;
}
export interface MapInt<T> {
    [key: number]: T;
}
export declare class History {
    type: 'rows' | 'cols' | 'cells';
    values: Array<[Array<any>, any, any]>;
    constructor(type: 'rows' | 'cols' | 'cells');
    add(keys: Array<any>, oldValue: any, value: any): void;
}
export declare type StandardCallback = (rindex: number, cindex: number, cell: Cell) => void;
export interface SpreadsheetData {
    rowHeight?: number;
    colWidth?: number;
    rows?: MapInt<Row>;
    cols?: MapInt<Col>;
    cell: Cell;
    cells?: MapInt<MapInt<Cell>>;
    [prop: string]: any;
}
export interface SpreadsheetOptions {
    formats?: Array<Format>;
    fonts?: Array<Font>;
    formulas?: Array<Formula>;
    data?: SpreadsheetData;
}
export declare class Spreadsheet {
    formats: Array<Format>;
    fonts: Array<Font>;
    formulas: Array<Formula>;
    data: SpreadsheetData;
    private histories;
    private histories2;
    private currentCellIndexes;
    select: Select | null;
    private copySelect;
    private cutSelect;
    change: (data: SpreadsheetData) => void;
    constructor(options?: SpreadsheetOptions);
    buildSelect(startTarget: any, endTarget: any): Select;
    defaultRowHeight(): number;
    defaultColWidth(): number;
    copy(): void;
    cut(): void;
    paste(cb: StandardCallback, state: 'copy' | 'cut' | 'copyformat', clear: StandardCallback): void;
    insert(type: 'row' | 'col', amount: number, cb: StandardCallback): void;
    batchPaste(arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number, seqCopy: boolean, cb: StandardCallback): void;
    private copyCell;
    isRedo(): boolean;
    redo(cb: StandardCallback): boolean;
    isUndo(): boolean;
    undo(cb: StandardCallback): boolean;
    resetByHistory(v: History, cb: StandardCallback, state: 'undo' | 'redo'): void;
    clearformat(cb: StandardCallback): void;
    merge(ok: StandardCallback, cancel: StandardCallback, other: StandardCallback): void;
    cellAttr(key: keyof Cell, value: any, cb: StandardCallback): void;
    cellText(value: any, cb: StandardCallback): Cell | null;
    currentCell(indexes?: [number, number]): Cell | null;
    cell(rindex: number, cindex: number, v: any, isCopy?: boolean): Cell;
    getCell(rindex: number, cindex: number): Cell | null;
    getFont(key: string | undefined): Font;
    getFormat(key: string | undefined): Format;
    row(index: number, v?: number): Row;
    rows(isData: boolean): Array<Row>;
    col(index: number, v?: number): Col;
    cols(): Array<Col>;
}


================================================
FILE: src/core/index.ts
================================================
import { Format, formats } from './format'
import { Font, fonts } from './font'
import { Formula, formulas, formulaReplaceParam } from './formula'
import { Cell, defaultCell } from './cell'
import { alphabet } from './alphabet'
import { Select } from './select'
import { unbind } from '../local/event';

export interface Row {
  height: number
}
export interface Col {
  title: string
  width: number
}
export interface MapInt<T> {
  [key: number]: T
}
export class History {
  values: Array<[Array<any>, any, any]> = [];
  constructor (public type: 'rows' | 'cols' | 'cells') {}
  add (keys: Array<any>, oldValue: any, value: any) {
    this.values.push([keys, oldValue, value])
  }
}
// types
export type StandardCallback = (rindex: number, cindex: number, cell: Cell) => void;

export interface SpreadsheetData {
  rowHeight?: number;
  colWidth?: number;
  rows?: MapInt<Row>;
  cols?: MapInt<Col>;
  cell: Cell; // global default cell
  cells?: MapInt<MapInt<Cell>>;
  [prop: string]: any
}

export interface SpreadsheetOptions {
  formats?: Array<Format>;
  fonts?: Array<Font>;
  formulas?: Array<Formula>;
  data?: SpreadsheetData;
}

export class Spreadsheet {
  formats: Array<Format>;
  fonts: Array<Font>;
  formulas: Array<Formula>;
  data: SpreadsheetData;
  private histories: Array<History> = [];
  private histories2: Array<History> = [];
  private currentCellIndexes: [number, number] = [0, 0];
  select: Select | null = null;
  private copySelect: Select | null = null;
  private cutSelect: Select | null = null;

  change: (data: SpreadsheetData) => void = () => {}

  constructor (options: SpreadsheetOptions = {}) {
    this.formats = options.formats || formats
    this.fonts = options.fonts || fonts
    this.formulas = options.formulas || formulas
    // init data
    this.data = {rowHeight: 22, colWidth: 100, cell: defaultCell}
    if (options.data) {
      const { data } = options;
      for (let prop of ['rowHeight', 'colWidth', 'rows', 'cols', 'cells']) {
        if (data[prop]) {
          this.data[prop] = data[prop];
        }
      }
      (<any>Object).assign(this.data.cell, data.cell || {});
    }
  }

  // build select
  buildSelect (startTarget: any, endTarget: any) {
    const startAttrs = getElementAttrs(startTarget)
    const endAttrs = getElementAttrs(endTarget)
    // console.log(':::::::>>>', startAttrs, endAttrs)
    let sRow = startAttrs.row
    let sCol = startAttrs.col
    let eRow = endAttrs.row
    let eCol = endAttrs.col
    if (sRow > eRow) {
      sRow = endAttrs.row
      eRow = startAttrs.row
    }
    if (sCol > eCol) {
      sCol = endAttrs.col
      eCol = startAttrs.col
    }
    // calc min, max of row
    // console.log('s: ', sRow, sCol, ', e: ', eRow, eCol)
    let [minRow, maxRow] = calcMinMaxRow((r: number, c: number) => this.getCell(r, c), sRow, eRow, sCol, eCol)
    // console.log('minRow: ', minRow, ', maxRow: ', maxRow)
    // calc min, max of col
    let [minCol, maxCol] = calcMinMaxCol((r: number, c: number) => this.getCell(r, c), minRow, maxRow, sCol, eCol)
    while (true) {
      const [minr, maxr] = calcMinMaxRow((r: number, c: number) => this.getCell(r, c), minRow, maxRow, minCol, maxCol)
      let [minc, maxc] = calcMinMaxCol((r: number, c: number) => this.getCell(r, c), minRow, maxRow, minCol, maxCol)
      if (minRow === minr && maxRow === maxr && minCol === minc && maxCol === maxc) {
        break
      }
      minRow = minr
      maxRow = maxr
      minCol = minc
      maxCol = maxc
    }
    const firstCell = this.getCell(minRow, minCol)
    // console.log('first => rowspan: ', firstCell.rowspan, ', colspan: ', firstCell.colspan)
    let canotMerge = minRow + (firstCell && firstCell.rowspan || 1) - 1 === maxRow && minCol + (firstCell && firstCell.colspan || 1) - 1 === maxCol
    // console.log('row: ', minRow, maxRow, ', col:', minCol, maxCol, canotMerge)
    // 计算是否可以merge
    this.select = new Select([minRow, minCol], [maxRow, maxCol], !canotMerge)
    return this.select
  }

  defaultRowHeight (): number {
    return this.data.rowHeight || 22
  }

  defaultColWidth (): number {
    return this.data.colWidth || 100
  }

  copy (): void {
    this.copySelect = this.select
  }
  cut (): void {
    this.cutSelect = this.select
  }
  paste (cb: StandardCallback, state: 'copy' | 'cut' | 'copyformat', clear: StandardCallback): void {
    let cselect = this.copySelect
    if (this.cutSelect) {
      cselect = this.cutSelect
      this.cutSelect = null
    }
    if (cselect && this.select) {
      const history = new History('cells')
      if (state === 'copyformat') {
        this.select.forEach((rindex, cindex, i, j, rowspan, colspan) => {
          if (cselect) {
            const srcRowIndex = cselect.rowIndex(i)
            const srcColIndex = cselect.colIndex(j)
            const [oldCell, newCell] = this.copyCell(srcRowIndex, srcColIndex, rindex, cindex, state, cb, clear)
            history.add([rindex, cindex], oldCell, newCell)
          }
        })
      } else {
        cselect.forEach((rindex, cindex, i, j, rowspan, colspan) => {
          if (this.select) {
            const destRowIndex = this.select.start[0] + i
            const destColIndex = this.select.start[1] + j
            const [oldCell, newCell] = this.copyCell(rindex, cindex, destRowIndex, destColIndex, state, cb, clear)
            history.add([destRowIndex, destColIndex], oldCell, newCell)
          }
        })
      }
      this.histories.push(history)
      this.change(this.data)
    }
  }
  insert (type: 'row' | 'col', amount: number, cb: StandardCallback) {
    if (this.select) {
      const { cells } = this.data
      const [srindex, scindex] = this.select.start
      if (!cells) return

      // console.log('insert.before.data:', cells)
      const history = new History('cells')
      if (type === 'row') {
        const newCells: MapInt<MapInt<Cell>> = {}
        Object.keys(cells).forEach(key => {
          let rindex = parseInt(key)
          let values = cells[rindex]
          if (srindex <= rindex) {
            Object.keys(values).forEach(key1 => {
              let cindex = parseInt(key1)
              // clear current cell
              cb(rindex, cindex, {})
              history.add([rindex, cindex], values[cindex], undefined)
            
              // set next cell is current celll
              cb(rindex + 1, cindex, values[cindex] || {})
              history.add([rindex + 1, cindex], this.getCell(rindex + 1, cindex), values[cindex])
            })
          }
          newCells[srindex <= rindex ? rindex + 1 : rindex] = cells[rindex]
        })
        this.data.cells = newCells
      } else if (type === 'col') {
        Object.keys(cells).forEach(key => {
          let rindex = parseInt(key)
          let values = cells[rindex]
          let newCell: MapInt<Cell> = {}
          Object.keys(values).forEach(key1 => {
            let cindex = parseInt(key1)
            if (scindex <= cindex) {
              // clear 当前cell
              cb(rindex, cindex, {})
              history.add([rindex, cindex], values[cindex], undefined)
            
              // 设置下一个cell 等于当前的cell
              cb(rindex, cindex + 1, values[cindex] || {})
              history.add([rindex, cindex + 1], this.getCell(rindex, cindex + 1), values[cindex])
            }
            newCell[scindex <= cindex ? cindex + 1 : cindex] = values[cindex]
          })
          cells[rindex] = newCell
        })
      }
      this.histories.push(history)
      // console.log('insert.after.data:', this.data.cells)
    } 
  }

  batchPaste (arrow: 'bottom' | 'top' | 'left' | 'right',
    startRow: number, startCol: number, stopRow: number, stopCol: number,
    seqCopy: boolean,
    cb: StandardCallback) {
    if (this.select) {
      const history = new History('cells')
      for (let i = startRow; i <= stopRow; i++) {
        for (let j = startCol; j <= stopCol; j++) {
          const srcRowIndex = this.select.rowIndex(i - startRow)
          const srcColIndex = this.select.colIndex(j - startCol)
          const [oldDestCell, destCell] = this.copyCell(srcRowIndex, srcColIndex, i, j, seqCopy ? 'seqCopy' : 'copy', cb, () => {})
          history.add([i, j], oldDestCell, destCell)
        }
      }
      this.histories.push(history)
      this.change(this.data)
    }
  }
  private copyCell (srcRowIndex: number, srcColIndex: number, destRowIndex: number, destColIndex: number,
    state: 'seqCopy' | 'copy' | 'cut' | 'copyformat', cb: StandardCallback, clear: StandardCallback): [Cell | null, Cell | null] {
    const srcCell = this.getCell(srcRowIndex, srcColIndex)
    const rowDiff = destRowIndex - srcRowIndex
    const colDiff = destColIndex - srcColIndex
    if (srcCell) {
      let oldDestCell = this.getCell(destRowIndex, destColIndex)
      // let destCell = cellCopy(srcCell, destRowIndex - srcRowIndex, destColIndex - srcColIndex, state === 'seqCopy')
      const destCell = Object.assign({}, srcCell)
      if (srcCell.merge) {
        const [m1, m2] = srcCell.merge
        destCell.merge = [m1 + rowDiff, m2 + colDiff];
      }
      

      if (state === 'cut') {
        clear(srcRowIndex, srcColIndex, this.cell(srcRowIndex, srcColIndex, {}))
      }
      if (state === 'copyformat') {
        if (oldDestCell && oldDestCell.text) {
          destCell.text = oldDestCell.text
        }
      } else {
        const txt = destCell.text
        if (txt && !/^\s*$/.test(txt)) {
          if (/^\d*$/.test(txt) && state === 'seqCopy') {
            destCell.text = (parseInt(txt) + (destRowIndex - srcRowIndex) + (destColIndex - srcColIndex)) + ''
          } else if (txt.indexOf('=') !== -1) {
            // 如果text的内容是formula,那么需要需要修改表达式参数
            destCell.text = formulaReplaceParam(txt, rowDiff, colDiff)
          }
        }
      }

      cb(destRowIndex, destColIndex, this.cell(destRowIndex, destColIndex, destCell))
      return [oldDestCell, destCell];
    }
    return [null, null];
  }

  isRedo (): boolean {
    return this.histories2.length > 0
  }
  redo (cb: StandardCallback): boolean {
    const { histories, histories2 } = this
    if (histories2.length > 0) {
      const history = histories2.pop()
      if (history) {
        this.resetByHistory(history, cb, 'redo')
        histories.push(history)
        this.change(this.data)
      }
    }
    return this.isRedo()
  }

  isUndo (): boolean {
    return this.histories.length > 0
  }
  undo (cb: StandardCallback): boolean {
    const { histories, histories2 } = this
    // console.log('histories:', histories, histories2)
    if (histories.length > 0) {
      const history = histories.pop()
      if (history) {
        this.resetByHistory(history, cb, 'undo')
        histories2.push(history)
        this.change(this.data)
      }
    }
    return this.isUndo()
  }

  resetByHistory (v: History, cb: StandardCallback, state: 'undo' | 'redo') {
    // console.log('history: ', history)
    v.values.forEach(([keys, oldValue, value]) => {
      if (v.type === 'cells') {
        const v = state === 'undo' ? oldValue : value
        const oldCell = this.getCell(keys[0], keys[1])
        if (!oldCell) {
          if (keys.length === 3) {
            if (v) {
              const nValue: Cell = {}
              nValue[keys[2]] = v
              cb(keys[0], keys[1], this.cell(keys[0], keys[1], nValue))
            }
          } else {
            cb(keys[0], keys[1], this.cell(keys[0], keys[1], v || {}))
          }
        } else {
          if (keys.length === 3) {
            const nValue: Cell = {}
            nValue[keys[2]] = v
            if (v) {
              cb(keys[0], keys[1], this.cell(keys[0], keys[1], nValue, true))
            } else {
              cb(keys[0], keys[1], this.cell(keys[0], keys[1], mapIntFilter(oldCell, keys[2])))
            }
          } else {
            cb(keys[0], keys[1], this.cell(keys[0], keys[1], v || {}))
          }
        }
      } else {
        // cols, rows
        // const v = state === 'undo' ? oldValue : value
        // if (v !== null) {
        //   this.data[v.type]
        // }
      }
      // console.log('keys:', keys, ', oldValue:', oldValue, ', value:', value)
    })
  }

  clearformat (cb: StandardCallback) {
    const { select } = this
    if (select !== null) {
      const history = new History('cells')
      select.forEach((rindex, cindex, i, j, rowspan, colspan) => {
        let c = this.getCell(rindex, cindex);
        if (c) {
          history.add([rindex, cindex], c, {text: c.text})
          c = this.cell(rindex, cindex, {text: c.text});
          cb(rindex, cindex, c);
        }
      });
      this.histories.push(history)
      this.change(this.data)
    }
  }

  /**
   * 
   * @param ok 合并单元格第一个单元格(左上角)的回调函数
   * @param cancel 取消合并单元格第一个单元格(左上角)的回调函数
   * @param other 其他单元格的回调函数
   */
  merge (ok: StandardCallback, cancel: StandardCallback, other: StandardCallback): void {
    const { select } = this
    // console.log('data.before: ', this.data)
    if (select !== null && select.cellLen() > 1) {
      // merge merge: [rows[0], cols[0]]
      const history = new History('cells')
      let index = 0
      let firstXY: [number, number] = [0, 0]
      select.forEach((rindex, cindex, i, j, rowspan, colspan) => {
        if (index++ === 0) {
          firstXY = [rindex, cindex]
          let v: Cell = {}
          if (rowspan > 1) v.rowspan = rowspan
          if (colspan > 1) v.colspan = colspan
          // console.log('rowspan:', rowspan, ', colspan:', colspan, select.canMerge)
          if (select.canMerge) {
            history.add([rindex, cindex, 'rowspan'], undefined, rowspan)
            history.add([rindex, cindex, 'colspan'], undefined, colspan)

            let cell = this.cell(rindex, cindex, v, true)
            ok(rindex, cindex, cell)
          } else {
            const oldCell = this.getCell(rindex, cindex)
            if (oldCell !== null) {
              history.add([rindex, cindex, 'rowspan'], oldCell.rowspan, undefined)
              history.add([rindex, cindex, 'colspan'], oldCell.colspan, undefined)

              let cell = this.cell(rindex, cindex, mapIntFilter(oldCell, 'rowspan', 'colspan', 'merge'))
              cancel(rindex, cindex, cell)
            }
          }
        } else {
          let v: Cell = {invisible: select.canMerge}
          if (select.canMerge) {
            history.add([rindex, cindex, 'invisible'], undefined, select.canMerge)

            v.merge = firstXY
            let cell = this.cell(rindex, cindex, v, true)
            other(rindex, cindex, cell)
          } else {
            const oldCell = this.getCell(rindex, cindex)
            if (oldCell !== null) {
              history.add([rindex, cindex, 'invisible'], oldCell.invisible, undefined)
              let cell = this.cell(rindex, cindex, mapIntFilter(oldCell, 'rowspan', 'colspan', 'merge', 'invisible'))
              other(rindex, cindex, cell)
            }
          }
        }
      })
      this.histories.push(history)
      select.canMerge = !select.canMerge
      this.change(this.data)
    }
  }
  cellAttr (key: keyof Cell, value: any, cb: StandardCallback): void {
    let v: Cell= {}
    v[key] = value
    const isDefault = value === this.data.cell[key]
    if (this.select !== null) {
      const history = new History('cells')
      this.select.forEach((rindex, cindex) => {
        const oldCell = this.getCell(rindex, cindex)
        
        history.add([rindex, cindex, key], oldCell !== null ? oldCell[key] : undefined, value)
        
        let cell = this.cell(rindex, cindex, isDefault ? mapIntFilter(oldCell, key) : v, !isDefault)
        cb(rindex, cindex, cell)
      
      })
      this.histories.push(history)
    }
    this.change(this.data)
  }
  cellText (value: any, cb: StandardCallback): Cell | null {
    if (this.currentCellIndexes) {
      // this.addHistoryValues()
      const history = new History('cells')
      const [rindex, cindex] = this.currentCellIndexes
      const oldCell = this.getCell(rindex, cindex)
      history.add([rindex, cindex, 'text'], oldCell !== null ? oldCell.text : undefined, value)
      const cell = this.cell(rindex, cindex, {text: value}, true)
      cb(rindex, cindex, cell)

      this.histories.push(history)
      this.change(this.data)
      return cell;
    }
    return null
  }
  currentCell (indexes?: [number, number]): Cell | null {
    if (indexes !== undefined) {
      this.currentCellIndexes = indexes
    }
    const [rindex, cindex] = this.currentCellIndexes
    return this.getCell(rindex, cindex)
  }

  cell (rindex: number, cindex: number, v: any, isCopy = false): Cell {
    this.data.cells = this.data.cells || {}
    this.data.cells[rindex] = this.data.cells[rindex] || {}
    this.data.cells[rindex][cindex] = this.data.cells[rindex][cindex] || {}
    if (isCopy) {
      (<any>Object).assign(this.data.cells[rindex][cindex], v)
    } else if (v) {
      this.data.cells[rindex][cindex] = v
    }
    return this.data.cells[rindex][cindex]
  }

  getCell (rindex: number, cindex: number): Cell | null {
    if (this.data.cells && this.data.cells[rindex] && this.data.cells[rindex][cindex]) {
      return this.data.cells[rindex][cindex];
    }
    return null;
  }

  getFont (key: string | undefined) {
    return this.fonts.filter(it => it.key === key)[0]
  }
  getFormat (key: string | undefined) {
    return this.formats.filter(it => it.key === key)[0]
  }

  row (index: number, v?: number): Row {
    const { data } = this;
    if (v !== undefined) {
      const history = new History('rows')
      data.rows = data.rows || {}
      data.rows[index] = data.rows[index] || {}
      data.rows[index].height = v
      history.add([index], null, data.rows[index])
      this.histories.push(history)
    }
    return (<any>Object).assign({height: data.rowHeight}, data.rows ? data.rows[index] : {})
  }
  // isData 是否返回数据的最大行数
  rows (isData: boolean): Array<Row> {
    const { data } = this;
    let maxRow;
    if (isData) {
      maxRow = 10
      if (this.data.cells) {
        maxRow = mapIntMaxKey(this.data.cells) + 2
      }
    } else {
      maxRow = mapIntMaxKeyWithDefault(100, data.rows)
    }
    return range(maxRow, (index) => this.row(index))
  }

  col (index: number, v?: number): Col {
    const { data } = this;
    if (v !== undefined) {
      const history = new History('cols')
      data.cols = data.cols || {}
      data.cols[index] = data.cols[index] || {}
      data.cols[index].width = v
      history.add([index], null, data.cols[index])
      this.histories.push(history)
    }
    const ret:any = {width: data.colWidth, title: alphabet(index)}
    if (data.cols && data.cols[index]) {
      for (let prop in data.cols[index]) {
        const col:any = data.cols[index]
        if (col[prop]) {
          ret[prop] = col[prop]
        }
      }
    }
    return ret
  }
  cols (): Array<Col> {
    const { data } = this;
    let maxCol = mapIntMaxKeyWithDefault(26 * 2, data.cols);
    return range(maxCol, (index) => this.col(index));
  }
}

const mapIntMaxKey = function<T>(mapInt: MapInt<T>): number {
  return Math.max(...Object.keys(mapInt).map(s => parseInt(s)))
}
// methods
const mapIntMaxKeyWithDefault = function<T>(max: number, mapInt: MapInt<T> | undefined): number {
  if (mapInt) {
    const m = mapIntMaxKey(mapInt)
    if (m > max) return m;
  }
  return max;
}
const mapIntFilter = function(obj: any, ...keys: Array<any>): any {
  const ret: any = {}
  if (obj){
    Object.keys(obj).forEach(e => {
      if (keys.indexOf(e) === -1) {
        ret[e] = obj[e]
      }
    })
  }
  return ret
}
const range = function<T>(stop:number, cb: (index: number) => T): Array<T> {
  const ret = []
  for (let i = 0; i < stop; i++) {
    ret.push(cb(i))
  }
  return ret
}
const getElementAttrs = (target: any) => {
  const { offsetTop, offsetLeft, offsetHeight, offsetWidth } = target
  return {
    row: parseInt(target.getAttribute('row-index')),
    col: parseInt(target.getAttribute('col-index')),
    rowspan: parseInt(target.getAttribute('rowspan')),
    colspan: parseInt(target.getAttribute('colspan')),
    left: offsetLeft,
    top: offsetTop,
    width: offsetWidth,
    height: offsetHeight
  }
}
const calcMinMaxCol = (cell: any, sRow: number, eRow: number, sCol: number, eCol: number) => {
  let minCol = sCol
  let maxCol = eCol
  // console.log(':::::::;start: ', maxCol, minCol)
  for (let j = sRow; j <= eRow; j++) {
    let cCol = sCol
    let dcell = cell(j, cCol)
    if (dcell && dcell.merge) {
      cCol += dcell.merge[1] - cCol
    }
    if (cCol < minCol) minCol = cCol

    cCol = maxCol
    dcell = cell(j, cCol)
    // console.log(j, cCol, dcell && dcell.colspan || 1)
    const cColspan = dcell ? dcell.colspan : 1
    if (parseInt(cColspan) > 1) {
      cCol += parseInt(cColspan)
    } else {
      if (dcell && dcell.merge) {
        // console.log('merge::', maxCol, dcell.merge)
        const [r, c] = dcell.merge
        const rc = cell(r, c).colspan
        cCol += rc + (c - cCol)
      }
    }
    // console.log('cCol: ', cCol, ', maxCol: ', maxCol)
    // console.log(':::::::;end: ', maxCol, minCol)
    if (cCol - 1 > maxCol) maxCol = cCol - 1
  }
  return [minCol, maxCol]
}
const calcMinMaxRow = (cell: any, sRow: number, eRow: number, sCol: number, eCol: number) => {
  let minRow = sRow
  let maxRow = eRow
  for (let j = sCol; j <= eCol; j++) {
    let cRow = sRow
    let dcell = cell(cRow, j)
    if (dcell && dcell.merge) {
      cRow += dcell.merge[0] - cRow
    }
    if (cRow < minRow) minRow = cRow

    cRow = maxRow
    dcell = cell(cRow, j)
    // console.log('row: ', j, cRow, dcell.rowspan)
    const cRowspan = dcell ? dcell.rowspan : 1
    if (parseInt(cRowspan) > 1) {
      cRow += parseInt(cRowspan)
    } else {
      if (dcell && dcell.merge) {
        const [r, c] = dcell.merge
        const rs = cell(r, c).rowspan
        cRow += rs + (r - cRow)
      }
    }
    if (cRow - 1 > maxRow) maxRow = cRow - 1
  }
  return [minRow, maxRow]
}

================================================
FILE: src/core/select.d.ts
================================================
export declare class Select {
    start: [number, number];
    stop: [number, number];
    canMerge: boolean;
    constructor(start: [number, number], stop: [number, number], canMerge: boolean);
    forEach(cb: (r: number, c: number, rindex: number, cindex: number, rowspan: number, colspan: number) => void): void;
    rowIndex(index: number): number;
    colIndex(index: number): number;
    rowLen(): number;
    colLen(): number;
    cellLen(): number;
    contains(rindex: number, cindex: number): boolean;
}


================================================
FILE: src/core/select.ts
================================================
export class Select {
  constructor(public start: [number, number], public stop: [number, number], public canMerge: boolean) {}
  forEach (cb: (r:number, c: number, rindex: number, cindex: number, rowspan: number, colspan: number) => void): void {
    const [sx, sy] = this.start
    const [ex, ey] = this.stop
    for (let i = sx; i <= ex; i++) {
      for (let j = sy; j <= ey; j++) {
        cb(i, j, i - sx, j - sy, ex - sx + 1, ey - sy + 1)
      }
    }
  }
  rowIndex (index: number) {
    return this.start[0] + index % this.rowLen()
  }
  colIndex (index: number) {
    return this.start[1] + index % this.colLen()
  }
  rowLen () {
    return this.stop[0] - this.start[0] + 1
  }
  colLen () {
    return this.stop[1] - this.start[1] + 1
  }
  cellLen () {
    return this.rowLen() * this.colLen()
  }
  contains (rindex: number, cindex: number) {
    const [sx, sy] = this.start
    const [ex, ey] = this.stop
    return sx <= rindex && ex >= rindex && sy <= cindex && ey >= cindex
  }
}

// export function buildSelect (start: any, end: )

================================================
FILE: src/local/base/colorPanel.d.ts
================================================
import { Element } from "./element";
export declare class ColorPanel extends Element {
    constructor(click: (color: string) => void);
}
export declare function buildColorPanel(click: (color: string) => void): ColorPanel;


================================================
FILE: src/local/base/colorPanel.ts
================================================
import { Element, h } from "./element";

const colorss = [
  ['#c00000', '#ff0000', '#ffc003', '#ffff00','#91d051', '#00af50', '#00b0f0', '#0070c0', '#002060', '#70309f'],
  ['#ffffff', '#000000', '#e7e6e6', '#44546a', '#4472c4', '#ed7d31', '#a5a5a5', '#ffc003', '#5b9bd5', '#70ad47'],
  ['#f4f5f8', '#848484', '#d0cece', '#d6dce4', '#d9e2f2', '#fae5d5', '#ededed', '#fff2cc', '#deebf6', '#e2efd9'],
  ['#d8d8d8', '#595959', '#afabab', '#adb9ca', '#b4c6e7', '#f7cbac', '#dbdbdb', '#fee598', '#bdd7ee', '#c5e0b3'],
  ['#bfbfbf', '#3f3f3f', '#757070', '#8496b0', '#8eaad8', '#f4b183', '#c9c9c9', '#ffd964', '#9dc2e5', '#a8d08d'],
  ['#a5a5a5', '#262626', '#3a3838', '#333f4f', '#2f5496', '#c55b11', '#7b7b7b', '#bf9001', '#2e75b5', '#538135'],
  ['#7e7e7e', '#0c0c0c', '#171616', '#232a35', '#1e3864', '#833d0b', '#525252', '#7e6000', '#1f4e79', '#375623']
]

export class ColorPanel extends Element {

  constructor (click: (color: string) => void) {
    super();
    this.class('spreadsheet-color-panel')
    .child(
      h('table').child(
        h('tbody').children(
          colorss.map(colors => {
            return h('tr').children(
              colors.map(color => {
                return h('td').child(
                  h()
                    .class('color-cell')
                    .on('click', click.bind(null, color))
                    .style('background-color', color)
                )
              })
            )
          })
        )));
  }

}

export function buildColorPanel (click: (color: string) => void) {
  return new ColorPanel(click);
}

================================================
FILE: src/local/base/dropdown.d.ts
================================================
import { Element } from "./element";
export declare class Dropdown extends Element {
    content: Element;
    title: Element;
    constructor(title: string | Element, width: string, contentChildren: Element[]);
    toggleHandler(evt: Event): void;
}
export declare function buildDropdown(title: string | Element, width: string, contentChildren: Element[]): Dropdown;


================================================
FILE: src/local/base/dropdown.ts
================================================
import { Element, h } from "./element";
import { buildIcon } from "./icon";

export class Dropdown extends Element {
  content: Element;
  title: Element;

  constructor (title: string | Element, width: string, contentChildren: Element[]) {
    super();
    this.class('spreadsheet-dropdown spreadsheet-item');

    this.content = h().class('spreadsheet-dropdown-content')
      .children(contentChildren)
      .onClickOutside(() => this.deactive())
      .on('click', (evt) => this.toggleHandler(evt))
      .style('width', width).hide();

    this.child(h().class('spreadsheet-dropdown-header').children([
      this.title = typeof title === 'string' ? h().class('spreadsheet-dropdown-title').child(title) : title,
      h().class('spreadsheet-dropdown-icon').on('click', (evt) => this.toggleHandler(evt)).child(buildIcon('arrow-down'))
    ])).child(this.content);
  }

  toggleHandler (evt: Event) {
    if (this.content.isHide()){
      this.content.show()
      this.active()
    } else {
      this.content.hide()
      this.deactive()
    }
  }
}
export function buildDropdown(title: string | Element, width: string, contentChildren: Element[]) {
  return new Dropdown(title, width, contentChildren)
}

================================================
FILE: src/local/base/element.d.ts
================================================
export declare class Element {
    tag: string;
    el: HTMLElement;
    _data: {
        [key: string]: any;
    };
    _clickOutside: any;
    constructor(tag?: string);
    data(key: string, value?: any): any;
    on(eventName: string, handler: (evt: any) => any): Element;
    onClickOutside(cb: () => void): Element;
    parent(): any;
    class(name: string): Element;
    attrs(map?: {
        [key: string]: string;
    }): Element;
    attr(attr: string, value?: any): any;
    removeAttr(attr: string): Element;
    offset(): any;
    clearStyle(): this;
    styles(map?: {
        [key: string]: string;
    }, isClear?: boolean): Element;
    style(key: string, value?: any): any;
    contains(el: any): boolean;
    removeStyle(key: string): void;
    children(cs: Array<HTMLElement | string | Element>): Element;
    child(c: HTMLElement | string | Element): Element;
    html(html?: string): string | this;
    val(v?: string): any;
    clone(): any;
    isHide(): boolean;
    toggle(): void;
    disabled(): Element;
    able(): Element;
    active(flag?: boolean): Element;
    deactive(): Element;
    isActive(): boolean;
    addClass(cls: string): Element;
    removeClass(cls: string): this;
    hasClass(cls: string): boolean;
    show(isRemove?: boolean): Element;
    hide(): Element;
}
export declare function h(tag?: string): Element;


================================================
FILE: src/local/base/element.ts
================================================
import { bind, unbind } from '../event'

export class Element {
  el: HTMLElement;
  _data: {[key: string]: any} = {};
  _clickOutside: any = null;

  constructor (public tag = 'div') {
    this.el = document.createElement(tag)
  }

  data (key: string, value?: any) {
    if (value !== undefined) {
      this._data[key] = value
    }
    return this._data[key]
  }

  on (eventName: string, handler: (evt: any) => any): Element {
    const [first, ...others] = eventName.split('.')
    // console.log('first:', first, ', others:', others)
    this.el.addEventListener(first, (evt: any) => {
      // console.log('>>>', others, evt.button)
      for (let k of others) {
        console.log('::::::::::', k)
        if (k === 'left' && evt.button !== 0) {
          return
        } else if (k === 'right' && evt.button !== 2) {
          return
        } else if (k === 'stop') {
          evt.stopPropagation()
        }
      }
      // console.log('>>>>>>>>>>>>')
      handler(evt)
    })
    return this;
  }

  onClickOutside (cb: () => void): Element {
    this._clickOutside = cb
    return this;
  }

  parent(): any {
    return this.el.parentNode
  }

  class (name: string): Element {
    this.el.className = name
    return this;
  }

  attrs (map: {[key: string]: string} = {}): Element {
    for (let key of Object.keys(map))
      this.attr(key, map[key]);
    return this;
  }

  attr (attr: string, value?: any): any {
    if (value !== undefined) {
      this.el.setAttribute(attr, value);
    } else {
      return this.el.getAttribute(attr)
    }
    return this;
  }
  removeAttr(attr: string): Element {
    this.el.removeAttribute(attr);
    return this;
  }

  offset (): any {
    const { offsetTop, offsetLeft, offsetHeight, offsetWidth } = this.el
    return {top: offsetTop, left: offsetLeft, height: offsetHeight, width: offsetWidth}
  }

  clearStyle () {
    (<any>this.el).style = ''
    return this;
  }

  styles (map: {[key: string]: string} = {}, isClear = false): Element {
    if (isClear) {
      this.clearStyle()
    }
    for (let key of Object.keys(map))
      this.style(key, map[key]);
    return this;
  }

  style (key: string, value?: any): any {
    if (value !== undefined) {
      this.el.style.setProperty(key, value);
    } else {
      return this.el.style.getPropertyValue(key)
    }
    return this;
  }

  contains (el: any) {
    return this.el.contains(el)
  }

  removeStyle (key: string) {
    this.el.style.removeProperty(key)
    return ;
  }

  children (cs: Array<HTMLElement | string | Element>): Element {
    for (let c of cs)
      this.child(c);
    return this;
  }

  child (c: HTMLElement | string | Element): Element {
    if (typeof c === 'string') {
      this.el.appendChild(document.createTextNode(c))
    } else if (c instanceof Element) {
      this.el.appendChild(c.el)
    } else if (c instanceof HTMLElement) {
      this.el.appendChild(c)
    }
    return this;
  }

  html (html?: string) {
    if (html !== undefined) {
      this.el.innerHTML = html
    } else {
      return this.el.innerHTML
    }
    return this;
  }

  val (v?: string) {
    if (v !== undefined) {
      // (<any>this.el).value = v
      (<any>this.el).value = v
    } else {
      return (<any>this.el).value
    }
    return this;
  }

  clone (): any {
    return this.el.cloneNode();
  }

  isHide () {
    return this.style('display') === 'none'
  }

  toggle () {
    if (this.isHide()) {
      this.show()
    } else {
      this.hide()
    }
  }

  disabled (): Element {
    // this.removeClass('disabled')
    this.addClass('disabled')
    return this;
  }
  able (): Element {
    this.removeClass('disabled')
    return this;
  }

  active (flag = true): Element {
    // this.el.className = this.el.className.split(' ').filter(c => c !== 'disabled').join(' ') + ' active'
    // this.removeClass('disabled')
    if (flag)
      this.addClass('active')
    else
      this.deactive()
    return this;
  }
  deactive (): Element {
    return this.removeClass('active')
  }
  isActive (): boolean {
    return this.hasClass('active');
  }

  addClass (cls: string): Element {
    this.el.className = this.el.className.split(' ').concat(cls).join(' ')
    return this;
  }
  removeClass (cls: string) {
    // console.log('before.className: ', this.el.className)
    this.el.className = this.el.className.split(' ').filter(c => c !== cls).join(' ')
    // console.log('after.className: ', this.el.className)
    return this;
  }
  hasClass (cls: string) {
    return this.el.className.indexOf(cls) !== -1
  }

  show (isRemove = false): Element {
    isRemove ? this.removeStyle('display') : this.style('display', 'block');
    // clickoutside
    if (this._clickOutside) {
      this.data('_outsidehandler', (evt: Event) => {
        if (this.contains(evt.target)) {
          return false
        }
        this.hide()
        unbind('click', this.data('_outsidehandler'))
        this._clickOutside && this._clickOutside()
      })
      setTimeout(() => {
        bind('click', this.data('_outsidehandler'))
      }, 0)
    }
    return this;
  }

  hide (): Element {
    this.style('display', 'none');
    if (this._clickOutside) {
      unbind('click', this.data('_outsidehandler'))
    }
    return this;
  }
}

export function h (tag = 'div'): Element {
  return new Element(tag)
}

================================================
FILE: src/local/base/icon.d.ts
================================================
import { Element } from "./element";
export declare class Icon extends Element {
    img: Element;
    constructor(name: string);
    replace(name: string): void;
}
export declare function buildIcon(name: string): Icon;


================================================
FILE: src/local/base/icon.ts
================================================
import { Element, h } from "./element";

export class Icon extends Element{

  img: Element;

  constructor (name: string) {
    super();
    this.class('spreadsheet-icon').child(this.img = h().class(`spreadsheet-icon-img ${name}`));
  }

  replace (name: string) {
    this.img.class(`spreadsheet-icon-img ${name}`)
  }

}

export function buildIcon (name: string) {
  return new Icon(name);
}

================================================
FILE: src/local/base/item.d.ts
================================================
import { Element } from "./element";
import { Icon } from "./icon";
export declare class Item extends Element {
    iconEl: Icon | null;
    static build(): Item;
    constructor();
    icon(name: string): this;
    replaceIcon(name: string): void;
}
export declare function buildItem(): Item;


================================================
FILE: src/local/base/item.ts
================================================
import { Element } from "./element";
import { Icon, buildIcon } from "./icon";

export class Item extends Element {

  iconEl: Icon | null = null;

  static build (): Item {
    return new Item()
  }
  
  constructor () {
    super();
    this.class('spreadsheet-item');
  }

  icon (name: string) {
    this.child(this.iconEl = buildIcon(name))
    return this;
  }

  replaceIcon (name: string) {
    this.iconEl && this.iconEl.replace(name)
  }

}

export function buildItem (): Item {
  return new Item();
}

================================================
FILE: src/local/base/menu.d.ts
================================================
import { Element } from "./element";
export declare class Menu extends Element {
    constructor(align?: string);
}
export declare function buildMenu(align?: string): Menu;


================================================
FILE: src/local/base/menu.ts
================================================
import { Element } from "./element";

export class Menu extends Element{

  constructor (align = 'vertical') {
    super();
    this.class(`spreadsheet-menu ${align}`)
  }

}

export function buildMenu (align = 'vertical') {
  return new Menu(align);
}

================================================
FILE: src/local/base/suggest.d.ts
================================================
import { Element } from "./element";
export declare class Suggest extends Element {
    list: Array<[string, string]>;
    width: number;
    filterList: Array<Element>;
    currentIndex: number;
    target: Element | null;
    evtTarget: Element | null;
    itemClick: (it: [string, string]) => void;
    constructor(list: Array<[string, string]>, width: number);
    private documentHandler;
    private documentKeydownHandler;
    private hideAndRemoveEvents;
    private removeEvents;
    private clickItemHandler;
    search(target: Element, input: Element, word: string): void;
}


================================================
FILE: src/local/base/suggest.ts
================================================
import { Element, h } from "./element";
import { buildItem } from "./item";
import { buildMenu } from "./menu";
import { bind, unbind } from "../event";

export class Suggest extends Element {
  
  filterList: Array<Element> = [];
  currentIndex = 0;
  target: Element | null = null;
  evtTarget: Element | null = null;

  itemClick: (it: [string, string]) => void = (it) => {}

  constructor (public list: Array<[string, string]>, public width: number) {
    super();
    this.class('spreadsheet-suggest').hide()
  }

  private documentHandler (e: any) {
    if (this.el.contains(e.target)) {
      return false
    }
    this.hideAndRemoveEvents()
  }
  private documentKeydownHandler (e: any) {
    console.log('keyCode: ', e)
    if (this.filterList.length <= 0 && e.target.type !== 'textarea') return ;

    switch (e.keyCode) {
      case 37: // left
        e.returnValue = false
        break;
      case 38: // up
        this.filterList[this.currentIndex].deactive()
        this.currentIndex--
        if (this.currentIndex < 0) {
          this.currentIndex = this.filterList.length - 1
        }
        this.filterList[this.currentIndex].active()
        e.returnValue = false
        e.stopPropagation();
        break;
      case 39: // right
        e.returnValue = false
        break;
      case 40: // down
        this.filterList[this.currentIndex].deactive()
        this.currentIndex++
        if (this.currentIndex > this.filterList.length - 1) {
          this.currentIndex = 0
        }
        this.filterList[this.currentIndex].active()
        e.returnValue = false
        break;
      case 13: // enter
        this.filterList[this.currentIndex].el.click()
        e.returnValue = false
        break;
    }
    e.stopPropagation();
  }

  private hideAndRemoveEvents () {
    this.hide()
    this.removeEvents();
  }
  private removeEvents () {
    if (this.evtTarget !== null) {
      unbind('click', this.data('_outsidehandler'), this.evtTarget.el)
      unbind('keydown', this.data('_keydownhandler'), this.evtTarget.el)
    }
  }

  private clickItemHandler (it: [string, string]) {
    // console.log('click.it: ', it)
    this.itemClick(it)
    this.hideAndRemoveEvents()
  }


  search (target: Element, input: Element, word: string) {
    this.removeEvents()
    this.target = target;
    this.evtTarget = input;

    const { left, top, width, height } = target.offset()
    this.styles({left: `${left}px`, top: `${top + height + 2}px`, width: `${this.width}px`})

    let lis: any = this.list
    if (!/^\s*$/.test(word)) {
      lis = this.list.filter(it => it[0].startsWith(word.toUpperCase()))
    }
    lis = lis.map((it: [string, string]) => {
      const item = buildItem().on('click', (evt) => this.clickItemHandler(it)).child(it[0])
      if (it[1]) {
        item.child(h().class('label').html(it[1]))
      }
      return item
      // return `<div class="spreadsheet-item" it-key="${it[0]}">${it[0]}${it[1] ? '<div class="label">'+it[1]+'</div>' : ''}</div>`
    })

    this.filterList = lis
    this.currentIndex = 0

    if (lis.length <= 0) {
      lis = [buildItem().child('No Result')] // `<div class="spreadsheet-item disabled">No Result</div>`
    } else {
      lis[0].active()

      // clickoutside
      this.data('_outsidehandler', (evt: Event) => {
        this.documentHandler(evt)
      })
      this.data('_keydownhandler', (evt: any) => this.documentKeydownHandler(evt))
      setTimeout(() => {
        if (this.evtTarget !== null) {
          bind('click', this.data('_outsidehandler'), this.evtTarget.el)
          bind('keydown', this.data('_keydownhandler'), this.evtTarget.el)
        }
      }, 0)
    }
    this.html(``)
    this.child(buildMenu().children(lis)).show()
  }
}

================================================
FILE: src/local/contextmenu.d.ts
================================================
import { Element } from "./base/element";
import { Table } from "./table";
export declare class ContextMenu {
    table: Table;
    el: Element;
    constructor(table: Table);
    set(evt: any): void;
}


================================================
FILE: src/local/contextmenu.ts
================================================
import { Element, h } from "./base/element";
import { buildItem } from "./base/item";
import { buildMenu } from "./base/menu";
import { Table } from "./table"

export class ContextMenu {
  el: Element;
  constructor (public table: Table) {
    this.el = h().class('spreadsheet-contextmenu')
    .style('width', '160px')
    .on('click', (evt: any) => this.el.hide())
    .children([
      buildMenu().children([
        buildItem().on('click', (evt) => table.copy()).children(['copy', h().class('label').html('ctrl + c')]),
        buildItem().on('click', (evt) => table.cut()).children(['cut', h().class('label').html('ctrl + x')]),
        buildItem().on('click', (evt) => table.paste()).children(['paste', h().class('label').html('ctrl + v')]),
        // h().class('spreadsheet-item-separator'),
        // buildItem().on('click', (evt) => table.insert('row', 1)).html('insert row'),
        // buildItem().on('click', (evt) => table.insert('col', 1)).html('insert col')
      ])
    ]).onClickOutside(() => {}).hide()
    // clickoutside
  }

  set (evt: any) {
    const { offsetLeft, offsetTop } = evt.target
    const elRect = this.el.el.getBoundingClientRect()
    // cal left top
    const { clientWidth, clientHeight } = document.documentElement
    let top = offsetTop + evt.offsetY
    let left = offsetLeft + evt.offsetX

    if (evt.clientY > clientHeight / 1.5) {
      top -= elRect.height
    }
    if (evt.clientX > clientWidth / 1.5) {
      left -= elRect.width
    }
    this.el.style('left', `${left}px`).style('top', `${top}px`).show()
  }

}

================================================
FILE: src/local/editor.d.ts
================================================
import { Element } from "./base/element";
import { Suggest } from "./base/suggest";
import { Cell } from "../core/cell";
import { Formula } from "../core/formula";
export declare class Editor {
    defaultRowHeight: number;
    formulas: Array<Formula>;
    el: Element;
    target: HTMLElement | null;
    value: Cell | null;
    editor: Element;
    textarea: Element;
    textline: Element;
    suggest: Suggest;
    change: (v: Cell) => void;
    constructor(defaultRowHeight: number, formulas: Array<Formula>);
    onChange(change: (v: Cell) => void): void;
    set(target: HTMLElement, value: Cell | null): void;
    setValue(value: Cell | null): string;
    setStyle(value: Cell | null): void;
    clear(): void;
    private setTextareaRange;
    private inputKeydown;
    private inputChange;
    private autocomplete;
    reload(): void;
}


================================================
FILE: src/local/editor.ts
================================================
import { Element, h } from "./base/element";
import { Suggest } from "./base/suggest";
import { Cell, getStyleFromCell } from "../core/cell"
import { Formula } from "../core/formula";

export class Editor {
  el: Element;
  target: HTMLElement | null = null; // 选中的当前的element
  value: Cell | null = null; // 选中的当前的cell
  editor: Element;
  textarea: Element;
  textline: Element; // 计算输入文本的宽度用的element
  suggest: Suggest; // autocomplete show

  change: (v: Cell) => void = (v) => {};
  constructor (public defaultRowHeight: number, public formulas : Array<Formula>) {
    const suggestList: any = formulas.map(it => [it.key, it.title])
    this.el = h().children([this.editor = h().class('spreadsheet-editor').children([
        this.textarea = h('textarea')
          .on('keydown', (evt: any) => this.inputKeydown(evt))
          .on('input', (evt: Event) => this.inputChange(evt)),
        this.textline = h().styles({visibility: 'hidden', overflow: 'hidden', position: 'fixed', top: '0', left: '0'})
      ])
    , this.suggest = new Suggest(suggestList, 180)]).hide()

    this.el.on('keydown', (evt: any) => {
      if (evt.keyCode !== 13 && evt.keyCode !== 9) {
        evt.stopPropagation();
      }
    })

    this.suggest.itemClick = (it) => {
      // console.log('>>>>>>>>>>>>', it)
      const text = `=${it[0]}()`;
      if (this.value) {
        this.value.text = text
      }
      this.textarea.val(text);
      this.textline.html(text);
      this.setTextareaRange(text.length - 1)
      // (<any>this.textarea.el).setSelectionRange(text.length + 1, text.length + 1);
      // setTimeout(() => (<any>this.textarea.el).focus(), 10)
    }
  }

  onChange (change: (v: Cell) => void) {
    this.change = change
  }

  set (target: HTMLElement, value: Cell | null) {
    // console.log('set::>>')
    this.target = target;
    const text = this.setValue(value)
    this.el.show();
    this.setTextareaRange(text.length)
    // (<any>this.textarea.el).setSelectionRange(text.length, text.length);
    // setTimeout(() => (<any>this.textarea.el).focus(), 10)
    this.reload();
  }

  setValue (value: Cell | null): string {
    this.setStyle(value);
    if (value) {
      this.value = value;
      const text = value.text || '';
      this.textarea.val(text);
      this.textline.html(text);
      return text
    } else {
      return '';
    }
  }
  setStyle (value: Cell | null): void {
    let attrs = {width: this.textarea.style('width'), height: this.textarea.style('height')}
    this.textarea.styles(Object.assign(attrs, getStyleFromCell(value)), true)
  }

  clear () {
    // console.log('clear:>>>')
    this.el.hide();
    this.target = null;
    this.value = null;
    this.textarea.val('')
    this.textline.html('')
  }

  private setTextareaRange (position: number) {
    setTimeout(() => {
      (<any>this.textarea.el).setSelectionRange(position, position);
      (<any>this.textarea.el).focus()
    }, 10)
  }

  private inputKeydown (evt: any) {
    if (evt.keyCode === 13) {
      evt.preventDefault()
    }
  }

  private inputChange (evt: any) {
    const v = evt.target.value
    if (this.value) {
      this.value.text = v
    } else {
      this.value = {text: v}
    }
    this.change(this.value)
    this.autocomplete(v);

    this.textline.html(v);
    this.reload()

  }

  private autocomplete (v: string) {
    if (v[0] === '=') {
      if (!v.includes('(')) {
        const search = v.substring(1)
        console.log(':::;search word:', search)
        this.suggest.search(this.editor, this.textarea, search);
      } else {
        this.suggest.hide()
      }
    } else {
      this.suggest.hide()
    }
  }

  reload () {
    // setTimeout(() => {
      if (this.target) {
        const { offsetTop, offsetLeft, offsetWidth, offsetHeight } = this.target
        this.editor.styles({left: `${offsetLeft - 1}px`, top: `${offsetTop - 1}px`})
        this.textarea.styles({width: `${offsetWidth - 8}px`, height: `${offsetHeight - 2}px`})
        let ow = this.textline.offset().width + 16
        // console.log(maxWidth, ow, '>>>>')
        if (this.value) {
          if (this.value.wordWrap) {
            // 如果单元格自动换行,那么宽度固定,高度变化
            // this.textarea.style('height', 'auto');
            const h = (parseInt(ow / offsetWidth + '') + (ow % offsetWidth > 0 ? 1 : 0)) * this.defaultRowHeight;
            if (h > offsetHeight) {
              this.textarea.style('height', `${h}px`);
            }
          } else {
            const clientWidth = document.documentElement.clientWidth
            const maxWidth = clientWidth - offsetLeft - 24
            if (ow > offsetWidth) {
              if (ow > maxWidth) {
                // console.log(':::::::::', ow, maxWidth)
                const h = (parseInt(ow / maxWidth + '') + (ow % maxWidth > 0 ? 1 : 0)) * this.defaultRowHeight;
                if (h > offsetHeight) {
                  this.textarea.style('height', `${h}px`)
                } else {
                  this.textarea.style('height', `${offsetHeight}px`)
                }
                ow = maxWidth
              }
              this.textarea.style('width', `${ow}px`)
            }
          }
        }
        this.el.show()
      }
    // }, 0)
    
  }
}

================================================
FILE: src/local/editorbar.d.ts
================================================
import { Element } from "./base/element";
import { Cell } from "../core/cell";
export declare class Editorbar {
    el: Element;
    value: Cell | null;
    textarea: Element;
    label: Element;
    change: (v: Cell) => void;
    constructor();
    set(title: string, value: Cell | null): void;
    setValue(value: Cell | null): void;
    input(evt: any): void;
}


================================================
FILE: src/local/editorbar.ts
================================================
import { Element, h } from "./base/element";
import { Cell } from "../core/cell";
import { mouseMoveUp } from "./event"

export class Editorbar {
  el: Element;
  value: Cell | null = null; // 选中的当前的cell
  textarea: Element;
  label: Element;
  change: (v: Cell) => void = (v) => {};
  constructor () {
    this.el = h().class('spreadsheet-editor-bar').children([
      h().class('spreadsheet-formula-bar').children([
        this.label = h().class('spreadsheet-formula-label'),
        this.textarea = h('textarea').on('input', (evt) => this.input(evt))
      ]),
      // h().class('spreadsheet-formular-bar-resizer').on('mousedown', this.mousedown)
    ])
  }

  set (title: string, value: Cell | null) {
    this.label.html(title)
    this.setValue(value)
  }

  setValue (value: Cell | null) {
    this.value = value
    this.textarea.val(value && value.text || '')
  }

  input (evt: any) {
    const v = evt.target.value
    
    if (this.value) {
      this.value.text = v
    } else {
      this.value = {text: v}
    }
    this.change(this.value)
  
  }

}

================================================
FILE: src/local/event.d.ts
================================================
export declare function bind<T extends Event>(name: string, fn: (evt: T) => void, target?: any): void;
export declare function unbind<T extends Event>(name: string, fn: (evt: T) => void, target?: any): void;
export declare function mouseMoveUp<T extends Event>(movefunc: (evt: T) => void, upfunc: (evt: T) => void): void;


================================================
FILE: src/local/event.ts
================================================
export function bind<T extends Event>(name: string, fn: (evt: T) => void, target: any = window) {
  target.addEventListener(name, fn)
}
export function unbind<T extends Event>(name: string, fn: (evt: T) => void, target: any = window) {
  target.removeEventListener(name, fn)
}
export function mouseMoveUp<T extends Event> (movefunc: (evt: T) => void, upfunc: (evt: T) => void) {
  bind('mousemove', movefunc)
  const up = (evt: T) => {
    unbind('mousemove', movefunc)
    unbind('mouseup', up)
    upfunc(evt)
  }
  bind('mouseup', up)
}

================================================
FILE: src/local/index.d.ts
================================================
import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index';
import '../style/index.less';
import { Table } from './table';
import { Toolbar } from './toolbar';
import { Editorbar } from './editorbar';
export interface Options extends SpreadsheetOptions {
    height?: () => number;
    mode?: 'design' | 'write' | 'read';
}
export declare class LocalSpreadsheet {
    ss: Spreadsheet;
    refs: {
        [key: string]: HTMLElement;
    };
    table: Table;
    toolbar: Toolbar | null;
    editorbar: Editorbar | null;
    bindEl: HTMLElement;
    options: Options;
    _change: (data: SpreadsheetData) => void;
    constructor(el: HTMLElement, options?: Options);
    loadData(data: SpreadsheetData): LocalSpreadsheet;
    change(cb: (data: SpreadsheetData) => void): LocalSpreadsheet;
    private render;
    private toolbarChange;
    private editorbarChange;
    private editorChange;
    private clickCell;
}


================================================
FILE: src/local/index.ts
================================================
import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index'
import '../style/index.less'
import { Cell, getStyleFromCell } from '../core/cell';
import { Format } from '../core/format';
import { Font } from '../core/font';
import { Editor } from './editor';
import { Selector } from './selector';
import { Table } from './table';
import { Toolbar } from './toolbar';
import { Editorbar } from './editorbar';
import { h, Element } from './base/element'

export interface Options extends SpreadsheetOptions {
  height?: () => number;
  mode?: 'design' | 'write' | 'read';
}

export class LocalSpreadsheet {
  ss: Spreadsheet;
  refs: {[key: string]: HTMLElement} = {};
  table: Table;
  toolbar: Toolbar | null = null;
  editorbar: Editorbar | null = null;

  bindEl: HTMLElement
  options: Options;

  _change: (data: SpreadsheetData) => void = () => {}

  constructor (el: HTMLElement, options: Options = {}) {
    this.bindEl = el
    this.options = Object.assign({mode: 'design'}, options)

    // clear content in el
    this.bindEl && (this.bindEl.innerHTML = '')

    this.ss = new Spreadsheet(options);
    // console.log('::::>>>select:', this.ss.select)
    if (this.options.mode === 'design') {
      this.editorbar = new Editorbar()
      this.editorbar.change = (v) => this.editorbarChange(v)

      this.toolbar = new Toolbar(this.ss);
      this.toolbar.change = (key, v) => this.toolbarChange(key, v)
      this.toolbar.undo = () => {
        // console.log('undo::')
        return this.table.undo()
      }
      this.toolbar.redo = () => {
        // console.log('redo::')
        return this.table.redo()
      }
    }

    let bodyHeightFn = (): number => {
      if (this.options.height) {
        return this.options.height()
      }
      return document.documentElement.clientHeight - 24 - 41 - 26
    }
    let bodyWidthFn = (): number => {
      return this.bindEl.offsetWidth
    }
    this.table = new Table(this.ss, Object.assign({height: bodyHeightFn, width: bodyWidthFn, mode: this.options.mode}));
    this.table.change = (data) => {
      this.toolbar && this.toolbar.setRedoAble(this.ss.isRedo())
      this.toolbar && this.toolbar.setUndoAble(this.ss.isUndo())
      this._change(data)
    }
    this.table.editorChange = (v) => this.editorChange(v)
    this.table.clickCell = (rindex, cindex, cell) => this.clickCell(rindex, cindex, cell)
    this.render();
  }

  loadData (data: SpreadsheetData): LocalSpreadsheet {
    // reload until waiting main thread
    setTimeout(() => {
      this.ss.data = data
      this.table.reload()
    }, 1)
    return this
  }

  change (cb: (data: SpreadsheetData) => void): LocalSpreadsheet {
    this._change = cb
    return this;
  }

  private render (): void {
    this.bindEl.appendChild(h().class('spreadsheet').children([
      h().class('spreadsheet-bars').children([
        this.toolbar && this.toolbar.el || '',
        this.editorbar && this.editorbar.el || '',
      ]),
      this.table.el
    ]).el);
  }

  private toolbarChange (k: keyof Cell, v: any) {
    if (k === 'merge') {
      this.table.merge();
      return;
    } else if (k === 'clearformat') {
      this.table.clearformat();
      return ;
    } else if (k === 'paintformat') {
      this.table.copyformat();
      return ;
    }

    this.table.setCellAttr(k, v);
  }

  private editorbarChange (v: Cell) {
    this.table.setValueWithText(v)
  }

  private editorChange (v: Cell) {
    this.editorbar && this.editorbar.setValue(v)
  }

  private clickCell (rindex: number, cindex: number, v: Cell | null) {
    const cols = this.ss.cols()
    this.editorbar && this.editorbar.set(`${cols[cindex].title}${rindex + 1}`, v)
    this.toolbar && this.toolbar.set(this.table.td(rindex, cindex), v)
  }

}


================================================
FILE: src/local/resizer.d.ts
================================================
import { Element } from "./base/element";
export declare class Resizer {
    vertical: boolean;
    change: (index: number, distance: number) => void;
    el: Element;
    resizer: Element;
    resizerLine: Element;
    moving: boolean;
    index: number;
    constructor(vertical: boolean, change: (index: number, distance: number) => void);
    set(target: any, index: number, scroll: number): void;
    mousedown(evt: any): void;
}


================================================
FILE: src/local/resizer.ts
================================================
import { Element, h } from "./base/element";
import { mouseMoveUp } from './event';

export class Resizer {
  el: Element;
  resizer: Element;
  resizerLine: Element;
  moving: boolean = false;
  index: number = 0;
  constructor (public vertical: boolean, public change: (index: number, distance: number) => void) {
    this.el = h().class('spreadsheet-resizer-wrapper').children([
      this.resizer = h().class(`spreadsheet-resizer ${vertical ? 'vertical' : 'horizontal'}`)
        .on('mousedown', (evt: Event) => this.mousedown(evt)),
      this.resizerLine = h().class(`spreadsheet-resizer-line ${vertical ? 'vertical' : 'horizontal'}`).hide()
    ])
  }

  set (target: any, index: number, scroll: number) {
    if (this.moving) return ;
    this.index = index
    const { vertical } = this
    const { offsetLeft, offsetTop, offsetHeight, offsetWidth, parentNode } = target
    this.resizer.styles({
      left: `${vertical ? offsetLeft + offsetWidth - 5 - scroll : offsetLeft}px`,
      top: `${vertical ? offsetTop : offsetTop + offsetHeight - 5 + 24  - scroll}px`,
      width: `${vertical ? 5 : offsetWidth}px`,
      height: `${vertical ? offsetHeight : 5}px`
    })
    this.resizerLine.styles({
      left: `${vertical ? offsetLeft + offsetWidth - scroll : offsetLeft}px`,
      top: `${vertical ? offsetTop : offsetTop + offsetHeight + 24 - scroll}px`,
      width: `${vertical ? 0 : parentNode.parentNode.parentNode.parentNode.parentNode.nextSibling.offsetWidth - 15}px`,
      height: `${vertical ? parentNode.parentNode.parentNode.parentNode.nextSibling.offsetHeight + parentNode.offsetHeight : 0}px`
    })
    // this.el.show()
  }

  mousedown (evt: any) {
    let startEvt = evt;
    let distance = 0;
    this.resizerLine.show()
    mouseMoveUp((e: any) => {
      this.moving = true
      if (startEvt !== null && e.buttons === 1) {
        if (this.vertical) {
          const d = e.x - startEvt.x
          distance += d
          this.resizer.style('left', `${this.resizer.offset().left + d}px`)
          this.resizerLine.style('left', `${this.resizerLine.offset().left + d}px`)
        } else {
          const d = e.y - startEvt.y
          distance += d
          this.resizer.style('top', `${this.resizer.offset().top + d}px`)
          this.resizerLine.style('top', `${this.resizerLine.offset().top + d}px`)
        }
        startEvt = e
      }
    }, (e: any) => {
      this.change(this.index, distance)
      startEvt = null
      this.resizerLine.hide()
      distance = 0
      this.moving = false
    })
  }
}

================================================
FILE: src/local/selector.d.ts
================================================
import { Element } from "./base/element";
import { Spreadsheet } from "../core/index";
import { Table } from './table';
export declare class Selector {
    ss: Spreadsheet;
    table: Table;
    topEl: Element;
    rightEl: Element;
    bottomEl: Element;
    leftEl: Element;
    areaEl: Element;
    cornerEl: Element;
    copyEl: Element;
    el: Element;
    _offset: {
        left: number;
        top: number;
        width: number;
        height: number;
    };
    startTarget: any;
    endTarget: any;
    change: () => void;
    changeCopy: (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) => void;
    constructor(ss: Spreadsheet, table: Table);
    mousedown(evt: any): void;
    setCurrentTarget(target: HTMLElement): void;
    private cornerMousedown;
    reload(): void;
    private setOffset;
    private rowsHeight;
    private colsWidth;
}
export declare class DashedSelector {
    el: Element;
    constructor();
    set(selector: Selector): void;
    hide(): void;
}


================================================
FILE: src/local/selector.ts
================================================
import { Element, h } from "./base/element";
import { bind, mouseMoveUp } from './event';
import { Spreadsheet } from "../core/index";
import { Table } from './table';

export class Selector {
  topEl: Element;
  rightEl: Element;
  bottomEl: Element;
  leftEl: Element;
  areaEl: Element;
  cornerEl: Element;
  copyEl: Element;
  el: Element;
  _offset = {left: 0, top: 0, width: 0, height: 0};

  startTarget: any;
  endTarget: any;

  change: () => void = () => {};
  changeCopy: (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) => void 
    = (evt, arrow, startRow, startCol, stopRow, stopCol) => {};

  constructor (public ss: Spreadsheet, public table: Table) {
    this.topEl = h().class('top-border');
    this.rightEl = h().class('right-border');
    this.bottomEl = h().class('bottom-border');
    this.leftEl = h().class('left-border');
    this.areaEl = h().class('area-border');
    this.cornerEl = h().class('corner').on('mousedown', (evt) => this.cornerMousedown(evt));
    this.copyEl = h().class('copy-border');
    this.el = h().class('spreadsheet-borders').children([
      this.topEl,
      this.rightEl,
      this.bottomEl,
      this.leftEl,
      this.areaEl,
      this.cornerEl,
      this.copyEl.hide(),
    ]).hide()
  }

  mousedown (evt: any) {
    // console.log('>>>>>>>>selector>>')
    // console.log(this, evt, evt.type, evt.detail, evt.buttons, evt.button)
    if (evt.detail === 1 && evt.target.getAttribute('type') === 'cell') {
      // console.log(evt.shiftKey)
      if (evt.shiftKey) {
        this.endTarget = evt.target
        this.setOffset()
        return
      }
      // Object.assign(this, {startTarget: evt.target, endTarget: evt.target})
      // this.setOffset()
      this.setCurrentTarget(evt.target)

      mouseMoveUp((e: any) => {
        if (e.buttons === 1 && e.target.getAttribute('type') === 'cell') {
          this.endTarget = e.target
          this.setOffset()
        }
      }, (e) => { this.change() })
      // show el
      this.el.show()
    }
  }

  setCurrentTarget (target: HTMLElement) {
    Object.assign(this, {startTarget: target, endTarget: target})
    this.setOffset()
  }

  private cornerMousedown (evt: any) {
    const { select } = this.ss
    if (select === null) {
      return ;
    }
    const [stopRow, stopCol] = select.stop;
    const [startRow, startCol] = select.start;
    
    let boxRange:['bottom' | 'top' | 'left' | 'right', number, number, number, number] | null = null;
    mouseMoveUp((e: any) => {
      const rowIndex = e.target.getAttribute('row-index')
      const colIndex = e.target.getAttribute('col-index')
      if (rowIndex && colIndex) {
        this.copyEl.show();
        let rdiff = stopRow - rowIndex
        let cdiff = stopCol - colIndex
        let _rdiff = startRow - rowIndex
        let _cdiff = startCol - colIndex
        const {left, top, height, width} = this._offset;
        // console.log(rdiff, cdiff, ',,,', _rdiff, _cdiff)
        if (rdiff < 0) {
          // bottom
          // console.log('FCK=>bottom', this.rowsHeight(stopRow, stopRow + Math.abs(rdiff)), rdiff)
          this.copyEl.styles({
            left: `${left - 1}px`,
            top: `${top - 1}px`,
            width: `${width - 1}px`,
            height: `${this.rowsHeight(stopRow - select.rowLen() + 1, stopRow + Math.abs(rdiff)) - 1}px`});
          boxRange = ['bottom', stopRow + 1, startCol, stopRow + Math.abs(rdiff), stopCol]
        } else if (cdiff < 0) {
          // right
          // console.log('FCK=>right')
          this.copyEl.styles({
            left: `${left - 1}px`,
            top: `${top - 1}px`,
            width: `${this.colsWidth(stopCol - select.colLen() + 1, stopCol + Math.abs(cdiff)) - 1}px`,
            height: `${height - 1}px`});
          boxRange = ['right', startRow, stopCol + 1, stopRow, stopCol + Math.abs(cdiff)]
        } else if (_rdiff > 0) {
          // top
          // console.log('FCK=>top')
          const h = this.rowsHeight(startRow - _rdiff, startRow - 1)
          this.copyEl.styles({
            left: `${left - 1}px`,
            top: `${top - h - 1}px`,
            width: `${width - 1}px`,
            height: `${h - 1}px`});
          boxRange = ['top', startRow - _rdiff, startCol, startRow - 1, stopCol]
        } else if (_cdiff > 0) {
          // left
          // console.log('FCK=>left')
          const w = this.colsWidth(startCol - _cdiff, startCol - 1)
          this.copyEl.styles({
            left: `${left - w - 1}px`,
            top: `${top - 1}px`,
            width: `${w - 1}px`,
            height: `${height - 1}px`});
          boxRange = ['left', startRow, startCol - _cdiff, stopRow, startCol - 1]
        } else {
          this.copyEl.styles({
            left: `${left - 1}px`,
            top: `${top - 1}px`,
            width: `${width - 1}px`,
            height: `${height - 1}px`});
          boxRange = null
        }
      }
    }, (e) => {
      this.copyEl.hide()
      if (boxRange !== null) {
        const [arrow, startRow, startCol, stopRow, stopCol] = boxRange
        this.changeCopy(e, arrow, startRow, startCol, stopRow, stopCol)
      }
    });
  }

  reload () {
    this.setOffset()
  }

  private setOffset () {
    if (this.startTarget === undefined) return ;
    let { select } = this.ss

    // console.log('select: ', select, this.table)
    if (select) {
      // console.log('clear>>>>>:::')
      // clear
      const [minRow, minCol] = select.start
      const [maxRow, maxCol] = select.stop
      _forEach(minRow, maxRow, this.table.firsttds, (e) => { e.deactive() })
      _forEach(minCol, maxCol, this.table.ths, (e) => { e.deactive() })
    }

    select = this.ss.buildSelect(this.startTarget, this.endTarget)
    const [minRow, minCol] = select.start
    const [maxRow, maxCol] = select.stop
    // let height = 0, width = 0;
    const height = this.rowsHeight(minRow, maxRow, (e) => e.active())
    // _forEach(minRow, maxRow, this.table.firsttds, (e) => { 
    //   e.active()
    //   height += parseInt(e.offset().height)
    // })
    // height /= 2
    const width = this.colsWidth(minCol, maxCol, (e) => e.active())
    // _forEach(minCol, maxCol, this.table.ths, (e) => {
    //   e.active()
    //   width += parseInt(e.offset().width)
    // })

    // console.log('>>', minRow, minCol, maxRow, maxCol, height, width)
    const td = this.table.td(minRow, minCol)
    if (td) {
      // console.log('td:', td)
      const {left, top} = td.offset()
      this._offset = {left, top, width, height};

      this.topEl.styles({left: `${left - 1}px`, top: `${top - 1}px`, width: `${width + 1}px`, height: '2px'})
      this.rightEl.styles({left: `${left + width - 1}px`, top: `${top - 1}px`, width: '2px', height: `${height}px`})
      this.bottomEl.styles({left: `${left - 1}px`, top: `${top + height - 1}px`, width: `${width}px`, height: '2px'})
      this.leftEl.styles({left: `${left - 1}px`, top: `${top - 1}px`, width: '2px', height: `${height}px`})
      this.areaEl.styles({left: `${left}px`, top: `${top}px`, width: `${width - 2}px`, height: `${height - 2}px`})
      this.cornerEl.styles({left: `${left + width - 5}px`, top: `${top + height - 5}px`})
    }
  }
  private rowsHeight (minRow:number, maxRow:number, cb: (e: Element) => void = (e) => {}): number {
    let height = 0
    _forEach(minRow, maxRow, this.table.firsttds, (e) => { 
      cb(e)
      height += parseInt(e.offset().height)
    })
    height /= 2
    return height
  }
  private colsWidth (minCol: number, maxCol: number, cb: (e: Element) => void = (e) => {}): number {
    let width = 0
    _forEach(minCol, maxCol, this.table.ths, (e) => {
      cb(e)
      width += parseInt(e.offset().width)
    })
    return width
  }
}

const _forEach = (start: number, stop: number, elements: {[key: string]: Array<Element> | Element}, cb: (e: Element) => void): void => {
  for (let i = start; i <= stop; i++) {
    const es = elements[i + ''];
    if (es) {
      if (es instanceof Element) {
        cb(es)
      } else {
        es.forEach(e => cb(e))
      }
    }
  }
}

export class DashedSelector {
  el: Element;
  constructor () {
    this.el = h().class('spreadsheet-borders dashed').hide();
  }

  set (selector: Selector) {
    if (selector._offset) {
      const { left, top, width, height } = selector._offset;
      this.el
        .style('left', `${left - 2}px`)
        .style('top', `${top - 2}px`)
        .style('width', `${width}px`)
        .style('height', `${height}px`)
        .show();
    }
  }

  hide () {
    this.el.hide();
  }
}


================================================
FILE: src/local/table.d.ts
================================================
import { Element } from "./base/element";
import { Spreadsheet, SpreadsheetData } from '../core/index';
import { Editor } from './editor';
import { Selector, DashedSelector } from './selector';
import { Resizer } from './resizer';
import { ContextMenu } from "./contextmenu";
import { Cell } from "../core/cell";
interface Map<T> {
    [key: string]: T;
}
export interface TableOption {
    height: () => number;
    width: () => number;
    mode: 'design' | 'write' | 'read';
}
export declare class Table {
    options: TableOption;
    cols: Map<Array<Element>>;
    firsttds: Map<Array<Element>>;
    tds: Map<Element>;
    ths: Map<Element>;
    ss: Spreadsheet;
    formulaCellIndexs: Set<string>;
    el: Element;
    header: Element;
    body: Element;
    fixedLeftBody: Element | null;
    editor: Editor | null;
    rowResizer: Resizer | null;
    colResizer: Resizer | null;
    contextmenu: ContextMenu | null;
    selector: Selector;
    dashedSelector: DashedSelector;
    state: 'copy' | 'cut' | 'copyformat' | null;
    currentIndexs: [number, number] | null;
    focusing: boolean;
    change: (data: SpreadsheetData) => void;
    editorChange: (v: Cell) => void;
    clickCell: (rindex: number, cindex: number, v: Cell | null) => void;
    constructor(ss: Spreadsheet, options: TableOption);
    reload(): void;
    private moveLeft;
    private moveUp;
    private moveDown;
    private moveRight;
    private moveSelector;
    setValueWithText(v: Cell): void;
    setTdWithCell(rindex: number, cindex: number, cell: Cell, autoWordWrap?: boolean): void;
    setCellAttr(k: keyof Cell, v: any): void;
    undo(): boolean;
    redo(): boolean;
    private setTdStylesAndAttrsAndText;
    copy(): void;
    cut(): void;
    copyformat(): void;
    paste(): void;
    clearformat(): void;
    merge(): void;
    insert(type: 'row' | 'col', amount: number): void;
    td(rindex: number, cindex: number): Element;
    private selectorChange;
    private selectorChangeCopy;
    private renderCell;
    private _renderCell;
    private reRenderFormulaCells;
    private setRowHeight;
    private setTdStyles;
    private setTdAttrs;
    private changeRowHeight;
    private changeRowResizer;
    private changeColResizer;
    private buildColGroup;
    private buildFixedLeft;
    private buildHeader;
    private mousedownCell;
    private editCell;
    private buildBody;
    private addRow;
    private firsttdsPush;
}
export {};


================================================
FILE: src/local/table.ts
================================================
import { Element, h } from "./base/element";
import { Spreadsheet, SpreadsheetData } from '../core/index'
import { Editor } from './editor';
import { Selector, DashedSelector } from './selector';
import { Resizer } from './resizer';
import { Editorbar } from "./editorbar";
import { Toolbar } from "./toolbar";
import { ContextMenu } from "./contextmenu";
import { Cell, getStyleFromCell } from "../core/cell";
import { formatRenderHtml } from "../core/format";
import { formulaRender } from "../core/formula";
import { bind } from "./event";

interface Map<T> {
  [key: string]: T
}

export interface TableOption {
  height: () => number,
  width: () => number,
  mode: 'design' | 'write' | 'read';
}

export class Table {
  cols: Map<Array<Element>> = {};
  firsttds: Map<Array<Element>> = {};
  tds: Map<Element> = {};
  ths: Map<Element> = {};
  ss: Spreadsheet;
  formulaCellIndexs: Set<string> = new Set(); // 表达式单元格set

  el: Element;
  header: Element;
  body: Element;
  fixedLeftBody: Element | null = null;

  editor: Editor | null = null;
  rowResizer: Resizer | null = null;
  colResizer: Resizer | null = null;

  contextmenu: ContextMenu | null = null;

  selector: Selector;
  dashedSelector: DashedSelector;
  state: 'copy' | 'cut' | 'copyformat' | null = null;

  currentIndexs: [number, number] | null = null;

  // 当前用户是否焦点再table上
  focusing: boolean = false;

  // change
  change: (data: SpreadsheetData) => void = () => {}
  editorChange: (v: Cell) => void = (v) => {}
  clickCell: (rindex: number, cindex: number, v: Cell | null) => void = (rindex, cindex, v) => {}

  constructor (ss: Spreadsheet, public options: TableOption) {
    this.ss = ss;
    this.ss.change = (data) => {
      this.change(data)
    }

    if (options.mode !== 'read') {
      this.editor = new Editor(ss.defaultRowHeight(), ss.formulas)
      this.editor.change = (v: Cell) => this.editorChange(v)
    }

    if (options.mode === 'design') {
      this.rowResizer = new Resizer(false, (index, distance) => this.changeRowResizer(index, distance))
      this.colResizer = new Resizer(true, (index, distance) => this.changeColResizer(index, distance))
      this.contextmenu = new ContextMenu(this)
    }

    this.selector = new Selector(this.ss, this);
    this.selector.change = () => this.selectorChange();
    this.selector.changeCopy = (e, arrow, startRow, startCol, stopRow, stopCol) => {
      this.selectorChangeCopy(e, arrow, startRow, startCol, stopRow, stopCol);
    }
    this.dashedSelector = new DashedSelector();

    this.el = h().class('spreadsheet-table').children([
      this.colResizer && this.colResizer.el || '',
      this.rowResizer && this.rowResizer.el || '',
      this.buildFixedLeft(),
      this.header = this.buildHeader(),
      this.body = this.buildBody()
    ]).on('contextmenu', (evt) => {
      evt.returnValue = false
      evt.preventDefault();
    });

    bind('resize', (evt: any) => {
      this.header.style('width', `${this.options.width()}px`)
      this.body.style('width', `${this.options.width()}px`)
      if (this.options.mode !== 'read') {
        this.body.style('height', `${this.options.height()}px`)
      }
    })

    bind('click', (evt: any) => {
      // console.log('::::::::', this.el.contains(evt.target))
      this.focusing = this.el.parent().contains(evt.target)
    })

    // bind ctrl + c, ctrl + x, ctrl + v
    bind('keydown', (evt: any) => {

      if (!this.focusing) {
        return
      }

      // console.log('::::::::', evt)
      if (!this.focusing) return;

      // ctrlKey
      if (evt.ctrlKey && evt.target.type !== 'textarea' && this.options.mode !== 'read') {
        // ctrl + c
        if (evt.keyCode === 67) {
          this.copy();
          evt.returnValue = false
        }
        // ctrl + x
        if (evt.keyCode === 88) {
          this.cut();
          evt.returnValue = false
        }
        // ctrl + v
        if (evt.keyCode === 86) {
          this.paste();
          evt.returnValue = false
        }
      } else {
        // console.log('>>>>>>>>>>>>>>', evt)
        switch (evt.keyCode) {
          case 37: // left
            this.moveLeft()
            evt.returnValue = false
            break;
          case 38: // up
            this.moveUp()
            evt.returnValue = false
            break;
          case 39: // right
            this.moveRight()
            evt.returnValue = false
            break;
          case 40: // down
            this.moveDown()
            evt.returnValue = false
            break;
          case 9: // tab
            this.moveRight();
            evt.returnValue = false
            break;
          case 13:
            this.moveDown();
            evt.returnValue = false
            break;
        }
      

        // 输入a-zA-Z1-9
        if (this.options.mode !== 'read') {
          if (evt.keyCode >= 65 && evt.keyCode <= 90 || evt.keyCode >= 48 && evt.keyCode <= 57 || evt.keyCode >= 96 && evt.keyCode <= 105 || evt.keyCode == 187) {
            // if (this.currentIndexs) {
            // console.log('::::::::', evt.target.type)
            if (evt.target.type !== 'textarea') {
              this.ss.cellText(evt.key, (rindex, cindex, cell) => {
                if (this.editor) {
                  const td = this.td(rindex, cindex)
                  td.html(this.renderCell(rindex, cindex, cell))
                  this.editor.set(td.el, this.ss.currentCell())
                }
              })
            }
          }
        }

      }
      
    });
  }

  reload () {
    this.firsttds = {}
    this.el.html('')
    this.el.children([
      this.colResizer && this.colResizer.el || '',
      this.rowResizer && this.rowResizer.el || '',
      this.buildFixedLeft(),
      this.header = this.buildHeader(),
      this.body = this.buildBody()
    ]);
  }
  
  private moveLeft () {
    if (this.currentIndexs && this.currentIndexs[1] > 0) {
      this.currentIndexs[1] -= 1
      this.moveSelector('left')
    }
  }
  private moveUp () {
    if (this.currentIndexs && this.currentIndexs[0] > 0) {
      this.currentIndexs[0] -= 1
      this.moveSelector('up')
    }
  }
  private moveDown () {
    if (this.currentIndexs && this.currentIndexs[0] < this.ss.rows(this.options.mode === 'read').length) {
      this.currentIndexs[0] += 1
      this.moveSelector('down')
    }
  }
  private moveRight () {
    if (this.currentIndexs && this.currentIndexs[1] < this.ss.cols().length) {
      this.currentIndexs[1] += 1
      this.moveSelector('right')
    }
  }

  // 移动选框
  private moveSelector (direction: 'right' | 'left' | 'up' | 'down') {
    if (this.currentIndexs) {
      const [rindex, cindex] = this.currentIndexs
      const td = this.td(rindex, cindex)
      // console.log('move.td:', td)
      if (td) {
        this.selector.setCurrentTarget(td.el)
        const bodyWidth = this.options.width()
        const bodyHeight = this.options.height()
        const {left, top, width, height} = td.offset()
        // console.log(this.body.el.scrollLeft, ', body-width:', bodyWidth, ', left:', left, ', width=', width)
        const leftDiff = left + width - bodyWidth
        if (leftDiff > 0 && direction === 'right') {
            this.body.el.scrollLeft = leftDiff + 15
        }
        if (direction === 'left' && this.body.el.scrollLeft + 60 > left) {
          this.body.el.scrollLeft -= (this.body.el.scrollLeft + 60 - left)
        }
        if (direction === 'up' && this.body.el.scrollTop > top) {
          this.body.el.scrollTop -= (this.body.el.scrollTop - top)
        }
        if (direction === 'down' && top + height - bodyHeight > 0) {
          this.body.el.scrollTop = top + height - bodyHeight + 15;
        }

        this.mousedownCell(rindex, cindex)
      }
      
    }
  }

  setValueWithText (v: Cell) {
    // console.log('setValueWithText: v = ', v)
    if (this.currentIndexs) {
      this.ss.cellText(v.text, (rindex, cindex, cell) => {
        this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell))
      })
    }
    this.editor && this.editor.setValue(v)
  }

  setTdWithCell (rindex: number, cindex: number, cell: Cell, autoWordWrap = true) {
    this.setTdStyles(rindex, cindex, cell);
    this.setRowHeight(rindex, cindex, autoWordWrap);
    this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell));
  }

  setCellAttr (k: keyof Cell, v: any) {
    // console.log('::k:', k, '::v:', v)
    this.ss.cellAttr(k, v, (rindex, cindex, cell) => {
      // console.log(':rindex:', rindex, '; cindex:', cindex, '; cell: ', cell)
      this.setTdWithCell(rindex, cindex, cell, k === 'wordWrap' && v);
    })
    this.editor && this.editor.setStyle(this.ss.currentCell())
  }

  undo (): boolean {
    return this.ss.undo((rindex, cindex, cell) => {
      // console.log('>', rindex, ',', cindex, '::', cell)
      this.setTdStylesAndAttrsAndText(rindex, cindex, cell)
    })
  }
  redo (): boolean {
    return this.ss.redo((rindex, cindex, cell) => {
      this.setTdStylesAndAttrsAndText(rindex, cindex, cell)
    })
  }
  private setTdStylesAndAttrsAndText (rindex: number, cindex: number, cell: Cell) {
    let td = this.td(rindex, cindex);
    this.setTdStyles(rindex, cindex, cell);
    this.setTdAttrs(rindex, cindex, cell);
    // console.log('txt>>>:', this.renderCell(rindex, cindex, cell))
    td.html(this.renderCell(rindex, cindex, cell));
  }

  copy () {
    this.ss.copy();
    this.dashedSelector.set(this.selector);
    this.state = 'copy';
  }

  cut () {
    this.ss.cut();
    this.dashedSelector.set(this.selector);
    this.state = 'cut';
  }

  copyformat () {
    this.ss.copy();
    this.dashedSelector.set(this.selector);
    this.state = 'copyformat';
  }

  paste () {
    // console.log('state: ', this.state, this.ss.select)
    if (this.state !== null && this.ss.select) {
      this.ss.paste((rindex, cindex, cell) => {
        // console.log('rindex: ', rindex, ', cindex: ', cindex);
        let td = this.td(rindex, cindex);
        this.setTdStyles(rindex, cindex, cell);
        this.setTdAttrs(rindex, cindex, cell);
        if (this.state === 'cut' || this.state === 'copy') {
          td.html(this.renderCell(rindex, cindex, cell));
        }
      }, this.state, (rindex, cindex, cell) => {
        let td = this.td(rindex, cindex);
        this.setTdStyles(rindex, cindex, cell);
        this.setTdAttrs(rindex, cindex, cell);
        td.html('');
      });
      this.selector.reload();
    }

    if (this.state === 'copyformat') {
      this.state = null;
    } else if (this.state === 'cut') {
      this.state = null;  
    } else if (this.state === 'copy') {
      // this.ss.paste()
    }
    
    this.dashedSelector.hide();
  }

  clearformat () {
    this.ss.clearformat((rindex, cindex, cell) => {
      this.td(rindex, cindex)
        .removeAttr('rowspan')
        .removeAttr('colspan')
        .styles({}, true)
        .show(true);
    })
  }

  merge () {
    this.ss.merge((rindex, cindex, cell) => {
      // console.log(rindex, cindex, '>>>', this.table.td(rindex, cindex))
      this.setTdAttrs(rindex, cindex, cell).show(true)
    }, (rindex, cindex, cell) => {
      this.setTdAttrs(rindex, cindex, cell).show(true)
    }, (rindex, cindex, cell) => {
      let td = this.td(rindex, cindex)
      !cell.invisible ? td.show(true) : td.hide()
    })
  }

  // insert
  insert (type: 'row' | 'col', amount: number) {
    if (type === 'col') {
      // insert col
    } else if (type === 'row') {
      // insert row
    }
    this.ss.insert(type, amount, (rindex, cindex, cell) => {
      this.setTdStylesAndAttrsAndText(rindex, cindex, cell)
    })
  }

  td (rindex: number, cindex: number): Element {
    const td = this.tds[`${rindex}_${cindex}`]
    return td
  }

  private selectorChange () {
    if (this.state === 'copyformat') {
      this.paste();
    }
  }

  private selectorChangeCopy (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) {
    this.ss.batchPaste(arrow, startRow, startCol, stopRow, stopCol, evt.ctrlKey, (rindex, cindex, cell) => {
      this.setTdStyles(rindex, cindex, cell);
      this.setTdAttrs(rindex, cindex, cell);
      this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell));
    })
  }

  private renderCell (rindex: number, cindex: number, cell: Cell | null): string {
    if (cell) {
      const setKey = `${rindex}_${cindex}`
      // console.log('text:', setKey, cell.text && cell.text)
      if (cell.text && cell.text[0] === '=') {
        this.formulaCellIndexs.add(setKey)
      } else {
        if (this.formulaCellIndexs.has(setKey)) {
          this.formulaCellIndexs.delete(setKey)
        }

        this.reRenderFormulaCells()
      }
      return formatRenderHtml(cell.format, this._renderCell(cell))
    }
    return '';
  }
  private _renderCell (cell: Cell | null): string {
    if (cell) {
      let text = cell.text || '';
      return formulaRender(text, (rindex, cindex) => this._renderCell(this.ss.getCell(rindex, cindex)))
    }
    return '';
  }
  private reRenderFormulaCells () {
    // console.log('formulaCellIndex: ', this.formulaCellIndexs)
    this.formulaCellIndexs.forEach(it => {
      let rcindexes = it.split('_')
      const rindex = parseInt(rcindexes[0])
      const cindex = parseInt(rcindexes[1])
      // console.log('>>>', this.ss.data, this.ss.getCell(rindex, cindex))
      const text = this.renderCell(rindex, cindex, this.ss.getCell(rindex, cindex))
      this.td(rindex, cindex).html(text);
    })
  }

  private setRowHeight (rindex: number, cindex: number, autoWordWrap: boolean) {
    // console.log('rowHeight: ', this.td(rindex, cindex).offset().height, ', autoWordWrap:', autoWordWrap)
    // 遍历rindex行的所有单元格,计算最大高度
    if (autoWordWrap === false) {
      return ;
    }
    const cols = this.ss.cols()
    const td = this.td(rindex, cindex)
    let h = td.offset().height
    console.log('h:', h)
    const tdRowspan = td.attr('rowspan')
    if (tdRowspan) {
      for (let i = 1; i < parseInt(tdRowspan); i++) {
        let firsttds = this.firsttds[(rindex + i) +'']
        firsttds && (h -= parseInt(firsttds[0].attr('height') || 0) + 1)
      }
    }
    // console.log('after.h:', h)
    this.changeRowHeight(rindex, h - 1);
  }

  private setTdStyles (rindex: number, cindex: number, cell: Cell): Element {
    return this.td(rindex, cindex).styles(getStyleFromCell(cell), true)
  }
  private setTdAttrs (rindex: number, cindex: number, cell: Cell): Element {
    return this.td(rindex, cindex)
      .attr('rowspan', cell.rowspan || 1)
      .attr('colspan', cell.colspan || 1);
  }

  private changeRowHeight (index: number, h: number) {
    if (h <= this.ss.defaultRowHeight()) return
    this.ss.row(index, h)
    const firstTds = this.firsttds[index+'']
    if (firstTds) {
      firstTds.forEach(td => td.attr('height', h))
    }
    this.selector.reload()
    this.editor && this.editor.reload()
  }
  private changeRowResizer (index: number, distance: number) {
    const h = this.ss.row(index).height + distance
    this.changeRowHeight(index, h);
  }
  private changeColResizer (index: number, distance: number) {
    const w = this.ss.col(index).width + distance
    if (w <= 50) return
    this.ss.col(index, w)
    const cols = this.cols[index+'']
    if (cols) {
      cols.forEach(col => col.attr('width', w))
    }
    this.selector.reload()
    this.editor && this.editor.reload()
  }

  private buildColGroup (lastColWidth: number): Element {
    const cols = this.ss.cols();
    return h('colgroup').children([
      h('col').attr('width', '60'),
      ...cols.map((col, index) => {
        let c = h('col').attr('width', col.width)
        this.cols[index+''] = this.cols[index+''] || []
        this.cols[index+''].push(c)
        return c; 
      }),
      h('col').attr('width', lastColWidth)
    ])
  }

  private buildFixedLeft (): Element {
    const rows = this.ss.rows(this.options.mode === 'read');
    return h().class('spreadsheet-fixed')
    .style('width', '60px')
    .children([
      h().class('spreadsheet-fixed-header').child(h('table').child(
        h('thead').child(
          h('tr').child(
            h('th').child('-')
          )
        ),
      )),
      this.fixedLeftBody = 
      h().class('spreadsheet-fixed-body')
      .style('height', `${this.options.mode === 'read' ? 'auto' : this.options.height() - 18}px`)
      .children([
        h('table').child(
          h('tbody').children(
            rows.map((row, rindex) => {
              let firstTd = h('td').attr('height', `${row.height}`).child(`${rindex + 1}`)
                .on('mouseover', (evt: Event) => this.rowResizer && this.rowResizer.set(evt.target, rindex, this.body.el.scrollTop));
              this.firsttdsPush(rindex, firstTd)
              return h('tr').child(firstTd)
            })
          )
        )
      ])
    ])
  }

  private buildHeader (): Element {
    const cols = this.ss.cols();
    const thead = h('thead').child(
      h('tr').children([
        h('th'),
        ...cols.map((col, index) => {
          let th = h('th').child(col.title).on('mouseover', (evt: Event) => {
            console.log(evt)
            this.colResizer && this.colResizer.set(evt.target, index, this.body.el.scrollLeft)
          });
          this.ths[index + ''] = th;
          return th;
        }),
        h('th')
      ]
    ))
    return h().class('spreadsheet-header').style('width', `${this.options.width()}px`).children([
      h('table').children([this.buildColGroup(15), thead])
    ])
  }

  private mousedownCell (rindex: number, cindex: number) {
    if (this.editor) {
      const editorValue = this.editor.value
      if (this.currentIndexs && this.editor.target && editorValue) {
        // console.log(':::editorValue:', editorValue)
        const oldCell = this.ss.cellText(editorValue.text, (_rindex, _cindex, _cell: Cell) => {
          this.td(_rindex, _cindex).html(this.renderCell(_rindex, _cindex, _cell))
        });
        // const oldTd = this.td(this.currentIndexs[0], this.currentIndexs[1]);
        // oldTd.html(this.renderCell(editorValue))
        if (oldCell) {
          // 设置内容之后,获取高度设置行高
          if (oldCell.wordWrap) {
            this.setRowHeight(this.currentIndexs[0], this.currentIndexs[1], true)
          }
          // console.log('old.td.offset:', oldCell)
          // this.editorChange(oldCell)
        }
      }
      this.editor.clear()
    }

    this.currentIndexs = [rindex, cindex]
    const cCell = this.ss.currentCell([rindex, cindex])
    this.clickCell(rindex, cindex, cCell)
  }

  private editCell(rindex: number, cindex: number) {
    const td = this.td(rindex, cindex)
    this.editor && this.editor.set(td.el, this.ss.currentCell())
  }

  private buildBody () {
    const rows = this.ss.rows(this.options.mode === 'read');
    const cols = this.ss.cols();

    const mousedown = (rindex: number, cindex: number, evt: any) => {
      const {select} = this.ss
      if (evt.button === 2) {
        // show contextmenu
        console.log(':::evt:', evt)
        this.contextmenu && this.contextmenu.set(evt)
        if (select && select.contains(rindex, cindex)) {
          return
        }
      }
      // left key
      this.selector.mousedown(evt)
      this.mousedownCell(rindex, cindex)
      this.focusing = true
    }

    const dblclick = (rindex: number, cindex: number) => {
      this.editCell(rindex, cindex)
    }

    const scrollFn = (evt: any) => {
      this.header.el.scrollLeft = evt.target.scrollLeft
      this.fixedLeftBody && (this.fixedLeftBody.el.scrollTop = evt.target.scrollTop)
      // console.log('>>>>>>>>scroll...', this.header, evt.target.scrollLeft, evt.target.scrollHeight)
    }

    const tbody = h('tbody').children(rows.map((row, rindex) => {
      let firstTd = h('td').attr('height', `${row.height}`).child(`${rindex + 1}`);
      this.firsttdsPush(rindex, firstTd)
      return h('tr').children([
        firstTd,
        ...cols.map((col, cindex) => {
          let cell = this.ss.getCell(rindex, cindex)
          let td = h('td')
            .child(this.renderCell(rindex, cindex, cell))
            .attr('type', 'cell')
            .attr('row-index', rindex + '')
            .attr('col-index', cindex + '')
            .attr('rowspan', cell && cell.rowspan || 1)
            .attr('colspan', cell && cell.colspan || 1)
            .styles(getStyleFromCell(cell), true)
            .on('mousedown', (evt: any) => mousedown(rindex, cindex, evt))
            .on('dblclick', dblclick.bind(null, rindex, cindex));
          this.tds[`${rindex}_${cindex}`] = td
          return td;
        }),
        h('td')
      ])
    }));

    return h().class('spreadsheet-body')
      .on('scroll', scrollFn)
      .style('height', `${this.options.mode === 'read' ? 'auto' : this.options.height()}px`)
      .style('width', `${this.options.width()}px`)
      .children([
        h('table').children([this.buildColGroup(0), tbody]),
        this.editor && this.editor.el || '',
        this.selector.el,
        this.contextmenu && this.contextmenu.el || '',
        this.dashedSelector.el
      ]
    )
  }

  // 向尾部添加行
  private addRow (num = 1) {
    if (num > 0) {

    }
  }

  private firsttdsPush (index: number, el: Element) {
    this.firsttds[`${index}`] = this.firsttds[`${index}`] || []  
    this.firsttds[`${index}`].push(el)
  }

}

================================================
FILE: src/local/toolbar.d.ts
================================================
import { Element } from "./base/element";
import { Spreadsheet } from "../core/index";
import { Cell } from '../core/cell';
import { Dropdown } from './base/dropdown';
export declare class Toolbar {
    ss: Spreadsheet;
    el: Element;
    defaultCell: Cell;
    target: Element | null;
    currentCell: Cell | null;
    elUndo: Element;
    elRedo: Element;
    elPaintformat: Element;
    elClearformat: Element;
    elFormat: Dropdown;
    elFont: Dropdown;
    elFontSize: Dropdown;
    elFontWeight: Element;
    elFontStyle: Element;
    elTextDecoration: Element;
    elColor: Dropdown;
    elBackgroundColor: Dropdown;
    elMerge: Element;
    elAlign: Dropdown;
    elValign: Dropdown;
    elWordWrap: Element;
    change: (key: keyof Cell, v: any) => void;
    redo: () => boolean;
    undo: () => boolean;
    constructor(ss: Spreadsheet);
    set(target: Element, cell: Cell | null): void;
    private setCell;
    private setCellStyle;
    setRedoAble(flag: boolean): void;
    setUndoAble(flag: boolean): void;
    private buildSeparator;
    private buildAligns;
    private buildValigns;
    private buildWordWrap;
    private buildFontWeight;
    private buildFontStyle;
    private buildTextDecoration;
    private buildMerge;
    private buildColor;
    private buildBackgroundColor;
    private buildUndo;
    private buildRedo;
    private buildPaintformat;
    private buildClearformat;
    private buildFormats;
    private buildFonts;
    private buildFontSizes;
}


================================================
FILE: src/local/toolbar.ts
================================================
import { Element, h } from "./base/element";
import { Spreadsheet } from "../core/index";
import { Cell, getStyleFromCell, defaultCell } from '../core/cell';
import { Table } from './table';
import { buildItem, Item } from './base/item';
import { buildIcon } from './base/icon';
import { buildDropdown, Dropdown } from './base/dropdown';
import { buildMenu } from './base/menu';
import { buildColorPanel } from './base/colorPanel';
import { Font } from "../core/font";
import { Format } from "../core/format";

export class Toolbar {
  el: Element;
  defaultCell: Cell;

  target: Element | null = null;
  currentCell: Cell | null = null;

  elUndo: Element;
  elRedo: Element;
  elPaintformat: Element;
  elClearformat: Element;
  elFormat: Dropdown;
  elFont: Dropdown;
  elFontSize: Dropdown;
  elFontWeight: Element;
  elFontStyle: Element;
  elTextDecoration: Element;
  elColor: Dropdown;
  elBackgroundColor: Dropdown;
  elMerge: Element;
  elAlign: Dropdown;
  elValign: Dropdown;
  elWordWrap: Element;

  change: (key: keyof Cell, v: any) => void = (key, v) => {}
  redo: () => boolean = () => false
  undo: () => boolean = () => false

  constructor (public ss: Spreadsheet) {
    this.defaultCell = ss.data.cell

    this.el = h().class('spreadsheet-toolbar').child(
        buildMenu('horizontal').children([
          this.elUndo = this.buildUndo(),
          this.elRedo = this.buildRedo(),
          this.elPaintformat = this.buildPaintformat(),
          this.elClearformat = this.buildClearformat(),
          this.elFormat = this.buildFormats(),
          this.buildSeparator(),
          this.elFont = this.buildFonts(),
          this.elFontSize = this.buildFontSizes(),
          this.buildSeparator(),
          this.elFontWeight = this.buildFontWeight(),
          this.elFontStyle = this.buildFontStyle(),
          this.elTextDecoration = this.buildTextDecoration(),
          this.elColor = this.buildColor(),
          this.buildSeparator(),
          this.elBackgroundColor = this.buildBackgroundColor(),
          this.elMerge = this.buildMerge(),
          this.buildSeparator(),
          this.elAlign = this.buildAligns(),
          this.elValign = this.buildValigns(),
          this.elWordWrap = this.buildWordWrap()
        ])
      )
    ;
  }

  set (target: Element, cell: Cell | null) {
    this.target = target
    this.setCell(cell)
  }

  private setCell (cell: Cell | null) {
    this.currentCell = cell
    this.setCellStyle()
  }

  private setCellStyle () {
    const { target, currentCell, defaultCell, ss } = this
    // console.log(':::', currentCell)
    if (target) {
      // target.clearStyle()
      // target.styles(getStyleFromCell(currentCell))
      this.elFormat.title.html(ss.getFormat(currentCell !== null && currentCell.format || defaultCell.format).title);
      this.elFont.title.html(ss.getFont(currentCell !== null && currentCell.font || defaultCell.font).title);
      this.elFontSize.title.html((currentCell !== null && currentCell.fontSize || defaultCell.fontSize) + '');
      this.elFontWeight.active(currentCell !== null && currentCell.bold !== undefined && currentCell.bold !== defaultCell.bold);
      this.elFontStyle.active(currentCell !== null && currentCell.italic !== undefined && currentCell.italic !== defaultCell.italic);
      this.elTextDecoration.active(currentCell !== null && currentCell.underline !== undefined && currentCell.underline !== defaultCell.underline);
      this.elColor.title.style('border-bottom-color', currentCell !== null && currentCell.color || defaultCell.color);
      this.elBackgroundColor.title.style('border-bottom-color', currentCell !== null && currentCell.backgroundColor || defaultCell.backgroundColor);
      (<any>this.elAlign.title).replace(`align-${currentCell !== null && currentCell.align || defaultCell.align}`);
      (<any>this.elValign.title).replace(`valign-${currentCell !== null && currentCell.valign || defaultCell.valign}`);
      this.elWordWrap.active(currentCell !== null && currentCell.wordWrap !== undefined && currentCell.wordWrap !== defaultCell.wordWrap);
      // console.log('select:', currentCell)
      if ((currentCell !== null && currentCell.rowspan && currentCell.rowspan > 1)
        || (currentCell !== null && currentCell.colspan && currentCell.colspan > 1)) {
        this.elMerge.active(true);
      } else {
        this.elMerge.active(false);
      }
    }
  }

  setRedoAble (flag: boolean) {
    flag ? this.elRedo.able() : this.elRedo.disabled()
  }

  setUndoAble (flag: boolean) {
    flag ? this.elUndo.able() : this.elUndo.disabled()
  }

  private buildSeparator (): Element {
    return h().class('spreadsheet-item-separator')
  }
  private buildAligns (): Dropdown {
    const titleIcon = buildIcon(`align-${this.defaultCell.align}`)
    const clickHandler = (it: string) => {
      titleIcon.replace(`align-${it}`)
      this.change('align', it)
    }
    return buildDropdown(titleIcon, '60px', [buildMenu().children(
      ['left', 'center', 'right'].map(it => 
        buildItem()
          .child(buildIcon(`align-${it}`).style('text-align', 'center'))
          .on('click', clickHandler.bind(null, it))
      )
    )])
  }
  private buildValigns (): Dropdown {
    const titleIcon = buildIcon(`valign-${this.defaultCell.valign}`)
    const clickHandler = (it: string) => {
      titleIcon.replace(`valign-${it}`)
      this.change('valign', it)
    }
    return buildDropdown(titleIcon, '60px', [buildMenu().children(
      ['top', 'middle', 'bottom'].map(it => 
        buildItem()
          .child(buildIcon(`valign-${it}`).style('text-align', 'center'))
          .on('click', clickHandler.bind(null, it))
        )
    )])
  }
  private buildWordWrap (): Element {
    return buildIconItem('textwrap', (is) => this.change('wordWrap', is))
  }
  private buildFontWeight (): Element {
    return buildIconItem('bold', (is) => this.change('bold', is))
  }
  private buildFontStyle (): Element {
    return buildIconItem('italic', (is) => this.change('italic', is))
  }
  private buildTextDecoration (): Element {
    return buildIconItem('underline', (is) => this.change('underline', is))
  }
  private buildMerge (): Element {
    return buildIconItem('merge', (is) => this.change('merge', is))
  }
  private buildColor (): Dropdown {
    const clickHandler = (color: string) => {
      this.elColor.title.style('border-bottom-color', color)
      this.change('color', color)
    }
    return buildDropdown(
      buildIcon('text-color').styles({'border-bottom': `3px solid ${this.defaultCell.color}`, 'margin-top': '2px', height: '16px'}),
      'auto',
      [buildColorPanel(clickHandler)])
  }
  private buildBackgroundColor (): Dropdown {
    const clickHandler = (color: string) => {
      this.elBackgroundColor.title.style('border-bottom-color', color)
      this.change('backgroundColor', color)
    }
    return buildDropdown(
      buildIcon('cell-color').styles({'border-bottom': `3px solid ${this.defaultCell.backgroundColor}`, 'margin-top': '2px', height: '16px'}),
      'auto',
      [buildColorPanel(clickHandler)])
  }
  private buildUndo (): Element {
    return buildItem().child(buildIcon('undo'))
      .on('click', (evt) => {
        this.undo() ? this.elUndo.able() : this.elUndo.disabled()
      })
      .disabled()
  }
  private buildRedo (): Element {
    return buildItem().child(buildIcon('redo'))
      .on('click', (evt) => {
        this.redo() ? this.elRedo.able() : this.elRedo.disabled()
      })
      .disabled()
  }
  private buildPaintformat (): Element {
    return buildIconItem('paintformat', (is) => { 
      this.change('paintformat', true);
      this.elPaintformat.deactive();
    })
  }
  private buildClearformat (): Element {
    return buildIconItem('clearformat', (is) => { 
      this.change('clearformat', true);
      this.elClearformat.deactive();
    });
  }
  private buildFormats (): Dropdown {
    const clickHandler = (it: Format) => {
      this.elFormat.title.html(this.ss.getFormat(it.key).title);
      this.change('format', it.key)
    }
    return buildDropdown(this.ss.getFormat(this.defaultCell.format).title, '250px', [buildMenu().children(
      this.ss.formats.map(it => 
        buildItem()
          .children([it.title, h().class('label').child(it.label||'')])
          .on('click', clickHandler.bind(null, it))
        )
    )])
  }
  private buildFonts (): Dropdown {
    const clickHandler = (it: Font) => {
      this.elFont.title.html(it.title)
      this.change('font', it.key)
    }
    return buildDropdown(this.ss.getFont(this.defaultCell.font).title, '170px', [buildMenu().children(
      this.ss.fonts.map(it => { 
        return buildItem()
          .child(it.title)
          .on('click', clickHandler.bind(null, it))
      })
    )])
  }
  private buildFontSizes (): Dropdown {
    const clickHandler = (it: number) => {
      this.elFontSize.title.html(`${it}`)
      this.change('fontSize', it)
    }
    return buildDropdown(this.defaultCell.fontSize + '', '70px', [buildMenu().children(
      [6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 30, 36].map(it => {
        return buildItem()
          .child(`${it}`)
          .on('click', clickHandler.bind(null, it))
      })
    )])
  }
}

const buildIconItem = (iconName: string, change: (flag: boolean) => void) => {
  const el = buildItem().child(buildIcon(iconName))
  el.on('click', (evt) => {
    let is = el.isActive()
    is ? el.deactive() : el.active()
    change(!is)
  })
  return el;
}

================================================
FILE: src/main.d.ts
================================================
import { LocalSpreadsheet, Options } from './local/index';
export default function xspreadsheet(el: HTMLElement, options?: Options): LocalSpreadsheet;
declare global {
    interface Window {
        xspreadsheet: any;
    }
}


================================================
FILE: src/main.ts
================================================
import { LocalSpreadsheet, Options } from './local/index';

export default function xspreadsheet (el: HTMLElement, options?: Options) {
  return new LocalSpreadsheet(el, options)
}

declare global {
  interface Window {
    xspreadsheet: any;
  }
}

window.xspreadsheet = xspreadsheet


================================================
FILE: src/style/index.less
================================================
@border-style: 1px solid #e0e2e4;
@icon-size: 18px;

body {
  margin: 0;
}

.spreadsheet {
  font-size: 14px;
  line-height: normal;
  user-select: none;
  -moz-user-select: none;
  font-family: Roboto, Helvetica, Arial, sans-serif;
  box-sizing: content-box;
  background: #fff;

  .spreadsheet-table {
    position: relative;
    background: #fff;
  }

  .spreadsheet-fixed {
    position: absolute;
    top: 0;
    left: 0;
    z-index: 10;
    background: #fff;

    .spreadsheet-fixed-body {
      overflow: hidden;
    }
    .spreadsheet-fixed-header {
      overflow: hidden;  
    }
  }

  .spreadsheet-body {
    overflow: scroll;
    position: relative;
  }
  .spreadsheet-header {
    overflow: hidden;
    width: 100%;
  }

  .spreadsheet-header, .spreadsheet-body, .spreadsheet-fixed {

    table {
      table-layout: fixed;
      text-align: left;
      width: 100%;
      border-collapse: separate;
      borde
Download .txt
gitextract_n0gowviz/

├── .gitignore
├── LICENSE
├── README.md
├── docs/
│   ├── index.html
│   └── xspreadsheet.js
├── index.html
├── package.json
├── src/
│   ├── core/
│   │   ├── alphabet.d.ts
│   │   ├── alphabet.ts
│   │   ├── cell.d.ts
│   │   ├── cell.ts
│   │   ├── font.d.ts
│   │   ├── font.ts
│   │   ├── format.d.ts
│   │   ├── format.ts
│   │   ├── formula.d.ts
│   │   ├── formula.ts
│   │   ├── index.d.ts
│   │   ├── index.ts
│   │   ├── select.d.ts
│   │   └── select.ts
│   ├── local/
│   │   ├── base/
│   │   │   ├── colorPanel.d.ts
│   │   │   ├── colorPanel.ts
│   │   │   ├── dropdown.d.ts
│   │   │   ├── dropdown.ts
│   │   │   ├── element.d.ts
│   │   │   ├── element.ts
│   │   │   ├── icon.d.ts
│   │   │   ├── icon.ts
│   │   │   ├── item.d.ts
│   │   │   ├── item.ts
│   │   │   ├── menu.d.ts
│   │   │   ├── menu.ts
│   │   │   ├── suggest.d.ts
│   │   │   └── suggest.ts
│   │   ├── contextmenu.d.ts
│   │   ├── contextmenu.ts
│   │   ├── editor.d.ts
│   │   ├── editor.ts
│   │   ├── editorbar.d.ts
│   │   ├── editorbar.ts
│   │   ├── event.d.ts
│   │   ├── event.ts
│   │   ├── index.d.ts
│   │   ├── index.ts
│   │   ├── resizer.d.ts
│   │   ├── resizer.ts
│   │   ├── selector.d.ts
│   │   ├── selector.ts
│   │   ├── table.d.ts
│   │   ├── table.ts
│   │   ├── toolbar.d.ts
│   │   └── toolbar.ts
│   ├── main.d.ts
│   ├── main.ts
│   └── style/
│       └── index.less
├── tsconfig.json
├── tslint.json
├── webpack.config.dev.js
└── webpack.config.js
Download .txt
SYMBOL INDEX (476 symbols across 47 files)

FILE: docs/xspreadsheet.js
  function s (line 1) | function s(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{...
  class n (line 1) | class n{constructor(e="div"){this.tag=e,this._data={},this._clickOutside...
    method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
    method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
    method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
    method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
    method parent (line 1) | parent(){return this.el.parentNode}
    method class (line 1) | class(e){return this.el.className=e,this}
    method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
    method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
    method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
    method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
    method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
    method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
    method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
    method contains (line 1) | contains(e){return this.el.contains(e)}
    method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
    method children (line 1) | children(e){for(let t of e)this.child(t);return this}
    method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
    method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
    method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
    method clone (line 1) | clone(){return this.el.cloneNode()}
    method isHide (line 1) | isHide(){return"none"===this.style("display")}
    method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
    method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
    method able (line 1) | able(){return this.removeClass("disabled"),this}
    method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
    method deactive (line 1) | deactive(){return this.removeClass("active")}
    method isActive (line 1) | isActive(){return this.hasClass("active")}
    method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
    method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
    method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
    method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
    method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
    method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
    method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
    method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
  function i (line 1) | function i(e,t,s=window){s.addEventListener(e,t)}
  function n (line 1) | function n(e,t,s=window){s.removeEventListener(e,t)}
    method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
    method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
    method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
    method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
    method parent (line 1) | parent(){return this.el.parentNode}
    method class (line 1) | class(e){return this.el.className=e,this}
    method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
    method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
    method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
    method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
    method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
    method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
    method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
    method contains (line 1) | contains(e){return this.el.contains(e)}
    method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
    method children (line 1) | children(e){for(let t of e)this.child(t);return this}
    method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
    method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
    method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
    method clone (line 1) | clone(){return this.el.cloneNode()}
    method isHide (line 1) | isHide(){return"none"===this.style("display")}
    method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
    method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
    method able (line 1) | able(){return this.removeClass("disabled"),this}
    method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
    method deactive (line 1) | deactive(){return this.removeClass("active")}
    method isActive (line 1) | isActive(){return this.hasClass("active")}
    method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
    method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
    method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
    method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
    method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
    method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
    method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
    method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
  class n (line 1) | class n extends i.Element{constructor(e="vertical"){super(),this.class(`...
    method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
    method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
    method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
    method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
    method parent (line 1) | parent(){return this.el.parentNode}
    method class (line 1) | class(e){return this.el.className=e,this}
    method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
    method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
    method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
    method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
    method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
    method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
    method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
    method contains (line 1) | contains(e){return this.el.contains(e)}
    method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
    method children (line 1) | children(e){for(let t of e)this.child(t);return this}
    method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
    method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
    method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
    method clone (line 1) | clone(){return this.el.cloneNode()}
    method isHide (line 1) | isHide(){return"none"===this.style("display")}
    method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
    method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
    method able (line 1) | able(){return this.removeClass("disabled"),this}
    method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
    method deactive (line 1) | deactive(){return this.removeClass("active")}
    method isActive (line 1) | isActive(){return this.hasClass("active")}
    method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
    method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
    method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
    method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
    method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
    method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
    method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
    method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
  class n (line 1) | class n extends i.Element{constructor(e){super(),this.class("spreadsheet...
    method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
    method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
    method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
    method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
    method parent (line 1) | parent(){return this.el.parentNode}
    method class (line 1) | class(e){return this.el.className=e,this}
    method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
    method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
    method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
    method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
    method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
    method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
    method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
    method contains (line 1) | contains(e){return this.el.contains(e)}
    method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
    method children (line 1) | children(e){for(let t of e)this.child(t);return this}
    method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
    method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
    method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
    method clone (line 1) | clone(){return this.el.cloneNode()}
    method isHide (line 1) | isHide(){return"none"===this.style("display")}
    method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
    method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
    method able (line 1) | able(){return this.removeClass("disabled"),this}
    method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
    method deactive (line 1) | deactive(){return this.removeClass("active")}
    method isActive (line 1) | isActive(){return this.hasClass("active")}
    method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
    method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
    method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
    method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
    method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
    method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
    method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
    method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
  class r (line 1) | class r extends i.Element{constructor(){super(),this.iconEl=null,this.cl...
    method constructor (line 1) | constructor(){super(),this.iconEl=null,this.class("spreadsheet-item")}
    method build (line 1) | static build(){return new r}
    method icon (line 1) | icon(e){return this.child(this.iconEl=n.buildIcon(e)),this}
    method replaceIcon (line 1) | replaceIcon(e){this.iconEl&&this.iconEl.replace(e)}
    method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-color-panel").child(i.h...
    method constructor (line 1) | constructor(e,t,s){super(),this.class("spreadsheet-dropdown spreadshee...
    method toggleHandler (line 1) | toggleHandler(e){this.content.isHide()?(this.content.show(),this.activ...
  method constructor (line 1) | constructor(){this.value=null,this.change=(e=>{}),this.el=i.h().class("s...
  method set (line 1) | set(e,t){this.label.html(e),this.setValue(t)}
  method setValue (line 1) | setValue(e){this.value=e,this.textarea.val(e&&e.text||"")}
  method input (line 1) | input(e){const t=e.target.value;this.value?this.value.text=t:this.value=...
  class r (line 1) | class r extends i.Element{constructor(e){super(),this.class("spreadsheet...
    method constructor (line 1) | constructor(){super(),this.iconEl=null,this.class("spreadsheet-item")}
    method build (line 1) | static build(){return new r}
    method icon (line 1) | icon(e){return this.child(this.iconEl=n.buildIcon(e)),this}
    method replaceIcon (line 1) | replaceIcon(e){this.iconEl&&this.iconEl.replace(e)}
    method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-color-panel").child(i.h...
    method constructor (line 1) | constructor(e,t,s){super(),this.class("spreadsheet-dropdown spreadshee...
    method toggleHandler (line 1) | toggleHandler(e){this.content.isHide()?(this.content.show(),this.activ...
  class r (line 1) | class r extends i.Element{constructor(e,t,s){super(),this.class("spreads...
    method constructor (line 1) | constructor(){super(),this.iconEl=null,this.class("spreadsheet-item")}
    method build (line 1) | static build(){return new r}
    method icon (line 1) | icon(e){return this.child(this.iconEl=n.buildIcon(e)),this}
    method replaceIcon (line 1) | replaceIcon(e){this.iconEl&&this.iconEl.replace(e)}
    method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-color-panel").child(i.h...
    method constructor (line 1) | constructor(e,t,s){super(),this.class("spreadsheet-dropdown spreadshee...
    method toggleHandler (line 1) | toggleHandler(e){this.content.isHide()?(this.content.show(),this.activ...
  method constructor (line 1) | constructor(e){this.ss=e,this.target=null,this.currentCell=null,this.cha...
  method set (line 1) | set(e,t){this.target=e,this.setCell(t)}
  method setCell (line 1) | setCell(e){this.currentCell=e,this.setCellStyle()}
  method setCellStyle (line 1) | setCellStyle(){const{target:e,currentCell:t,defaultCell:s,ss:i}=this;e&&...
  method setRedoAble (line 1) | setRedoAble(e){e?this.elRedo.able():this.elRedo.disabled()}
  method setUndoAble (line 1) | setUndoAble(e){e?this.elUndo.able():this.elUndo.disabled()}
  method buildSeparator (line 1) | buildSeparator(){return i.h().class("spreadsheet-item-separator")}
  method buildAligns (line 1) | buildAligns(){const e=r.buildIcon(`align-${this.defaultCell.align}`),t=t...
  method buildValigns (line 1) | buildValigns(){const e=r.buildIcon(`valign-${this.defaultCell.valign}`),...
  method buildWordWrap (line 1) | buildWordWrap(){return a("textwrap",e=>this.change("wordWrap",e))}
  method buildFontWeight (line 1) | buildFontWeight(){return a("bold",e=>this.change("bold",e))}
  method buildFontStyle (line 1) | buildFontStyle(){return a("italic",e=>this.change("italic",e))}
  method buildTextDecoration (line 1) | buildTextDecoration(){return a("underline",e=>this.change("underline",e))}
  method buildMerge (line 1) | buildMerge(){return a("merge",e=>this.change("merge",e))}
  method buildColor (line 1) | buildColor(){return o.buildDropdown(r.buildIcon("text-color").styles({"b...
  method buildBackgroundColor (line 1) | buildBackgroundColor(){return o.buildDropdown(r.buildIcon("cell-color")....
  method buildUndo (line 1) | buildUndo(){return n.buildItem().child(r.buildIcon("undo")).on("click",e...
  method buildRedo (line 1) | buildRedo(){return n.buildItem().child(r.buildIcon("redo")).on("click",e...
  method buildPaintformat (line 1) | buildPaintformat(){return a("paintformat",e=>{this.change("paintformat",...
  method buildClearformat (line 1) | buildClearformat(){return a("clearformat",e=>{this.change("clearformat",...
  method buildFormats (line 1) | buildFormats(){const e=e=>{this.elFormat.title.html(this.ss.getFormat(e....
  method buildFonts (line 1) | buildFonts(){const e=e=>{this.elFont.title.html(e.title),this.change("fo...
  method buildFontSizes (line 1) | buildFontSizes(){const e=e=>{this.elFontSize.title.html(`${e}`),this.cha...
  method constructor (line 1) | constructor(e){this.table=e,this.el=i.h().class("spreadsheet-contextmenu...
  method set (line 1) | set(e){const{offsetLeft:t,offsetTop:s}=e.target,i=this.el.el.getBounding...
  method constructor (line 1) | constructor(e,t){this.vertical=e,this.change=t,this.moving=!1,this.index...
  method set (line 1) | set(e,t,s){if(this.moving)return;this.index=t;const{vertical:i}=this,{of...
  method mousedown (line 1) | mousedown(e){let t=e,s=0;this.resizerLine.show(),n.mouseMoveUp(e=>{if(th...
  method constructor (line 1) | constructor(e,t){this.ss=e,this.table=t,this._offset={left:0,top:0,width...
  method mousedown (line 1) | mousedown(e){if(1===e.detail&&"cell"===e.target.getAttribute("type")){if...
  method setCurrentTarget (line 1) | setCurrentTarget(e){Object.assign(this,{startTarget:e,endTarget:e}),this...
  method cornerMousedown (line 1) | cornerMousedown(e){const{select:t}=this.ss;if(null===t)return;const[s,i]...
  method reload (line 1) | reload(){this.setOffset()}
  method setOffset (line 1) | setOffset(){if(void 0===this.startTarget)return;let{select:e}=this.ss;if...
  method rowsHeight (line 1) | rowsHeight(e,t,s=(e=>{})){let i=0;return r(e,t,this.table.firsttds,e=>{s...
  method colsWidth (line 1) | colsWidth(e,t,s=(e=>{})){let i=0;return r(e,t,this.table.ths,e=>{s(e),i+...
  method constructor (line 1) | constructor(){this.el=i.h().class("spreadsheet-borders dashed").hide()}
  method set (line 1) | set(e){if(e._offset){const{left:t,top:s,width:i,height:n}=e._offset;this...
  method hide (line 1) | hide(){this.el.hide()}
  method constructor (line 1) | constructor(e,t){super(),this.list=e,this.width=t,this.filterList=[],thi...
  method documentHandler (line 1) | documentHandler(e){if(this.el.contains(e.target))return!1;this.hideAndRe...
  method documentKeydownHandler (line 1) | documentKeydownHandler(e){if(console.log("keyCode: ",e),!(this.filterLis...
  method hideAndRemoveEvents (line 1) | hideAndRemoveEvents(){this.hide(),this.removeEvents()}
  method removeEvents (line 1) | removeEvents(){null!==this.evtTarget&&(o.unbind("click",this.data("_outs...
  method clickItemHandler (line 1) | clickItemHandler(e){this.itemClick(e),this.hideAndRemoveEvents()}
  method search (line 1) | search(e,t,s){this.removeEvents(),this.target=e,this.evtTarget=t;const{l...
  method constructor (line 1) | constructor(e,t){this.defaultRowHeight=e,this.formulas=t,this.target=nul...
  method onChange (line 1) | onChange(e){this.change=e}
  method set (line 1) | set(e,t){this.target=e;const s=this.setValue(t);this.el.show(),this.setT...
  method setValue (line 1) | setValue(e){if(this.setStyle(e),e){this.value=e;const t=e.text||"";retur...
  method setStyle (line 1) | setStyle(e){let t={width:this.textarea.style("width"),height:this.textar...
  method clear (line 1) | clear(){this.el.hide(),this.target=null,this.value=null,this.textarea.va...
  method setTextareaRange (line 1) | setTextareaRange(e){setTimeout(()=>{this.textarea.el.setSelectionRange(e...
  method inputKeydown (line 1) | inputKeydown(e){13===e.keyCode&&e.preventDefault()}
  method inputChange (line 1) | inputChange(e){const t=e.target.value;this.value?this.value.text=t:this....
  method autocomplete (line 1) | autocomplete(e){if("="===e[0])if(e.includes("("))this.suggest.hide();els...
  method reload (line 1) | reload(){if(this.target){const{offsetTop:e,offsetLeft:t,offsetWidth:s,of...
  method constructor (line 1) | constructor(e,t){this.options=t,this.cols={},this.firsttds={},this.tds={...
  method reload (line 1) | reload(){this.firsttds={},this.el.html(""),this.el.children([this.colRes...
  method moveLeft (line 1) | moveLeft(){this.currentIndexs&&this.currentIndexs[1]>0&&(this.currentInd...
  method moveUp (line 1) | moveUp(){this.currentIndexs&&this.currentIndexs[0]>0&&(this.currentIndex...
  method moveDown (line 1) | moveDown(){this.currentIndexs&&this.currentIndexs[0]<this.ss.rows("read"...
  method moveRight (line 1) | moveRight(){this.currentIndexs&&this.currentIndexs[1]<this.ss.cols().len...
  method moveSelector (line 1) | moveSelector(e){if(this.currentIndexs){const[t,s]=this.currentIndexs,i=t...
  method setValueWithText (line 1) | setValueWithText(e){this.currentIndexs&&this.ss.cellText(e.text,(e,t,s)=...
  method setTdWithCell (line 1) | setTdWithCell(e,t,s,i=!0){this.setTdStyles(e,t,s),this.setRowHeight(e,t,...
  method setCellAttr (line 1) | setCellAttr(e,t){this.ss.cellAttr(e,t,(s,i,n)=>{this.setTdWithCell(s,i,n...
  method undo (line 1) | undo(){return this.ss.undo((e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t...
  method redo (line 1) | redo(){return this.ss.redo((e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t...
  method setTdStylesAndAttrsAndText (line 1) | setTdStylesAndAttrsAndText(e,t,s){let i=this.td(e,t);this.setTdStyles(e,...
  method copy (line 1) | copy(){this.ss.copy(),this.dashedSelector.set(this.selector),this.state=...
  method cut (line 1) | cut(){this.ss.cut(),this.dashedSelector.set(this.selector),this.state="c...
  method copyformat (line 1) | copyformat(){this.ss.copy(),this.dashedSelector.set(this.selector),this....
  method paste (line 1) | paste(){null!==this.state&&this.ss.select&&(this.ss.paste((e,t,s)=>{let ...
  method clearformat (line 1) | clearformat(){this.ss.clearformat((e,t,s)=>{this.td(e,t).removeAttr("row...
  method merge (line 1) | merge(){this.ss.merge((e,t,s)=>{this.setTdAttrs(e,t,s).show(!0)},(e,t,s)...
  method insert (line 1) | insert(e,t){this.ss.insert(e,t,(e,t,s)=>{this.setTdStylesAndAttrsAndText...
  method td (line 1) | td(e,t){return this.tds[`${e}_${t}`]}
  method selectorChange (line 1) | selectorChange(){"copyformat"===this.state&&this.paste()}
  method selectorChangeCopy (line 1) | selectorChangeCopy(e,t,s,i,n,r){this.ss.batchPaste(t,s,i,n,r,e.ctrlKey,(...
  method renderCell (line 1) | renderCell(e,t,s){if(s){const i=`${e}_${t}`;return s.text&&"="===s.text[...
  method _renderCell (line 1) | _renderCell(e){if(e){let t=e.text||"";return d.formulaRender(t,(e,t)=>th...
  method reRenderFormulaCells (line 1) | reRenderFormulaCells(){this.formulaCellIndexs.forEach(e=>{let t=e.split(...
  method setRowHeight (line 1) | setRowHeight(e,t,s){if(!1===s)return;this.ss.cols();const i=this.td(e,t)...
  method setTdStyles (line 1) | setTdStyles(e,t,s){return this.td(e,t).styles(h.getStyleFromCell(s),!0)}
  method setTdAttrs (line 1) | setTdAttrs(e,t,s){return this.td(e,t).attr("rowspan",s.rowspan||1).attr(...
  method changeRowHeight (line 1) | changeRowHeight(e,t){if(t<=this.ss.defaultRowHeight())return;this.ss.row...
  method changeRowResizer (line 1) | changeRowResizer(e,t){const s=this.ss.row(e).height+t;this.changeRowHeig...
  method changeColResizer (line 1) | changeColResizer(e,t){const s=this.ss.col(e).width+t;if(s<=50)return;thi...
  method buildColGroup (line 1) | buildColGroup(e){const t=this.ss.cols();return i.h("colgroup").children(...
  method buildFixedLeft (line 1) | buildFixedLeft(){const e=this.ss.rows("read"===this.options.mode);return...
  method buildHeader (line 1) | buildHeader(){const e=this.ss.cols(),t=i.h("thead").child(i.h("tr").chil...
  method mousedownCell (line 1) | mousedownCell(e,t){if(this.editor){const e=this.editor.value;if(this.cur...
  method editCell (line 1) | editCell(e,t){const s=this.td(e,t);this.editor&&this.editor.set(s.el,thi...
  method buildBody (line 1) | buildBody(){const e=this.ss.rows("read"===this.options.mode),t=this.ss.c...
  method addRow (line 1) | addRow(e=1){}
  method firsttdsPush (line 1) | firsttdsPush(e,t){this.firsttds[`${e}`]=this.firsttds[`${e}`]||[],this.f...
  function p (line 1) | function p(e,t){for(var s=0;s<e.length;s++){var i=e[s],n=r[i.id];if(n){n...
  function u (line 1) | function u(e,t){for(var s=[],i={},n=0;n<e.length;n++){var r=e[n],o=t.bas...
  function f (line 1) | function f(e,t){var s=l(e.insertInto);if(!s)throw new Error("Couldn't fi...
  function b (line 1) | function b(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e...
  function g (line 1) | function g(e){var t=document.createElement("style");return e.attrs.type=...
  function m (line 1) | function m(e,t){Object.keys(t).forEach(function(s){e.setAttribute(s,t[s]...
  function x (line 1) | function x(e,t){var s,i,n,r;if(t.transform&&e.css){if(!(r=t.transform(e....
  function v (line 1) | function v(e,t,s,i){var n=s?"":i.css;if(e.styleSheet)e.styleSheet.cssTex...
  method constructor (line 1) | constructor(e,t,s){this.start=e,this.stop=t,this.canMerge=s}
  method forEach (line 1) | forEach(e){const[t,s]=this.start,[i,n]=this.stop;for(let r=t;r<=i;r++)fo...
  method rowIndex (line 1) | rowIndex(e){return this.start[0]+e%this.rowLen()}
  method colIndex (line 1) | colIndex(e){return this.start[1]+e%this.colLen()}
  method rowLen (line 1) | rowLen(){return this.stop[0]-this.start[0]+1}
  method colLen (line 1) | colLen(){return this.stop[1]-this.start[1]+1}
  method cellLen (line 1) | cellLen(){return this.rowLen()*this.colLen()}
  method contains (line 1) | contains(e,t){const[s,i]=this.start,[n,r]=this.stop;return s<=e&&n>=e&&i...
  class a (line 1) | class a{constructor(e){this.type=e,this.values=[]}add(e,t,s){this.values...
    method constructor (line 1) | constructor(e){this.type=e,this.values=[]}
    method add (line 1) | add(e,t,s){this.values.push([e,t,s])}
  method constructor (line 1) | constructor(e={}){if(this.histories=[],this.histories2=[],this.currentCe...
  method buildSelect (line 1) | buildSelect(e,t){const s=f(e),i=f(t);let n=s.row,r=s.col,o=i.row,l=i.col...
  method defaultRowHeight (line 1) | defaultRowHeight(){return this.data.rowHeight||22}
  method defaultColWidth (line 1) | defaultColWidth(){return this.data.colWidth||100}
  method copy (line 1) | copy(){this.copySelect=this.select}
  method cut (line 1) | cut(){this.cutSelect=this.select}
  method paste (line 1) | paste(e,t,s){let i=this.copySelect;if(this.cutSelect&&(i=this.cutSelect,...
  method insert (line 1) | insert(e,t,s){if(this.select){const{cells:t}=this.data,[i,n]=this.select...
  method batchPaste (line 1) | batchPaste(e,t,s,i,n,r,o){if(this.select){const e=new a("cells");for(let...
  method copyCell (line 1) | copyCell(e,t,s,i,n,o,l){const h=this.getCell(e,t),a=s-e,d=i-t;if(h){let ...
  method isRedo (line 1) | isRedo(){return this.histories2.length>0}
  method redo (line 1) | redo(e){const{histories:t,histories2:s}=this;if(s.length>0){const i=s.po...
  method isUndo (line 1) | isUndo(){return this.histories.length>0}
  method undo (line 1) | undo(e){const{histories:t,histories2:s}=this;if(t.length>0){const i=t.po...
  method resetByHistory (line 1) | resetByHistory(e,t,s){e.values.forEach(([i,n,r])=>{if("cells"===e.type){...
  method clearformat (line 1) | clearformat(e){const{select:t}=this;if(null!==t){const s=new a("cells");...
  method merge (line 1) | merge(e,t,s){const{select:i}=this;if(null!==i&&i.cellLen()>1){const n=ne...
  method cellAttr (line 1) | cellAttr(e,t,s){let i={};i[e]=t;const n=t===this.data.cell[e];if(null!==...
  method cellText (line 1) | cellText(e,t){if(this.currentCellIndexes){const s=new a("cells"),[i,n]=t...
  method currentCell (line 1) | currentCell(e){void 0!==e&&(this.currentCellIndexes=e);const[t,s]=this.c...
  method cell (line 1) | cell(e,t,s,i=!1){return this.data.cells=this.data.cells||{},this.data.ce...
  method getCell (line 1) | getCell(e,t){return this.data.cells&&this.data.cells[e]&&this.data.cells...
  method getFont (line 1) | getFont(e){return this.fonts.filter(t=>t.key===e)[0]}
  method getFormat (line 1) | getFormat(e){return this.formats.filter(t=>t.key===e)[0]}
  method row (line 1) | row(e,t){const{data:s}=this;if(void 0!==t){const i=new a("rows");s.rows=...
  method rows (line 1) | rows(e){const{data:t}=this;let s;return e?(s=10,this.data.cells&&(s=d(th...
  method col (line 1) | col(e,t){const{data:s}=this;if(void 0!==t){const i=new a("cols");s.cols=...
  method cols (line 1) | cols(){const{data:e}=this;let t=c(52,e.cols);return u(t,e=>this.col(e))}
  method constructor (line 1) | constructor(e,t={}){this.refs={},this.toolbar=null,this.editorbar=null,t...
  method loadData (line 1) | loadData(e){return setTimeout(()=>{this.ss.data=e,this.table.reload()},1...
  method change (line 1) | change(e){return this._change=e,this}
  method render (line 1) | render(){this.bindEl.appendChild(l.h().class("spreadsheet").children([l....
  method toolbarChange (line 1) | toolbarChange(e,t){"merge"!==e?"clearformat"!==e?"paintformat"!==e?this....
  method editorbarChange (line 1) | editorbarChange(e){this.table.setValueWithText(e)}
  method editorChange (line 1) | editorChange(e){this.editorbar&&this.editorbar.setValue(e)}
  method clickCell (line 1) | clickCell(e,t,s){const i=this.ss.cols();this.editorbar&&this.editorbar.s...
  function n (line 1) | function n(e,t){return new i.LocalSpreadsheet(e,t)}
    method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
    method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
    method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
    method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
    method parent (line 1) | parent(){return this.el.parentNode}
    method class (line 1) | class(e){return this.el.className=e,this}
    method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
    method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
    method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
    method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
    method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
    method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
    method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
    method contains (line 1) | contains(e){return this.el.contains(e)}
    method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
    method children (line 1) | children(e){for(let t of e)this.child(t);return this}
    method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
    method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
    method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
    method clone (line 1) | clone(){return this.el.cloneNode()}
    method isHide (line 1) | isHide(){return"none"===this.style("display")}
    method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
    method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
    method able (line 1) | able(){return this.removeClass("disabled"),this}
    method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
    method deactive (line 1) | deactive(){return this.removeClass("active")}
    method isActive (line 1) | isActive(){return this.hasClass("active")}
    method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
    method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
    method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
    method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
    method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
    method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
    method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
    method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}

FILE: src/core/alphabet.ts
  function alphabet (line 2) | function alphabet(index: number): string {
  function alphabetIndex (line 8) | function alphabetIndex (key: string): number {

FILE: src/core/cell.d.ts
  type Cell (line 1) | interface Cell {

FILE: src/core/cell.ts
  type Cell (line 1) | interface Cell {
  function getStyleFromCell (line 40) | function getStyleFromCell (cell: Cell | null): {[key: string]: string} {

FILE: src/core/font.d.ts
  type Font (line 1) | interface Font {

FILE: src/core/font.ts
  type Font (line 1) | interface Font {

FILE: src/core/format.d.ts
  type Format (line 1) | interface Format {

FILE: src/core/format.ts
  type Format (line 1) | interface Format {

FILE: src/core/formula.d.ts
  type Formula (line 1) | interface Formula {

FILE: src/core/formula.ts
  type Formula (line 3) | interface Formula {

FILE: src/core/index.d.ts
  type Row (line 6) | interface Row {
  type Col (line 9) | interface Col {
  type MapInt (line 13) | interface MapInt<T> {
  class History (line 16) | class History {
  type StandardCallback (line 22) | type StandardCallback = (rindex: number, cindex: number, cell: Cell) => ...
  type SpreadsheetData (line 23) | interface SpreadsheetData {
  type SpreadsheetOptions (line 32) | interface SpreadsheetOptions {
  class Spreadsheet (line 38) | class Spreadsheet {

FILE: src/core/index.ts
  type Row (line 9) | interface Row {
  type Col (line 12) | interface Col {
  type MapInt (line 16) | interface MapInt<T> {
  class History (line 19) | class History {
    method constructor (line 21) | constructor (public type: 'rows' | 'cols' | 'cells') {}
    method add (line 22) | add (keys: Array<any>, oldValue: any, value: any) {
  type StandardCallback (line 27) | type StandardCallback = (rindex: number, cindex: number, cell: Cell) => ...
  type SpreadsheetData (line 29) | interface SpreadsheetData {
  type SpreadsheetOptions (line 39) | interface SpreadsheetOptions {
  class Spreadsheet (line 46) | class Spreadsheet {
    method constructor (line 60) | constructor (options: SpreadsheetOptions = {}) {
    method buildSelect (line 78) | buildSelect (startTarget: any, endTarget: any) {
    method defaultRowHeight (line 120) | defaultRowHeight (): number {
    method defaultColWidth (line 124) | defaultColWidth (): number {
    method copy (line 128) | copy (): void {
    method cut (line 131) | cut (): void {
    method paste (line 134) | paste (cb: StandardCallback, state: 'copy' | 'cut' | 'copyformat', cle...
    method insert (line 165) | insert (type: 'row' | 'col', amount: number, cb: StandardCallback) {
    method batchPaste (line 219) | batchPaste (arrow: 'bottom' | 'top' | 'left' | 'right',
    method copyCell (line 237) | private copyCell (srcRowIndex: number, srcColIndex: number, destRowInd...
    method isRedo (line 277) | isRedo (): boolean {
    method redo (line 280) | redo (cb: StandardCallback): boolean {
    method isUndo (line 293) | isUndo (): boolean {
    method undo (line 296) | undo (cb: StandardCallback): boolean {
    method resetByHistory (line 310) | resetByHistory (v: History, cb: StandardCallback, state: 'undo' | 'red...
    method clearformat (line 350) | clearformat (cb: StandardCallback) {
    method merge (line 373) | merge (ok: StandardCallback, cancel: StandardCallback, other: Standard...
    method cellAttr (line 427) | cellAttr (key: keyof Cell, value: any, cb: StandardCallback): void {
    method cellText (line 446) | cellText (value: any, cb: StandardCallback): Cell | null {
    method currentCell (line 462) | currentCell (indexes?: [number, number]): Cell | null {
    method cell (line 470) | cell (rindex: number, cindex: number, v: any, isCopy = false): Cell {
    method getCell (line 482) | getCell (rindex: number, cindex: number): Cell | null {
    method getFont (line 489) | getFont (key: string | undefined) {
    method getFormat (line 492) | getFormat (key: string | undefined) {
    method row (line 496) | row (index: number, v?: number): Row {
    method rows (line 509) | rows (isData: boolean): Array<Row> {
    method col (line 523) | col (index: number, v?: number): Col {
    method cols (line 544) | cols (): Array<Col> {

FILE: src/core/select.d.ts
  class Select (line 1) | class Select {

FILE: src/core/select.ts
  class Select (line 1) | class Select {
    method constructor (line 2) | constructor(public start: [number, number], public stop: [number, numb...
    method forEach (line 3) | forEach (cb: (r:number, c: number, rindex: number, cindex: number, row...
    method rowIndex (line 12) | rowIndex (index: number) {
    method colIndex (line 15) | colIndex (index: number) {
    method rowLen (line 18) | rowLen () {
    method colLen (line 21) | colLen () {
    method cellLen (line 24) | cellLen () {
    method contains (line 27) | contains (rindex: number, cindex: number) {

FILE: src/local/base/colorPanel.d.ts
  class ColorPanel (line 2) | class ColorPanel extends Element {

FILE: src/local/base/colorPanel.ts
  class ColorPanel (line 13) | class ColorPanel extends Element {
    method constructor (line 15) | constructor (click: (color: string) => void) {
  function buildColorPanel (line 38) | function buildColorPanel (click: (color: string) => void) {

FILE: src/local/base/dropdown.d.ts
  class Dropdown (line 2) | class Dropdown extends Element {

FILE: src/local/base/dropdown.ts
  class Dropdown (line 4) | class Dropdown extends Element {
    method constructor (line 8) | constructor (title: string | Element, width: string, contentChildren: ...
    method toggleHandler (line 24) | toggleHandler (evt: Event) {
  function buildDropdown (line 34) | function buildDropdown(title: string | Element, width: string, contentCh...

FILE: src/local/base/element.d.ts
  class Element (line 1) | class Element {

FILE: src/local/base/element.ts
  class Element (line 3) | class Element {
    method constructor (line 8) | constructor (public tag = 'div') {
    method data (line 12) | data (key: string, value?: any) {
    method on (line 19) | on (eventName: string, handler: (evt: any) => any): Element {
    method onClickOutside (line 40) | onClickOutside (cb: () => void): Element {
    method parent (line 45) | parent(): any {
    method class (line 49) | class (name: string): Element {
    method attrs (line 54) | attrs (map: {[key: string]: string} = {}): Element {
    method attr (line 60) | attr (attr: string, value?: any): any {
    method removeAttr (line 68) | removeAttr(attr: string): Element {
    method offset (line 73) | offset (): any {
    method clearStyle (line 78) | clearStyle () {
    method styles (line 83) | styles (map: {[key: string]: string} = {}, isClear = false): Element {
    method style (line 92) | style (key: string, value?: any): any {
    method contains (line 101) | contains (el: any) {
    method removeStyle (line 105) | removeStyle (key: string) {
    method children (line 110) | children (cs: Array<HTMLElement | string | Element>): Element {
    method child (line 116) | child (c: HTMLElement | string | Element): Element {
    method html (line 127) | html (html?: string) {
    method val (line 136) | val (v?: string) {
    method clone (line 146) | clone (): any {
    method isHide (line 150) | isHide () {
    method toggle (line 154) | toggle () {
    method disabled (line 162) | disabled (): Element {
    method able (line 167) | able (): Element {
    method active (line 172) | active (flag = true): Element {
    method deactive (line 181) | deactive (): Element {
    method isActive (line 184) | isActive (): boolean {
    method addClass (line 188) | addClass (cls: string): Element {
    method removeClass (line 192) | removeClass (cls: string) {
    method hasClass (line 198) | hasClass (cls: string) {
    method show (line 202) | show (isRemove = false): Element {
    method hide (line 221) | hide (): Element {
  function h (line 230) | function h (tag = 'div'): Element {

FILE: src/local/base/icon.d.ts
  class Icon (line 2) | class Icon extends Element {

FILE: src/local/base/icon.ts
  class Icon (line 3) | class Icon extends Element{
    method constructor (line 7) | constructor (name: string) {
    method replace (line 12) | replace (name: string) {
  function buildIcon (line 18) | function buildIcon (name: string) {

FILE: src/local/base/item.d.ts
  class Item (line 3) | class Item extends Element {

FILE: src/local/base/item.ts
  class Item (line 4) | class Item extends Element {
    method build (line 8) | static build (): Item {
    method constructor (line 12) | constructor () {
    method icon (line 17) | icon (name: string) {
    method replaceIcon (line 22) | replaceIcon (name: string) {
  function buildItem (line 28) | function buildItem (): Item {

FILE: src/local/base/menu.d.ts
  class Menu (line 2) | class Menu extends Element {

FILE: src/local/base/menu.ts
  class Menu (line 3) | class Menu extends Element{
    method constructor (line 5) | constructor (align = 'vertical') {
  function buildMenu (line 12) | function buildMenu (align = 'vertical') {

FILE: src/local/base/suggest.d.ts
  class Suggest (line 2) | class Suggest extends Element {

FILE: src/local/base/suggest.ts
  class Suggest (line 6) | class Suggest extends Element {
    method constructor (line 15) | constructor (public list: Array<[string, string]>, public width: numbe...
    method documentHandler (line 20) | private documentHandler (e: any) {
    method documentKeydownHandler (line 26) | private documentKeydownHandler (e: any) {
    method hideAndRemoveEvents (line 64) | private hideAndRemoveEvents () {
    method removeEvents (line 68) | private removeEvents () {
    method clickItemHandler (line 75) | private clickItemHandler (it: [string, string]) {
    method search (line 82) | search (target: Element, input: Element, word: string) {

FILE: src/local/contextmenu.d.ts
  class ContextMenu (line 3) | class ContextMenu {

FILE: src/local/contextmenu.ts
  class ContextMenu (line 6) | class ContextMenu {
    method constructor (line 8) | constructor (public table: Table) {
    method set (line 25) | set (evt: any) {

FILE: src/local/editor.d.ts
  class Editor (line 5) | class Editor {

FILE: src/local/editor.ts
  class Editor (line 6) | class Editor {
    method constructor (line 16) | constructor (public defaultRowHeight: number, public formulas : Array<...
    method onChange (line 46) | onChange (change: (v: Cell) => void) {
    method set (line 50) | set (target: HTMLElement, value: Cell | null) {
    method setValue (line 61) | setValue (value: Cell | null): string {
    method setStyle (line 73) | setStyle (value: Cell | null): void {
    method clear (line 78) | clear () {
    method setTextareaRange (line 87) | private setTextareaRange (position: number) {
    method inputKeydown (line 94) | private inputKeydown (evt: any) {
    method inputChange (line 100) | private inputChange (evt: any) {
    method autocomplete (line 115) | private autocomplete (v: string) {
    method reload (line 129) | reload () {

FILE: src/local/editorbar.d.ts
  class Editorbar (line 3) | class Editorbar {

FILE: src/local/editorbar.ts
  class Editorbar (line 5) | class Editorbar {
    method constructor (line 11) | constructor () {
    method set (line 21) | set (title: string, value: Cell | null) {
    method setValue (line 26) | setValue (value: Cell | null) {
    method input (line 31) | input (evt: any) {

FILE: src/local/event.ts
  function bind (line 1) | function bind<T extends Event>(name: string, fn: (evt: T) => void, targe...
  function unbind (line 4) | function unbind<T extends Event>(name: string, fn: (evt: T) => void, tar...
  function mouseMoveUp (line 7) | function mouseMoveUp<T extends Event> (movefunc: (evt: T) => void, upfun...

FILE: src/local/index.d.ts
  type Options (line 6) | interface Options extends SpreadsheetOptions {
  class LocalSpreadsheet (line 10) | class LocalSpreadsheet {

FILE: src/local/index.ts
  type Options (line 13) | interface Options extends SpreadsheetOptions {
  class LocalSpreadsheet (line 18) | class LocalSpreadsheet {
    method constructor (line 30) | constructor (el: HTMLElement, options: Options = {}) {
    method loadData (line 75) | loadData (data: SpreadsheetData): LocalSpreadsheet {
    method change (line 84) | change (cb: (data: SpreadsheetData) => void): LocalSpreadsheet {
    method render (line 89) | private render (): void {
    method toolbarChange (line 99) | private toolbarChange (k: keyof Cell, v: any) {
    method editorbarChange (line 114) | private editorbarChange (v: Cell) {
    method editorChange (line 118) | private editorChange (v: Cell) {
    method clickCell (line 122) | private clickCell (rindex: number, cindex: number, v: Cell | null) {

FILE: src/local/resizer.d.ts
  class Resizer (line 2) | class Resizer {

FILE: src/local/resizer.ts
  class Resizer (line 4) | class Resizer {
    method constructor (line 10) | constructor (public vertical: boolean, public change: (index: number, ...
    method set (line 18) | set (target: any, index: number, scroll: number) {
    method mousedown (line 38) | mousedown (evt: any) {

FILE: src/local/selector.d.ts
  class Selector (line 4) | class Selector {
  class DashedSelector (line 34) | class DashedSelector {

FILE: src/local/selector.ts
  class Selector (line 6) | class Selector {
    method constructor (line 24) | constructor (public ss: Spreadsheet, public table: Table) {
    method mousedown (line 43) | mousedown (evt: any) {
    method setCurrentTarget (line 68) | setCurrentTarget (target: HTMLElement) {
    method cornerMousedown (line 73) | private cornerMousedown (evt: any) {
    method reload (line 149) | reload () {
    method setOffset (line 153) | private setOffset () {
    method rowsHeight (line 198) | private rowsHeight (minRow:number, maxRow:number, cb: (e: Element) => ...
    method colsWidth (line 207) | private colsWidth (minCol: number, maxCol: number, cb: (e: Element) =>...
  class DashedSelector (line 230) | class DashedSelector {
    method constructor (line 232) | constructor () {
    method set (line 236) | set (selector: Selector) {
    method hide (line 248) | hide () {

FILE: src/local/table.d.ts
  type Map (line 8) | interface Map<T> {
  type TableOption (line 11) | interface TableOption {
  class Table (line 16) | class Table {

FILE: src/local/table.ts
  type Map (line 14) | interface Map<T> {
  type TableOption (line 18) | interface TableOption {
  class Table (line 24) | class Table {
    method constructor (line 57) | constructor (ss: Spreadsheet, public options: TableOption) {
    method reload (line 184) | reload () {
    method moveLeft (line 196) | private moveLeft () {
    method moveUp (line 202) | private moveUp () {
    method moveDown (line 208) | private moveDown () {
    method moveRight (line 214) | private moveRight () {
    method moveSelector (line 222) | private moveSelector (direction: 'right' | 'left' | 'up' | 'down') {
    method setValueWithText (line 253) | setValueWithText (v: Cell) {
    method setTdWithCell (line 263) | setTdWithCell (rindex: number, cindex: number, cell: Cell, autoWordWra...
    method setCellAttr (line 269) | setCellAttr (k: keyof Cell, v: any) {
    method undo (line 278) | undo (): boolean {
    method redo (line 284) | redo (): boolean {
    method setTdStylesAndAttrsAndText (line 289) | private setTdStylesAndAttrsAndText (rindex: number, cindex: number, ce...
    method copy (line 297) | copy () {
    method cut (line 303) | cut () {
    method copyformat (line 309) | copyformat () {
    method paste (line 315) | paste () {
    method clearformat (line 346) | clearformat () {
    method merge (line 356) | merge () {
    method insert (line 369) | insert (type: 'row' | 'col', amount: number) {
    method td (line 380) | td (rindex: number, cindex: number): Element {
    method selectorChange (line 385) | private selectorChange () {
    method selectorChangeCopy (line 391) | private selectorChangeCopy (evt: any, arrow: 'bottom' | 'top' | 'left'...
    method renderCell (line 399) | private renderCell (rindex: number, cindex: number, cell: Cell | null)...
    method _renderCell (line 416) | private _renderCell (cell: Cell | null): string {
    method reRenderFormulaCells (line 423) | private reRenderFormulaCells () {
    method setRowHeight (line 435) | private setRowHeight (rindex: number, cindex: number, autoWordWrap: bo...
    method setTdStyles (line 456) | private setTdStyles (rindex: number, cindex: number, cell: Cell): Elem...
    method setTdAttrs (line 459) | private setTdAttrs (rindex: number, cindex: number, cell: Cell): Eleme...
    method changeRowHeight (line 465) | private changeRowHeight (index: number, h: number) {
    method changeRowResizer (line 475) | private changeRowResizer (index: number, distance: number) {
    method changeColResizer (line 479) | private changeColResizer (index: number, distance: number) {
    method buildColGroup (line 491) | private buildColGroup (lastColWidth: number): Element {
    method buildFixedLeft (line 505) | private buildFixedLeft (): Element {
    method buildHeader (line 535) | private buildHeader (): Element {
    method mousedownCell (line 556) | private mousedownCell (rindex: number, cindex: number) {
    method editCell (line 583) | private editCell(rindex: number, cindex: number) {
    method buildBody (line 588) | private buildBody () {
    method addRow (line 657) | private addRow (num = 1) {
    method firsttdsPush (line 663) | private firsttdsPush (index: number, el: Element) {

FILE: src/local/toolbar.d.ts
  class Toolbar (line 5) | class Toolbar {

FILE: src/local/toolbar.ts
  class Toolbar (line 13) | class Toolbar {
    method constructor (line 41) | constructor (public ss: Spreadsheet) {
    method set (line 71) | set (target: Element, cell: Cell | null) {
    method setCell (line 76) | private setCell (cell: Cell | null) {
    method setCellStyle (line 81) | private setCellStyle () {
    method setRedoAble (line 108) | setRedoAble (flag: boolean) {
    method setUndoAble (line 112) | setUndoAble (flag: boolean) {
    method buildSeparator (line 116) | private buildSeparator (): Element {
    method buildAligns (line 119) | private buildAligns (): Dropdown {
    method buildValigns (line 133) | private buildValigns (): Dropdown {
    method buildWordWrap (line 147) | private buildWordWrap (): Element {
    method buildFontWeight (line 150) | private buildFontWeight (): Element {
    method buildFontStyle (line 153) | private buildFontStyle (): Element {
    method buildTextDecoration (line 156) | private buildTextDecoration (): Element {
    method buildMerge (line 159) | private buildMerge (): Element {
    method buildColor (line 162) | private buildColor (): Dropdown {
    method buildBackgroundColor (line 172) | private buildBackgroundColor (): Dropdown {
    method buildUndo (line 182) | private buildUndo (): Element {
    method buildRedo (line 189) | private buildRedo (): Element {
    method buildPaintformat (line 196) | private buildPaintformat (): Element {
    method buildClearformat (line 202) | private buildClearformat (): Element {
    method buildFormats (line 208) | private buildFormats (): Dropdown {
    method buildFonts (line 221) | private buildFonts (): Dropdown {
    method buildFontSizes (line 234) | private buildFontSizes (): Dropdown {

FILE: src/main.d.ts
  type Window (line 4) | interface Window {

FILE: src/main.ts
  function xspreadsheet (line 3) | function xspreadsheet (el: HTMLElement, options?: Options) {
  type Window (line 8) | interface Window {
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (221K chars).
[
  {
    "path": ".gitignore",
    "chars": 22,
    "preview": "node_modules/\n.vscode/"
  },
  {
    "path": "LICENSE",
    "chars": 1064,
    "preview": "MIT License\n\nCopyright (c) 2017 myliang\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
  },
  {
    "path": "README.md",
    "chars": 1035,
    "preview": "# XSpreadsheet\n\n[![npm package](https://img.shields.io/npm/v/xspreadsheet.svg)](https://www.npmjs.org/package/xspreadshe"
  },
  {
    "path": "docs/index.html",
    "chars": 673,
    "preview": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\""
  },
  {
    "path": "docs/xspreadsheet.js",
    "chars": 66593,
    "preview": "!function(e){var t={};function s(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.expo"
  },
  {
    "path": "index.html",
    "chars": 6952,
    "preview": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\""
  },
  {
    "path": "package.json",
    "chars": 1064,
    "preview": "{\n  \"name\": \"xspreadsheet\",\n  \"version\": \"1.0.4\",\n  \"description\": \"a javascript spreadsheet\",\n  \"author\": \"myliang <lia"
  },
  {
    "path": "src/core/alphabet.d.ts",
    "chars": 117,
    "preview": "export declare function alphabet(index: number): string;\nexport declare function alphabetIndex(key: string): number;\n"
  },
  {
    "path": "src/core/alphabet.ts",
    "chars": 629,
    "preview": "const _alphabet = ['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','"
  },
  {
    "path": "src/core/cell.d.ts",
    "chars": 544,
    "preview": "export interface Cell {\n    font?: string;\n    format?: string;\n    fontSize?: number;\n    bold?: boolean;\n    italic?: "
  },
  {
    "path": "src/core/cell.ts",
    "chars": 1515,
    "preview": "export interface Cell {\n  font?: string;\n  format?: string;\n  fontSize?: number;\n  bold?: boolean;\n  italic?: boolean;\n "
  },
  {
    "path": "src/core/font.d.ts",
    "chars": 103,
    "preview": "export interface Font {\n    key: string;\n    title: string;\n}\nexport declare const fonts: Array<Font>;\n"
  },
  {
    "path": "src/core/font.ts",
    "chars": 344,
    "preview": "export interface Font {\n  key: string;\n  title: string;\n}\n\nexport const fonts: Array<Font> = [\n  {key: 'Microsoft YaHei'"
  },
  {
    "path": "src/core/format.d.ts",
    "chars": 263,
    "preview": "export interface Format {\n    key: string;\n    title: string;\n    label?: string;\n    render(txt: string): string;\n}\nexp"
  },
  {
    "path": "src/core/format.ts",
    "chars": 1181,
    "preview": "export interface Format {\n  key: string;\n  title: string;\n  label?: string;\n  render(txt: string): string;\n}\nexport cons"
  },
  {
    "path": "src/core/formula.d.ts",
    "chars": 482,
    "preview": "export interface Formula {\n    key: string;\n    title: string;\n    render(ary: Array<number>): number;\n}\nexport declare "
  },
  {
    "path": "src/core/formula.ts",
    "chars": 3661,
    "preview": "import { alphabetIndex, alphabet } from \"./alphabet\";\n\nexport interface Formula {\n  key: string;\n  title: string;\n  rend"
  },
  {
    "path": "src/core/index.d.ts",
    "chars": 2837,
    "preview": "import { Format } from './format';\nimport { Font } from './font';\nimport { Formula } from './formula';\nimport { Cell } f"
  },
  {
    "path": "src/core/index.ts",
    "chars": 22064,
    "preview": "import { Format, formats } from './format'\nimport { Font, fonts } from './font'\nimport { Formula, formulas, formulaRepla"
  },
  {
    "path": "src/core/select.d.ts",
    "chars": 514,
    "preview": "export declare class Select {\n    start: [number, number];\n    stop: [number, number];\n    canMerge: boolean;\n    constr"
  },
  {
    "path": "src/core/select.ts",
    "chars": 1050,
    "preview": "export class Select {\n  constructor(public start: [number, number], public stop: [number, number], public canMerge: bool"
  },
  {
    "path": "src/local/base/colorPanel.d.ts",
    "chars": 223,
    "preview": "import { Element } from \"./element\";\nexport declare class ColorPanel extends Element {\n    constructor(click: (color: st"
  },
  {
    "path": "src/local/base/colorPanel.ts",
    "chars": 1573,
    "preview": "import { Element, h } from \"./element\";\n\nconst colorss = [\n  ['#c00000', '#ff0000', '#ffc003', '#ffff00','#91d051', '#00"
  },
  {
    "path": "src/local/base/dropdown.d.ts",
    "chars": 368,
    "preview": "import { Element } from \"./element\";\nexport declare class Dropdown extends Element {\n    content: Element;\n    title: El"
  },
  {
    "path": "src/local/base/dropdown.ts",
    "chars": 1210,
    "preview": "import { Element, h } from \"./element\";\nimport { buildIcon } from \"./icon\";\n\nexport class Dropdown extends Element {\n  c"
  },
  {
    "path": "src/local/base/element.d.ts",
    "chars": 1362,
    "preview": "export declare class Element {\n    tag: string;\n    el: HTMLElement;\n    _data: {\n        [key: string]: any;\n    };\n   "
  },
  {
    "path": "src/local/base/element.ts",
    "chars": 5360,
    "preview": "import { bind, unbind } from '../event'\n\nexport class Element {\n  el: HTMLElement;\n  _data: {[key: string]: any} = {};\n "
  },
  {
    "path": "src/local/base/icon.d.ts",
    "chars": 220,
    "preview": "import { Element } from \"./element\";\nexport declare class Icon extends Element {\n    img: Element;\n    constructor(name:"
  },
  {
    "path": "src/local/base/icon.ts",
    "chars": 394,
    "preview": "import { Element, h } from \"./element\";\n\nexport class Icon extends Element{\n\n  img: Element;\n\n  constructor (name: strin"
  },
  {
    "path": "src/local/base/item.d.ts",
    "chars": 294,
    "preview": "import { Element } from \"./element\";\nimport { Icon } from \"./icon\";\nexport declare class Item extends Element {\n    icon"
  },
  {
    "path": "src/local/base/item.ts",
    "chars": 511,
    "preview": "import { Element } from \"./element\";\nimport { Icon, buildIcon } from \"./icon\";\n\nexport class Item extends Element {\n\n  i"
  },
  {
    "path": "src/local/base/menu.d.ts",
    "chars": 173,
    "preview": "import { Element } from \"./element\";\nexport declare class Menu extends Element {\n    constructor(align?: string);\n}\nexpo"
  },
  {
    "path": "src/local/base/menu.ts",
    "chars": 252,
    "preview": "import { Element } from \"./element\";\n\nexport class Menu extends Element{\n\n  constructor (align = 'vertical') {\n    super"
  },
  {
    "path": "src/local/base/suggest.d.ts",
    "chars": 586,
    "preview": "import { Element } from \"./element\";\nexport declare class Suggest extends Element {\n    list: Array<[string, string]>;\n "
  },
  {
    "path": "src/local/base/suggest.ts",
    "chars": 3753,
    "preview": "import { Element, h } from \"./element\";\nimport { buildItem } from \"./item\";\nimport { buildMenu } from \"./menu\";\nimport {"
  },
  {
    "path": "src/local/contextmenu.d.ts",
    "chars": 203,
    "preview": "import { Element } from \"./base/element\";\nimport { Table } from \"./table\";\nexport declare class ContextMenu {\n    table:"
  },
  {
    "path": "src/local/contextmenu.ts",
    "chars": 1566,
    "preview": "import { Element, h } from \"./base/element\";\nimport { buildItem } from \"./base/item\";\nimport { buildMenu } from \"./base/"
  },
  {
    "path": "src/local/editor.d.ts",
    "chars": 849,
    "preview": "import { Element } from \"./base/element\";\nimport { Suggest } from \"./base/suggest\";\nimport { Cell } from \"../core/cell\";"
  },
  {
    "path": "src/local/editor.ts",
    "chars": 5244,
    "preview": "import { Element, h } from \"./base/element\";\nimport { Suggest } from \"./base/suggest\";\nimport { Cell, getStyleFromCell }"
  },
  {
    "path": "src/local/editorbar.d.ts",
    "chars": 365,
    "preview": "import { Element } from \"./base/element\";\nimport { Cell } from \"../core/cell\";\nexport declare class Editorbar {\n    el: "
  },
  {
    "path": "src/local/editorbar.ts",
    "chars": 1066,
    "preview": "import { Element, h } from \"./base/element\";\nimport { Cell } from \"../core/cell\";\nimport { mouseMoveUp } from \"./event\"\n"
  },
  {
    "path": "src/local/event.d.ts",
    "chars": 322,
    "preview": "export declare function bind<T extends Event>(name: string, fn: (evt: T) => void, target?: any): void;\nexport declare fu"
  },
  {
    "path": "src/local/event.ts",
    "chars": 539,
    "preview": "export function bind<T extends Event>(name: string, fn: (evt: T) => void, target: any = window) {\n  target.addEventListe"
  },
  {
    "path": "src/local/index.d.ts",
    "chars": 937,
    "preview": "import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index';\nimport '../style/index.less';\nimport {"
  },
  {
    "path": "src/local/index.ts",
    "chars": 3774,
    "preview": "import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index'\nimport '../style/index.less'\nimport { C"
  },
  {
    "path": "src/local/resizer.d.ts",
    "chars": 435,
    "preview": "import { Element } from \"./base/element\";\nexport declare class Resizer {\n    vertical: boolean;\n    change: (index: numb"
  },
  {
    "path": "src/local/resizer.ts",
    "chars": 2550,
    "preview": "import { Element, h } from \"./base/element\";\nimport { mouseMoveUp } from './event';\n\nexport class Resizer {\n  el: Elemen"
  },
  {
    "path": "src/local/selector.d.ts",
    "chars": 1065,
    "preview": "import { Element } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Table } from './table';\n"
  },
  {
    "path": "src/local/selector.ts",
    "chars": 8648,
    "preview": "import { Element, h } from \"./base/element\";\nimport { bind, mouseMoveUp } from './event';\nimport { Spreadsheet } from \"."
  },
  {
    "path": "src/local/table.d.ts",
    "chars": 2445,
    "preview": "import { Element } from \"./base/element\";\nimport { Spreadsheet, SpreadsheetData } from '../core/index';\nimport { Editor "
  },
  {
    "path": "src/local/table.ts",
    "chars": 21460,
    "preview": "import { Element, h } from \"./base/element\";\nimport { Spreadsheet, SpreadsheetData } from '../core/index'\nimport { Edito"
  },
  {
    "path": "src/local/toolbar.d.ts",
    "chars": 1491,
    "preview": "import { Element } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Cell } from '../core/cel"
  },
  {
    "path": "src/local/toolbar.ts",
    "chars": 9507,
    "preview": "import { Element, h } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Cell, getStyleFromCel"
  },
  {
    "path": "src/main.d.ts",
    "chars": 226,
    "preview": "import { LocalSpreadsheet, Options } from './local/index';\nexport default function xspreadsheet(el: HTMLElement, options"
  },
  {
    "path": "src/main.ts",
    "chars": 285,
    "preview": "import { LocalSpreadsheet, Options } from './local/index';\n\nexport default function xspreadsheet (el: HTMLElement, optio"
  },
  {
    "path": "src/style/index.less",
    "chars": 9326,
    "preview": "@border-style: 1px solid #e0e2e4;\n@icon-size: 18px;\n\nbody {\n  margin: 0;\n}\n\n.spreadsheet {\n  font-size: 14px;\n  line-hei"
  },
  {
    "path": "tsconfig.json",
    "chars": 5192,
    "preview": "{\n  \"compilerOptions\": {\n    /* Basic Options */\n    \"target\": \"ES2015\",                          /* Specify ECMAScript "
  },
  {
    "path": "tslint.json",
    "chars": 217,
    "preview": "{\n    \"defaultSeverity\": \"error\",\n    \"extends\": [\n        \"tslint:recommended\",\n        \"tslint-eslint-rules\"\n    ],\n  "
  },
  {
    "path": "webpack.config.dev.js",
    "chars": 1666,
    "preview": "var ExtractTextPlugin = require('extract-text-webpack-plugin');\nmodule.exports = {\n  entry: \"./src/main.ts\",\n  output: {"
  },
  {
    "path": "webpack.config.js",
    "chars": 1396,
    "preview": "var ExtractTextPlugin = require('extract-text-webpack-plugin');\nmodule.exports = {\n  entry: \"./src/main.ts\",\n  output: {"
  }
]

About this extraction

This page contains the full source code of the myliang/xspreadsheet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (204.8 KB), approximately 62.2k tokens, and a symbol index with 476 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!