[
  {
    "path": ".gitignore",
    "content": "node_modules/\n.vscode/"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2017 myliang\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# XSpreadsheet\n\n[![npm package](https://img.shields.io/npm/v/xspreadsheet.svg)](https://www.npmjs.org/package/xspreadsheet)\n[![NPM downloads](http://img.shields.io/npm/dm/xspreadsheet.svg)](https://npmjs.org/package/xspreadsheet)\n\n> a javascript spreadsheet for web\n\n<p align=\"center\">\n  <a href=\"https://github.com/myliang/xspreadsheet\">\n    <img width=\"100%\" src=\"/docs/demo.png?raw=true\">\n  </a>\n</p>\n\n## Install\n```shell\nnpm install typescript --save-dev\nnpm install awesome-typescript-loader --save-dev\nnpm install xspreadsheet --save-dev\n```\n\n## Quick Start\n\n``` javascript\nimport xspreadsheet from 'xspreadsheet'\n\nconst x = xspreadsheet(document.getElementById('#id'))\nx.change = (data) => {\n  console.log('data:', data)\n}\n\n// edit\n// data is param in the change method\nxspreadsheet(document.getElementById('#id'), {d: data})\n```\n\n### in tsconfig.json\n```\n{\n  \"compilerOptions\": {\n    ....\n    \"types\": [\"xspreadsheet\"],\n    ....\n  }\n}\n\n```\n\n## Browser Support\nModern browsers and Internet Explorer 9+(no test).\n\n## LICENSE\nMIT\n"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"xspreadsheet.css\"></link>\n    <script type=\"text/javascript\" src=\"xspreadsheet.js\"></script>\n    <script type=\"text/javascript\">\n      window.onload = function () {\n        xspreadsheet(document.getElementById('wrapper')).change(function (data) {\n          console.log('data:', data)\n        })\n      }\n    </script> \n    <title>XSpreadsheet Demo</title>\n  </head>\n  <body>\n    <div id=\"wrapper\"></div>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/xspreadsheet.js",
    "content": "!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}]);\n//# sourceMappingURL=xspreadsheet.js.map"
  },
  {
    "path": "index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"spreadsheet.css\"></link>\n    <script type=\"text/javascript\" src=\"bundle.js\"></script>\n    <script type=\"text/javascript\">\n      window.onload = function () {\n        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\"}}}};\n        xspreadsheet(document.getElementById('wrapper'), {mode: 'design'}).loadData(data)\n      }\n    </script> \n    <title>TypeScript with VSCode</title>\n  </head>\n  <body>\n      <div style=\"display: flex;\">\n        <div style=\"width: 300px; flex: 0 0 auto;\">\n          xxxxxx\n        </div>\n        <div style=\"flex: 1 1 auto;overflow: hidden;\">\n          <div id=\"wrapper\"></div>  \n        </div>\n      </div>\n\n  </body>\n</html>\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"xspreadsheet\",\n  \"version\": \"1.0.4\",\n  \"description\": \"a javascript spreadsheet\",\n  \"author\": \"myliang <liangyuliang0335@126.com>\",\n  \"private\": false,\n  \"main\": \"src/main.ts\",\n  \"types\": \"src/main.d.ts\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/myliang/spreadsheet.git\"\n  },\n  \"scripts\": {\n    \"dev\": \"webpack-dev-server --color --inline --hot --config webpack.config.dev.js --open\",\n    \"build\": \"webpack --config webpack.config.js --progress --color\"\n  },\n  \"keywords\": [\n    \"excel\",\n    \"js\",\n    \"component\",\n    \"ui\",\n    \"spreadsheet\"\n  ],\n  \"license\": \"MIT\",\n  \"devDependencies\": {\n    \"awesome-typescript-loader\": \"^5.2.0\",\n    \"css-loader\": \"^0.28.11\",\n    \"extract-text-webpack-plugin\": \"^4.0.0-beta.0\",\n    \"file-loader\": \"^1.1.11\",\n    \"less\": \"^3.0.1\",\n    \"less-loader\": \"^4.1.0\",\n    \"source-map-loader\": \"^0.2.3\",\n    \"style-loader\": \"^0.20.3\",\n    \"tslint-eslint-rules\": \"^5.2.0\",\n    \"typescript\": \"^2.9.2\",\n    \"webpack\": \"^4.5.0\",\n    \"webpack-cli\": \"^2.0.14\",\n    \"webpack-dev-server\": \"^3.1.3\"\n  }\n}\n"
  },
  {
    "path": "src/core/alphabet.d.ts",
    "content": "export declare function alphabet(index: number): string;\nexport declare function alphabetIndex(key: string): number;\n"
  },
  {
    "path": "src/core/alphabet.ts",
    "content": "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']\nexport function alphabet(index: number): string {\n  const [a, b] = [parseInt(index / _alphabet.length + ''), index % _alphabet.length]\n  // console.log('a: ', a, '; b: ', b)\n  return a > 0 ? `${_alphabet[a - 1]}${_alphabet[b]}` : _alphabet[b]\n}\n\nexport function alphabetIndex (key: string): number {\n  let ret = 0;\n  for (let i = 0; i < key.length; i++) {\n    // console.log(key.charCodeAt(i), key[i])\n    let cindex = key.charCodeAt(i) - 65;\n    ret += i * _alphabet.length + cindex;\n  }\n  return ret;\n}\n"
  },
  {
    "path": "src/core/cell.d.ts",
    "content": "export interface Cell {\n    font?: string;\n    format?: string;\n    fontSize?: number;\n    bold?: boolean;\n    italic?: boolean;\n    underline?: boolean;\n    color?: string;\n    backgroundColor?: string;\n    align?: string;\n    valign?: string;\n    wordWrap?: boolean;\n    visable?: boolean;\n    rowspan?: number;\n    colspan?: number;\n    text?: string;\n    merge?: [number, number];\n    [key: string]: any;\n}\nexport declare const defaultCell: Cell;\nexport declare function getStyleFromCell(cell: Cell | null): {\n    [key: string]: string;\n};\n"
  },
  {
    "path": "src/core/cell.ts",
    "content": "export interface Cell {\n  font?: string;\n  format?: string;\n  fontSize?: number;\n  bold?: boolean;\n  italic?: boolean;\n  underline?: boolean;\n  color?: string;\n  backgroundColor?: string;\n  align?: string;\n  valign?: string;\n  wordWrap?: boolean;\n  visable?: boolean;\n  rowspan?: number;\n  colspan?: number;\n  text?: string;\n  merge?: [number, number];\n  [key: string]: any\n}\n\nexport const defaultCell: Cell = {\n  font: 'Microsoft YaHei',\n  format: 'normal',\n  fontSize: 14,\n  bold: false,\n  italic: false,\n  underline: false,\n  color: '#333',\n  backgroundColor: '#fff',\n  align: 'left',\n  valign: 'middle',\n  wordWrap: false,\n  invisible: false,\n  rowspan: 1,\n  colspan: 1,\n  text: '',\n\n}\n\nexport function getStyleFromCell (cell: Cell | null): {[key: string]: string} {\n  const map: {[key: string]: string} = {}\n  if (cell) {\n    if (cell.font) map['font-family'] = cell.font\n    if (cell.fontSize) map['font-size'] = `${cell.fontSize}px`\n    if (cell.bold) map['font-weight'] = 'bold'\n    if (cell.italic) map['font-style'] = 'italic'\n    if (cell.underline) map['text-decoration'] = 'underline'\n    if (cell.color) map['color'] = cell.color\n    if (cell.backgroundColor) map['background-color'] = cell.backgroundColor\n    if (cell.align) map['text-align'] = cell.align\n    if (cell.valign) map['vertical-align'] = cell.valign\n    if (cell.invisible) {\n      map['display'] = 'none'\n    }\n    if (cell.wordWrap) {\n      map['word-wrap'] = 'break-word'\n      map['white-space'] = 'normal'\n    }\n  }\n  return map\n}\n"
  },
  {
    "path": "src/core/font.d.ts",
    "content": "export interface Font {\n    key: string;\n    title: string;\n}\nexport declare const fonts: Array<Font>;\n"
  },
  {
    "path": "src/core/font.ts",
    "content": "export interface Font {\n  key: string;\n  title: string;\n}\n\nexport const fonts: Array<Font> = [\n  {key: 'Microsoft YaHei', title: '微软雅黑'},\n  {key: 'STFangsong', title: '华文仿宋'},\n  {key: 'Comic Sans MS', title: 'Comic Sans MS'},\n  {key: 'Arial', title: 'Arial'},\n  {key: 'Courier New', title: 'Courier New'},\n  {key: 'Verdana', title: 'Verdana'}\n]"
  },
  {
    "path": "src/core/format.d.ts",
    "content": "export interface Format {\n    key: string;\n    title: string;\n    label?: string;\n    render(txt: string): string;\n}\nexport declare const formatRenderHtml: (key: string | undefined, txt: string | undefined) => string;\nexport declare const formats: Array<Format>;\n"
  },
  {
    "path": "src/core/format.ts",
    "content": "export interface Format {\n  key: string;\n  title: string;\n  label?: string;\n  render(txt: string): string;\n}\nexport const formatRenderHtml = (key: string | undefined, txt: string | undefined) => {\n  for (let i = 0; i < formats.length; i++) {\n    if (formats[i].key === key) {\n      return formats[i].render(txt || '')\n    }\n  }\n  return txt || ''\n}\n\nconst formatNumberRender = (v: string) => {\n  if (/^(-?\\d*.?\\d*)$/.test(v)) {\n    v = Number(v).toFixed(2).toString()\n    const parts = v.split('.')\n    parts[0] = parts[0].toString().replace(/(\\d)(?=(\\d{3})+(?!\\d))/g, '$1' + ',')\n    return parts.join('.')\n  }\n  return v\n}\n\nconst formatRender = (v: string) => v\n\nexport const formats: Array<Format> = [\n  {key: 'normal', title: 'Normal', render: formatRender},\n  {key: 'text', title: 'Text', render: formatRender},\n  {key: 'number', title: 'Number', label: '1,000.12', render: formatNumberRender},\n  {key: 'percent', title: 'Percent', label: '10.12%', render: (v) => `${formatNumberRender(v)}%`},\n  {key: 'RMB', title: 'RMB', label: '￥10.00', render: (v) => `￥${formatNumberRender(v)}`},\n  {key: 'USD', title: 'USD', label: '$10.00', render: (v) => `$${formatNumberRender(v)}`}\n]"
  },
  {
    "path": "src/core/formula.d.ts",
    "content": "export interface Formula {\n    key: string;\n    title: string;\n    render(ary: Array<number>): number;\n}\nexport declare const formulaFilterKey: (v: string, filter: (formula: Formula, param: string) => string) => string;\nexport declare const formulaRender: (v: string, renderCell: (rindex: number, cindex: number) => any) => string;\nexport declare const formulaReplaceParam: (param: string, rowDiff: number, colDiff: number) => string;\nexport declare const formulas: Array<Formula>;\n"
  },
  {
    "path": "src/core/formula.ts",
    "content": "import { alphabetIndex, alphabet } from \"./alphabet\";\n\nexport interface Formula {\n  key: string;\n  title: string;\n  render(ary: Array<number>): number\n}\n\nexport const formulaFilterKey = (v: string, filter: (formula: Formula, param: string) => string) => {\n  if (v[0] === '=') {\n    const fx = v.substring(1, v.indexOf('('))\n    for (let formula of formulas) {\n      if (formula.key.toLowerCase() === fx.toLowerCase()) {\n        return filter(formula, v.substring(v.indexOf('(') + 1, v.lastIndexOf(')')))\n      }\n    }\n  }\n  return v\n}\n\nexport const formulaRender = (v: string, renderCell: (rindex: number, cindex: number) => any) => {\n  return formulaFilterKey(v, (fx, param) => {\n    return fx.render(formulaParamToArray(param, renderCell)) + '';\n  })\n}\n\nexport const formulaReplaceParam = (param: string, rowDiff: number, colDiff: number): string => {\n  return formulaFilterKey(param, (fx, params) => {\n    const replaceFormula = (_v: string):string => {\n      if (/^[0-9\\-\\+\\*\\/()\\s]+$/.test(_v.trim())) {\n        return _v\n      }\n      const idx = /\\d+/.exec(_v)\n      if (idx) {\n        let vc = _v.substring(0, idx.index).trim()\n        let vr = parseInt(_v.substring(idx.index).trim())\n        return `${alphabet(alphabetIndex(vc) + colDiff)}${vr + rowDiff}`\n      }\n      return _v;\n    }\n\n    if (params.indexOf(':') !== -1) {\n      params = params.split(':').map(replaceFormula).join(':')\n    } else {\n      params = params.split(',').map(replaceFormula).join(',')\n    }\n    return `=${fx.key}(${params})`\n  })\n}\n\nconst formulaParamToArray = (param: string, renderCell: (rindex: number, cindex: number) => any) => {\n  let paramValues = []\n  try {\n    if (param.indexOf(':') !== -1) {\n      const [min, max] = param.split(':');\n      const idx = /\\d+/.exec(min);\n      const maxIdx = /\\d+/.exec(max);\n      if (idx && maxIdx) {\n        // idx = idx.index;\n        // maxIdx = maxIdx.index;\n        let minC = min.substring(0, idx.index).trim()\n        let minR = parseInt(min.substring(idx.index).trim())\n\n        let maxC = max.substring(0, maxIdx.index).trim()\n        let maxR = parseInt(max.substring(maxIdx.index).trim())\n        // console.log(min, max, minR, maxR, minC, maxC)\n        if (maxC === minC) {\n          for (let i = minR; i <= maxR; i++) {\n            // console.log('value:::', i-1, alphabetIndex(minC), renderCell(i - 1, alphabetIndex(minC)))\n            paramValues.push(renderCell(i - 1, alphabetIndex(minC)))\n          }\n        } else {\n          for (let i = alphabetIndex(minC); i <= alphabetIndex(maxC); i++) {\n            paramValues.push(renderCell(minR - 1, i))\n          }\n        }\n      }\n    } else {\n      paramValues = param.split(',').map(p => {\n        // console.log(/^[0-9\\-\\+\\*\\/() ]+$/.test(p), p)\n        if (/^[0-9\\-\\+\\*\\/()\\s]+$/.test(p.trim())) {\n          try {\n            return eval(p)\n          } catch (e) {\n            return 0\n          }\n        }\n        const idx = /\\d+/.exec(p)\n        if (idx) {\n          const c = p.substring(0, idx.index).trim()\n          const r = p.substring(idx.index).trim()\n          return renderCell(parseInt(r) - 1, alphabetIndex(c))\n        }\n        return 0\n      })\n    }\n  } catch (e) {\n    console.log('warning:', e)\n  }\n  return paramValues;\n}\n\nexport const formulas: Array<Formula> = [\n  {key: 'SUM', title: '求和', render: (vv) => vv.reduce((a, b) => Number(a) + Number(b), 0)},\n  {key: 'AVERAGE', title: '平均值', render: (vv) => vv.reduce((a, b) => Number(a) + Number(b), 0) / vv.length},\n  {key: 'MAX', title: '最大值', render: (vv) => Math.max(...vv.map(v => Number(v)))},\n  {key: 'MIN', title: '最小值', render: (vv) => Math.min(...vv.map(v => Number(v)))}\n]"
  },
  {
    "path": "src/core/index.d.ts",
    "content": "import { Format } from './format';\nimport { Font } from './font';\nimport { Formula } from './formula';\nimport { Cell } from './cell';\nimport { Select } from './select';\nexport interface Row {\n    height: number;\n}\nexport interface Col {\n    title: string;\n    width: number;\n}\nexport interface MapInt<T> {\n    [key: number]: T;\n}\nexport declare class History {\n    type: 'rows' | 'cols' | 'cells';\n    values: Array<[Array<any>, any, any]>;\n    constructor(type: 'rows' | 'cols' | 'cells');\n    add(keys: Array<any>, oldValue: any, value: any): void;\n}\nexport declare type StandardCallback = (rindex: number, cindex: number, cell: Cell) => void;\nexport interface SpreadsheetData {\n    rowHeight?: number;\n    colWidth?: number;\n    rows?: MapInt<Row>;\n    cols?: MapInt<Col>;\n    cell: Cell;\n    cells?: MapInt<MapInt<Cell>>;\n    [prop: string]: any;\n}\nexport interface SpreadsheetOptions {\n    formats?: Array<Format>;\n    fonts?: Array<Font>;\n    formulas?: Array<Formula>;\n    data?: SpreadsheetData;\n}\nexport declare class Spreadsheet {\n    formats: Array<Format>;\n    fonts: Array<Font>;\n    formulas: Array<Formula>;\n    data: SpreadsheetData;\n    private histories;\n    private histories2;\n    private currentCellIndexes;\n    select: Select | null;\n    private copySelect;\n    private cutSelect;\n    change: (data: SpreadsheetData) => void;\n    constructor(options?: SpreadsheetOptions);\n    buildSelect(startTarget: any, endTarget: any): Select;\n    defaultRowHeight(): number;\n    defaultColWidth(): number;\n    copy(): void;\n    cut(): void;\n    paste(cb: StandardCallback, state: 'copy' | 'cut' | 'copyformat', clear: StandardCallback): void;\n    insert(type: 'row' | 'col', amount: number, cb: StandardCallback): void;\n    batchPaste(arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number, seqCopy: boolean, cb: StandardCallback): void;\n    private copyCell;\n    isRedo(): boolean;\n    redo(cb: StandardCallback): boolean;\n    isUndo(): boolean;\n    undo(cb: StandardCallback): boolean;\n    resetByHistory(v: History, cb: StandardCallback, state: 'undo' | 'redo'): void;\n    clearformat(cb: StandardCallback): void;\n    merge(ok: StandardCallback, cancel: StandardCallback, other: StandardCallback): void;\n    cellAttr(key: keyof Cell, value: any, cb: StandardCallback): void;\n    cellText(value: any, cb: StandardCallback): Cell | null;\n    currentCell(indexes?: [number, number]): Cell | null;\n    cell(rindex: number, cindex: number, v: any, isCopy?: boolean): Cell;\n    getCell(rindex: number, cindex: number): Cell | null;\n    getFont(key: string | undefined): Font;\n    getFormat(key: string | undefined): Format;\n    row(index: number, v?: number): Row;\n    rows(isData: boolean): Array<Row>;\n    col(index: number, v?: number): Col;\n    cols(): Array<Col>;\n}\n"
  },
  {
    "path": "src/core/index.ts",
    "content": "import { Format, formats } from './format'\nimport { Font, fonts } from './font'\nimport { Formula, formulas, formulaReplaceParam } from './formula'\nimport { Cell, defaultCell } from './cell'\nimport { alphabet } from './alphabet'\nimport { Select } from './select'\nimport { unbind } from '../local/event';\n\nexport interface Row {\n  height: number\n}\nexport interface Col {\n  title: string\n  width: number\n}\nexport interface MapInt<T> {\n  [key: number]: T\n}\nexport class History {\n  values: Array<[Array<any>, any, any]> = [];\n  constructor (public type: 'rows' | 'cols' | 'cells') {}\n  add (keys: Array<any>, oldValue: any, value: any) {\n    this.values.push([keys, oldValue, value])\n  }\n}\n// types\nexport type StandardCallback = (rindex: number, cindex: number, cell: Cell) => void;\n\nexport interface SpreadsheetData {\n  rowHeight?: number;\n  colWidth?: number;\n  rows?: MapInt<Row>;\n  cols?: MapInt<Col>;\n  cell: Cell; // global default cell\n  cells?: MapInt<MapInt<Cell>>;\n  [prop: string]: any\n}\n\nexport interface SpreadsheetOptions {\n  formats?: Array<Format>;\n  fonts?: Array<Font>;\n  formulas?: Array<Formula>;\n  data?: SpreadsheetData;\n}\n\nexport class Spreadsheet {\n  formats: Array<Format>;\n  fonts: Array<Font>;\n  formulas: Array<Formula>;\n  data: SpreadsheetData;\n  private histories: Array<History> = [];\n  private histories2: Array<History> = [];\n  private currentCellIndexes: [number, number] = [0, 0];\n  select: Select | null = null;\n  private copySelect: Select | null = null;\n  private cutSelect: Select | null = null;\n\n  change: (data: SpreadsheetData) => void = () => {}\n\n  constructor (options: SpreadsheetOptions = {}) {\n    this.formats = options.formats || formats\n    this.fonts = options.fonts || fonts\n    this.formulas = options.formulas || formulas\n    // init data\n    this.data = {rowHeight: 22, colWidth: 100, cell: defaultCell}\n    if (options.data) {\n      const { data } = options;\n      for (let prop of ['rowHeight', 'colWidth', 'rows', 'cols', 'cells']) {\n        if (data[prop]) {\n          this.data[prop] = data[prop];\n        }\n      }\n      (<any>Object).assign(this.data.cell, data.cell || {});\n    }\n  }\n\n  // build select\n  buildSelect (startTarget: any, endTarget: any) {\n    const startAttrs = getElementAttrs(startTarget)\n    const endAttrs = getElementAttrs(endTarget)\n    // console.log(':::::::>>>', startAttrs, endAttrs)\n    let sRow = startAttrs.row\n    let sCol = startAttrs.col\n    let eRow = endAttrs.row\n    let eCol = endAttrs.col\n    if (sRow > eRow) {\n      sRow = endAttrs.row\n      eRow = startAttrs.row\n    }\n    if (sCol > eCol) {\n      sCol = endAttrs.col\n      eCol = startAttrs.col\n    }\n    // calc min, max of row\n    // console.log('s: ', sRow, sCol, ', e: ', eRow, eCol)\n    let [minRow, maxRow] = calcMinＭaxRow((r: number, c: number) => this.getCell(r, c), sRow, eRow, sCol, eCol)\n    // console.log('minRow: ', minRow, ', maxRow: ', maxRow)\n    // calc min, max of col\n    let [minCol, maxCol] = calcMinMaxCol((r: number, c: number) => this.getCell(r, c), minRow, maxRow, sCol, eCol)\n    while (true) {\n      const [minr, maxr] = calcMinＭaxRow((r: number, c: number) => this.getCell(r, c), minRow, maxRow, minCol, maxCol)\n      let [minc, maxc] = calcMinMaxCol((r: number, c: number) => this.getCell(r, c), minRow, maxRow, minCol, maxCol)\n      if (minRow === minr && maxRow === maxr && minCol === minc && maxCol === maxc) {\n        break\n      }\n      minRow = minr\n      maxRow = maxr\n      minCol = minc\n      maxCol = maxc\n    }\n    const firstCell = this.getCell(minRow, minCol)\n    // console.log('first => rowspan: ', firstCell.rowspan, ', colspan: ', firstCell.colspan)\n    let canotMerge = minRow + (firstCell && firstCell.rowspan || 1) - 1 === maxRow && minCol + (firstCell && firstCell.colspan || 1) - 1 === maxCol\n    // console.log('row: ', minRow, maxRow, ', col:', minCol, maxCol, canotMerge)\n    // 计算是否可以merge\n    this.select = new Select([minRow, minCol], [maxRow, maxCol], !canotMerge)\n    return this.select\n  }\n\n  defaultRowHeight (): number {\n    return this.data.rowHeight || 22\n  }\n\n  defaultColWidth (): number {\n    return this.data.colWidth || 100\n  }\n\n  copy (): void {\n    this.copySelect = this.select\n  }\n  cut (): void {\n    this.cutSelect = this.select\n  }\n  paste (cb: StandardCallback, state: 'copy' | 'cut' | 'copyformat', clear: StandardCallback): void {\n    let cselect = this.copySelect\n    if (this.cutSelect) {\n      cselect = this.cutSelect\n      this.cutSelect = null\n    }\n    if (cselect && this.select) {\n      const history = new History('cells')\n      if (state === 'copyformat') {\n        this.select.forEach((rindex, cindex, i, j, rowspan, colspan) => {\n          if (cselect) {\n            const srcRowIndex = cselect.rowIndex(i)\n            const srcColIndex = cselect.colIndex(j)\n            const [oldCell, newCell] = this.copyCell(srcRowIndex, srcColIndex, rindex, cindex, state, cb, clear)\n            history.add([rindex, cindex], oldCell, newCell)\n          }\n        })\n      } else {\n        cselect.forEach((rindex, cindex, i, j, rowspan, colspan) => {\n          if (this.select) {\n            const destRowIndex = this.select.start[0] + i\n            const destColIndex = this.select.start[1] + j\n            const [oldCell, newCell] = this.copyCell(rindex, cindex, destRowIndex, destColIndex, state, cb, clear)\n            history.add([destRowIndex, destColIndex], oldCell, newCell)\n          }\n        })\n      }\n      this.histories.push(history)\n      this.change(this.data)\n    }\n  }\n  insert (type: 'row' | 'col', amount: number, cb: StandardCallback) {\n    if (this.select) {\n      const { cells } = this.data\n      const [srindex, scindex] = this.select.start\n      if (!cells) return\n\n      // console.log('insert.before.data:', cells)\n      const history = new History('cells')\n      if (type === 'row') {\n        const newCells: MapInt<MapInt<Cell>> = {}\n        Object.keys(cells).forEach(key => {\n          let rindex = parseInt(key)\n          let values = cells[rindex]\n          if (srindex <= rindex) {\n            Object.keys(values).forEach(key1 => {\n              let cindex = parseInt(key1)\n              // clear current cell\n              cb(rindex, cindex, {})\n              history.add([rindex, cindex], values[cindex], undefined)\n            \n              // set next cell is current celll\n              cb(rindex + 1, cindex, values[cindex] || {})\n              history.add([rindex + 1, cindex], this.getCell(rindex + 1, cindex), values[cindex])\n            })\n          }\n          newCells[srindex <= rindex ? rindex + 1 : rindex] = cells[rindex]\n        })\n        this.data.cells = newCells\n      } else if (type === 'col') {\n        Object.keys(cells).forEach(key => {\n          let rindex = parseInt(key)\n          let values = cells[rindex]\n          let newCell: MapInt<Cell> = {}\n          Object.keys(values).forEach(key1 => {\n            let cindex = parseInt(key1)\n            if (scindex <= cindex) {\n              // clear 当前cell\n              cb(rindex, cindex, {})\n              history.add([rindex, cindex], values[cindex], undefined)\n            \n              // 设置下一个cell 等于当前的cell\n              cb(rindex, cindex + 1, values[cindex] || {})\n              history.add([rindex, cindex + 1], this.getCell(rindex, cindex + 1), values[cindex])\n            }\n            newCell[scindex <= cindex ? cindex + 1 : cindex] = values[cindex]\n          })\n          cells[rindex] = newCell\n        })\n      }\n      this.histories.push(history)\n      // console.log('insert.after.data:', this.data.cells)\n    } \n  }\n\n  batchPaste (arrow: 'bottom' | 'top' | 'left' | 'right',\n    startRow: number, startCol: number, stopRow: number, stopCol: number,\n    seqCopy: boolean,\n    cb: StandardCallback) {\n    if (this.select) {\n      const history = new History('cells')\n      for (let i = startRow; i <= stopRow; i++) {\n        for (let j = startCol; j <= stopCol; j++) {\n          const srcRowIndex = this.select.rowIndex(i - startRow)\n          const srcColIndex = this.select.colIndex(j - startCol)\n          const [oldDestCell, destCell] = this.copyCell(srcRowIndex, srcColIndex, i, j, seqCopy ? 'seqCopy' : 'copy', cb, () => {})\n          history.add([i, j], oldDestCell, destCell)\n        }\n      }\n      this.histories.push(history)\n      this.change(this.data)\n    }\n  }\n  private copyCell (srcRowIndex: number, srcColIndex: number, destRowIndex: number, destColIndex: number,\n    state: 'seqCopy' | 'copy' | 'cut' | 'copyformat', cb: StandardCallback, clear: StandardCallback): [Cell | null, Cell | null] {\n    const srcCell = this.getCell(srcRowIndex, srcColIndex)\n    const rowDiff = destRowIndex - srcRowIndex\n    const colDiff = destColIndex - srcColIndex\n    if (srcCell) {\n      let oldDestCell = this.getCell(destRowIndex, destColIndex)\n      // let destCell = cellCopy(srcCell, destRowIndex - srcRowIndex, destColIndex - srcColIndex, state === 'seqCopy')\n      const destCell = Object.assign({}, srcCell)\n      if (srcCell.merge) {\n        const [m1, m2] = srcCell.merge\n        destCell.merge = [m1 + rowDiff, m2 + colDiff];\n      }\n      \n\n      if (state === 'cut') {\n        clear(srcRowIndex, srcColIndex, this.cell(srcRowIndex, srcColIndex, {}))\n      }\n      if (state === 'copyformat') {\n        if (oldDestCell && oldDestCell.text) {\n          destCell.text = oldDestCell.text\n        }\n      } else {\n        const txt = destCell.text\n        if (txt && !/^\\s*$/.test(txt)) {\n          if (/^\\d*$/.test(txt) && state === 'seqCopy') {\n            destCell.text = (parseInt(txt) + (destRowIndex - srcRowIndex) + (destColIndex - srcColIndex)) + ''\n          } else if (txt.indexOf('=') !== -1) {\n            // 如果text的内容是formula,那么需要需要修改表达式参数\n            destCell.text = formulaReplaceParam(txt, rowDiff, colDiff)\n          }\n        }\n      }\n\n      cb(destRowIndex, destColIndex, this.cell(destRowIndex, destColIndex, destCell))\n      return [oldDestCell, destCell];\n    }\n    return [null, null];\n  }\n\n  isRedo (): boolean {\n    return this.histories2.length > 0\n  }\n  redo (cb: StandardCallback): boolean {\n    const { histories, histories2 } = this\n    if (histories2.length > 0) {\n      const history = histories2.pop()\n      if (history) {\n        this.resetByHistory(history, cb, 'redo')\n        histories.push(history)\n        this.change(this.data)\n      }\n    }\n    return this.isRedo()\n  }\n\n  isUndo (): boolean {\n    return this.histories.length > 0\n  }\n  undo (cb: StandardCallback): boolean {\n    const { histories, histories2 } = this\n    // console.log('histories:', histories, histories2)\n    if (histories.length > 0) {\n      const history = histories.pop()\n      if (history) {\n        this.resetByHistory(history, cb, 'undo')\n        histories2.push(history)\n        this.change(this.data)\n      }\n    }\n    return this.isUndo()\n  }\n\n  resetByHistory (v: History, cb: StandardCallback, state: 'undo' | 'redo') {\n    // console.log('history: ', history)\n    v.values.forEach(([keys, oldValue, value]) => {\n      if (v.type === 'cells') {\n        const v = state === 'undo' ? oldValue : value\n        const oldCell = this.getCell(keys[0], keys[1])\n        if (!oldCell) {\n          if (keys.length === 3) {\n            if (v) {\n              const nValue: Cell = {}\n              nValue[keys[2]] = v\n              cb(keys[0], keys[1], this.cell(keys[0], keys[1], nValue))\n            }\n          } else {\n            cb(keys[0], keys[1], this.cell(keys[0], keys[1], v || {}))\n          }\n        } else {\n          if (keys.length === 3) {\n            const nValue: Cell = {}\n            nValue[keys[2]] = v\n            if (v) {\n              cb(keys[0], keys[1], this.cell(keys[0], keys[1], nValue, true))\n            } else {\n              cb(keys[0], keys[1], this.cell(keys[0], keys[1], mapIntFilter(oldCell, keys[2])))\n            }\n          } else {\n            cb(keys[0], keys[1], this.cell(keys[0], keys[1], v || {}))\n          }\n        }\n      } else {\n        // cols, rows\n        // const v = state === 'undo' ? oldValue : value\n        // if (v !== null) {\n        //   this.data[v.type]\n        // }\n      }\n      // console.log('keys:', keys, ', oldValue:', oldValue, ', value:', value)\n    })\n  }\n\n  clearformat (cb: StandardCallback) {\n    const { select } = this\n    if (select !== null) {\n      const history = new History('cells')\n      select.forEach((rindex, cindex, i, j, rowspan, colspan) => {\n        let c = this.getCell(rindex, cindex);\n        if (c) {\n          history.add([rindex, cindex], c, {text: c.text})\n          c = this.cell(rindex, cindex, {text: c.text});\n          cb(rindex, cindex, c);\n        }\n      });\n      this.histories.push(history)\n      this.change(this.data)\n    }\n  }\n\n  /**\n   * \n   * @param ok 合并单元格第一个单元格（左上角）的回调函数\n   * @param cancel 取消合并单元格第一个单元格（左上角）的回调函数\n   * @param other 其他单元格的回调函数\n   */\n  merge (ok: StandardCallback, cancel: StandardCallback, other: StandardCallback): void {\n    const { select } = this\n    // console.log('data.before: ', this.data)\n    if (select !== null && select.cellLen() > 1) {\n      // merge merge: [rows[0], cols[0]]\n      const history = new History('cells')\n      let index = 0\n      let firstXY: [number, number] = [0, 0]\n      select.forEach((rindex, cindex, i, j, rowspan, colspan) => {\n        if (index++ === 0) {\n          firstXY = [rindex, cindex]\n          let v: Cell = {}\n          if (rowspan > 1) v.rowspan = rowspan\n          if (colspan > 1) v.colspan = colspan\n          // console.log('rowspan:', rowspan, ', colspan:', colspan, select.canMerge)\n          if (select.canMerge) {\n            history.add([rindex, cindex, 'rowspan'], undefined, rowspan)\n            history.add([rindex, cindex, 'colspan'], undefined, colspan)\n\n            let cell = this.cell(rindex, cindex, v, true)\n            ok(rindex, cindex, cell)\n          } else {\n            const oldCell = this.getCell(rindex, cindex)\n            if (oldCell !== null) {\n              history.add([rindex, cindex, 'rowspan'], oldCell.rowspan, undefined)\n              history.add([rindex, cindex, 'colspan'], oldCell.colspan, undefined)\n\n              let cell = this.cell(rindex, cindex, mapIntFilter(oldCell, 'rowspan', 'colspan', 'merge'))\n              cancel(rindex, cindex, cell)\n            }\n          }\n        } else {\n          let v: Cell = {invisible: select.canMerge}\n          if (select.canMerge) {\n            history.add([rindex, cindex, 'invisible'], undefined, select.canMerge)\n\n            v.merge = firstXY\n            let cell = this.cell(rindex, cindex, v, true)\n            other(rindex, cindex, cell)\n          } else {\n            const oldCell = this.getCell(rindex, cindex)\n            if (oldCell !== null) {\n              history.add([rindex, cindex, 'invisible'], oldCell.invisible, undefined)\n              let cell = this.cell(rindex, cindex, mapIntFilter(oldCell, 'rowspan', 'colspan', 'merge', 'invisible'))\n              other(rindex, cindex, cell)\n            }\n          }\n        }\n      })\n      this.histories.push(history)\n      select.canMerge = !select.canMerge\n      this.change(this.data)\n    }\n  }\n  cellAttr (key: keyof Cell, value: any, cb: StandardCallback): void {\n    let v: Cell= {}\n    v[key] = value\n    const isDefault = value === this.data.cell[key]\n    if (this.select !== null) {\n      const history = new History('cells')\n      this.select.forEach((rindex, cindex) => {\n        const oldCell = this.getCell(rindex, cindex)\n        \n        history.add([rindex, cindex, key], oldCell !== null ? oldCell[key] : undefined, value)\n        \n        let cell = this.cell(rindex, cindex, isDefault ? mapIntFilter(oldCell, key) : v, !isDefault)\n        cb(rindex, cindex, cell)\n      \n      })\n      this.histories.push(history)\n    }\n    this.change(this.data)\n  }\n  cellText (value: any, cb: StandardCallback): Cell | null {\n    if (this.currentCellIndexes) {\n      // this.addHistoryValues()\n      const history = new History('cells')\n      const [rindex, cindex] = this.currentCellIndexes\n      const oldCell = this.getCell(rindex, cindex)\n      history.add([rindex, cindex, 'text'], oldCell !== null ? oldCell.text : undefined, value)\n      const cell = this.cell(rindex, cindex, {text: value}, true)\n      cb(rindex, cindex, cell)\n\n      this.histories.push(history)\n      this.change(this.data)\n      return cell;\n    }\n    return null\n  }\n  currentCell (indexes?: [number, number]): Cell | null {\n    if (indexes !== undefined) {\n      this.currentCellIndexes = indexes\n    }\n    const [rindex, cindex] = this.currentCellIndexes\n    return this.getCell(rindex, cindex)\n  }\n\n  cell (rindex: number, cindex: number, v: any, isCopy = false): Cell {\n    this.data.cells = this.data.cells || {}\n    this.data.cells[rindex] = this.data.cells[rindex] || {}\n    this.data.cells[rindex][cindex] = this.data.cells[rindex][cindex] || {}\n    if (isCopy) {\n      (<any>Object).assign(this.data.cells[rindex][cindex], v)\n    } else if (v) {\n      this.data.cells[rindex][cindex] = v\n    }\n    return this.data.cells[rindex][cindex]\n  }\n\n  getCell (rindex: number, cindex: number): Cell | null {\n    if (this.data.cells && this.data.cells[rindex] && this.data.cells[rindex][cindex]) {\n      return this.data.cells[rindex][cindex];\n    }\n    return null;\n  }\n\n  getFont (key: string | undefined) {\n    return this.fonts.filter(it => it.key === key)[0]\n  }\n  getFormat (key: string | undefined) {\n    return this.formats.filter(it => it.key === key)[0]\n  }\n\n  row (index: number, v?: number): Row {\n    const { data } = this;\n    if (v !== undefined) {\n      const history = new History('rows')\n      data.rows = data.rows || {}\n      data.rows[index] = data.rows[index] || {}\n      data.rows[index].height = v\n      history.add([index], null, data.rows[index])\n      this.histories.push(history)\n    }\n    return (<any>Object).assign({height: data.rowHeight}, data.rows ? data.rows[index] : {})\n  }\n  // isData 是否返回数据的最大行数\n  rows (isData: boolean): Array<Row> {\n    const { data } = this;\n    let maxRow;\n    if (isData) {\n      maxRow = 10\n      if (this.data.cells) {\n        maxRow = mapIntMaxKey(this.data.cells) + 2\n      }\n    } else {\n      maxRow = mapIntMaxKeyWithDefault(100, data.rows)\n    }\n    return range(maxRow, (index) => this.row(index))\n  }\n\n  col (index: number, v?: number): Col {\n    const { data } = this;\n    if (v !== undefined) {\n      const history = new History('cols')\n      data.cols = data.cols || {}\n      data.cols[index] = data.cols[index] || {}\n      data.cols[index].width = v\n      history.add([index], null, data.cols[index])\n      this.histories.push(history)\n    }\n    const ret:any = {width: data.colWidth, title: alphabet(index)}\n    if (data.cols && data.cols[index]) {\n      for (let prop in data.cols[index]) {\n        const col:any = data.cols[index]\n        if (col[prop]) {\n          ret[prop] = col[prop]\n        }\n      }\n    }\n    return ret\n  }\n  cols (): Array<Col> {\n    const { data } = this;\n    let maxCol = mapIntMaxKeyWithDefault(26 * 2, data.cols);\n    return range(maxCol, (index) => this.col(index));\n  }\n}\n\nconst mapIntMaxKey = function<T>(mapInt: MapInt<T>): number {\n  return Math.max(...Object.keys(mapInt).map(s => parseInt(s)))\n}\n// methods\nconst mapIntMaxKeyWithDefault = function<T>(max: number, mapInt: MapInt<T> | undefined): number {\n  if (mapInt) {\n    const m = mapIntMaxKey(mapInt)\n    if (m > max) return m;\n  }\n  return max;\n}\nconst mapIntFilter = function(obj: any, ...keys: Array<any>): any {\n  const ret: any = {}\n  if (obj){\n    Object.keys(obj).forEach(e => {\n      if (keys.indexOf(e) === -1) {\n        ret[e] = obj[e]\n      }\n    })\n  }\n  return ret\n}\nconst range = function<T>(stop:number, cb: (index: number) => T): Array<T> {\n  const ret = []\n  for (let i = 0; i < stop; i++) {\n    ret.push(cb(i))\n  }\n  return ret\n}\nconst getElementAttrs = (target: any) => {\n  const { offsetTop, offsetLeft, offsetHeight, offsetWidth } = target\n  return {\n    row: parseInt(target.getAttribute('row-index')),\n    col: parseInt(target.getAttribute('col-index')),\n    rowspan: parseInt(target.getAttribute('rowspan')),\n    colspan: parseInt(target.getAttribute('colspan')),\n    left: offsetLeft,\n    top: offsetTop,\n    width: offsetWidth,\n    height: offsetHeight\n  }\n}\nconst calcMinMaxCol = (cell: any, sRow: number, eRow: number, sCol: number, eCol: number) => {\n  let minCol = sCol\n  let maxCol = eCol\n  // console.log(':::::::;start: ', maxCol, minCol)\n  for (let j = sRow; j <= eRow; j++) {\n    let cCol = sCol\n    let dcell = cell(j, cCol)\n    if (dcell && dcell.merge) {\n      cCol += dcell.merge[1] - cCol\n    }\n    if (cCol < minCol) minCol = cCol\n\n    cCol = maxCol\n    dcell = cell(j, cCol)\n    // console.log(j, cCol, dcell && dcell.colspan || 1)\n    const cColspan = dcell ? dcell.colspan : 1\n    if (parseInt(cColspan) > 1) {\n      cCol += parseInt(cColspan)\n    } else {\n      if (dcell && dcell.merge) {\n        // console.log('merge::', maxCol, dcell.merge)\n        const [r, c] = dcell.merge\n        const rc = cell(r, c).colspan\n        cCol += rc + (c - cCol)\n      }\n    }\n    // console.log('cCol: ', cCol, ', maxCol: ', maxCol)\n    // console.log(':::::::;end: ', maxCol, minCol)\n    if (cCol - 1 > maxCol) maxCol = cCol - 1\n  }\n  return [minCol, maxCol]\n}\nconst calcMinＭaxRow = (cell: any, sRow: number, eRow: number, sCol: number, eCol: number) => {\n  let minRow = sRow\n  let maxRow = eRow\n  for (let j = sCol; j <= eCol; j++) {\n    let cRow = sRow\n    let dcell = cell(cRow, j)\n    if (dcell && dcell.merge) {\n      cRow += dcell.merge[0] - cRow\n    }\n    if (cRow < minRow) minRow = cRow\n\n    cRow = maxRow\n    dcell = cell(cRow, j)\n    // console.log('row: ', j, cRow, dcell.rowspan)\n    const cRowspan = dcell ? dcell.rowspan : 1\n    if (parseInt(cRowspan) > 1) {\n      cRow += parseInt(cRowspan)\n    } else {\n      if (dcell && dcell.merge) {\n        const [r, c] = dcell.merge\n        const rs = cell(r, c).rowspan\n        cRow += rs + (r - cRow)\n      }\n    }\n    if (cRow - 1 > maxRow) maxRow = cRow - 1\n  }\n  return [minRow, maxRow]\n}"
  },
  {
    "path": "src/core/select.d.ts",
    "content": "export declare class Select {\n    start: [number, number];\n    stop: [number, number];\n    canMerge: boolean;\n    constructor(start: [number, number], stop: [number, number], canMerge: boolean);\n    forEach(cb: (r: number, c: number, rindex: number, cindex: number, rowspan: number, colspan: number) => void): void;\n    rowIndex(index: number): number;\n    colIndex(index: number): number;\n    rowLen(): number;\n    colLen(): number;\n    cellLen(): number;\n    contains(rindex: number, cindex: number): boolean;\n}\n"
  },
  {
    "path": "src/core/select.ts",
    "content": "export class Select {\n  constructor(public start: [number, number], public stop: [number, number], public canMerge: boolean) {}\n  forEach (cb: (r:number, c: number, rindex: number, cindex: number, rowspan: number, colspan: number) => void): void {\n    const [sx, sy] = this.start\n    const [ex, ey] = this.stop\n    for (let i = sx; i <= ex; i++) {\n      for (let j = sy; j <= ey; j++) {\n        cb(i, j, i - sx, j - sy, ex - sx + 1, ey - sy + 1)\n      }\n    }\n  }\n  rowIndex (index: number) {\n    return this.start[0] + index % this.rowLen()\n  }\n  colIndex (index: number) {\n    return this.start[1] + index % this.colLen()\n  }\n  rowLen () {\n    return this.stop[0] - this.start[0] + 1\n  }\n  colLen () {\n    return this.stop[1] - this.start[1] + 1\n  }\n  cellLen () {\n    return this.rowLen() * this.colLen()\n  }\n  contains (rindex: number, cindex: number) {\n    const [sx, sy] = this.start\n    const [ex, ey] = this.stop\n    return sx <= rindex && ex >= rindex && sy <= cindex && ey >= cindex\n  }\n}\n\n// export function buildSelect (start: any, end: )"
  },
  {
    "path": "src/local/base/colorPanel.d.ts",
    "content": "import { Element } from \"./element\";\nexport declare class ColorPanel extends Element {\n    constructor(click: (color: string) => void);\n}\nexport declare function buildColorPanel(click: (color: string) => void): ColorPanel;\n"
  },
  {
    "path": "src/local/base/colorPanel.ts",
    "content": "import { Element, h } from \"./element\";\n\nconst colorss = [\n  ['#c00000', '#ff0000', '#ffc003', '#ffff00','#91d051', '#00af50', '#00b0f0', '#0070c0', '#002060', '#70309f'],\n  ['#ffffff', '#000000', '#e7e6e6', '#44546a', '#4472c4', '#ed7d31', '#a5a5a5', '#ffc003', '#5b9bd5', '#70ad47'],\n  ['#f4f5f8', '#848484', '#d0cece', '#d6dce4', '#d9e2f2', '#fae5d5', '#ededed', '#fff2cc', '#deebf6', '#e2efd9'],\n  ['#d8d8d8', '#595959', '#afabab', '#adb9ca', '#b4c6e7', '#f7cbac', '#dbdbdb', '#fee598', '#bdd7ee', '#c5e0b3'],\n  ['#bfbfbf', '#3f3f3f', '#757070', '#8496b0', '#8eaad8', '#f4b183', '#c9c9c9', '#ffd964', '#9dc2e5', '#a8d08d'],\n  ['#a5a5a5', '#262626', '#3a3838', '#333f4f', '#2f5496', '#c55b11', '#7b7b7b', '#bf9001', '#2e75b5', '#538135'],\n  ['#7e7e7e', '#0c0c0c', '#171616', '#232a35', '#1e3864', '#833d0b', '#525252', '#7e6000', '#1f4e79', '#375623']\n]\n\nexport class ColorPanel extends Element {\n\n  constructor (click: (color: string) => void) {\n    super();\n    this.class('spreadsheet-color-panel')\n    .child(\n      h('table').child(\n        h('tbody').children(\n          colorss.map(colors => {\n            return h('tr').children(\n              colors.map(color => {\n                return h('td').child(\n                  h()\n                    .class('color-cell')\n                    .on('click', click.bind(null, color))\n                    .style('background-color', color)\n                )\n              })\n            )\n          })\n        )));\n  }\n\n}\n\nexport function buildColorPanel (click: (color: string) => void) {\n  return new ColorPanel(click);\n}"
  },
  {
    "path": "src/local/base/dropdown.d.ts",
    "content": "import { Element } from \"./element\";\nexport declare class Dropdown extends Element {\n    content: Element;\n    title: Element;\n    constructor(title: string | Element, width: string, contentChildren: Element[]);\n    toggleHandler(evt: Event): void;\n}\nexport declare function buildDropdown(title: string | Element, width: string, contentChildren: Element[]): Dropdown;\n"
  },
  {
    "path": "src/local/base/dropdown.ts",
    "content": "import { Element, h } from \"./element\";\nimport { buildIcon } from \"./icon\";\n\nexport class Dropdown extends Element {\n  content: Element;\n  title: Element;\n\n  constructor (title: string | Element, width: string, contentChildren: Element[]) {\n    super();\n    this.class('spreadsheet-dropdown spreadsheet-item');\n\n    this.content = h().class('spreadsheet-dropdown-content')\n      .children(contentChildren)\n      .onClickOutside(() => this.deactive())\n      .on('click', (evt) => this.toggleHandler(evt))\n      .style('width', width).hide();\n\n    this.child(h().class('spreadsheet-dropdown-header').children([\n      this.title = typeof title === 'string' ? h().class('spreadsheet-dropdown-title').child(title) : title,\n      h().class('spreadsheet-dropdown-icon').on('click', (evt) => this.toggleHandler(evt)).child(buildIcon('arrow-down'))\n    ])).child(this.content);\n  }\n\n  toggleHandler (evt: Event) {\n    if (this.content.isHide()){\n      this.content.show()\n      this.active()\n    } else {\n      this.content.hide()\n      this.deactive()\n    }\n  }\n}\nexport function buildDropdown(title: string | Element, width: string, contentChildren: Element[]) {\n  return new Dropdown(title, width, contentChildren)\n}"
  },
  {
    "path": "src/local/base/element.d.ts",
    "content": "export declare class Element {\n    tag: string;\n    el: HTMLElement;\n    _data: {\n        [key: string]: any;\n    };\n    _clickOutside: any;\n    constructor(tag?: string);\n    data(key: string, value?: any): any;\n    on(eventName: string, handler: (evt: any) => any): Element;\n    onClickOutside(cb: () => void): Element;\n    parent(): any;\n    class(name: string): Element;\n    attrs(map?: {\n        [key: string]: string;\n    }): Element;\n    attr(attr: string, value?: any): any;\n    removeAttr(attr: string): Element;\n    offset(): any;\n    clearStyle(): this;\n    styles(map?: {\n        [key: string]: string;\n    }, isClear?: boolean): Element;\n    style(key: string, value?: any): any;\n    contains(el: any): boolean;\n    removeStyle(key: string): void;\n    children(cs: Array<HTMLElement | string | Element>): Element;\n    child(c: HTMLElement | string | Element): Element;\n    html(html?: string): string | this;\n    val(v?: string): any;\n    clone(): any;\n    isHide(): boolean;\n    toggle(): void;\n    disabled(): Element;\n    able(): Element;\n    active(flag?: boolean): Element;\n    deactive(): Element;\n    isActive(): boolean;\n    addClass(cls: string): Element;\n    removeClass(cls: string): this;\n    hasClass(cls: string): boolean;\n    show(isRemove?: boolean): Element;\n    hide(): Element;\n}\nexport declare function h(tag?: string): Element;\n"
  },
  {
    "path": "src/local/base/element.ts",
    "content": "import { bind, unbind } from '../event'\n\nexport class Element {\n  el: HTMLElement;\n  _data: {[key: string]: any} = {};\n  _clickOutside: any = null;\n\n  constructor (public tag = 'div') {\n    this.el = document.createElement(tag)\n  }\n\n  data (key: string, value?: any) {\n    if (value !== undefined) {\n      this._data[key] = value\n    }\n    return this._data[key]\n  }\n\n  on (eventName: string, handler: (evt: any) => any): Element {\n    const [first, ...others] = eventName.split('.')\n    // console.log('first:', first, ', others:', others)\n    this.el.addEventListener(first, (evt: any) => {\n      // console.log('>>>', others, evt.button)\n      for (let k of others) {\n        console.log('::::::::::', k)\n        if (k === 'left' && evt.button !== 0) {\n          return\n        } else if (k === 'right' && evt.button !== 2) {\n          return\n        } else if (k === 'stop') {\n          evt.stopPropagation()\n        }\n      }\n      // console.log('>>>>>>>>>>>>')\n      handler(evt)\n    })\n    return this;\n  }\n\n  onClickOutside (cb: () => void): Element {\n    this._clickOutside = cb\n    return this;\n  }\n\n  parent(): any {\n    return this.el.parentNode\n  }\n\n  class (name: string): Element {\n    this.el.className = name\n    return this;\n  }\n\n  attrs (map: {[key: string]: string} = {}): Element {\n    for (let key of Object.keys(map))\n      this.attr(key, map[key]);\n    return this;\n  }\n\n  attr (attr: string, value?: any): any {\n    if (value !== undefined) {\n      this.el.setAttribute(attr, value);\n    } else {\n      return this.el.getAttribute(attr)\n    }\n    return this;\n  }\n  removeAttr(attr: string): Element {\n    this.el.removeAttribute(attr);\n    return this;\n  }\n\n  offset (): any {\n    const { offsetTop, offsetLeft, offsetHeight, offsetWidth } = this.el\n    return {top: offsetTop, left: offsetLeft, height: offsetHeight, width: offsetWidth}\n  }\n\n  clearStyle () {\n    (<any>this.el).style = ''\n    return this;\n  }\n\n  styles (map: {[key: string]: string} = {}, isClear = false): Element {\n    if (isClear) {\n      this.clearStyle()\n    }\n    for (let key of Object.keys(map))\n      this.style(key, map[key]);\n    return this;\n  }\n\n  style (key: string, value?: any): any {\n    if (value !== undefined) {\n      this.el.style.setProperty(key, value);\n    } else {\n      return this.el.style.getPropertyValue(key)\n    }\n    return this;\n  }\n\n  contains (el: any) {\n    return this.el.contains(el)\n  }\n\n  removeStyle (key: string) {\n    this.el.style.removeProperty(key)\n    return ;\n  }\n\n  children (cs: Array<HTMLElement | string | Element>): Element {\n    for (let c of cs)\n      this.child(c);\n    return this;\n  }\n\n  child (c: HTMLElement | string | Element): Element {\n    if (typeof c === 'string') {\n      this.el.appendChild(document.createTextNode(c))\n    } else if (c instanceof Element) {\n      this.el.appendChild(c.el)\n    } else if (c instanceof HTMLElement) {\n      this.el.appendChild(c)\n    }\n    return this;\n  }\n\n  html (html?: string) {\n    if (html !== undefined) {\n      this.el.innerHTML = html\n    } else {\n      return this.el.innerHTML\n    }\n    return this;\n  }\n\n  val (v?: string) {\n    if (v !== undefined) {\n      // (<any>this.el).value = v\n      (<any>this.el).value = v\n    } else {\n      return (<any>this.el).value\n    }\n    return this;\n  }\n\n  clone (): any {\n    return this.el.cloneNode();\n  }\n\n  isHide () {\n    return this.style('display') === 'none'\n  }\n\n  toggle () {\n    if (this.isHide()) {\n      this.show()\n    } else {\n      this.hide()\n    }\n  }\n\n  disabled (): Element {\n    // this.removeClass('disabled')\n    this.addClass('disabled')\n    return this;\n  }\n  able (): Element {\n    this.removeClass('disabled')\n    return this;\n  }\n\n  active (flag = true): Element {\n    // this.el.className = this.el.className.split(' ').filter(c => c !== 'disabled').join(' ') + ' active'\n    // this.removeClass('disabled')\n    if (flag)\n      this.addClass('active')\n    else\n      this.deactive()\n    return this;\n  }\n  deactive (): Element {\n    return this.removeClass('active')\n  }\n  isActive (): boolean {\n    return this.hasClass('active');\n  }\n\n  addClass (cls: string): Element {\n    this.el.className = this.el.className.split(' ').concat(cls).join(' ')\n    return this;\n  }\n  removeClass (cls: string) {\n    // console.log('before.className: ', this.el.className)\n    this.el.className = this.el.className.split(' ').filter(c => c !== cls).join(' ')\n    // console.log('after.className: ', this.el.className)\n    return this;\n  }\n  hasClass (cls: string) {\n    return this.el.className.indexOf(cls) !== -1\n  }\n\n  show (isRemove = false): Element {\n    isRemove ? this.removeStyle('display') : this.style('display', 'block');\n    // clickoutside\n    if (this._clickOutside) {\n      this.data('_outsidehandler', (evt: Event) => {\n        if (this.contains(evt.target)) {\n          return false\n        }\n        this.hide()\n        unbind('click', this.data('_outsidehandler'))\n        this._clickOutside && this._clickOutside()\n      })\n      setTimeout(() => {\n        bind('click', this.data('_outsidehandler'))\n      }, 0)\n    }\n    return this;\n  }\n\n  hide (): Element {\n    this.style('display', 'none');\n    if (this._clickOutside) {\n      unbind('click', this.data('_outsidehandler'))\n    }\n    return this;\n  }\n}\n\nexport function h (tag = 'div'): Element {\n  return new Element(tag)\n}"
  },
  {
    "path": "src/local/base/icon.d.ts",
    "content": "import { Element } from \"./element\";\nexport declare class Icon extends Element {\n    img: Element;\n    constructor(name: string);\n    replace(name: string): void;\n}\nexport declare function buildIcon(name: string): Icon;\n"
  },
  {
    "path": "src/local/base/icon.ts",
    "content": "import { Element, h } from \"./element\";\n\nexport class Icon extends Element{\n\n  img: Element;\n\n  constructor (name: string) {\n    super();\n    this.class('spreadsheet-icon').child(this.img = h().class(`spreadsheet-icon-img ${name}`));\n  }\n\n  replace (name: string) {\n    this.img.class(`spreadsheet-icon-img ${name}`)\n  }\n\n}\n\nexport function buildIcon (name: string) {\n  return new Icon(name);\n}"
  },
  {
    "path": "src/local/base/item.d.ts",
    "content": "import { Element } from \"./element\";\nimport { Icon } from \"./icon\";\nexport declare class Item extends Element {\n    iconEl: Icon | null;\n    static build(): Item;\n    constructor();\n    icon(name: string): this;\n    replaceIcon(name: string): void;\n}\nexport declare function buildItem(): Item;\n"
  },
  {
    "path": "src/local/base/item.ts",
    "content": "import { Element } from \"./element\";\nimport { Icon, buildIcon } from \"./icon\";\n\nexport class Item extends Element {\n\n  iconEl: Icon | null = null;\n\n  static build (): Item {\n    return new Item()\n  }\n  \n  constructor () {\n    super();\n    this.class('spreadsheet-item');\n  }\n\n  icon (name: string) {\n    this.child(this.iconEl = buildIcon(name))\n    return this;\n  }\n\n  replaceIcon (name: string) {\n    this.iconEl && this.iconEl.replace(name)\n  }\n\n}\n\nexport function buildItem (): Item {\n  return new Item();\n}"
  },
  {
    "path": "src/local/base/menu.d.ts",
    "content": "import { Element } from \"./element\";\nexport declare class Menu extends Element {\n    constructor(align?: string);\n}\nexport declare function buildMenu(align?: string): Menu;\n"
  },
  {
    "path": "src/local/base/menu.ts",
    "content": "import { Element } from \"./element\";\n\nexport class Menu extends Element{\n\n  constructor (align = 'vertical') {\n    super();\n    this.class(`spreadsheet-menu ${align}`)\n  }\n\n}\n\nexport function buildMenu (align = 'vertical') {\n  return new Menu(align);\n}"
  },
  {
    "path": "src/local/base/suggest.d.ts",
    "content": "import { Element } from \"./element\";\nexport declare class Suggest extends Element {\n    list: Array<[string, string]>;\n    width: number;\n    filterList: Array<Element>;\n    currentIndex: number;\n    target: Element | null;\n    evtTarget: Element | null;\n    itemClick: (it: [string, string]) => void;\n    constructor(list: Array<[string, string]>, width: number);\n    private documentHandler;\n    private documentKeydownHandler;\n    private hideAndRemoveEvents;\n    private removeEvents;\n    private clickItemHandler;\n    search(target: Element, input: Element, word: string): void;\n}\n"
  },
  {
    "path": "src/local/base/suggest.ts",
    "content": "import { Element, h } from \"./element\";\nimport { buildItem } from \"./item\";\nimport { buildMenu } from \"./menu\";\nimport { bind, unbind } from \"../event\";\n\nexport class Suggest extends Element {\n  \n  filterList: Array<Element> = [];\n  currentIndex = 0;\n  target: Element | null = null;\n  evtTarget: Element | null = null;\n\n  itemClick: (it: [string, string]) => void = (it) => {}\n\n  constructor (public list: Array<[string, string]>, public width: number) {\n    super();\n    this.class('spreadsheet-suggest').hide()\n  }\n\n  private documentHandler (e: any) {\n    if (this.el.contains(e.target)) {\n      return false\n    }\n    this.hideAndRemoveEvents()\n  }\n  private documentKeydownHandler (e: any) {\n    console.log('keyCode: ', e)\n    if (this.filterList.length <= 0 && e.target.type !== 'textarea') return ;\n\n    switch (e.keyCode) {\n      case 37: // left\n        e.returnValue = false\n        break;\n      case 38: // up\n        this.filterList[this.currentIndex].deactive()\n        this.currentIndex--\n        if (this.currentIndex < 0) {\n          this.currentIndex = this.filterList.length - 1\n        }\n        this.filterList[this.currentIndex].active()\n        e.returnValue = false\n        e.stopPropagation();\n        break;\n      case 39: // right\n        e.returnValue = false\n        break;\n      case 40: // down\n        this.filterList[this.currentIndex].deactive()\n        this.currentIndex++\n        if (this.currentIndex > this.filterList.length - 1) {\n          this.currentIndex = 0\n        }\n        this.filterList[this.currentIndex].active()\n        e.returnValue = false\n        break;\n      case 13: // enter\n        this.filterList[this.currentIndex].el.click()\n        e.returnValue = false\n        break;\n    }\n    e.stopPropagation();\n  }\n\n  private hideAndRemoveEvents () {\n    this.hide()\n    this.removeEvents();\n  }\n  private removeEvents () {\n    if (this.evtTarget !== null) {\n      unbind('click', this.data('_outsidehandler'), this.evtTarget.el)\n      unbind('keydown', this.data('_keydownhandler'), this.evtTarget.el)\n    }\n  }\n\n  private clickItemHandler (it: [string, string]) {\n    // console.log('click.it: ', it)\n    this.itemClick(it)\n    this.hideAndRemoveEvents()\n  }\n\n\n  search (target: Element, input: Element, word: string) {\n    this.removeEvents()\n    this.target = target;\n    this.evtTarget = input;\n\n    const { left, top, width, height } = target.offset()\n    this.styles({left: `${left}px`, top: `${top + height + 2}px`, width: `${this.width}px`})\n\n    let lis: any = this.list\n    if (!/^\\s*$/.test(word)) {\n      lis = this.list.filter(it => it[0].startsWith(word.toUpperCase()))\n    }\n    lis = lis.map((it: [string, string]) => {\n      const item = buildItem().on('click', (evt) => this.clickItemHandler(it)).child(it[0])\n      if (it[1]) {\n        item.child(h().class('label').html(it[1]))\n      }\n      return item\n      // return `<div class=\"spreadsheet-item\" it-key=\"${it[0]}\">${it[0]}${it[1] ? '<div class=\"label\">'+it[1]+'</div>' : ''}</div>`\n    })\n\n    this.filterList = lis\n    this.currentIndex = 0\n\n    if (lis.length <= 0) {\n      lis = [buildItem().child('No Result')] // `<div class=\"spreadsheet-item disabled\">No Result</div>`\n    } else {\n      lis[0].active()\n\n      // clickoutside\n      this.data('_outsidehandler', (evt: Event) => {\n        this.documentHandler(evt)\n      })\n      this.data('_keydownhandler', (evt: any) => this.documentKeydownHandler(evt))\n      setTimeout(() => {\n        if (this.evtTarget !== null) {\n          bind('click', this.data('_outsidehandler'), this.evtTarget.el)\n          bind('keydown', this.data('_keydownhandler'), this.evtTarget.el)\n        }\n      }, 0)\n    }\n    this.html(``)\n    this.child(buildMenu().children(lis)).show()\n  }\n}"
  },
  {
    "path": "src/local/contextmenu.d.ts",
    "content": "import { Element } from \"./base/element\";\nimport { Table } from \"./table\";\nexport declare class ContextMenu {\n    table: Table;\n    el: Element;\n    constructor(table: Table);\n    set(evt: any): void;\n}\n"
  },
  {
    "path": "src/local/contextmenu.ts",
    "content": "import { Element, h } from \"./base/element\";\nimport { buildItem } from \"./base/item\";\nimport { buildMenu } from \"./base/menu\";\nimport { Table } from \"./table\"\n\nexport class ContextMenu {\n  el: Element;\n  constructor (public table: Table) {\n    this.el = h().class('spreadsheet-contextmenu')\n    .style('width', '160px')\n    .on('click', (evt: any) => this.el.hide())\n    .children([\n      buildMenu().children([\n        buildItem().on('click', (evt) => table.copy()).children(['copy', h().class('label').html('ctrl + c')]),\n        buildItem().on('click', (evt) => table.cut()).children(['cut', h().class('label').html('ctrl + x')]),\n        buildItem().on('click', (evt) => table.paste()).children(['paste', h().class('label').html('ctrl + v')]),\n        // h().class('spreadsheet-item-separator'),\n        // buildItem().on('click', (evt) => table.insert('row', 1)).html('insert row'),\n        // buildItem().on('click', (evt) => table.insert('col', 1)).html('insert col')\n      ])\n    ]).onClickOutside(() => {}).hide()\n    // clickoutside\n  }\n\n  set (evt: any) {\n    const { offsetLeft, offsetTop } = evt.target\n    const elRect = this.el.el.getBoundingClientRect()\n    // cal left top\n    const { clientWidth, clientHeight } = document.documentElement\n    let top = offsetTop + evt.offsetY\n    let left = offsetLeft + evt.offsetX\n\n    if (evt.clientY > clientHeight / 1.5) {\n      top -= elRect.height\n    }\n    if (evt.clientX > clientWidth / 1.5) {\n      left -= elRect.width\n    }\n    this.el.style('left', `${left}px`).style('top', `${top}px`).show()\n  }\n\n}"
  },
  {
    "path": "src/local/editor.d.ts",
    "content": "import { Element } from \"./base/element\";\nimport { Suggest } from \"./base/suggest\";\nimport { Cell } from \"../core/cell\";\nimport { Formula } from \"../core/formula\";\nexport declare class Editor {\n    defaultRowHeight: number;\n    formulas: Array<Formula>;\n    el: Element;\n    target: HTMLElement | null;\n    value: Cell | null;\n    editor: Element;\n    textarea: Element;\n    textline: Element;\n    suggest: Suggest;\n    change: (v: Cell) => void;\n    constructor(defaultRowHeight: number, formulas: Array<Formula>);\n    onChange(change: (v: Cell) => void): void;\n    set(target: HTMLElement, value: Cell | null): void;\n    setValue(value: Cell | null): string;\n    setStyle(value: Cell | null): void;\n    clear(): void;\n    private setTextareaRange;\n    private inputKeydown;\n    private inputChange;\n    private autocomplete;\n    reload(): void;\n}\n"
  },
  {
    "path": "src/local/editor.ts",
    "content": "import { Element, h } from \"./base/element\";\nimport { Suggest } from \"./base/suggest\";\nimport { Cell, getStyleFromCell } from \"../core/cell\"\nimport { Formula } from \"../core/formula\";\n\nexport class Editor {\n  el: Element;\n  target: HTMLElement | null = null; // 选中的当前的element\n  value: Cell | null = null; // 选中的当前的cell\n  editor: Element;\n  textarea: Element;\n  textline: Element; // 计算输入文本的宽度用的element\n  suggest: Suggest; // autocomplete show\n\n  change: (v: Cell) => void = (v) => {};\n  constructor (public defaultRowHeight: number, public formulas : Array<Formula>) {\n    const suggestList: any = formulas.map(it => [it.key, it.title])\n    this.el = h().children([this.editor = h().class('spreadsheet-editor').children([\n        this.textarea = h('textarea')\n          .on('keydown', (evt: any) => this.inputKeydown(evt))\n          .on('input', (evt: Event) => this.inputChange(evt)),\n        this.textline = h().styles({visibility: 'hidden', overflow: 'hidden', position: 'fixed', top: '0', left: '0'})\n      ])\n    , this.suggest = new Suggest(suggestList, 180)]).hide()\n\n    this.el.on('keydown', (evt: any) => {\n      if (evt.keyCode !== 13 && evt.keyCode !== 9) {\n        evt.stopPropagation();\n      }\n    })\n\n    this.suggest.itemClick = (it) => {\n      // console.log('>>>>>>>>>>>>', it)\n      const text = `=${it[0]}()`;\n      if (this.value) {\n        this.value.text = text\n      }\n      this.textarea.val(text);\n      this.textline.html(text);\n      this.setTextareaRange(text.length - 1)\n      // (<any>this.textarea.el).setSelectionRange(text.length + 1, text.length + 1);\n      // setTimeout(() => (<any>this.textarea.el).focus(), 10)\n    }\n  }\n\n  onChange (change: (v: Cell) => void) {\n    this.change = change\n  }\n\n  set (target: HTMLElement, value: Cell | null) {\n    // console.log('set::>>')\n    this.target = target;\n    const text = this.setValue(value)\n    this.el.show();\n    this.setTextareaRange(text.length)\n    // (<any>this.textarea.el).setSelectionRange(text.length, text.length);\n    // setTimeout(() => (<any>this.textarea.el).focus(), 10)\n    this.reload();\n  }\n\n  setValue (value: Cell | null): string {\n    this.setStyle(value);\n    if (value) {\n      this.value = value;\n      const text = value.text || '';\n      this.textarea.val(text);\n      this.textline.html(text);\n      return text\n    } else {\n      return '';\n    }\n  }\n  setStyle (value: Cell | null): void {\n    let attrs = {width: this.textarea.style('width'), height: this.textarea.style('height')}\n    this.textarea.styles(Object.assign(attrs, getStyleFromCell(value)), true)\n  }\n\n  clear () {\n    // console.log('clear:>>>')\n    this.el.hide();\n    this.target = null;\n    this.value = null;\n    this.textarea.val('')\n    this.textline.html('')\n  }\n\n  private setTextareaRange (position: number) {\n    setTimeout(() => {\n      (<any>this.textarea.el).setSelectionRange(position, position);\n      (<any>this.textarea.el).focus()\n    }, 10)\n  }\n\n  private inputKeydown (evt: any) {\n    if (evt.keyCode === 13) {\n      evt.preventDefault()\n    }\n  }\n\n  private inputChange (evt: any) {\n    const v = evt.target.value\n    if (this.value) {\n      this.value.text = v\n    } else {\n      this.value = {text: v}\n    }\n    this.change(this.value)\n    this.autocomplete(v);\n\n    this.textline.html(v);\n    this.reload()\n\n  }\n\n  private autocomplete (v: string) {\n    if (v[0] === '=') {\n      if (!v.includes('(')) {\n        const search = v.substring(1)\n        console.log(':::;search word:', search)\n        this.suggest.search(this.editor, this.textarea, search);\n      } else {\n        this.suggest.hide()\n      }\n    } else {\n      this.suggest.hide()\n    }\n  }\n\n  reload () {\n    // setTimeout(() => {\n      if (this.target) {\n        const { offsetTop, offsetLeft, offsetWidth, offsetHeight } = this.target\n        this.editor.styles({left: `${offsetLeft - 1}px`, top: `${offsetTop - 1}px`})\n        this.textarea.styles({width: `${offsetWidth - 8}px`, height: `${offsetHeight - 2}px`})\n        let ow = this.textline.offset().width + 16\n        // console.log(maxWidth, ow, '>>>>')\n        if (this.value) {\n          if (this.value.wordWrap) {\n            // 如果单元格自动换行，那么宽度固定，高度变化\n            // this.textarea.style('height', 'auto');\n            const h = (parseInt(ow / offsetWidth + '') + (ow % offsetWidth > 0 ? 1 : 0)) * this.defaultRowHeight;\n            if (h > offsetHeight) {\n              this.textarea.style('height', `${h}px`);\n            }\n          } else {\n            const clientWidth = document.documentElement.clientWidth\n            const maxWidth = clientWidth - offsetLeft - 24\n            if (ow > offsetWidth) {\n              if (ow > maxWidth) {\n                // console.log(':::::::::', ow, maxWidth)\n                const h = (parseInt(ow / maxWidth + '') + (ow % maxWidth > 0 ? 1 : 0)) * this.defaultRowHeight;\n                if (h > offsetHeight) {\n                  this.textarea.style('height', `${h}px`)\n                } else {\n                  this.textarea.style('height', `${offsetHeight}px`)\n                }\n                ow = maxWidth\n              }\n              this.textarea.style('width', `${ow}px`)\n            }\n          }\n        }\n        this.el.show()\n      }\n    // }, 0)\n    \n  }\n}"
  },
  {
    "path": "src/local/editorbar.d.ts",
    "content": "import { Element } from \"./base/element\";\nimport { Cell } from \"../core/cell\";\nexport declare class Editorbar {\n    el: Element;\n    value: Cell | null;\n    textarea: Element;\n    label: Element;\n    change: (v: Cell) => void;\n    constructor();\n    set(title: string, value: Cell | null): void;\n    setValue(value: Cell | null): void;\n    input(evt: any): void;\n}\n"
  },
  {
    "path": "src/local/editorbar.ts",
    "content": "import { Element, h } from \"./base/element\";\nimport { Cell } from \"../core/cell\";\nimport { mouseMoveUp } from \"./event\"\n\nexport class Editorbar {\n  el: Element;\n  value: Cell | null = null; // 选中的当前的cell\n  textarea: Element;\n  label: Element;\n  change: (v: Cell) => void = (v) => {};\n  constructor () {\n    this.el = h().class('spreadsheet-editor-bar').children([\n      h().class('spreadsheet-formula-bar').children([\n        this.label = h().class('spreadsheet-formula-label'),\n        this.textarea = h('textarea').on('input', (evt) => this.input(evt))\n      ]),\n      // h().class('spreadsheet-formular-bar-resizer').on('mousedown', this.mousedown)\n    ])\n  }\n\n  set (title: string, value: Cell | null) {\n    this.label.html(title)\n    this.setValue(value)\n  }\n\n  setValue (value: Cell | null) {\n    this.value = value\n    this.textarea.val(value && value.text || '')\n  }\n\n  input (evt: any) {\n    const v = evt.target.value\n    \n    if (this.value) {\n      this.value.text = v\n    } else {\n      this.value = {text: v}\n    }\n    this.change(this.value)\n  \n  }\n\n}"
  },
  {
    "path": "src/local/event.d.ts",
    "content": "export declare function bind<T extends Event>(name: string, fn: (evt: T) => void, target?: any): void;\nexport declare function unbind<T extends Event>(name: string, fn: (evt: T) => void, target?: any): void;\nexport declare function mouseMoveUp<T extends Event>(movefunc: (evt: T) => void, upfunc: (evt: T) => void): void;\n"
  },
  {
    "path": "src/local/event.ts",
    "content": "export function bind<T extends Event>(name: string, fn: (evt: T) => void, target: any = window) {\n  target.addEventListener(name, fn)\n}\nexport function unbind<T extends Event>(name: string, fn: (evt: T) => void, target: any = window) {\n  target.removeEventListener(name, fn)\n}\nexport function mouseMoveUp<T extends Event> (movefunc: (evt: T) => void, upfunc: (evt: T) => void) {\n  bind('mousemove', movefunc)\n  const up = (evt: T) => {\n    unbind('mousemove', movefunc)\n    unbind('mouseup', up)\n    upfunc(evt)\n  }\n  bind('mouseup', up)\n}"
  },
  {
    "path": "src/local/index.d.ts",
    "content": "import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index';\nimport '../style/index.less';\nimport { Table } from './table';\nimport { Toolbar } from './toolbar';\nimport { Editorbar } from './editorbar';\nexport interface Options extends SpreadsheetOptions {\n    height?: () => number;\n    mode?: 'design' | 'write' | 'read';\n}\nexport declare class LocalSpreadsheet {\n    ss: Spreadsheet;\n    refs: {\n        [key: string]: HTMLElement;\n    };\n    table: Table;\n    toolbar: Toolbar | null;\n    editorbar: Editorbar | null;\n    bindEl: HTMLElement;\n    options: Options;\n    _change: (data: SpreadsheetData) => void;\n    constructor(el: HTMLElement, options?: Options);\n    loadData(data: SpreadsheetData): LocalSpreadsheet;\n    change(cb: (data: SpreadsheetData) => void): LocalSpreadsheet;\n    private render;\n    private toolbarChange;\n    private editorbarChange;\n    private editorChange;\n    private clickCell;\n}\n"
  },
  {
    "path": "src/local/index.ts",
    "content": "import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index'\nimport '../style/index.less'\nimport { Cell, getStyleFromCell } from '../core/cell';\nimport { Format } from '../core/format';\nimport { Font } from '../core/font';\nimport { Editor } from './editor';\nimport { Selector } from './selector';\nimport { Table } from './table';\nimport { Toolbar } from './toolbar';\nimport { Editorbar } from './editorbar';\nimport { h, Element } from './base/element'\n\nexport interface Options extends SpreadsheetOptions {\n  height?: () => number;\n  mode?: 'design' | 'write' | 'read';\n}\n\nexport class LocalSpreadsheet {\n  ss: Spreadsheet;\n  refs: {[key: string]: HTMLElement} = {};\n  table: Table;\n  toolbar: Toolbar | null = null;\n  editorbar: Editorbar | null = null;\n\n  bindEl: HTMLElement\n  options: Options;\n\n  _change: (data: SpreadsheetData) => void = () => {}\n\n  constructor (el: HTMLElement, options: Options = {}) {\n    this.bindEl = el\n    this.options = Object.assign({mode: 'design'}, options)\n\n    // clear content in el\n    this.bindEl && (this.bindEl.innerHTML = '')\n\n    this.ss = new Spreadsheet(options);\n    // console.log('::::>>>select:', this.ss.select)\n    if (this.options.mode === 'design') {\n      this.editorbar = new Editorbar()\n      this.editorbar.change = (v) => this.editorbarChange(v)\n\n      this.toolbar = new Toolbar(this.ss);\n      this.toolbar.change = (key, v) => this.toolbarChange(key, v)\n      this.toolbar.undo = () => {\n        // console.log('undo::')\n        return this.table.undo()\n      }\n      this.toolbar.redo = () => {\n        // console.log('redo::')\n        return this.table.redo()\n      }\n    }\n\n    let bodyHeightFn = (): number => {\n      if (this.options.height) {\n        return this.options.height()\n      }\n      return document.documentElement.clientHeight - 24 - 41 - 26\n    }\n    let bodyWidthFn = (): number => {\n      return this.bindEl.offsetWidth\n    }\n    this.table = new Table(this.ss, Object.assign({height: bodyHeightFn, width: bodyWidthFn, mode: this.options.mode}));\n    this.table.change = (data) => {\n      this.toolbar && this.toolbar.setRedoAble(this.ss.isRedo())\n      this.toolbar && this.toolbar.setUndoAble(this.ss.isUndo())\n      this._change(data)\n    }\n    this.table.editorChange = (v) => this.editorChange(v)\n    this.table.clickCell = (rindex, cindex, cell) => this.clickCell(rindex, cindex, cell)\n    this.render();\n  }\n\n  loadData (data: SpreadsheetData): LocalSpreadsheet {\n    // reload until waiting main thread\n    setTimeout(() => {\n      this.ss.data = data\n      this.table.reload()\n    }, 1)\n    return this\n  }\n\n  change (cb: (data: SpreadsheetData) => void): LocalSpreadsheet {\n    this._change = cb\n    return this;\n  }\n\n  private render (): void {\n    this.bindEl.appendChild(h().class('spreadsheet').children([\n      h().class('spreadsheet-bars').children([\n        this.toolbar && this.toolbar.el || '',\n        this.editorbar && this.editorbar.el || '',\n      ]),\n      this.table.el\n    ]).el);\n  }\n\n  private toolbarChange (k: keyof Cell, v: any) {\n    if (k === 'merge') {\n      this.table.merge();\n      return;\n    } else if (k === 'clearformat') {\n      this.table.clearformat();\n      return ;\n    } else if (k === 'paintformat') {\n      this.table.copyformat();\n      return ;\n    }\n\n    this.table.setCellAttr(k, v);\n  }\n\n  private editorbarChange (v: Cell) {\n    this.table.setValueWithText(v)\n  }\n\n  private editorChange (v: Cell) {\n    this.editorbar && this.editorbar.setValue(v)\n  }\n\n  private clickCell (rindex: number, cindex: number, v: Cell | null) {\n    const cols = this.ss.cols()\n    this.editorbar && this.editorbar.set(`${cols[cindex].title}${rindex + 1}`, v)\n    this.toolbar && this.toolbar.set(this.table.td(rindex, cindex), v)\n  }\n\n}\n"
  },
  {
    "path": "src/local/resizer.d.ts",
    "content": "import { Element } from \"./base/element\";\nexport declare class Resizer {\n    vertical: boolean;\n    change: (index: number, distance: number) => void;\n    el: Element;\n    resizer: Element;\n    resizerLine: Element;\n    moving: boolean;\n    index: number;\n    constructor(vertical: boolean, change: (index: number, distance: number) => void);\n    set(target: any, index: number, scroll: number): void;\n    mousedown(evt: any): void;\n}\n"
  },
  {
    "path": "src/local/resizer.ts",
    "content": "import { Element, h } from \"./base/element\";\nimport { mouseMoveUp } from './event';\n\nexport class Resizer {\n  el: Element;\n  resizer: Element;\n  resizerLine: Element;\n  moving: boolean = false;\n  index: number = 0;\n  constructor (public vertical: boolean, public change: (index: number, distance: number) => void) {\n    this.el = h().class('spreadsheet-resizer-wrapper').children([\n      this.resizer = h().class(`spreadsheet-resizer ${vertical ? 'vertical' : 'horizontal'}`)\n        .on('mousedown', (evt: Event) => this.mousedown(evt)),\n      this.resizerLine = h().class(`spreadsheet-resizer-line ${vertical ? 'vertical' : 'horizontal'}`).hide()\n    ])\n  }\n\n  set (target: any, index: number, scroll: number) {\n    if (this.moving) return ;\n    this.index = index\n    const { vertical } = this\n    const { offsetLeft, offsetTop, offsetHeight, offsetWidth, parentNode } = target\n    this.resizer.styles({\n      left: `${vertical ? offsetLeft + offsetWidth - 5 - scroll : offsetLeft}px`,\n      top: `${vertical ? offsetTop : offsetTop + offsetHeight - 5 + 24  - scroll}px`,\n      width: `${vertical ? 5 : offsetWidth}px`,\n      height: `${vertical ? offsetHeight : 5}px`\n    })\n    this.resizerLine.styles({\n      left: `${vertical ? offsetLeft + offsetWidth - scroll : offsetLeft}px`,\n      top: `${vertical ? offsetTop : offsetTop + offsetHeight + 24 - scroll}px`,\n      width: `${vertical ? 0 : parentNode.parentNode.parentNode.parentNode.parentNode.nextSibling.offsetWidth - 15}px`,\n      height: `${vertical ? parentNode.parentNode.parentNode.parentNode.nextSibling.offsetHeight + parentNode.offsetHeight : 0}px`\n    })\n    // this.el.show()\n  }\n\n  mousedown (evt: any) {\n    let startEvt = evt;\n    let distance = 0;\n    this.resizerLine.show()\n    mouseMoveUp((e: any) => {\n      this.moving = true\n      if (startEvt !== null && e.buttons === 1) {\n        if (this.vertical) {\n          const d = e.x - startEvt.x\n          distance += d\n          this.resizer.style('left', `${this.resizer.offset().left + d}px`)\n          this.resizerLine.style('left', `${this.resizerLine.offset().left + d}px`)\n        } else {\n          const d = e.y - startEvt.y\n          distance += d\n          this.resizer.style('top', `${this.resizer.offset().top + d}px`)\n          this.resizerLine.style('top', `${this.resizerLine.offset().top + d}px`)\n        }\n        startEvt = e\n      }\n    }, (e: any) => {\n      this.change(this.index, distance)\n      startEvt = null\n      this.resizerLine.hide()\n      distance = 0\n      this.moving = false\n    })\n  }\n}"
  },
  {
    "path": "src/local/selector.d.ts",
    "content": "import { Element } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Table } from './table';\nexport declare class Selector {\n    ss: Spreadsheet;\n    table: Table;\n    topEl: Element;\n    rightEl: Element;\n    bottomEl: Element;\n    leftEl: Element;\n    areaEl: Element;\n    cornerEl: Element;\n    copyEl: Element;\n    el: Element;\n    _offset: {\n        left: number;\n        top: number;\n        width: number;\n        height: number;\n    };\n    startTarget: any;\n    endTarget: any;\n    change: () => void;\n    changeCopy: (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) => void;\n    constructor(ss: Spreadsheet, table: Table);\n    mousedown(evt: any): void;\n    setCurrentTarget(target: HTMLElement): void;\n    private cornerMousedown;\n    reload(): void;\n    private setOffset;\n    private rowsHeight;\n    private colsWidth;\n}\nexport declare class DashedSelector {\n    el: Element;\n    constructor();\n    set(selector: Selector): void;\n    hide(): void;\n}\n"
  },
  {
    "path": "src/local/selector.ts",
    "content": "import { Element, h } from \"./base/element\";\nimport { bind, mouseMoveUp } from './event';\nimport { Spreadsheet } from \"../core/index\";\nimport { Table } from './table';\n\nexport class Selector {\n  topEl: Element;\n  rightEl: Element;\n  bottomEl: Element;\n  leftEl: Element;\n  areaEl: Element;\n  cornerEl: Element;\n  copyEl: Element;\n  el: Element;\n  _offset = {left: 0, top: 0, width: 0, height: 0};\n\n  startTarget: any;\n  endTarget: any;\n\n  change: () => void = () => {};\n  changeCopy: (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) => void \n    = (evt, arrow, startRow, startCol, stopRow, stopCol) => {};\n\n  constructor (public ss: Spreadsheet, public table: Table) {\n    this.topEl = h().class('top-border');\n    this.rightEl = h().class('right-border');\n    this.bottomEl = h().class('bottom-border');\n    this.leftEl = h().class('left-border');\n    this.areaEl = h().class('area-border');\n    this.cornerEl = h().class('corner').on('mousedown', (evt) => this.cornerMousedown(evt));\n    this.copyEl = h().class('copy-border');\n    this.el = h().class('spreadsheet-borders').children([\n      this.topEl,\n      this.rightEl,\n      this.bottomEl,\n      this.leftEl,\n      this.areaEl,\n      this.cornerEl,\n      this.copyEl.hide(),\n    ]).hide()\n  }\n\n  mousedown (evt: any) {\n    // console.log('>>>>>>>>selector>>')\n    // console.log(this, evt, evt.type, evt.detail, evt.buttons, evt.button)\n    if (evt.detail === 1 && evt.target.getAttribute('type') === 'cell') {\n      // console.log(evt.shiftKey)\n      if (evt.shiftKey) {\n        this.endTarget = evt.target\n        this.setOffset()\n        return\n      }\n      // Object.assign(this, {startTarget: evt.target, endTarget: evt.target})\n      // this.setOffset()\n      this.setCurrentTarget(evt.target)\n\n      mouseMoveUp((e: any) => {\n        if (e.buttons === 1 && e.target.getAttribute('type') === 'cell') {\n          this.endTarget = e.target\n          this.setOffset()\n        }\n      }, (e) => { this.change() })\n      // show el\n      this.el.show()\n    }\n  }\n\n  setCurrentTarget (target: HTMLElement) {\n    Object.assign(this, {startTarget: target, endTarget: target})\n    this.setOffset()\n  }\n\n  private cornerMousedown (evt: any) {\n    const { select } = this.ss\n    if (select === null) {\n      return ;\n    }\n    const [stopRow, stopCol] = select.stop;\n    const [startRow, startCol] = select.start;\n    \n    let boxRange:['bottom' | 'top' | 'left' | 'right', number, number, number, number] | null = null;\n    mouseMoveUp((e: any) => {\n      const rowIndex = e.target.getAttribute('row-index')\n      const colIndex = e.target.getAttribute('col-index')\n      if (rowIndex && colIndex) {\n        this.copyEl.show();\n        let rdiff = stopRow - rowIndex\n        let cdiff = stopCol - colIndex\n        let _rdiff = startRow - rowIndex\n        let _cdiff = startCol - colIndex\n        const {left, top, height, width} = this._offset;\n        // console.log(rdiff, cdiff, ',,,', _rdiff, _cdiff)\n        if (rdiff < 0) {\n          // bottom\n          // console.log('FCK=>bottom', this.rowsHeight(stopRow, stopRow + Math.abs(rdiff)), rdiff)\n          this.copyEl.styles({\n            left: `${left - 1}px`,\n            top: `${top - 1}px`,\n            width: `${width - 1}px`,\n            height: `${this.rowsHeight(stopRow - select.rowLen() + 1, stopRow + Math.abs(rdiff)) - 1}px`});\n          boxRange = ['bottom', stopRow + 1, startCol, stopRow + Math.abs(rdiff), stopCol]\n        } else if (cdiff < 0) {\n          // right\n          // console.log('FCK=>right')\n          this.copyEl.styles({\n            left: `${left - 1}px`,\n            top: `${top - 1}px`,\n            width: `${this.colsWidth(stopCol - select.colLen() + 1, stopCol + Math.abs(cdiff)) - 1}px`,\n            height: `${height - 1}px`});\n          boxRange = ['right', startRow, stopCol + 1, stopRow, stopCol + Math.abs(cdiff)]\n        } else if (_rdiff > 0) {\n          // top\n          // console.log('FCK=>top')\n          const h = this.rowsHeight(startRow - _rdiff, startRow - 1)\n          this.copyEl.styles({\n            left: `${left - 1}px`,\n            top: `${top - h - 1}px`,\n            width: `${width - 1}px`,\n            height: `${h - 1}px`});\n          boxRange = ['top', startRow - _rdiff, startCol, startRow - 1, stopCol]\n        } else if (_cdiff > 0) {\n          // left\n          // console.log('FCK=>left')\n          const w = this.colsWidth(startCol - _cdiff, startCol - 1)\n          this.copyEl.styles({\n            left: `${left - w - 1}px`,\n            top: `${top - 1}px`,\n            width: `${w - 1}px`,\n            height: `${height - 1}px`});\n          boxRange = ['left', startRow, startCol - _cdiff, stopRow, startCol - 1]\n        } else {\n          this.copyEl.styles({\n            left: `${left - 1}px`,\n            top: `${top - 1}px`,\n            width: `${width - 1}px`,\n            height: `${height - 1}px`});\n          boxRange = null\n        }\n      }\n    }, (e) => {\n      this.copyEl.hide()\n      if (boxRange !== null) {\n        const [arrow, startRow, startCol, stopRow, stopCol] = boxRange\n        this.changeCopy(e, arrow, startRow, startCol, stopRow, stopCol)\n      }\n    });\n  }\n\n  reload () {\n    this.setOffset()\n  }\n\n  private setOffset () {\n    if (this.startTarget === undefined) return ;\n    let { select } = this.ss\n\n    // console.log('select: ', select, this.table)\n    if (select) {\n      // console.log('clear>>>>>:::')\n      // clear\n      const [minRow, minCol] = select.start\n      const [maxRow, maxCol] = select.stop\n      _forEach(minRow, maxRow, this.table.firsttds, (e) => { e.deactive() })\n      _forEach(minCol, maxCol, this.table.ths, (e) => { e.deactive() })\n    }\n\n    select = this.ss.buildSelect(this.startTarget, this.endTarget)\n    const [minRow, minCol] = select.start\n    const [maxRow, maxCol] = select.stop\n    // let height = 0, width = 0;\n    const height = this.rowsHeight(minRow, maxRow, (e) => e.active())\n    // _forEach(minRow, maxRow, this.table.firsttds, (e) => { \n    //   e.active()\n    //   height += parseInt(e.offset().height)\n    // })\n    // height /= 2\n    const width = this.colsWidth(minCol, maxCol, (e) => e.active())\n    // _forEach(minCol, maxCol, this.table.ths, (e) => {\n    //   e.active()\n    //   width += parseInt(e.offset().width)\n    // })\n\n    // console.log('>>', minRow, minCol, maxRow, maxCol, height, width)\n    const td = this.table.td(minRow, minCol)\n    if (td) {\n      // console.log('td:', td)\n      const {left, top} = td.offset()\n      this._offset = {left, top, width, height};\n\n      this.topEl.styles({left: `${left - 1}px`, top: `${top - 1}px`, width: `${width + 1}px`, height: '2px'})\n      this.rightEl.styles({left: `${left + width - 1}px`, top: `${top - 1}px`, width: '2px', height: `${height}px`})\n      this.bottomEl.styles({left: `${left - 1}px`, top: `${top + height - 1}px`, width: `${width}px`, height: '2px'})\n      this.leftEl.styles({left: `${left - 1}px`, top: `${top - 1}px`, width: '2px', height: `${height}px`})\n      this.areaEl.styles({left: `${left}px`, top: `${top}px`, width: `${width - 2}px`, height: `${height - 2}px`})\n      this.cornerEl.styles({left: `${left + width - 5}px`, top: `${top + height - 5}px`})\n    }\n  }\n  private rowsHeight (minRow:number, maxRow:number, cb: (e: Element) => void = (e) => {}): number {\n    let height = 0\n    _forEach(minRow, maxRow, this.table.firsttds, (e) => { \n      cb(e)\n      height += parseInt(e.offset().height)\n    })\n    height /= 2\n    return height\n  }\n  private colsWidth (minCol: number, maxCol: number, cb: (e: Element) => void = (e) => {}): number {\n    let width = 0\n    _forEach(minCol, maxCol, this.table.ths, (e) => {\n      cb(e)\n      width += parseInt(e.offset().width)\n    })\n    return width\n  }\n}\n\nconst _forEach = (start: number, stop: number, elements: {[key: string]: Array<Element> | Element}, cb: (e: Element) => void): void => {\n  for (let i = start; i <= stop; i++) {\n    const es = elements[i + ''];\n    if (es) {\n      if (es instanceof Element) {\n        cb(es)\n      } else {\n        es.forEach(e => cb(e))\n      }\n    }\n  }\n}\n\nexport class DashedSelector {\n  el: Element;\n  constructor () {\n    this.el = h().class('spreadsheet-borders dashed').hide();\n  }\n\n  set (selector: Selector) {\n    if (selector._offset) {\n      const { left, top, width, height } = selector._offset;\n      this.el\n        .style('left', `${left - 2}px`)\n        .style('top', `${top - 2}px`)\n        .style('width', `${width}px`)\n        .style('height', `${height}px`)\n        .show();\n    }\n  }\n\n  hide () {\n    this.el.hide();\n  }\n}\n"
  },
  {
    "path": "src/local/table.d.ts",
    "content": "import { Element } from \"./base/element\";\nimport { Spreadsheet, SpreadsheetData } from '../core/index';\nimport { Editor } from './editor';\nimport { Selector, DashedSelector } from './selector';\nimport { Resizer } from './resizer';\nimport { ContextMenu } from \"./contextmenu\";\nimport { Cell } from \"../core/cell\";\ninterface Map<T> {\n    [key: string]: T;\n}\nexport interface TableOption {\n    height: () => number;\n    width: () => number;\n    mode: 'design' | 'write' | 'read';\n}\nexport declare class Table {\n    options: TableOption;\n    cols: Map<Array<Element>>;\n    firsttds: Map<Array<Element>>;\n    tds: Map<Element>;\n    ths: Map<Element>;\n    ss: Spreadsheet;\n    formulaCellIndexs: Set<string>;\n    el: Element;\n    header: Element;\n    body: Element;\n    fixedLeftBody: Element | null;\n    editor: Editor | null;\n    rowResizer: Resizer | null;\n    colResizer: Resizer | null;\n    contextmenu: ContextMenu | null;\n    selector: Selector;\n    dashedSelector: DashedSelector;\n    state: 'copy' | 'cut' | 'copyformat' | null;\n    currentIndexs: [number, number] | null;\n    focusing: boolean;\n    change: (data: SpreadsheetData) => void;\n    editorChange: (v: Cell) => void;\n    clickCell: (rindex: number, cindex: number, v: Cell | null) => void;\n    constructor(ss: Spreadsheet, options: TableOption);\n    reload(): void;\n    private moveLeft;\n    private moveUp;\n    private moveDown;\n    private moveRight;\n    private moveSelector;\n    setValueWithText(v: Cell): void;\n    setTdWithCell(rindex: number, cindex: number, cell: Cell, autoWordWrap?: boolean): void;\n    setCellAttr(k: keyof Cell, v: any): void;\n    undo(): boolean;\n    redo(): boolean;\n    private setTdStylesAndAttrsAndText;\n    copy(): void;\n    cut(): void;\n    copyformat(): void;\n    paste(): void;\n    clearformat(): void;\n    merge(): void;\n    insert(type: 'row' | 'col', amount: number): void;\n    td(rindex: number, cindex: number): Element;\n    private selectorChange;\n    private selectorChangeCopy;\n    private renderCell;\n    private _renderCell;\n    private reRenderFormulaCells;\n    private setRowHeight;\n    private setTdStyles;\n    private setTdAttrs;\n    private changeRowHeight;\n    private changeRowResizer;\n    private changeColResizer;\n    private buildColGroup;\n    private buildFixedLeft;\n    private buildHeader;\n    private mousedownCell;\n    private editCell;\n    private buildBody;\n    private addRow;\n    private firsttdsPush;\n}\nexport {};\n"
  },
  {
    "path": "src/local/table.ts",
    "content": "import { Element, h } from \"./base/element\";\nimport { Spreadsheet, SpreadsheetData } from '../core/index'\nimport { Editor } from './editor';\nimport { Selector, DashedSelector } from './selector';\nimport { Resizer } from './resizer';\nimport { Editorbar } from \"./editorbar\";\nimport { Toolbar } from \"./toolbar\";\nimport { ContextMenu } from \"./contextmenu\";\nimport { Cell, getStyleFromCell } from \"../core/cell\";\nimport { formatRenderHtml } from \"../core/format\";\nimport { formulaRender } from \"../core/formula\";\nimport { bind } from \"./event\";\n\ninterface Map<T> {\n  [key: string]: T\n}\n\nexport interface TableOption {\n  height: () => number,\n  width: () => number,\n  mode: 'design' | 'write' | 'read';\n}\n\nexport class Table {\n  cols: Map<Array<Element>> = {};\n  firsttds: Map<Array<Element>> = {};\n  tds: Map<Element> = {};\n  ths: Map<Element> = {};\n  ss: Spreadsheet;\n  formulaCellIndexs: Set<string> = new Set(); // 表达式单元格set\n\n  el: Element;\n  header: Element;\n  body: Element;\n  fixedLeftBody: Element | null = null;\n\n  editor: Editor | null = null;\n  rowResizer: Resizer | null = null;\n  colResizer: Resizer | null = null;\n\n  contextmenu: ContextMenu | null = null;\n\n  selector: Selector;\n  dashedSelector: DashedSelector;\n  state: 'copy' | 'cut' | 'copyformat' | null = null;\n\n  currentIndexs: [number, number] | null = null;\n\n  // 当前用户是否焦点再table上\n  focusing: boolean = false;\n\n  // change\n  change: (data: SpreadsheetData) => void = () => {}\n  editorChange: (v: Cell) => void = (v) => {}\n  clickCell: (rindex: number, cindex: number, v: Cell | null) => void = (rindex, cindex, v) => {}\n\n  constructor (ss: Spreadsheet, public options: TableOption) {\n    this.ss = ss;\n    this.ss.change = (data) => {\n      this.change(data)\n    }\n\n    if (options.mode !== 'read') {\n      this.editor = new Editor(ss.defaultRowHeight(), ss.formulas)\n      this.editor.change = (v: Cell) => this.editorChange(v)\n    }\n\n    if (options.mode === 'design') {\n      this.rowResizer = new Resizer(false, (index, distance) => this.changeRowResizer(index, distance))\n      this.colResizer = new Resizer(true, (index, distance) => this.changeColResizer(index, distance))\n      this.contextmenu = new ContextMenu(this)\n    }\n\n    this.selector = new Selector(this.ss, this);\n    this.selector.change = () => this.selectorChange();\n    this.selector.changeCopy = (e, arrow, startRow, startCol, stopRow, stopCol) => {\n      this.selectorChangeCopy(e, arrow, startRow, startCol, stopRow, stopCol);\n    }\n    this.dashedSelector = new DashedSelector();\n\n    this.el = h().class('spreadsheet-table').children([\n      this.colResizer && this.colResizer.el || '',\n      this.rowResizer && this.rowResizer.el || '',\n      this.buildFixedLeft(),\n      this.header = this.buildHeader(),\n      this.body = this.buildBody()\n    ]).on('contextmenu', (evt) => {\n      evt.returnValue = false\n      evt.preventDefault();\n    });\n\n    bind('resize', (evt: any) => {\n      this.header.style('width', `${this.options.width()}px`)\n      this.body.style('width', `${this.options.width()}px`)\n      if (this.options.mode !== 'read') {\n        this.body.style('height', `${this.options.height()}px`)\n      }\n    })\n\n    bind('click', (evt: any) => {\n      // console.log('::::::::', this.el.contains(evt.target))\n      this.focusing = this.el.parent().contains(evt.target)\n    })\n\n    // bind ctrl + c, ctrl + x, ctrl + v\n    bind('keydown', (evt: any) => {\n\n      if (!this.focusing) {\n        return\n      }\n\n      // console.log('::::::::', evt)\n      if (!this.focusing) return;\n\n      // ctrlKey\n      if (evt.ctrlKey && evt.target.type !== 'textarea' && this.options.mode !== 'read') {\n        // ctrl + c\n        if (evt.keyCode === 67) {\n          this.copy();\n          evt.returnValue = false\n        }\n        // ctrl + x\n        if (evt.keyCode === 88) {\n          this.cut();\n          evt.returnValue = false\n        }\n        // ctrl + v\n        if (evt.keyCode === 86) {\n          this.paste();\n          evt.returnValue = false\n        }\n      } else {\n        // console.log('>>>>>>>>>>>>>>', evt)\n        switch (evt.keyCode) {\n          case 37: // left\n            this.moveLeft()\n            evt.returnValue = false\n            break;\n          case 38: // up\n            this.moveUp()\n            evt.returnValue = false\n            break;\n          case 39: // right\n            this.moveRight()\n            evt.returnValue = false\n            break;\n          case 40: // down\n            this.moveDown()\n            evt.returnValue = false\n            break;\n          case 9: // tab\n            this.moveRight();\n            evt.returnValue = false\n            break;\n          case 13:\n            this.moveDown();\n            evt.returnValue = false\n            break;\n        }\n      \n\n        // 输入a-zA-Z1-9\n        if (this.options.mode !== 'read') {\n          if (evt.keyCode >= 65 && evt.keyCode <= 90 || evt.keyCode >= 48 && evt.keyCode <= 57 || evt.keyCode >= 96 && evt.keyCode <= 105 || evt.keyCode == 187) {\n            // if (this.currentIndexs) {\n            // console.log('::::::::', evt.target.type)\n            if (evt.target.type !== 'textarea') {\n              this.ss.cellText(evt.key, (rindex, cindex, cell) => {\n                if (this.editor) {\n                  const td = this.td(rindex, cindex)\n                  td.html(this.renderCell(rindex, cindex, cell))\n                  this.editor.set(td.el, this.ss.currentCell())\n                }\n              })\n            }\n          }\n        }\n\n      }\n      \n    });\n  }\n\n  reload () {\n    this.firsttds = {}\n    this.el.html('')\n    this.el.children([\n      this.colResizer && this.colResizer.el || '',\n      this.rowResizer && this.rowResizer.el || '',\n      this.buildFixedLeft(),\n      this.header = this.buildHeader(),\n      this.body = this.buildBody()\n    ]);\n  }\n  \n  private moveLeft () {\n    if (this.currentIndexs && this.currentIndexs[1] > 0) {\n      this.currentIndexs[1] -= 1\n      this.moveSelector('left')\n    }\n  }\n  private moveUp () {\n    if (this.currentIndexs && this.currentIndexs[0] > 0) {\n      this.currentIndexs[0] -= 1\n      this.moveSelector('up')\n    }\n  }\n  private moveDown () {\n    if (this.currentIndexs && this.currentIndexs[0] < this.ss.rows(this.options.mode === 'read').length) {\n      this.currentIndexs[0] += 1\n      this.moveSelector('down')\n    }\n  }\n  private moveRight () {\n    if (this.currentIndexs && this.currentIndexs[1] < this.ss.cols().length) {\n      this.currentIndexs[1] += 1\n      this.moveSelector('right')\n    }\n  }\n\n  // 移动选框\n  private moveSelector (direction: 'right' | 'left' | 'up' | 'down') {\n    if (this.currentIndexs) {\n      const [rindex, cindex] = this.currentIndexs\n      const td = this.td(rindex, cindex)\n      // console.log('move.td:', td)\n      if (td) {\n        this.selector.setCurrentTarget(td.el)\n        const bodyWidth = this.options.width()\n        const bodyHeight = this.options.height()\n        const {left, top, width, height} = td.offset()\n        // console.log(this.body.el.scrollLeft, ', body-width:', bodyWidth, ', left:', left, ', width=', width)\n        const leftDiff = left + width - bodyWidth\n        if (leftDiff > 0 && direction === 'right') {\n            this.body.el.scrollLeft = leftDiff + 15\n        }\n        if (direction === 'left' && this.body.el.scrollLeft + 60 > left) {\n          this.body.el.scrollLeft -= (this.body.el.scrollLeft + 60 - left)\n        }\n        if (direction === 'up' && this.body.el.scrollTop > top) {\n          this.body.el.scrollTop -= (this.body.el.scrollTop - top)\n        }\n        if (direction === 'down' && top + height - bodyHeight > 0) {\n          this.body.el.scrollTop = top + height - bodyHeight + 15;\n        }\n\n        this.mousedownCell(rindex, cindex)\n      }\n      \n    }\n  }\n\n  setValueWithText (v: Cell) {\n    // console.log('setValueWithText: v = ', v)\n    if (this.currentIndexs) {\n      this.ss.cellText(v.text, (rindex, cindex, cell) => {\n        this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell))\n      })\n    }\n    this.editor && this.editor.setValue(v)\n  }\n\n  setTdWithCell (rindex: number, cindex: number, cell: Cell, autoWordWrap = true) {\n    this.setTdStyles(rindex, cindex, cell);\n    this.setRowHeight(rindex, cindex, autoWordWrap);\n    this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell));\n  }\n\n  setCellAttr (k: keyof Cell, v: any) {\n    // console.log('::k:', k, '::v:', v)\n    this.ss.cellAttr(k, v, (rindex, cindex, cell) => {\n      // console.log(':rindex:', rindex, '; cindex:', cindex, '; cell: ', cell)\n      this.setTdWithCell(rindex, cindex, cell, k === 'wordWrap' && v);\n    })\n    this.editor && this.editor.setStyle(this.ss.currentCell())\n  }\n\n  undo (): boolean {\n    return this.ss.undo((rindex, cindex, cell) => {\n      // console.log('>', rindex, ',', cindex, '::', cell)\n      this.setTdStylesAndAttrsAndText(rindex, cindex, cell)\n    })\n  }\n  redo (): boolean {\n    return this.ss.redo((rindex, cindex, cell) => {\n      this.setTdStylesAndAttrsAndText(rindex, cindex, cell)\n    })\n  }\n  private setTdStylesAndAttrsAndText (rindex: number, cindex: number, cell: Cell) {\n    let td = this.td(rindex, cindex);\n    this.setTdStyles(rindex, cindex, cell);\n    this.setTdAttrs(rindex, cindex, cell);\n    // console.log('txt>>>:', this.renderCell(rindex, cindex, cell))\n    td.html(this.renderCell(rindex, cindex, cell));\n  }\n\n  copy () {\n    this.ss.copy();\n    this.dashedSelector.set(this.selector);\n    this.state = 'copy';\n  }\n\n  cut () {\n    this.ss.cut();\n    this.dashedSelector.set(this.selector);\n    this.state = 'cut';\n  }\n\n  copyformat () {\n    this.ss.copy();\n    this.dashedSelector.set(this.selector);\n    this.state = 'copyformat';\n  }\n\n  paste () {\n    // console.log('state: ', this.state, this.ss.select)\n    if (this.state !== null && this.ss.select) {\n      this.ss.paste((rindex, cindex, cell) => {\n        // console.log('rindex: ', rindex, ', cindex: ', cindex);\n        let td = this.td(rindex, cindex);\n        this.setTdStyles(rindex, cindex, cell);\n        this.setTdAttrs(rindex, cindex, cell);\n        if (this.state === 'cut' || this.state === 'copy') {\n          td.html(this.renderCell(rindex, cindex, cell));\n        }\n      }, this.state, (rindex, cindex, cell) => {\n        let td = this.td(rindex, cindex);\n        this.setTdStyles(rindex, cindex, cell);\n        this.setTdAttrs(rindex, cindex, cell);\n        td.html('');\n      });\n      this.selector.reload();\n    }\n\n    if (this.state === 'copyformat') {\n      this.state = null;\n    } else if (this.state === 'cut') {\n      this.state = null;  \n    } else if (this.state === 'copy') {\n      // this.ss.paste()\n    }\n    \n    this.dashedSelector.hide();\n  }\n\n  clearformat () {\n    this.ss.clearformat((rindex, cindex, cell) => {\n      this.td(rindex, cindex)\n        .removeAttr('rowspan')\n        .removeAttr('colspan')\n        .styles({}, true)\n        .show(true);\n    })\n  }\n\n  merge () {\n    this.ss.merge((rindex, cindex, cell) => {\n      // console.log(rindex, cindex, '>>>', this.table.td(rindex, cindex))\n      this.setTdAttrs(rindex, cindex, cell).show(true)\n    }, (rindex, cindex, cell) => {\n      this.setTdAttrs(rindex, cindex, cell).show(true)\n    }, (rindex, cindex, cell) => {\n      let td = this.td(rindex, cindex)\n      !cell.invisible ? td.show(true) : td.hide()\n    })\n  }\n\n  // insert\n  insert (type: 'row' | 'col', amount: number) {\n    if (type === 'col') {\n      // insert col\n    } else if (type === 'row') {\n      // insert row\n    }\n    this.ss.insert(type, amount, (rindex, cindex, cell) => {\n      this.setTdStylesAndAttrsAndText(rindex, cindex, cell)\n    })\n  }\n\n  td (rindex: number, cindex: number): Element {\n    const td = this.tds[`${rindex}_${cindex}`]\n    return td\n  }\n\n  private selectorChange () {\n    if (this.state === 'copyformat') {\n      this.paste();\n    }\n  }\n\n  private selectorChangeCopy (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) {\n    this.ss.batchPaste(arrow, startRow, startCol, stopRow, stopCol, evt.ctrlKey, (rindex, cindex, cell) => {\n      this.setTdStyles(rindex, cindex, cell);\n      this.setTdAttrs(rindex, cindex, cell);\n      this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell));\n    })\n  }\n\n  private renderCell (rindex: number, cindex: number, cell: Cell | null): string {\n    if (cell) {\n      const setKey = `${rindex}_${cindex}`\n      // console.log('text:', setKey, cell.text && cell.text)\n      if (cell.text && cell.text[0] === '=') {\n        this.formulaCellIndexs.add(setKey)\n      } else {\n        if (this.formulaCellIndexs.has(setKey)) {\n          this.formulaCellIndexs.delete(setKey)\n        }\n\n        this.reRenderFormulaCells()\n      }\n      return formatRenderHtml(cell.format, this._renderCell(cell))\n    }\n    return '';\n  }\n  private _renderCell (cell: Cell | null): string {\n    if (cell) {\n      let text = cell.text || '';\n      return formulaRender(text, (rindex, cindex) => this._renderCell(this.ss.getCell(rindex, cindex)))\n    }\n    return '';\n  }\n  private reRenderFormulaCells () {\n    // console.log('formulaCellIndex: ', this.formulaCellIndexs)\n    this.formulaCellIndexs.forEach(it => {\n      let rcindexes = it.split('_')\n      const rindex = parseInt(rcindexes[0])\n      const cindex = parseInt(rcindexes[1])\n      // console.log('>>>', this.ss.data, this.ss.getCell(rindex, cindex))\n      const text = this.renderCell(rindex, cindex, this.ss.getCell(rindex, cindex))\n      this.td(rindex, cindex).html(text);\n    })\n  }\n\n  private setRowHeight (rindex: number, cindex: number, autoWordWrap: boolean) {\n    // console.log('rowHeight: ', this.td(rindex, cindex).offset().height, ', autoWordWrap:', autoWordWrap)\n    // 遍历rindex行的所有单元格，计算最大高度\n    if (autoWordWrap === false) {\n      return ;\n    }\n    const cols = this.ss.cols()\n    const td = this.td(rindex, cindex)\n    let h = td.offset().height\n    console.log('h:', h)\n    const tdRowspan = td.attr('rowspan')\n    if (tdRowspan) {\n      for (let i = 1; i < parseInt(tdRowspan); i++) {\n        let firsttds = this.firsttds[(rindex + i) +'']\n        firsttds && (h -= parseInt(firsttds[0].attr('height') || 0) + 1)\n      }\n    }\n    // console.log('after.h:', h)\n    this.changeRowHeight(rindex, h - 1);\n  }\n\n  private setTdStyles (rindex: number, cindex: number, cell: Cell): Element {\n    return this.td(rindex, cindex).styles(getStyleFromCell(cell), true)\n  }\n  private setTdAttrs (rindex: number, cindex: number, cell: Cell): Element {\n    return this.td(rindex, cindex)\n      .attr('rowspan', cell.rowspan || 1)\n      .attr('colspan', cell.colspan || 1);\n  }\n\n  private changeRowHeight (index: number, h: number) {\n    if (h <= this.ss.defaultRowHeight()) return\n    this.ss.row(index, h)\n    const firstTds = this.firsttds[index+'']\n    if (firstTds) {\n      firstTds.forEach(td => td.attr('height', h))\n    }\n    this.selector.reload()\n    this.editor && this.editor.reload()\n  }\n  private changeRowResizer (index: number, distance: number) {\n    const h = this.ss.row(index).height + distance\n    this.changeRowHeight(index, h);\n  }\n  private changeColResizer (index: number, distance: number) {\n    const w = this.ss.col(index).width + distance\n    if (w <= 50) return\n    this.ss.col(index, w)\n    const cols = this.cols[index+'']\n    if (cols) {\n      cols.forEach(col => col.attr('width', w))\n    }\n    this.selector.reload()\n    this.editor && this.editor.reload()\n  }\n\n  private buildColGroup (lastColWidth: number): Element {\n    const cols = this.ss.cols();\n    return h('colgroup').children([\n      h('col').attr('width', '60'),\n      ...cols.map((col, index) => {\n        let c = h('col').attr('width', col.width)\n        this.cols[index+''] = this.cols[index+''] || []\n        this.cols[index+''].push(c)\n        return c; \n      }),\n      h('col').attr('width', lastColWidth)\n    ])\n  }\n\n  private buildFixedLeft (): Element {\n    const rows = this.ss.rows(this.options.mode === 'read');\n    return h().class('spreadsheet-fixed')\n    .style('width', '60px')\n    .children([\n      h().class('spreadsheet-fixed-header').child(h('table').child(\n        h('thead').child(\n          h('tr').child(\n            h('th').child('-')\n          )\n        ),\n      )),\n      this.fixedLeftBody = \n      h().class('spreadsheet-fixed-body')\n      .style('height', `${this.options.mode === 'read' ? 'auto' : this.options.height() - 18}px`)\n      .children([\n        h('table').child(\n          h('tbody').children(\n            rows.map((row, rindex) => {\n              let firstTd = h('td').attr('height', `${row.height}`).child(`${rindex + 1}`)\n                .on('mouseover', (evt: Event) => this.rowResizer && this.rowResizer.set(evt.target, rindex, this.body.el.scrollTop));\n              this.firsttdsPush(rindex, firstTd)\n              return h('tr').child(firstTd)\n            })\n          )\n        )\n      ])\n    ])\n  }\n\n  private buildHeader (): Element {\n    const cols = this.ss.cols();\n    const thead = h('thead').child(\n      h('tr').children([\n        h('th'),\n        ...cols.map((col, index) => {\n          let th = h('th').child(col.title).on('mouseover', (evt: Event) => {\n            console.log(evt)\n            this.colResizer && this.colResizer.set(evt.target, index, this.body.el.scrollLeft)\n          });\n          this.ths[index + ''] = th;\n          return th;\n        }),\n        h('th')\n      ]\n    ))\n    return h().class('spreadsheet-header').style('width', `${this.options.width()}px`).children([\n      h('table').children([this.buildColGroup(15), thead])\n    ])\n  }\n\n  private mousedownCell (rindex: number, cindex: number) {\n    if (this.editor) {\n      const editorValue = this.editor.value\n      if (this.currentIndexs && this.editor.target && editorValue) {\n        // console.log(':::editorValue:', editorValue)\n        const oldCell = this.ss.cellText(editorValue.text, (_rindex, _cindex, _cell: Cell) => {\n          this.td(_rindex, _cindex).html(this.renderCell(_rindex, _cindex, _cell))\n        });\n        // const oldTd = this.td(this.currentIndexs[0], this.currentIndexs[1]);\n        // oldTd.html(this.renderCell(editorValue))\n        if (oldCell) {\n          // 设置内容之后，获取高度设置行高\n          if (oldCell.wordWrap) {\n            this.setRowHeight(this.currentIndexs[0], this.currentIndexs[1], true)\n          }\n          // console.log('old.td.offset:', oldCell)\n          // this.editorChange(oldCell)\n        }\n      }\n      this.editor.clear()\n    }\n\n    this.currentIndexs = [rindex, cindex]\n    const cCell = this.ss.currentCell([rindex, cindex])\n    this.clickCell(rindex, cindex, cCell)\n  }\n\n  private editCell(rindex: number, cindex: number) {\n    const td = this.td(rindex, cindex)\n    this.editor && this.editor.set(td.el, this.ss.currentCell())\n  }\n\n  private buildBody () {\n    const rows = this.ss.rows(this.options.mode === 'read');\n    const cols = this.ss.cols();\n\n    const mousedown = (rindex: number, cindex: number, evt: any) => {\n      const {select} = this.ss\n      if (evt.button === 2) {\n        // show contextmenu\n        console.log(':::evt:', evt)\n        this.contextmenu && this.contextmenu.set(evt)\n        if (select && select.contains(rindex, cindex)) {\n          return\n        }\n      }\n      // left key\n      this.selector.mousedown(evt)\n      this.mousedownCell(rindex, cindex)\n      this.focusing = true\n    }\n\n    const dblclick = (rindex: number, cindex: number) => {\n      this.editCell(rindex, cindex)\n    }\n\n    const scrollFn = (evt: any) => {\n      this.header.el.scrollLeft = evt.target.scrollLeft\n      this.fixedLeftBody && (this.fixedLeftBody.el.scrollTop = evt.target.scrollTop)\n      // console.log('>>>>>>>>scroll...', this.header, evt.target.scrollLeft, evt.target.scrollHeight)\n    }\n\n    const tbody = h('tbody').children(rows.map((row, rindex) => {\n      let firstTd = h('td').attr('height', `${row.height}`).child(`${rindex + 1}`);\n      this.firsttdsPush(rindex, firstTd)\n      return h('tr').children([\n        firstTd,\n        ...cols.map((col, cindex) => {\n          let cell = this.ss.getCell(rindex, cindex)\n          let td = h('td')\n            .child(this.renderCell(rindex, cindex, cell))\n            .attr('type', 'cell')\n            .attr('row-index', rindex + '')\n            .attr('col-index', cindex + '')\n            .attr('rowspan', cell && cell.rowspan || 1)\n            .attr('colspan', cell && cell.colspan || 1)\n            .styles(getStyleFromCell(cell), true)\n            .on('mousedown', (evt: any) => mousedown(rindex, cindex, evt))\n            .on('dblclick', dblclick.bind(null, rindex, cindex));\n          this.tds[`${rindex}_${cindex}`] = td\n          return td;\n        }),\n        h('td')\n      ])\n    }));\n\n    return h().class('spreadsheet-body')\n      .on('scroll', scrollFn)\n      .style('height', `${this.options.mode === 'read' ? 'auto' : this.options.height()}px`)\n      .style('width', `${this.options.width()}px`)\n      .children([\n        h('table').children([this.buildColGroup(0), tbody]),\n        this.editor && this.editor.el || '',\n        this.selector.el,\n        this.contextmenu && this.contextmenu.el || '',\n        this.dashedSelector.el\n      ]\n    )\n  }\n\n  // 向尾部添加行\n  private addRow (num = 1) {\n    if (num > 0) {\n\n    }\n  }\n\n  private firsttdsPush (index: number, el: Element) {\n    this.firsttds[`${index}`] = this.firsttds[`${index}`] || []  \n    this.firsttds[`${index}`].push(el)\n  }\n\n}"
  },
  {
    "path": "src/local/toolbar.d.ts",
    "content": "import { Element } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Cell } from '../core/cell';\nimport { Dropdown } from './base/dropdown';\nexport declare class Toolbar {\n    ss: Spreadsheet;\n    el: Element;\n    defaultCell: Cell;\n    target: Element | null;\n    currentCell: Cell | null;\n    elUndo: Element;\n    elRedo: Element;\n    elPaintformat: Element;\n    elClearformat: Element;\n    elFormat: Dropdown;\n    elFont: Dropdown;\n    elFontSize: Dropdown;\n    elFontWeight: Element;\n    elFontStyle: Element;\n    elTextDecoration: Element;\n    elColor: Dropdown;\n    elBackgroundColor: Dropdown;\n    elMerge: Element;\n    elAlign: Dropdown;\n    elValign: Dropdown;\n    elWordWrap: Element;\n    change: (key: keyof Cell, v: any) => void;\n    redo: () => boolean;\n    undo: () => boolean;\n    constructor(ss: Spreadsheet);\n    set(target: Element, cell: Cell | null): void;\n    private setCell;\n    private setCellStyle;\n    setRedoAble(flag: boolean): void;\n    setUndoAble(flag: boolean): void;\n    private buildSeparator;\n    private buildAligns;\n    private buildValigns;\n    private buildWordWrap;\n    private buildFontWeight;\n    private buildFontStyle;\n    private buildTextDecoration;\n    private buildMerge;\n    private buildColor;\n    private buildBackgroundColor;\n    private buildUndo;\n    private buildRedo;\n    private buildPaintformat;\n    private buildClearformat;\n    private buildFormats;\n    private buildFonts;\n    private buildFontSizes;\n}\n"
  },
  {
    "path": "src/local/toolbar.ts",
    "content": "import { Element, h } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Cell, getStyleFromCell, defaultCell } from '../core/cell';\nimport { Table } from './table';\nimport { buildItem, Item } from './base/item';\nimport { buildIcon } from './base/icon';\nimport { buildDropdown, Dropdown } from './base/dropdown';\nimport { buildMenu } from './base/menu';\nimport { buildColorPanel } from './base/colorPanel';\nimport { Font } from \"../core/font\";\nimport { Format } from \"../core/format\";\n\nexport class Toolbar {\n  el: Element;\n  defaultCell: Cell;\n\n  target: Element | null = null;\n  currentCell: Cell | null = null;\n\n  elUndo: Element;\n  elRedo: Element;\n  elPaintformat: Element;\n  elClearformat: Element;\n  elFormat: Dropdown;\n  elFont: Dropdown;\n  elFontSize: Dropdown;\n  elFontWeight: Element;\n  elFontStyle: Element;\n  elTextDecoration: Element;\n  elColor: Dropdown;\n  elBackgroundColor: Dropdown;\n  elMerge: Element;\n  elAlign: Dropdown;\n  elValign: Dropdown;\n  elWordWrap: Element;\n\n  change: (key: keyof Cell, v: any) => void = (key, v) => {}\n  redo: () => boolean = () => false\n  undo: () => boolean = () => false\n\n  constructor (public ss: Spreadsheet) {\n    this.defaultCell = ss.data.cell\n\n    this.el = h().class('spreadsheet-toolbar').child(\n        buildMenu('horizontal').children([\n          this.elUndo = this.buildUndo(),\n          this.elRedo = this.buildRedo(),\n          this.elPaintformat = this.buildPaintformat(),\n          this.elClearformat = this.buildClearformat(),\n          this.elFormat = this.buildFormats(),\n          this.buildSeparator(),\n          this.elFont = this.buildFonts(),\n          this.elFontSize = this.buildFontSizes(),\n          this.buildSeparator(),\n          this.elFontWeight = this.buildFontWeight(),\n          this.elFontStyle = this.buildFontStyle(),\n          this.elTextDecoration = this.buildTextDecoration(),\n          this.elColor = this.buildColor(),\n          this.buildSeparator(),\n          this.elBackgroundColor = this.buildBackgroundColor(),\n          this.elMerge = this.buildMerge(),\n          this.buildSeparator(),\n          this.elAlign = this.buildAligns(),\n          this.elValign = this.buildValigns(),\n          this.elWordWrap = this.buildWordWrap()\n        ])\n      )\n    ;\n  }\n\n  set (target: Element, cell: Cell | null) {\n    this.target = target\n    this.setCell(cell)\n  }\n\n  private setCell (cell: Cell | null) {\n    this.currentCell = cell\n    this.setCellStyle()\n  }\n\n  private setCellStyle () {\n    const { target, currentCell, defaultCell, ss } = this\n    // console.log(':::', currentCell)\n    if (target) {\n      // target.clearStyle()\n      // target.styles(getStyleFromCell(currentCell))\n      this.elFormat.title.html(ss.getFormat(currentCell !== null && currentCell.format || defaultCell.format).title);\n      this.elFont.title.html(ss.getFont(currentCell !== null && currentCell.font || defaultCell.font).title);\n      this.elFontSize.title.html((currentCell !== null && currentCell.fontSize || defaultCell.fontSize) + '');\n      this.elFontWeight.active(currentCell !== null && currentCell.bold !== undefined && currentCell.bold !== defaultCell.bold);\n      this.elFontStyle.active(currentCell !== null && currentCell.italic !== undefined && currentCell.italic !== defaultCell.italic);\n      this.elTextDecoration.active(currentCell !== null && currentCell.underline !== undefined && currentCell.underline !== defaultCell.underline);\n      this.elColor.title.style('border-bottom-color', currentCell !== null && currentCell.color || defaultCell.color);\n      this.elBackgroundColor.title.style('border-bottom-color', currentCell !== null && currentCell.backgroundColor || defaultCell.backgroundColor);\n      (<any>this.elAlign.title).replace(`align-${currentCell !== null && currentCell.align || defaultCell.align}`);\n      (<any>this.elValign.title).replace(`valign-${currentCell !== null && currentCell.valign || defaultCell.valign}`);\n      this.elWordWrap.active(currentCell !== null && currentCell.wordWrap !== undefined && currentCell.wordWrap !== defaultCell.wordWrap);\n      // console.log('select:', currentCell)\n      if ((currentCell !== null && currentCell.rowspan && currentCell.rowspan > 1)\n        || (currentCell !== null && currentCell.colspan && currentCell.colspan > 1)) {\n        this.elMerge.active(true);\n      } else {\n        this.elMerge.active(false);\n      }\n    }\n  }\n\n  setRedoAble (flag: boolean) {\n    flag ? this.elRedo.able() : this.elRedo.disabled()\n  }\n\n  setUndoAble (flag: boolean) {\n    flag ? this.elUndo.able() : this.elUndo.disabled()\n  }\n\n  private buildSeparator (): Element {\n    return h().class('spreadsheet-item-separator')\n  }\n  private buildAligns (): Dropdown {\n    const titleIcon = buildIcon(`align-${this.defaultCell.align}`)\n    const clickHandler = (it: string) => {\n      titleIcon.replace(`align-${it}`)\n      this.change('align', it)\n    }\n    return buildDropdown(titleIcon, '60px', [buildMenu().children(\n      ['left', 'center', 'right'].map(it => \n        buildItem()\n          .child(buildIcon(`align-${it}`).style('text-align', 'center'))\n          .on('click', clickHandler.bind(null, it))\n      )\n    )])\n  }\n  private buildValigns (): Dropdown {\n    const titleIcon = buildIcon(`valign-${this.defaultCell.valign}`)\n    const clickHandler = (it: string) => {\n      titleIcon.replace(`valign-${it}`)\n      this.change('valign', it)\n    }\n    return buildDropdown(titleIcon, '60px', [buildMenu().children(\n      ['top', 'middle', 'bottom'].map(it => \n        buildItem()\n          .child(buildIcon(`valign-${it}`).style('text-align', 'center'))\n          .on('click', clickHandler.bind(null, it))\n        )\n    )])\n  }\n  private buildWordWrap (): Element {\n    return buildIconItem('textwrap', (is) => this.change('wordWrap', is))\n  }\n  private buildFontWeight (): Element {\n    return buildIconItem('bold', (is) => this.change('bold', is))\n  }\n  private buildFontStyle (): Element {\n    return buildIconItem('italic', (is) => this.change('italic', is))\n  }\n  private buildTextDecoration (): Element {\n    return buildIconItem('underline', (is) => this.change('underline', is))\n  }\n  private buildMerge (): Element {\n    return buildIconItem('merge', (is) => this.change('merge', is))\n  }\n  private buildColor (): Dropdown {\n    const clickHandler = (color: string) => {\n      this.elColor.title.style('border-bottom-color', color)\n      this.change('color', color)\n    }\n    return buildDropdown(\n      buildIcon('text-color').styles({'border-bottom': `3px solid ${this.defaultCell.color}`, 'margin-top': '2px', height: '16px'}),\n      'auto',\n      [buildColorPanel(clickHandler)])\n  }\n  private buildBackgroundColor (): Dropdown {\n    const clickHandler = (color: string) => {\n      this.elBackgroundColor.title.style('border-bottom-color', color)\n      this.change('backgroundColor', color)\n    }\n    return buildDropdown(\n      buildIcon('cell-color').styles({'border-bottom': `3px solid ${this.defaultCell.backgroundColor}`, 'margin-top': '2px', height: '16px'}),\n      'auto',\n      [buildColorPanel(clickHandler)])\n  }\n  private buildUndo (): Element {\n    return buildItem().child(buildIcon('undo'))\n      .on('click', (evt) => {\n        this.undo() ? this.elUndo.able() : this.elUndo.disabled()\n      })\n      .disabled()\n  }\n  private buildRedo (): Element {\n    return buildItem().child(buildIcon('redo'))\n      .on('click', (evt) => {\n        this.redo() ? this.elRedo.able() : this.elRedo.disabled()\n      })\n      .disabled()\n  }\n  private buildPaintformat (): Element {\n    return buildIconItem('paintformat', (is) => { \n      this.change('paintformat', true);\n      this.elPaintformat.deactive();\n    })\n  }\n  private buildClearformat (): Element {\n    return buildIconItem('clearformat', (is) => { \n      this.change('clearformat', true);\n      this.elClearformat.deactive();\n    });\n  }\n  private buildFormats (): Dropdown {\n    const clickHandler = (it: Format) => {\n      this.elFormat.title.html(this.ss.getFormat(it.key).title);\n      this.change('format', it.key)\n    }\n    return buildDropdown(this.ss.getFormat(this.defaultCell.format).title, '250px', [buildMenu().children(\n      this.ss.formats.map(it => \n        buildItem()\n          .children([it.title, h().class('label').child(it.label||'')])\n          .on('click', clickHandler.bind(null, it))\n        )\n    )])\n  }\n  private buildFonts (): Dropdown {\n    const clickHandler = (it: Font) => {\n      this.elFont.title.html(it.title)\n      this.change('font', it.key)\n    }\n    return buildDropdown(this.ss.getFont(this.defaultCell.font).title, '170px', [buildMenu().children(\n      this.ss.fonts.map(it => { \n        return buildItem()\n          .child(it.title)\n          .on('click', clickHandler.bind(null, it))\n      })\n    )])\n  }\n  private buildFontSizes (): Dropdown {\n    const clickHandler = (it: number) => {\n      this.elFontSize.title.html(`${it}`)\n      this.change('fontSize', it)\n    }\n    return buildDropdown(this.defaultCell.fontSize + '', '70px', [buildMenu().children(\n      [6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 30, 36].map(it => {\n        return buildItem()\n          .child(`${it}`)\n          .on('click', clickHandler.bind(null, it))\n      })\n    )])\n  }\n}\n\nconst buildIconItem = (iconName: string, change: (flag: boolean) => void) => {\n  const el = buildItem().child(buildIcon(iconName))\n  el.on('click', (evt) => {\n    let is = el.isActive()\n    is ? el.deactive() : el.active()\n    change(!is)\n  })\n  return el;\n}"
  },
  {
    "path": "src/main.d.ts",
    "content": "import { LocalSpreadsheet, Options } from './local/index';\nexport default function xspreadsheet(el: HTMLElement, options?: Options): LocalSpreadsheet;\ndeclare global {\n    interface Window {\n        xspreadsheet: any;\n    }\n}\n"
  },
  {
    "path": "src/main.ts",
    "content": "import { LocalSpreadsheet, Options } from './local/index';\n\nexport default function xspreadsheet (el: HTMLElement, options?: Options) {\n  return new LocalSpreadsheet(el, options)\n}\n\ndeclare global {\n  interface Window {\n    xspreadsheet: any;\n  }\n}\n\nwindow.xspreadsheet = xspreadsheet\n"
  },
  {
    "path": "src/style/index.less",
    "content": "@border-style: 1px solid #e0e2e4;\n@icon-size: 18px;\n\nbody {\n  margin: 0;\n}\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-table {\n    position: relative;\n    background: #fff;\n  }\n\n  .spreadsheet-fixed {\n    position: absolute;\n    top: 0;\n    left: 0;\n    z-index: 10;\n    background: #fff;\n\n    .spreadsheet-fixed-body {\n      overflow: hidden;\n    }\n    .spreadsheet-fixed-header {\n      overflow: hidden;  \n    }\n  }\n\n  .spreadsheet-body {\n    overflow: scroll;\n    position: relative;\n  }\n  .spreadsheet-header {\n    overflow: hidden;\n    width: 100%;\n  }\n\n  .spreadsheet-header, .spreadsheet-body, .spreadsheet-fixed {\n\n    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      td, th {\n        transition: background .1s ease,color .1s ease;\n        border-bottom: @border-style;\n        border-right: @border-style;\n        white-space: nowrap;\n        text-overflow: ellipsis;\n        overflow: hidden;\n        padding: 0 4px;\n        // height: 22px;\n        line-height: 22px;\n      }\n  \n      td.active, th.active {\n        background: rgba(75, 137, 255, .05)!important;\n      }\n  \n      th {\n        border-top: @border-style;\n        text-align: center;\n      }\n  \n      th, td:first-child {\n        font-size: 12px;\n        background: #f4f5f8;\n        font-weight: normal;\n        color: #666;\n      }\n  \n      td:first-child, th:first-child {\n        border-left: @border-style;\n        text-align: center;\n      }\n    }\n  }\n\n}\n\n.spreadsheet-editor {\n  position: absolute;\n  text-align: left;\n  // z-index: 10;\n  border: 2px solid rgb(75, 137, 255);\n  line-height: 0;\n  z-index: 10;\n\n  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    // max-width: 500px;\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}\n\n.spreadsheet-suggest, .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\n.spreadsheet-resizer {\n  position: absolute;\n  z-index: 11;\n  &.horizontal {\n    cursor: row-resize;\n  }\n  &.vertical {\n    cursor: col-resize;\n  }\n}\n.spreadsheet-resizer-line {\n  position: absolute;\n  z-index: 100;\n  &.horizontal {\n    border-bottom: 2px dashed rgb(75, 137, 255);\n  }\n  &.vertical {\n    border-right: 2px dashed rgb(75, 137, 255);\n  }\n}\n\n.spreadsheet-borders {\n  box-sizing: content-box;\n\n  &.dashed {\n    border: 2px dashed rgb(75, 137, 255);\n    position: absolute;\n    background: rgba(75, 137, 255, 0.03);\n  }\n\n  .left-border, .right-border, .bottom-border, .top-border, .area-border {\n    position: absolute;\n    font-size: 0;\n    pointer-events: none;\n    background: rgb(75, 137, 255);\n  }\n\n  .area-border {\n    background: rgba(75, 137, 255, 0.03);\n  }\n\n  .corner {\n    cursor: crosshair;\n    font-size: 0;\n    height: 5px;\n    width: 5px;\n    border: 2px solid rgb(255, 255, 255);\n    position: absolute;\n    bottom: -6px;\n    right: -6px;\n    background: rgb(75, 137, 255);\n    // z-index: 12;\n  }\n\n  .copy-border {\n    position: absolute;\n    pointer-events: none;\n    border: 1px dashed rgb(75, 137, 255);\n    background: rgba(75, 137, 255, .03);\n  }\n}\n\n.spreadsheet-paint-border {\n  position: absolute;\n  pointer-events: none;\n  border: 1px dashed rgb(75, 137, 255);\n  background: rgba(75, 137, 255, .03);\n}\n\n.spreadsheet-bars {\n  .spreadsheet-toolbar {\n    // width: 100%;\n    height: 40px;\n    text-align: left;\n    padding: 0 60px;\n    border-bottom: @border-style;\n    background: #f5f6f7;\n\n    >.spreadsheet-menu > .spreadsheet-item {\n      margin: 7px 1px 0;\n    }\n\n  }\n  .spreadsheet-editor-bar {\n    width: 100%;\n    height: 26px;\n    line-height: 26px;\n    position: relative;\n    background: #fff;\n    padding: 0;\n  }\n}\n\n.spreadsheet-formula-bar {\n  position: relative;\n  height: 100%;\n\n  .spreadsheet-formula-label {\n    width: 60px;\n    height: 100%;\n    box-sizing: border-box;\n    display: inline-block;\n    text-align: center;\n    // line-height: inherit;\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\n  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}\n.spreadsheet-formula-bar-resizer {\n  cursor: ns-resize;\n  // border-bottom: 1px solid #c0c0c0;\n  height: 4px;\n  position: absolute;\n  width: 100%;\n  left: 0;\n  bottom: 0;\n}\n\n\n.spreadsheet-menu {\n  &.vertical {\n    > .spreadsheet-item-separator {\n      background: #e0e2e4;\n      height: 1px;\n      margin: 5px 0;\n    }\n    > .spreadsheet-item {\n      padding: 2px 10px;\n      border-radius: 0;\n      // border-top: 1px solid #fafafa;\n    }\n  }\n  &.horizontal {\n    > .spreadsheet-item {\n      display: inline-block;\n    }\n    > .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  }\n  > .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, .8);\n    line-height: 24px;\n    list-style: none;\n    // font-weight: bold;\n    cursor: default;\n\n    &.disabled {\n      pointer-events: none;\n      opacity: 0.5;\n    }\n\n    &:not(.separator):hover, &.active {\n      background: rgba(0, 0, 0, .08);\n      // color: rgba(0, 0, 0, 0.7);\n      .spreadsheet-icon-img {\n        opacity: 0.7;\n      }\n\n      .spreadsheet-dropdown-icon {\n        background-color: rgba(0, 0, 0, .15);\n        opacity: 0.6;\n      }\n    }\n    \n    > .label {\n      float: right;\n      opacity: .8;\n    }\n  }\n\n}\n\n.spreadsheet-dropdown {\n  position: relative;\n  display: inline-block;\n  width: auto!important;\n\n  .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,.15);\n    width: auto;\n  }\n\n  .spreadsheet-dropdown-header {\n    .spreadsheet-dropdown-title {\n      padding: 0 5px;\n      display: inline-block;\n    }\n    // > .spreadsheet-icon {\n    //   width: 18px;\n    //   height: 16px;\n    // }\n    \n    .spreadsheet-dropdown-icon {\n      display: inline-block;\n      vertical-align: top;\n      // border: 1px solid transparent;\n      .spreadsheet-icon {\n        width: 10px;\n        .arrow-down {\n          left: -7 * @icon-size - 4px;\n        }\n      }\n    }\n  }\n}\n\n.spreadsheet-color-panel {\n  padding: 10px;\n  width: 100%;\n\n  table {\n    border-collapse: separate;\n    border-spacing: 0;\n    border: none;\n  }\n\n  table tr td {\n    padding: 0;\n    border: none;\n\n  }\n\n  .color-cell {\n    width: 20px;\n    height: 20px;\n    margin: 3px;\n\n    &:hover {\n      box-shadow: 0 0 2px rgba(0,0,0,.8);\n    }\n  }\n}\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('../assets/sprite.svg');\n  position: absolute;\n  width: 262px;\n  height: 444px;\n  opacity: 0.55;\n\n  &.undo {\n    left: 0;\n    top: 0;\n  }\n  &.redo {\n    left: -1 * @icon-size;\n    top: 0;\n  }\n  &.print {\n    left: -2 * @icon-size;\n    top: 0;\n  }\n  &.paintformat {\n    left: -3 * @icon-size;\n    top: 0;\n  }\n  &.clearformat {\n    left: -4 * @icon-size;\n    top: 0;\n  }\n  &.bold {\n    left: -5 * @icon-size;\n    top: 0;\n  }\n  &.italic {\n    left: -6 * @icon-size;\n    top: 0;\n  }\n  &.underline {\n    left: -7 * @icon-size;\n    top: 0;\n  }\n  &.strikethrough {\n    left: -8 * @icon-size;\n    top: 0;\n  }\n  &.text-color {\n    left: -9 * @icon-size;\n    top: 0;\n  }\n  &.cell-color {\n    left: -10 * @icon-size;\n    top: 0;\n  }\n  &.merge {\n    left: -11 * @icon-size;\n    top: 0;\n  }\n  &.align-left {\n    left: -12 * @icon-size;\n    top: 0;\n  }\n  &.align-center {\n    left: -13 * @icon-size;\n    top: 0;\n  }\n  &.align-right {\n    left: 0;\n    top: -1 * @icon-size;\n  }\n  &.valign-top {\n    left: -1 * @icon-size;\n    top: -1 * @icon-size;\n  }\n  &.valign-middle {\n    left: -2 * @icon-size;\n    top: -1 * @icon-size;\n  }\n  &.valign-bottom {\n    left: -3 * @icon-size;\n    top: -1 * @icon-size;\n  }\n  &.textwrap {\n    left: -4 * @icon-size;\n    top: -1 * @icon-size;\n  }\n  &.autofilter {\n    left: -5 * @icon-size;\n    top: -1 * @icon-size;\n  }\n  &.formula {\n    left: -6 * @icon-size;\n    top: -1 * @icon-size;\n  }\n  &.arrow-down {\n    left: -7 * @icon-size;\n    top: -1 * @icon-size;\n  }\n  &.arrow-right {\n    left: -8 * @icon-size;\n    top: -1 * @icon-size;\n  }\n}"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    /* Basic Options */\n    \"target\": \"ES2015\",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */\n    \"module\": \"commonjs\",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */\n    // \"lib\": [\"es6\"],                             /* Specify library files to be included in the compilation. */\n    // \"allowJs\": true,                       /* Allow javascript files to be compiled. */\n    // \"checkJs\": true,                       /* Report errors in .js files. */\n    // \"jsx\": \"preserve\",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */\n    \"declaration\": true,                   /* Generates corresponding '.d.ts' file. */\n    \"sourceMap\": true,                     /* Generates corresponding '.map' file. */\n    // \"outFile\": \"./xpreadsheet\",                       /* Concatenate and emit output to single file. */\n    // \"outDir\": \"./distjs/\",                        /* Redirect output structure to the directory. */\n    // \"rootDir\": \"./\",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */\n    \"removeComments\": true,                /* Do not emit comments to output. */\n    // \"noEmit\": true,                        /* Do not emit outputs. */\n    // \"importHelpers\": true,                 /* Import emit helpers from 'tslib'. */\n    // \"downlevelIteration\": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */\n    // \"isolatedModules\": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */\n\n    /* Strict Type-Checking Options */\n    \"strict\": true,                           /* Enable all strict type-checking options. */\n    \"noImplicitAny\": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */\n    // \"strictNullChecks\": true,              /* Enable strict null checks. */\n    // \"strictFunctionTypes\": true,           /* Enable strict checking of function types. */\n    // \"strictPropertyInitialization\": true,  /* Enable strict checking of property initialization in classes. */\n    // \"noImplicitThis\": true,                /* Raise error on 'this' expressions with an implied 'any' type. */\n    // \"alwaysStrict\": true,                  /* Parse in strict mode and emit \"use strict\" for each source file. */\n\n    /* Additional Checks */\n    // \"noUnusedLocals\": true,                /* Report errors on unused locals. */\n    // \"noUnusedParameters\": true,            /* Report errors on unused parameters. */\n    // \"noImplicitReturns\": true,             /* Report error when not all code paths in function return a value. */\n    // \"noFallthroughCasesInSwitch\": true,    /* Report errors for fallthrough cases in switch statement. */\n\n    /* Module Resolution Options */\n    // \"moduleResolution\": \"node\",            /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */\n    // \"baseUrl\": \"./\",                       /* Base directory to resolve non-absolute module names. */\n    // \"paths\": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */\n    // \"rootDirs\": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */\n    // \"typeRoots\": [],                       /* List of folders to include type definitions from. */\n    // \"types\": [],                           /* Type declaration files to be included in compilation. */\n    // \"allowSyntheticDefaultImports\": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */\n    // \"esModuleInterop\": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */\n    // \"preserveSymlinks\": true,              /* Do not resolve the real path of symlinks. */\n\n    /* Source Map Options */\n    // \"sourceRoot\": \"./\",                    /* Specify the location where debugger should locate TypeScript files instead of source locations. */\n    // \"mapRoot\": \"./\",                       /* Specify the location where debugger should locate map files instead of generated locations. */\n    // \"inlineSourceMap\": true,               /* Emit a single file with source maps instead of having a separate file. */\n    // \"inlineSources\": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */\n\n    /* Experimental Options */\n    // \"experimentalDecorators\": true,        /* Enables experimental support for ES7 decorators. */\n    // \"emitDecoratorMetadata\": true,         /* Enables experimental support for emitting type metadata for decorators. */\n  },\n  \"include\": [\n    \"./src/**/*\"\n  ]\n}"
  },
  {
    "path": "tslint.json",
    "content": "{\n    \"defaultSeverity\": \"error\",\n    \"extends\": [\n        \"tslint:recommended\",\n        \"tslint-eslint-rules\"\n    ],\n    \"jsRules\": {},\n    \"rules\": {\n        \"ter-indent\": [true, 2]\n    },\n    \"rulesDirectory\": []\n}"
  },
  {
    "path": "webpack.config.dev.js",
    "content": "var ExtractTextPlugin = require('extract-text-webpack-plugin');\nmodule.exports = {\n  entry: \"./src/main.ts\",\n  output: {\n      filename: \"bundle.js\",\n      path: __dirname + \"/dist\"\n  },\n\n  // Enable sourcemaps for debugging webpack's output.\n  devtool: \"source-map\",\n\n  devServer: {\n    clientLogLevel: 'warning',\n    hot: true,\n    publicPath: '/'\n  },\n\n  resolve: {\n      // Add '.ts' and '.tsx' as resolvable extensions.\n      extensions: [\".ts\", \".tsx\", \".js\", \".json\"]\n  },\n\n  module: {\n      rules: [\n        {test: /\\.css$/, loader: ExtractTextPlugin.extract(\"style-loader\",\"css-loader\")},\n        {\n          test: /\\.less$/,\n          use:ExtractTextPlugin.extract({\n            fallback:'style-loader',\n            use:['css-loader','less-loader']\n          })\n        },\n        {test: /\\.(eot|woff|woff2|ttf|svg)([\\\\?]?.*)$/, loader: \"file-loader\"},\n        // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.\n        { test: /\\.tsx?$/, loader: \"awesome-typescript-loader\" },\n\n        // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.\n        { enforce: \"pre\", test: /\\.js$/, loader: \"source-map-loader\" }\n      ]\n  },\n  plugins: [\n    new ExtractTextPlugin(\"spreadsheet.css\")\n  ]\n\n  // When importing a module whose path matches one of the following, just\n  // assume a corresponding global variable exists and use that instead.\n  // This is important because it allows us to avoid bundling all of our\n  // dependencies, which allows browsers to cache those libraries between builds.\n  // externals: {\n  //     \"react\": \"React\",\n  //     \"react-dom\": \"ReactDOM\"\n  // },\n};"
  },
  {
    "path": "webpack.config.js",
    "content": "var ExtractTextPlugin = require('extract-text-webpack-plugin');\nmodule.exports = {\n  entry: \"./src/main.ts\",\n  output: {\n      filename: \"xspreadsheet.js\",\n      path: __dirname + \"/docs\"\n  },\n\n  // Enable sourcemaps for debugging webpack's output.\n  devtool: \"source-map\",\n\n  resolve: {\n      // Add '.ts' and '.tsx' as resolvable extensions.\n      extensions: [\".ts\", \".tsx\", \".js\", \".json\"]\n  },\n\n  module: {\n      rules: [\n          {test: /\\.less$/, loader: 'style-loader!css-loader!less-loader'},\n          // All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.\n          { test: /\\.tsx?$/, loader: \"awesome-typescript-loader\" },\n          {test: /\\.(eot|woff|woff2|ttf|svg)([\\\\?]?.*)$/, loader: \"file-loader\"},\n          // All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.\n          { enforce: \"pre\", test: /\\.js$/, loader: \"source-map-loader\" }\n      ]\n  },\n  plugins: [\n    new ExtractTextPlugin(\"xspreadsheet.css\")\n  ]\n\n  // When importing a module whose path matches one of the following, just\n  // assume a corresponding global variable exists and use that instead.\n  // This is important because it allows us to avoid bundling all of our\n  // dependencies, which allows browsers to cache those libraries between builds.\n  // externals: {\n  //     \"react\": \"React\",\n  //     \"react-dom\": \"ReactDOM\"\n  // },\n};"
  }
]