Showing preview only (220K chars total). Download the full file or copy to clipboard to get everything.
Repository: myliang/xspreadsheet
Branch: master
Commit: 3075e5007eaa
Files: 60
Total size: 204.8 KB
Directory structure:
gitextract_n0gowviz/
├── .gitignore
├── LICENSE
├── README.md
├── docs/
│ ├── index.html
│ └── xspreadsheet.js
├── index.html
├── package.json
├── src/
│ ├── core/
│ │ ├── alphabet.d.ts
│ │ ├── alphabet.ts
│ │ ├── cell.d.ts
│ │ ├── cell.ts
│ │ ├── font.d.ts
│ │ ├── font.ts
│ │ ├── format.d.ts
│ │ ├── format.ts
│ │ ├── formula.d.ts
│ │ ├── formula.ts
│ │ ├── index.d.ts
│ │ ├── index.ts
│ │ ├── select.d.ts
│ │ └── select.ts
│ ├── local/
│ │ ├── base/
│ │ │ ├── colorPanel.d.ts
│ │ │ ├── colorPanel.ts
│ │ │ ├── dropdown.d.ts
│ │ │ ├── dropdown.ts
│ │ │ ├── element.d.ts
│ │ │ ├── element.ts
│ │ │ ├── icon.d.ts
│ │ │ ├── icon.ts
│ │ │ ├── item.d.ts
│ │ │ ├── item.ts
│ │ │ ├── menu.d.ts
│ │ │ ├── menu.ts
│ │ │ ├── suggest.d.ts
│ │ │ └── suggest.ts
│ │ ├── contextmenu.d.ts
│ │ ├── contextmenu.ts
│ │ ├── editor.d.ts
│ │ ├── editor.ts
│ │ ├── editorbar.d.ts
│ │ ├── editorbar.ts
│ │ ├── event.d.ts
│ │ ├── event.ts
│ │ ├── index.d.ts
│ │ ├── index.ts
│ │ ├── resizer.d.ts
│ │ ├── resizer.ts
│ │ ├── selector.d.ts
│ │ ├── selector.ts
│ │ ├── table.d.ts
│ │ ├── table.ts
│ │ ├── toolbar.d.ts
│ │ └── toolbar.ts
│ ├── main.d.ts
│ ├── main.ts
│ └── style/
│ └── index.less
├── tsconfig.json
├── tslint.json
├── webpack.config.dev.js
└── webpack.config.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
node_modules/
.vscode/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2017 myliang
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# XSpreadsheet
[](https://www.npmjs.org/package/xspreadsheet)
[](https://npmjs.org/package/xspreadsheet)
> a javascript spreadsheet for web
<p align="center">
<a href="https://github.com/myliang/xspreadsheet">
<img width="100%" src="/docs/demo.png?raw=true">
</a>
</p>
## Install
```shell
npm install typescript --save-dev
npm install awesome-typescript-loader --save-dev
npm install xspreadsheet --save-dev
```
## Quick Start
``` javascript
import xspreadsheet from 'xspreadsheet'
const x = xspreadsheet(document.getElementById('#id'))
x.change = (data) => {
console.log('data:', data)
}
// edit
// data is param in the change method
xspreadsheet(document.getElementById('#id'), {d: data})
```
### in tsconfig.json
```
{
"compilerOptions": {
....
"types": ["xspreadsheet"],
....
}
}
```
## Browser Support
Modern browsers and Internet Explorer 9+(no test).
## LICENSE
MIT
================================================
FILE: docs/index.html
================================================
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="xspreadsheet.css"></link>
<script type="text/javascript" src="xspreadsheet.js"></script>
<script type="text/javascript">
window.onload = function () {
xspreadsheet(document.getElementById('wrapper')).change(function (data) {
console.log('data:', data)
})
}
</script>
<title>XSpreadsheet Demo</title>
</head>
<body>
<div id="wrapper"></div>
</body>
</html>
================================================
FILE: docs/xspreadsheet.js
================================================
!function(e){var t={};function s(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.exports,n,n.exports,s),n.l=!0,n.exports}s.m=e,s.c=t,s.d=function(e,t,i){s.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:i})},s.r=function(e){Object.defineProperty(e,"__esModule",{value:!0})},s.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return s.d(t,"a",t),t},s.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},s.p="",s(s.s=30)}([function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(1);class n{constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,this.el=document.createElement(e)}data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e=>{for(let t of i){if(console.log("::::::::::",t),"left"===t&&0!==e.button)return;if("right"===t&&2!==e.button)return;"stop"===t&&e.stopPropagation()}t(e)}),this}onClickOutside(e){return this._clickOutside=e,this}parent(){return this.el.parentNode}class(e){return this.el.className=e,this}attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttribute(e,t),this)}removeAttr(e){return this.el.removeAttribute(e),this}offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=this.el;return{top:e,left:t,height:s,width:i}}clearStyle(){return this.el.style="",this}styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))this.style(t,e[t]);return this}style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.el.style.setProperty(e,t),this)}contains(e){return this.el.contains(e)}removeStyle(e){this.el.style.removeProperty(e)}children(e){for(let t of e)this.child(t);return this}child(e){return"string"==typeof e?this.el.appendChild(document.createTextNode(e)):e instanceof n?this.el.appendChild(e.el):e instanceof HTMLElement&&this.el.appendChild(e),this}html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}val(e){return void 0===e?this.el.value:(this.el.value=e,this)}clone(){return this.el.cloneNode()}isHide(){return"none"===this.style("display")}toggle(){this.isHide()?this.show():this.hide()}disabled(){return this.addClass("disabled"),this}able(){return this.removeClass("disabled"),this}active(e=!0){return e?this.addClass("active"):this.deactive(),this}deactive(){return this.removeClass("active")}isActive(){return this.hasClass("active")}addClass(e){return this.el.className=this.el.className.split(" ").concat(e).join(" "),this}removeClass(e){return this.el.className=this.el.className.split(" ").filter(t=>t!==e).join(" "),this}hasClass(e){return-1!==this.el.className.indexOf(e)}show(e=!1){return e?this.removeStyle("display"):this.style("display","block"),this._clickOutside&&(this.data("_outsidehandler",e=>{if(this.contains(e.target))return!1;this.hide(),i.unbind("click",this.data("_outsidehandler")),this._clickOutside&&this._clickOutside()}),setTimeout(()=>{i.bind("click",this.data("_outsidehandler"))},0)),this}hide(){return this.style("display","none"),this._clickOutside&&i.unbind("click",this.data("_outsidehandler")),this}}t.Element=n,t.h=function(e="div"){return new n(e)}},function(e,t,s){"use strict";function i(e,t,s=window){s.addEventListener(e,t)}function n(e,t,s=window){s.removeEventListener(e,t)}Object.defineProperty(t,"__esModule",{value:!0}),t.bind=i,t.unbind=n,t.mouseMoveUp=function(e,t){i("mousemove",e);const s=i=>{n("mousemove",e),n("mouseup",s),t(i)};i("mouseup",s)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0);class n extends i.Element{constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}}t.Menu=n,t.buildMenu=function(e="vertical"){return new n(e)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0);class n extends i.Element{constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i.h().class(`spreadsheet-icon-img ${e}`))}replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}}t.Icon=n,t.buildIcon=function(e){return new n(e)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(3);class r extends i.Element{constructor(){super(),this.iconEl=null,this.class("spreadsheet-item")}static build(){return new r}icon(e){return this.child(this.iconEl=n.buildIcon(e)),this}replaceIcon(e){this.iconEl&&this.iconEl.replace(e)}}t.Item=r,t.buildItem=function(){return new r}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.defaultCell={font:"Microsoft YaHei",format:"normal",fontSize:14,bold:!1,italic:!1,underline:!1,color:"#333",backgroundColor:"#fff",align:"left",valign:"middle",wordWrap:!1,invisible:!1,rowspan:1,colspan:1,text:""},t.getStyleFromCell=function(e){const t={};return e&&(e.font&&(t["font-family"]=e.font),e.fontSize&&(t["font-size"]=`${e.fontSize}px`),e.bold&&(t["font-weight"]="bold"),e.italic&&(t["font-style"]="italic"),e.underline&&(t["text-decoration"]="underline"),e.color&&(t.color=e.color),e.backgroundColor&&(t["background-color"]=e.backgroundColor),e.align&&(t["text-align"]=e.align),e.valign&&(t["vertical-align"]=e.valign),e.invisible&&(t.display="none"),e.wordWrap&&(t["word-wrap"]="break-word",t["white-space"]="normal")),t}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];t.alphabet=function(e){const[t,s]=[parseInt(e/i.length+""),e%i.length];return t>0?`${i[t-1]}${i[s]}`:i[s]},t.alphabetIndex=function(e){let t=0;for(let s=0;s<e.length;s++){let n=e.charCodeAt(s)-65;t+=s*i.length+n}return t}},function(module,exports,__webpack_require__){"use strict";Object.defineProperty(exports,"__esModule",{value:!0});const alphabet_1=__webpack_require__(6);exports.formulaFilterKey=((e,t)=>{if("="===e[0]){const s=e.substring(1,e.indexOf("("));for(let i of exports.formulas)if(i.key.toLowerCase()===s.toLowerCase())return t(i,e.substring(e.indexOf("(")+1,e.lastIndexOf(")")))}return e}),exports.formulaRender=((e,t)=>exports.formulaFilterKey(e,(e,s)=>e.render(formulaParamToArray(s,t))+"")),exports.formulaReplaceParam=((e,t,s)=>exports.formulaFilterKey(e,(e,i)=>{const n=e=>{if(/^[0-9\-\+\*\/()\s]+$/.test(e.trim()))return e;const i=/\d+/.exec(e);if(i){let n=e.substring(0,i.index).trim(),r=parseInt(e.substring(i.index).trim());return`${alphabet_1.alphabet(alphabet_1.alphabetIndex(n)+s)}${r+t}`}return e};return i=-1!==i.indexOf(":")?i.split(":").map(n).join(":"):i.split(",").map(n).join(","),`=${e.key}(${i})`}));const formulaParamToArray=(param,renderCell)=>{let paramValues=[];try{if(-1!==param.indexOf(":")){const[e,t]=param.split(":"),s=/\d+/.exec(e),i=/\d+/.exec(t);if(s&&i){let n=e.substring(0,s.index).trim(),r=parseInt(e.substring(s.index).trim()),o=t.substring(0,i.index).trim(),l=parseInt(t.substring(i.index).trim());if(o===n)for(let e=r;e<=l;e++)paramValues.push(renderCell(e-1,alphabet_1.alphabetIndex(n)));else for(let e=alphabet_1.alphabetIndex(n);e<=alphabet_1.alphabetIndex(o);e++)paramValues.push(renderCell(r-1,e))}}else paramValues=param.split(",").map(p=>{if(/^[0-9\-\+\*\/()\s]+$/.test(p.trim()))try{return eval(p)}catch(e){return 0}const idx=/\d+/.exec(p);if(idx){const e=p.substring(0,idx.index).trim(),t=p.substring(idx.index).trim();return renderCell(parseInt(t)-1,alphabet_1.alphabetIndex(e))}return 0})}catch(e){console.log("warning:",e)}return paramValues};exports.formulas=[{key:"SUM",title:"求和",render:e=>e.reduce((e,t)=>Number(e)+Number(t),0)},{key:"AVERAGE",title:"平均值",render:e=>e.reduce((e,t)=>Number(e)+Number(t),0)/e.length},{key:"MAX",title:"最大值",render:e=>Math.max(...e.map(e=>Number(e)))},{key:"MIN",title:"最小值",render:e=>Math.min(...e.map(e=>Number(e)))}]},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.formatRenderHtml=((e,s)=>{for(let i=0;i<t.formats.length;i++)if(t.formats[i].key===e)return t.formats[i].render(s||"");return s||""});const i=e=>{if(/^(-?\d*.?\d*)$/.test(e)){const t=(e=Number(e).toFixed(2).toString()).split(".");return t[0]=t[0].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g,"$1,"),t.join(".")}return e},n=e=>e;t.formats=[{key:"normal",title:"Normal",render:n},{key:"text",title:"Text",render:n},{key:"number",title:"Number",label:"1,000.12",render:i},{key:"percent",title:"Percent",label:"10.12%",render:e=>`${i(e)}%`},{key:"RMB",title:"RMB",label:"¥10.00",render:e=>`¥${i(e)}`},{key:"USD",title:"USD",label:"$10.00",render:e=>`$${i(e)}`}]},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0);t.Editorbar=class{constructor(){this.value=null,this.change=(e=>{}),this.el=i.h().class("spreadsheet-editor-bar").children([i.h().class("spreadsheet-formula-bar").children([this.label=i.h().class("spreadsheet-formula-label"),this.textarea=i.h("textarea").on("input",e=>this.input(e))])])}set(e,t){this.label.html(e),this.setValue(t)}setValue(e){this.value=e,this.textarea.val(e&&e.text||"")}input(e){const t=e.target.value;this.value?this.value.text=t:this.value={text:t},this.change(this.value)}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=[["#c00000","#ff0000","#ffc003","#ffff00","#91d051","#00af50","#00b0f0","#0070c0","#002060","#70309f"],["#ffffff","#000000","#e7e6e6","#44546a","#4472c4","#ed7d31","#a5a5a5","#ffc003","#5b9bd5","#70ad47"],["#f4f5f8","#848484","#d0cece","#d6dce4","#d9e2f2","#fae5d5","#ededed","#fff2cc","#deebf6","#e2efd9"],["#d8d8d8","#595959","#afabab","#adb9ca","#b4c6e7","#f7cbac","#dbdbdb","#fee598","#bdd7ee","#c5e0b3"],["#bfbfbf","#3f3f3f","#757070","#8496b0","#8eaad8","#f4b183","#c9c9c9","#ffd964","#9dc2e5","#a8d08d"],["#a5a5a5","#262626","#3a3838","#333f4f","#2f5496","#c55b11","#7b7b7b","#bf9001","#2e75b5","#538135"],["#7e7e7e","#0c0c0c","#171616","#232a35","#1e3864","#833d0b","#525252","#7e6000","#1f4e79","#375623"]];class r extends i.Element{constructor(e){super(),this.class("spreadsheet-color-panel").child(i.h("table").child(i.h("tbody").children(n.map(t=>i.h("tr").children(t.map(t=>i.h("td").child(i.h().class("color-cell").on("click",e.bind(null,t)).style("background-color",t))))))))}}t.ColorPanel=r,t.buildColorPanel=function(e){return new r(e)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(3);class r extends i.Element{constructor(e,t,s){super(),this.class("spreadsheet-dropdown spreadsheet-item"),this.content=i.h().class("spreadsheet-dropdown-content").children(s).onClickOutside(()=>this.deactive()).on("click",e=>this.toggleHandler(e)).style("width",t).hide(),this.child(i.h().class("spreadsheet-dropdown-header").children([this.title="string"==typeof e?i.h().class("spreadsheet-dropdown-title").child(e):e,i.h().class("spreadsheet-dropdown-icon").on("click",e=>this.toggleHandler(e)).child(n.buildIcon("arrow-down"))])).child(this.content)}toggleHandler(e){this.content.isHide()?(this.content.show(),this.active()):(this.content.hide(),this.deactive())}}t.Dropdown=r,t.buildDropdown=function(e,t,s){return new r(e,t,s)}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(4),r=s(3),o=s(11),l=s(2),h=s(10);t.Toolbar=class{constructor(e){this.ss=e,this.target=null,this.currentCell=null,this.change=((e,t)=>{}),this.redo=(()=>!1),this.undo=(()=>!1),this.defaultCell=e.data.cell,this.el=i.h().class("spreadsheet-toolbar").child(l.buildMenu("horizontal").children([this.elUndo=this.buildUndo(),this.elRedo=this.buildRedo(),this.elPaintformat=this.buildPaintformat(),this.elClearformat=this.buildClearformat(),this.elFormat=this.buildFormats(),this.buildSeparator(),this.elFont=this.buildFonts(),this.elFontSize=this.buildFontSizes(),this.buildSeparator(),this.elFontWeight=this.buildFontWeight(),this.elFontStyle=this.buildFontStyle(),this.elTextDecoration=this.buildTextDecoration(),this.elColor=this.buildColor(),this.buildSeparator(),this.elBackgroundColor=this.buildBackgroundColor(),this.elMerge=this.buildMerge(),this.buildSeparator(),this.elAlign=this.buildAligns(),this.elValign=this.buildValigns(),this.elWordWrap=this.buildWordWrap()]))}set(e,t){this.target=e,this.setCell(t)}setCell(e){this.currentCell=e,this.setCellStyle()}setCellStyle(){const{target:e,currentCell:t,defaultCell:s,ss:i}=this;e&&(this.elFormat.title.html(i.getFormat(null!==t&&t.format||s.format).title),this.elFont.title.html(i.getFont(null!==t&&t.font||s.font).title),this.elFontSize.title.html((null!==t&&t.fontSize||s.fontSize)+""),this.elFontWeight.active(null!==t&&void 0!==t.bold&&t.bold!==s.bold),this.elFontStyle.active(null!==t&&void 0!==t.italic&&t.italic!==s.italic),this.elTextDecoration.active(null!==t&&void 0!==t.underline&&t.underline!==s.underline),this.elColor.title.style("border-bottom-color",null!==t&&t.color||s.color),this.elBackgroundColor.title.style("border-bottom-color",null!==t&&t.backgroundColor||s.backgroundColor),this.elAlign.title.replace(`align-${null!==t&&t.align||s.align}`),this.elValign.title.replace(`valign-${null!==t&&t.valign||s.valign}`),this.elWordWrap.active(null!==t&&void 0!==t.wordWrap&&t.wordWrap!==s.wordWrap),null!==t&&t.rowspan&&t.rowspan>1||null!==t&&t.colspan&&t.colspan>1?this.elMerge.active(!0):this.elMerge.active(!1))}setRedoAble(e){e?this.elRedo.able():this.elRedo.disabled()}setUndoAble(e){e?this.elUndo.able():this.elUndo.disabled()}buildSeparator(){return i.h().class("spreadsheet-item-separator")}buildAligns(){const e=r.buildIcon(`align-${this.defaultCell.align}`),t=t=>{e.replace(`align-${t}`),this.change("align",t)};return o.buildDropdown(e,"60px",[l.buildMenu().children(["left","center","right"].map(e=>n.buildItem().child(r.buildIcon(`align-${e}`).style("text-align","center")).on("click",t.bind(null,e))))])}buildValigns(){const e=r.buildIcon(`valign-${this.defaultCell.valign}`),t=t=>{e.replace(`valign-${t}`),this.change("valign",t)};return o.buildDropdown(e,"60px",[l.buildMenu().children(["top","middle","bottom"].map(e=>n.buildItem().child(r.buildIcon(`valign-${e}`).style("text-align","center")).on("click",t.bind(null,e))))])}buildWordWrap(){return a("textwrap",e=>this.change("wordWrap",e))}buildFontWeight(){return a("bold",e=>this.change("bold",e))}buildFontStyle(){return a("italic",e=>this.change("italic",e))}buildTextDecoration(){return a("underline",e=>this.change("underline",e))}buildMerge(){return a("merge",e=>this.change("merge",e))}buildColor(){return o.buildDropdown(r.buildIcon("text-color").styles({"border-bottom":`3px solid ${this.defaultCell.color}`,"margin-top":"2px",height:"16px"}),"auto",[h.buildColorPanel(e=>{this.elColor.title.style("border-bottom-color",e),this.change("color",e)})])}buildBackgroundColor(){return o.buildDropdown(r.buildIcon("cell-color").styles({"border-bottom":`3px solid ${this.defaultCell.backgroundColor}`,"margin-top":"2px",height:"16px"}),"auto",[h.buildColorPanel(e=>{this.elBackgroundColor.title.style("border-bottom-color",e),this.change("backgroundColor",e)})])}buildUndo(){return n.buildItem().child(r.buildIcon("undo")).on("click",e=>{this.undo()?this.elUndo.able():this.elUndo.disabled()}).disabled()}buildRedo(){return n.buildItem().child(r.buildIcon("redo")).on("click",e=>{this.redo()?this.elRedo.able():this.elRedo.disabled()}).disabled()}buildPaintformat(){return a("paintformat",e=>{this.change("paintformat",!0),this.elPaintformat.deactive()})}buildClearformat(){return a("clearformat",e=>{this.change("clearformat",!0),this.elClearformat.deactive()})}buildFormats(){const e=e=>{this.elFormat.title.html(this.ss.getFormat(e.key).title),this.change("format",e.key)};return o.buildDropdown(this.ss.getFormat(this.defaultCell.format).title,"250px",[l.buildMenu().children(this.ss.formats.map(t=>n.buildItem().children([t.title,i.h().class("label").child(t.label||"")]).on("click",e.bind(null,t))))])}buildFonts(){const e=e=>{this.elFont.title.html(e.title),this.change("font",e.key)};return o.buildDropdown(this.ss.getFont(this.defaultCell.font).title,"170px",[l.buildMenu().children(this.ss.fonts.map(t=>n.buildItem().child(t.title).on("click",e.bind(null,t))))])}buildFontSizes(){const e=e=>{this.elFontSize.title.html(`${e}`),this.change("fontSize",e)};return o.buildDropdown(this.defaultCell.fontSize+"","70px",[l.buildMenu().children([6,8,10,12,14,16,18,20,22,24,30,36].map(t=>n.buildItem().child(`${t}`).on("click",e.bind(null,t))))])}};const a=(e,t)=>{const s=n.buildItem().child(r.buildIcon(e));return s.on("click",e=>{let i=s.isActive();i?s.deactive():s.active(),t(!i)}),s}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(4),r=s(2);t.ContextMenu=class{constructor(e){this.table=e,this.el=i.h().class("spreadsheet-contextmenu").style("width","160px").on("click",e=>this.el.hide()).children([r.buildMenu().children([n.buildItem().on("click",t=>e.copy()).children(["copy",i.h().class("label").html("ctrl + c")]),n.buildItem().on("click",t=>e.cut()).children(["cut",i.h().class("label").html("ctrl + x")]),n.buildItem().on("click",t=>e.paste()).children(["paste",i.h().class("label").html("ctrl + v")])])]).onClickOutside(()=>{}).hide()}set(e){const{offsetLeft:t,offsetTop:s}=e.target,i=this.el.el.getBoundingClientRect(),{clientWidth:n,clientHeight:r}=document.documentElement;let o=s+e.offsetY,l=t+e.offsetX;e.clientY>r/1.5&&(o-=i.height),e.clientX>n/1.5&&(l-=i.width),this.el.style("left",`${l}px`).style("top",`${o}px`).show()}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(1);t.Resizer=class{constructor(e,t){this.vertical=e,this.change=t,this.moving=!1,this.index=0,this.el=i.h().class("spreadsheet-resizer-wrapper").children([this.resizer=i.h().class(`spreadsheet-resizer ${e?"vertical":"horizontal"}`).on("mousedown",e=>this.mousedown(e)),this.resizerLine=i.h().class(`spreadsheet-resizer-line ${e?"vertical":"horizontal"}`).hide()])}set(e,t,s){if(this.moving)return;this.index=t;const{vertical:i}=this,{offsetLeft:n,offsetTop:r,offsetHeight:o,offsetWidth:l,parentNode:h}=e;this.resizer.styles({left:`${i?n+l-5-s:n}px`,top:`${i?r:r+o-5+24-s}px`,width:`${i?5:l}px`,height:`${i?o:5}px`}),this.resizerLine.styles({left:`${i?n+l-s:n}px`,top:`${i?r:r+o+24-s}px`,width:`${i?0:h.parentNode.parentNode.parentNode.parentNode.nextSibling.offsetWidth-15}px`,height:`${i?h.parentNode.parentNode.parentNode.nextSibling.offsetHeight+h.offsetHeight:0}px`})}mousedown(e){let t=e,s=0;this.resizerLine.show(),n.mouseMoveUp(e=>{if(this.moving=!0,null!==t&&1===e.buttons){if(this.vertical){const i=e.x-t.x;s+=i,this.resizer.style("left",`${this.resizer.offset().left+i}px`),this.resizerLine.style("left",`${this.resizerLine.offset().left+i}px`)}else{const i=e.y-t.y;s+=i,this.resizer.style("top",`${this.resizer.offset().top+i}px`),this.resizerLine.style("top",`${this.resizerLine.offset().top+i}px`)}t=e}},e=>{this.change(this.index,s),t=null,this.resizerLine.hide(),s=0,this.moving=!1})}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(1);t.Selector=class{constructor(e,t){this.ss=e,this.table=t,this._offset={left:0,top:0,width:0,height:0},this.change=(()=>{}),this.changeCopy=((e,t,s,i,n,r)=>{}),this.topEl=i.h().class("top-border"),this.rightEl=i.h().class("right-border"),this.bottomEl=i.h().class("bottom-border"),this.leftEl=i.h().class("left-border"),this.areaEl=i.h().class("area-border"),this.cornerEl=i.h().class("corner").on("mousedown",e=>this.cornerMousedown(e)),this.copyEl=i.h().class("copy-border"),this.el=i.h().class("spreadsheet-borders").children([this.topEl,this.rightEl,this.bottomEl,this.leftEl,this.areaEl,this.cornerEl,this.copyEl.hide()]).hide()}mousedown(e){if(1===e.detail&&"cell"===e.target.getAttribute("type")){if(e.shiftKey)return this.endTarget=e.target,void this.setOffset();this.setCurrentTarget(e.target),n.mouseMoveUp(e=>{1===e.buttons&&"cell"===e.target.getAttribute("type")&&(this.endTarget=e.target,this.setOffset())},e=>{this.change()}),this.el.show()}}setCurrentTarget(e){Object.assign(this,{startTarget:e,endTarget:e}),this.setOffset()}cornerMousedown(e){const{select:t}=this.ss;if(null===t)return;const[s,i]=t.stop,[r,o]=t.start;let l=null;n.mouseMoveUp(e=>{const n=e.target.getAttribute("row-index"),h=e.target.getAttribute("col-index");if(n&&h){this.copyEl.show();let e=s-n,a=i-h,d=r-n,c=o-h;const{left:p,top:u,height:f,width:b}=this._offset;if(e<0)this.copyEl.styles({left:`${p-1}px`,top:`${u-1}px`,width:`${b-1}px`,height:`${this.rowsHeight(s-t.rowLen()+1,s+Math.abs(e))-1}px`}),l=["bottom",s+1,o,s+Math.abs(e),i];else if(a<0)this.copyEl.styles({left:`${p-1}px`,top:`${u-1}px`,width:`${this.colsWidth(i-t.colLen()+1,i+Math.abs(a))-1}px`,height:`${f-1}px`}),l=["right",r,i+1,s,i+Math.abs(a)];else if(d>0){const e=this.rowsHeight(r-d,r-1);this.copyEl.styles({left:`${p-1}px`,top:`${u-e-1}px`,width:`${b-1}px`,height:`${e-1}px`}),l=["top",r-d,o,r-1,i]}else if(c>0){const e=this.colsWidth(o-c,o-1);this.copyEl.styles({left:`${p-e-1}px`,top:`${u-1}px`,width:`${e-1}px`,height:`${f-1}px`}),l=["left",r,o-c,s,o-1]}else this.copyEl.styles({left:`${p-1}px`,top:`${u-1}px`,width:`${b-1}px`,height:`${f-1}px`}),l=null}},e=>{if(this.copyEl.hide(),null!==l){const[t,s,i,n,r]=l;this.changeCopy(e,t,s,i,n,r)}})}reload(){this.setOffset()}setOffset(){if(void 0===this.startTarget)return;let{select:e}=this.ss;if(e){const[t,s]=e.start,[i,n]=e.stop;r(t,i,this.table.firsttds,e=>{e.deactive()}),r(s,n,this.table.ths,e=>{e.deactive()})}e=this.ss.buildSelect(this.startTarget,this.endTarget);const[t,s]=e.start,[i,n]=e.stop,o=this.rowsHeight(t,i,e=>e.active()),l=this.colsWidth(s,n,e=>e.active()),h=this.table.td(t,s);if(h){const{left:e,top:t}=h.offset();this._offset={left:e,top:t,width:l,height:o},this.topEl.styles({left:`${e-1}px`,top:`${t-1}px`,width:`${l+1}px`,height:"2px"}),this.rightEl.styles({left:`${e+l-1}px`,top:`${t-1}px`,width:"2px",height:`${o}px`}),this.bottomEl.styles({left:`${e-1}px`,top:`${t+o-1}px`,width:`${l}px`,height:"2px"}),this.leftEl.styles({left:`${e-1}px`,top:`${t-1}px`,width:"2px",height:`${o}px`}),this.areaEl.styles({left:`${e}px`,top:`${t}px`,width:`${l-2}px`,height:`${o-2}px`}),this.cornerEl.styles({left:`${e+l-5}px`,top:`${t+o-5}px`})}}rowsHeight(e,t,s=(e=>{})){let i=0;return r(e,t,this.table.firsttds,e=>{s(e),i+=parseInt(e.offset().height)}),i/=2}colsWidth(e,t,s=(e=>{})){let i=0;return r(e,t,this.table.ths,e=>{s(e),i+=parseInt(e.offset().width)}),i}};const r=(e,t,s,n)=>{for(let r=e;r<=t;r++){const e=s[r+""];e&&(e instanceof i.Element?n(e):e.forEach(e=>n(e)))}};t.DashedSelector=class{constructor(){this.el=i.h().class("spreadsheet-borders dashed").hide()}set(e){if(e._offset){const{left:t,top:s,width:i,height:n}=e._offset;this.el.style("left",`${t-2}px`).style("top",`${s-2}px`).style("width",`${i}px`).style("height",`${n}px`).show()}}hide(){this.el.hide()}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(4),r=s(2),o=s(1);t.Suggest=class extends i.Element{constructor(e,t){super(),this.list=e,this.width=t,this.filterList=[],this.currentIndex=0,this.target=null,this.evtTarget=null,this.itemClick=(e=>{}),this.class("spreadsheet-suggest").hide()}documentHandler(e){if(this.el.contains(e.target))return!1;this.hideAndRemoveEvents()}documentKeydownHandler(e){if(console.log("keyCode: ",e),!(this.filterList.length<=0&&"textarea"!==e.target.type)){switch(e.keyCode){case 37:e.returnValue=!1;break;case 38:this.filterList[this.currentIndex].deactive(),this.currentIndex--,this.currentIndex<0&&(this.currentIndex=this.filterList.length-1),this.filterList[this.currentIndex].active(),e.returnValue=!1,e.stopPropagation();break;case 39:e.returnValue=!1;break;case 40:this.filterList[this.currentIndex].deactive(),this.currentIndex++,this.currentIndex>this.filterList.length-1&&(this.currentIndex=0),this.filterList[this.currentIndex].active(),e.returnValue=!1;break;case 13:this.filterList[this.currentIndex].el.click(),e.returnValue=!1}e.stopPropagation()}}hideAndRemoveEvents(){this.hide(),this.removeEvents()}removeEvents(){null!==this.evtTarget&&(o.unbind("click",this.data("_outsidehandler"),this.evtTarget.el),o.unbind("keydown",this.data("_keydownhandler"),this.evtTarget.el))}clickItemHandler(e){this.itemClick(e),this.hideAndRemoveEvents()}search(e,t,s){this.removeEvents(),this.target=e,this.evtTarget=t;const{left:l,top:h,width:a,height:d}=e.offset();this.styles({left:`${l}px`,top:`${h+d+2}px`,width:`${this.width}px`});let c=this.list;/^\s*$/.test(s)||(c=this.list.filter(e=>e[0].startsWith(s.toUpperCase()))),c=c.map(e=>{const t=n.buildItem().on("click",t=>this.clickItemHandler(e)).child(e[0]);return e[1]&&t.child(i.h().class("label").html(e[1])),t}),this.filterList=c,this.currentIndex=0,c.length<=0?c=[n.buildItem().child("No Result")]:(c[0].active(),this.data("_outsidehandler",e=>{this.documentHandler(e)}),this.data("_keydownhandler",e=>this.documentKeydownHandler(e)),setTimeout(()=>{null!==this.evtTarget&&(o.bind("click",this.data("_outsidehandler"),this.evtTarget.el),o.bind("keydown",this.data("_keydownhandler"),this.evtTarget.el))},0)),this.html(""),this.child(r.buildMenu().children(c)).show()}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(16),r=s(5);t.Editor=class{constructor(e,t){this.defaultRowHeight=e,this.formulas=t,this.target=null,this.value=null,this.change=(e=>{});const s=t.map(e=>[e.key,e.title]);this.el=i.h().children([this.editor=i.h().class("spreadsheet-editor").children([this.textarea=i.h("textarea").on("keydown",e=>this.inputKeydown(e)).on("input",e=>this.inputChange(e)),this.textline=i.h().styles({visibility:"hidden",overflow:"hidden",position:"fixed",top:"0",left:"0"})]),this.suggest=new n.Suggest(s,180)]).hide(),this.el.on("keydown",e=>{13!==e.keyCode&&9!==e.keyCode&&e.stopPropagation()}),this.suggest.itemClick=(e=>{const t=`=${e[0]}()`;this.value&&(this.value.text=t),this.textarea.val(t),this.textline.html(t),this.setTextareaRange(t.length-1)})}onChange(e){this.change=e}set(e,t){this.target=e;const s=this.setValue(t);this.el.show(),this.setTextareaRange(s.length),this.reload()}setValue(e){if(this.setStyle(e),e){this.value=e;const t=e.text||"";return this.textarea.val(t),this.textline.html(t),t}return""}setStyle(e){let t={width:this.textarea.style("width"),height:this.textarea.style("height")};this.textarea.styles(Object.assign(t,r.getStyleFromCell(e)),!0)}clear(){this.el.hide(),this.target=null,this.value=null,this.textarea.val(""),this.textline.html("")}setTextareaRange(e){setTimeout(()=>{this.textarea.el.setSelectionRange(e,e),this.textarea.el.focus()},10)}inputKeydown(e){13===e.keyCode&&e.preventDefault()}inputChange(e){const t=e.target.value;this.value?this.value.text=t:this.value={text:t},this.change(this.value),this.autocomplete(t),this.textline.html(t),this.reload()}autocomplete(e){if("="===e[0])if(e.includes("("))this.suggest.hide();else{const t=e.substring(1);console.log(":::;search word:",t),this.suggest.search(this.editor,this.textarea,t)}else this.suggest.hide()}reload(){if(this.target){const{offsetTop:e,offsetLeft:t,offsetWidth:s,offsetHeight:i}=this.target;this.editor.styles({left:`${t-1}px`,top:`${e-1}px`}),this.textarea.styles({width:`${s-8}px`,height:`${i-2}px`});let n=this.textline.offset().width+16;if(this.value)if(this.value.wordWrap){const e=(parseInt(n/s+"")+(n%s>0?1:0))*this.defaultRowHeight;e>i&&this.textarea.style("height",`${e}px`)}else{const e=document.documentElement.clientWidth-t-24;if(n>s){if(n>e){const t=(parseInt(n/e+"")+(n%e>0?1:0))*this.defaultRowHeight;t>i?this.textarea.style("height",`${t}px`):this.textarea.style("height",`${i}px`),n=e}this.textarea.style("width",`${n}px`)}}this.el.show()}}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(0),n=s(17),r=s(15),o=s(14),l=s(13),h=s(5),a=s(8),d=s(7),c=s(1);t.Table=class{constructor(e,t){this.options=t,this.cols={},this.firsttds={},this.tds={},this.ths={},this.formulaCellIndexs=new Set,this.fixedLeftBody=null,this.editor=null,this.rowResizer=null,this.colResizer=null,this.contextmenu=null,this.state=null,this.currentIndexs=null,this.focusing=!1,this.change=(()=>{}),this.editorChange=(e=>{}),this.clickCell=((e,t,s)=>{}),this.ss=e,this.ss.change=(e=>{this.change(e)}),"read"!==t.mode&&(this.editor=new n.Editor(e.defaultRowHeight(),e.formulas),this.editor.change=(e=>this.editorChange(e))),"design"===t.mode&&(this.rowResizer=new o.Resizer(!1,(e,t)=>this.changeRowResizer(e,t)),this.colResizer=new o.Resizer(!0,(e,t)=>this.changeColResizer(e,t)),this.contextmenu=new l.ContextMenu(this)),this.selector=new r.Selector(this.ss,this),this.selector.change=(()=>this.selectorChange()),this.selector.changeCopy=((e,t,s,i,n,r)=>{this.selectorChangeCopy(e,t,s,i,n,r)}),this.dashedSelector=new r.DashedSelector,this.el=i.h().class("spreadsheet-table").children([this.colResizer&&this.colResizer.el||"",this.rowResizer&&this.rowResizer.el||"",this.buildFixedLeft(),this.header=this.buildHeader(),this.body=this.buildBody()]).on("contextmenu",e=>{e.returnValue=!1,e.preventDefault()}),c.bind("resize",e=>{this.header.style("width",`${this.options.width()}px`),this.body.style("width",`${this.options.width()}px`),"read"!==this.options.mode&&this.body.style("height",`${this.options.height()}px`)}),c.bind("click",e=>{this.focusing=this.el.parent().contains(e.target)}),c.bind("keydown",e=>{if(this.focusing&&this.focusing)if(e.ctrlKey&&"textarea"!==e.target.type&&"read"!==this.options.mode)67===e.keyCode&&(this.copy(),e.returnValue=!1),88===e.keyCode&&(this.cut(),e.returnValue=!1),86===e.keyCode&&(this.paste(),e.returnValue=!1);else{switch(e.keyCode){case 37:this.moveLeft(),e.returnValue=!1;break;case 38:this.moveUp(),e.returnValue=!1;break;case 39:this.moveRight(),e.returnValue=!1;break;case 40:this.moveDown(),e.returnValue=!1;break;case 9:this.moveRight(),e.returnValue=!1;break;case 13:this.moveDown(),e.returnValue=!1}"read"!==this.options.mode&&(e.keyCode>=65&&e.keyCode<=90||e.keyCode>=48&&e.keyCode<=57||e.keyCode>=96&&e.keyCode<=105||187==e.keyCode)&&"textarea"!==e.target.type&&this.ss.cellText(e.key,(e,t,s)=>{if(this.editor){const i=this.td(e,t);i.html(this.renderCell(e,t,s)),this.editor.set(i.el,this.ss.currentCell())}})}})}reload(){this.firsttds={},this.el.html(""),this.el.children([this.colResizer&&this.colResizer.el||"",this.rowResizer&&this.rowResizer.el||"",this.buildFixedLeft(),this.header=this.buildHeader(),this.body=this.buildBody()])}moveLeft(){this.currentIndexs&&this.currentIndexs[1]>0&&(this.currentIndexs[1]-=1,this.moveSelector("left"))}moveUp(){this.currentIndexs&&this.currentIndexs[0]>0&&(this.currentIndexs[0]-=1,this.moveSelector("up"))}moveDown(){this.currentIndexs&&this.currentIndexs[0]<this.ss.rows("read"===this.options.mode).length&&(this.currentIndexs[0]+=1,this.moveSelector("down"))}moveRight(){this.currentIndexs&&this.currentIndexs[1]<this.ss.cols().length&&(this.currentIndexs[1]+=1,this.moveSelector("right"))}moveSelector(e){if(this.currentIndexs){const[t,s]=this.currentIndexs,i=this.td(t,s);if(i){this.selector.setCurrentTarget(i.el);const n=this.options.width(),r=this.options.height(),{left:o,top:l,width:h,height:a}=i.offset(),d=o+h-n;d>0&&"right"===e&&(this.body.el.scrollLeft=d+15),"left"===e&&this.body.el.scrollLeft+60>o&&(this.body.el.scrollLeft-=this.body.el.scrollLeft+60-o),"up"===e&&this.body.el.scrollTop>l&&(this.body.el.scrollTop-=this.body.el.scrollTop-l),"down"===e&&l+a-r>0&&(this.body.el.scrollTop=l+a-r+15),this.mousedownCell(t,s)}}}setValueWithText(e){this.currentIndexs&&this.ss.cellText(e.text,(e,t,s)=>{this.td(e,t).html(this.renderCell(e,t,s))}),this.editor&&this.editor.setValue(e)}setTdWithCell(e,t,s,i=!0){this.setTdStyles(e,t,s),this.setRowHeight(e,t,i),this.td(e,t).html(this.renderCell(e,t,s))}setCellAttr(e,t){this.ss.cellAttr(e,t,(s,i,n)=>{this.setTdWithCell(s,i,n,"wordWrap"===e&&t)}),this.editor&&this.editor.setStyle(this.ss.currentCell())}undo(){return this.ss.undo((e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t,s)})}redo(){return this.ss.redo((e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t,s)})}setTdStylesAndAttrsAndText(e,t,s){let i=this.td(e,t);this.setTdStyles(e,t,s),this.setTdAttrs(e,t,s),i.html(this.renderCell(e,t,s))}copy(){this.ss.copy(),this.dashedSelector.set(this.selector),this.state="copy"}cut(){this.ss.cut(),this.dashedSelector.set(this.selector),this.state="cut"}copyformat(){this.ss.copy(),this.dashedSelector.set(this.selector),this.state="copyformat"}paste(){null!==this.state&&this.ss.select&&(this.ss.paste((e,t,s)=>{let i=this.td(e,t);this.setTdStyles(e,t,s),this.setTdAttrs(e,t,s),"cut"!==this.state&&"copy"!==this.state||i.html(this.renderCell(e,t,s))},this.state,(e,t,s)=>{let i=this.td(e,t);this.setTdStyles(e,t,s),this.setTdAttrs(e,t,s),i.html("")}),this.selector.reload()),"copyformat"===this.state?this.state=null:"cut"===this.state?this.state=null:this.state,this.dashedSelector.hide()}clearformat(){this.ss.clearformat((e,t,s)=>{this.td(e,t).removeAttr("rowspan").removeAttr("colspan").styles({},!0).show(!0)})}merge(){this.ss.merge((e,t,s)=>{this.setTdAttrs(e,t,s).show(!0)},(e,t,s)=>{this.setTdAttrs(e,t,s).show(!0)},(e,t,s)=>{let i=this.td(e,t);s.invisible?i.hide():i.show(!0)})}insert(e,t){this.ss.insert(e,t,(e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t,s)})}td(e,t){return this.tds[`${e}_${t}`]}selectorChange(){"copyformat"===this.state&&this.paste()}selectorChangeCopy(e,t,s,i,n,r){this.ss.batchPaste(t,s,i,n,r,e.ctrlKey,(e,t,s)=>{this.setTdStyles(e,t,s),this.setTdAttrs(e,t,s),this.td(e,t).html(this.renderCell(e,t,s))})}renderCell(e,t,s){if(s){const i=`${e}_${t}`;return s.text&&"="===s.text[0]?this.formulaCellIndexs.add(i):(this.formulaCellIndexs.has(i)&&this.formulaCellIndexs.delete(i),this.reRenderFormulaCells()),a.formatRenderHtml(s.format,this._renderCell(s))}return""}_renderCell(e){if(e){let t=e.text||"";return d.formulaRender(t,(e,t)=>this._renderCell(this.ss.getCell(e,t)))}return""}reRenderFormulaCells(){this.formulaCellIndexs.forEach(e=>{let t=e.split("_");const s=parseInt(t[0]),i=parseInt(t[1]),n=this.renderCell(s,i,this.ss.getCell(s,i));this.td(s,i).html(n)})}setRowHeight(e,t,s){if(!1===s)return;this.ss.cols();const i=this.td(e,t);let n=i.offset().height;console.log("h:",n);const r=i.attr("rowspan");if(r)for(let t=1;t<parseInt(r);t++){let s=this.firsttds[e+t+""];s&&(n-=parseInt(s[0].attr("height")||0)+1)}this.changeRowHeight(e,n-1)}setTdStyles(e,t,s){return this.td(e,t).styles(h.getStyleFromCell(s),!0)}setTdAttrs(e,t,s){return this.td(e,t).attr("rowspan",s.rowspan||1).attr("colspan",s.colspan||1)}changeRowHeight(e,t){if(t<=this.ss.defaultRowHeight())return;this.ss.row(e,t);const s=this.firsttds[e+""];s&&s.forEach(e=>e.attr("height",t)),this.selector.reload(),this.editor&&this.editor.reload()}changeRowResizer(e,t){const s=this.ss.row(e).height+t;this.changeRowHeight(e,s)}changeColResizer(e,t){const s=this.ss.col(e).width+t;if(s<=50)return;this.ss.col(e,s);const i=this.cols[e+""];i&&i.forEach(e=>e.attr("width",s)),this.selector.reload(),this.editor&&this.editor.reload()}buildColGroup(e){const t=this.ss.cols();return i.h("colgroup").children([i.h("col").attr("width","60"),...t.map((e,t)=>{let s=i.h("col").attr("width",e.width);return this.cols[t+""]=this.cols[t+""]||[],this.cols[t+""].push(s),s}),i.h("col").attr("width",e)])}buildFixedLeft(){const e=this.ss.rows("read"===this.options.mode);return i.h().class("spreadsheet-fixed").style("width","60px").children([i.h().class("spreadsheet-fixed-header").child(i.h("table").child(i.h("thead").child(i.h("tr").child(i.h("th").child("-"))))),this.fixedLeftBody=i.h().class("spreadsheet-fixed-body").style("height",`${"read"===this.options.mode?"auto":this.options.height()-18}px`).children([i.h("table").child(i.h("tbody").children(e.map((e,t)=>{let s=i.h("td").attr("height",`${e.height}`).child(`${t+1}`).on("mouseover",e=>this.rowResizer&&this.rowResizer.set(e.target,t,this.body.el.scrollTop));return this.firsttdsPush(t,s),i.h("tr").child(s)})))])])}buildHeader(){const e=this.ss.cols(),t=i.h("thead").child(i.h("tr").children([i.h("th"),...e.map((e,t)=>{let s=i.h("th").child(e.title).on("mouseover",e=>{console.log(e),this.colResizer&&this.colResizer.set(e.target,t,this.body.el.scrollLeft)});return this.ths[t+""]=s,s}),i.h("th")]));return i.h().class("spreadsheet-header").style("width",`${this.options.width()}px`).children([i.h("table").children([this.buildColGroup(15),t])])}mousedownCell(e,t){if(this.editor){const e=this.editor.value;if(this.currentIndexs&&this.editor.target&&e){const t=this.ss.cellText(e.text,(e,t,s)=>{this.td(e,t).html(this.renderCell(e,t,s))});t&&t.wordWrap&&this.setRowHeight(this.currentIndexs[0],this.currentIndexs[1],!0)}this.editor.clear()}this.currentIndexs=[e,t];const s=this.ss.currentCell([e,t]);this.clickCell(e,t,s)}editCell(e,t){const s=this.td(e,t);this.editor&&this.editor.set(s.el,this.ss.currentCell())}buildBody(){const e=this.ss.rows("read"===this.options.mode),t=this.ss.cols(),s=(e,t,s)=>{const{select:i}=this.ss;2===s.button&&(console.log(":::evt:",s),this.contextmenu&&this.contextmenu.set(s),i&&i.contains(e,t))||(this.selector.mousedown(s),this.mousedownCell(e,t),this.focusing=!0)},n=(e,t)=>{this.editCell(e,t)},r=i.h("tbody").children(e.map((e,r)=>{let o=i.h("td").attr("height",`${e.height}`).child(`${r+1}`);return this.firsttdsPush(r,o),i.h("tr").children([o,...t.map((e,t)=>{let o=this.ss.getCell(r,t),l=i.h("td").child(this.renderCell(r,t,o)).attr("type","cell").attr("row-index",r+"").attr("col-index",t+"").attr("rowspan",o&&o.rowspan||1).attr("colspan",o&&o.colspan||1).styles(h.getStyleFromCell(o),!0).on("mousedown",e=>s(r,t,e)).on("dblclick",n.bind(null,r,t));return this.tds[`${r}_${t}`]=l,l}),i.h("td")])}));return i.h().class("spreadsheet-body").on("scroll",e=>{this.header.el.scrollLeft=e.target.scrollLeft,this.fixedLeftBody&&(this.fixedLeftBody.el.scrollTop=e.target.scrollTop)}).style("height",`${"read"===this.options.mode?"auto":this.options.height()}px`).style("width",`${this.options.width()}px`).children([i.h("table").children([this.buildColGroup(0),r]),this.editor&&this.editor.el||"",this.selector.el,this.contextmenu&&this.contextmenu.el||"",this.dashedSelector.el])}addRow(e=1){}firsttdsPush(e,t){this.firsttds[`${e}`]=this.firsttds[`${e}`]||[],this.firsttds[`${e}`].push(t)}}},function(e,t){e.exports=function(e){var t="undefined"!=typeof window&&window.location;if(!t)throw new Error("fixUrls requires window.location");if(!e||"string"!=typeof e)return e;var s=t.protocol+"//"+t.host,i=s+t.pathname.replace(/\/[^\/]*$/,"/");return e.replace(/url\s*\(((?:[^)(]|\((?:[^)(]+|\([^)(]*\))*\))*)\)/gi,function(e,t){var n,r=t.trim().replace(/^"(.*)"$/,function(e,t){return t}).replace(/^'(.*)'$/,function(e,t){return t});return/^(#|data:|http:\/\/|https:\/\/|file:\/\/\/|\s*$)/i.test(r)?e:(n=0===r.indexOf("//")?r:0===r.indexOf("/")?s+r:i+r.replace(/^\.\//,""),"url("+JSON.stringify(n)+")")})}},function(e,t,s){var i,n,r={},o=(i=function(){return window&&document&&document.all&&!window.atob},function(){return void 0===n&&(n=i.apply(this,arguments)),n}),l=function(e){var t={};return function(e){if("function"==typeof e)return e();if(void 0===t[e]){var s=function(e){return document.querySelector(e)}.call(this,e);if(window.HTMLIFrameElement&&s instanceof window.HTMLIFrameElement)try{s=s.contentDocument.head}catch(e){s=null}t[e]=s}return t[e]}}(),h=null,a=0,d=[],c=s(19);function p(e,t){for(var s=0;s<e.length;s++){var i=e[s],n=r[i.id];if(n){n.refs++;for(var o=0;o<n.parts.length;o++)n.parts[o](i.parts[o]);for(;o<i.parts.length;o++)n.parts.push(x(i.parts[o],t))}else{var l=[];for(o=0;o<i.parts.length;o++)l.push(x(i.parts[o],t));r[i.id]={id:i.id,refs:1,parts:l}}}}function u(e,t){for(var s=[],i={},n=0;n<e.length;n++){var r=e[n],o=t.base?r[0]+t.base:r[0],l={css:r[1],media:r[2],sourceMap:r[3]};i[o]?i[o].parts.push(l):s.push(i[o]={id:o,parts:[l]})}return s}function f(e,t){var s=l(e.insertInto);if(!s)throw new Error("Couldn't find a style target. This probably means that the value for the 'insertInto' parameter is invalid.");var i=d[d.length-1];if("top"===e.insertAt)i?i.nextSibling?s.insertBefore(t,i.nextSibling):s.appendChild(t):s.insertBefore(t,s.firstChild),d.push(t);else if("bottom"===e.insertAt)s.appendChild(t);else{if("object"!=typeof e.insertAt||!e.insertAt.before)throw new Error("[Style Loader]\n\n Invalid value for parameter 'insertAt' ('options.insertAt') found.\n Must be 'top', 'bottom', or Object.\n (https://github.com/webpack-contrib/style-loader#insertat)\n");var n=l(e.insertInto+" "+e.insertAt.before);s.insertBefore(t,n)}}function b(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e);var t=d.indexOf(e);t>=0&&d.splice(t,1)}function g(e){var t=document.createElement("style");return e.attrs.type="text/css",m(t,e.attrs),f(e,t),t}function m(e,t){Object.keys(t).forEach(function(s){e.setAttribute(s,t[s])})}function x(e,t){var s,i,n,r;if(t.transform&&e.css){if(!(r=t.transform(e.css)))return function(){};e.css=r}if(t.singleton){var o=a++;s=h||(h=g(t)),i=v.bind(null,s,o,!1),n=v.bind(null,s,o,!0)}else e.sourceMap&&"function"==typeof URL&&"function"==typeof URL.createObjectURL&&"function"==typeof URL.revokeObjectURL&&"function"==typeof Blob&&"function"==typeof btoa?(s=function(e){var t=document.createElement("link");return e.attrs.type="text/css",e.attrs.rel="stylesheet",m(t,e.attrs),f(e,t),t}(t),i=function(e,t,s){var i=s.css,n=s.sourceMap,r=void 0===t.convertToAbsoluteUrls&&n;(t.convertToAbsoluteUrls||r)&&(i=c(i));n&&(i+="\n/*# sourceMappingURL=data:application/json;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(n))))+" */");var o=new Blob([i],{type:"text/css"}),l=e.href;e.href=URL.createObjectURL(o),l&&URL.revokeObjectURL(l)}.bind(null,s,t),n=function(){b(s),s.href&&URL.revokeObjectURL(s.href)}):(s=g(t),i=function(e,t){var s=t.css,i=t.media;i&&e.setAttribute("media",i);if(e.styleSheet)e.styleSheet.cssText=s;else{for(;e.firstChild;)e.removeChild(e.firstChild);e.appendChild(document.createTextNode(s))}}.bind(null,s),n=function(){b(s)});return i(e),function(t){if(t){if(t.css===e.css&&t.media===e.media&&t.sourceMap===e.sourceMap)return;i(e=t)}else n()}}e.exports=function(e,t){if("undefined"!=typeof DEBUG&&DEBUG&&"object"!=typeof document)throw new Error("The style-loader cannot be used in a non-browser environment");(t=t||{}).attrs="object"==typeof t.attrs?t.attrs:{},t.singleton||"boolean"==typeof t.singleton||(t.singleton=o()),t.insertInto||(t.insertInto="head"),t.insertAt||(t.insertAt="bottom");var s=u(e,t);return p(s,t),function(e){for(var i=[],n=0;n<s.length;n++){var o=s[n];(l=r[o.id]).refs--,i.push(l)}e&&p(u(e,t),t);for(n=0;n<i.length;n++){var l;if(0===(l=i[n]).refs){for(var h=0;h<l.parts.length;h++)l.parts[h]();delete r[l.id]}}}};var y,w=(y=[],function(e,t){return y[e]=t,y.filter(Boolean).join("\n")});function v(e,t,s,i){var n=s?"":i.css;if(e.styleSheet)e.styleSheet.cssText=w(t,n);else{var r=document.createTextNode(n),o=e.childNodes;o[t]&&e.removeChild(o[t]),o.length?e.insertBefore(r,o[t]):e.appendChild(r)}}},function(e,t,s){e.exports=s.p+"13b240062f9cf9a7f4131b86a426f140.svg"},function(e,t){e.exports=function(e){var t=[];return t.toString=function(){return this.map(function(t){var s=function(e,t){var s=e[1]||"",i=e[3];if(!i)return s;if(t&&"function"==typeof btoa){var n=(o=i,"/*# sourceMappingURL=data:application/json;charset=utf-8;base64,"+btoa(unescape(encodeURIComponent(JSON.stringify(o))))+" */"),r=i.sources.map(function(e){return"/*# sourceURL="+i.sourceRoot+e+" */"});return[s].concat(r).concat([n]).join("\n")}var o;return[s].join("\n")}(t,e);return t[2]?"@media "+t[2]+"{"+s+"}":s}).join("")},t.i=function(e,s){"string"==typeof e&&(e=[[null,e,""]]);for(var i={},n=0;n<this.length;n++){var r=this[n][0];"number"==typeof r&&(i[r]=!0)}for(n=0;n<e.length;n++){var o=e[n];"number"==typeof o[0]&&i[o[0]]||(s&&!o[2]?o[2]=s:s&&(o[2]="("+o[2]+") and ("+s+")"),t.push(o))}},t}},function(e,t){e.exports=function(e){return"string"!=typeof e?e:(/^['"].*['"]$/.test(e)&&(e=e.slice(1,-1)),/["'() \t\n]/.test(e)?'"'+e.replace(/"/g,'\\"').replace(/\n/g,"\\n")+'"':e)}},function(e,t,s){var i=s(23);(e.exports=s(22)(!1)).push([e.i,"body {\n margin: 0;\n}\n.spreadsheet {\n font-size: 14px;\n line-height: normal;\n user-select: none;\n -moz-user-select: none;\n font-family: Roboto, Helvetica, Arial, sans-serif;\n box-sizing: content-box;\n background: #fff;\n}\n.spreadsheet .spreadsheet-table {\n position: relative;\n background: #fff;\n}\n.spreadsheet .spreadsheet-fixed {\n position: absolute;\n top: 0;\n left: 0;\n z-index: 10;\n background: #fff;\n}\n.spreadsheet .spreadsheet-fixed .spreadsheet-fixed-body {\n overflow: hidden;\n}\n.spreadsheet .spreadsheet-fixed .spreadsheet-fixed-header {\n overflow: hidden;\n}\n.spreadsheet .spreadsheet-body {\n overflow: scroll;\n position: relative;\n}\n.spreadsheet .spreadsheet-header {\n overflow: hidden;\n width: 100%;\n}\n.spreadsheet .spreadsheet-header table,\n.spreadsheet .spreadsheet-body table,\n.spreadsheet .spreadsheet-fixed table {\n table-layout: fixed;\n text-align: left;\n width: 100%;\n border-collapse: separate;\n border-spacing: 0;\n color: #000;\n}\n.spreadsheet .spreadsheet-header table td,\n.spreadsheet .spreadsheet-body table td,\n.spreadsheet .spreadsheet-fixed table td,\n.spreadsheet .spreadsheet-header table th,\n.spreadsheet .spreadsheet-body table th,\n.spreadsheet .spreadsheet-fixed table th {\n transition: background .1s ease,color .1s ease;\n border-bottom: 1px solid #e0e2e4;\n border-right: 1px solid #e0e2e4;\n white-space: nowrap;\n text-overflow: ellipsis;\n overflow: hidden;\n padding: 0 4px;\n line-height: 22px;\n}\n.spreadsheet .spreadsheet-header table td.active,\n.spreadsheet .spreadsheet-body table td.active,\n.spreadsheet .spreadsheet-fixed table td.active,\n.spreadsheet .spreadsheet-header table th.active,\n.spreadsheet .spreadsheet-body table th.active,\n.spreadsheet .spreadsheet-fixed table th.active {\n background: rgba(75, 137, 255, 0.05) !important;\n}\n.spreadsheet .spreadsheet-header table th,\n.spreadsheet .spreadsheet-body table th,\n.spreadsheet .spreadsheet-fixed table th {\n border-top: 1px solid #e0e2e4;\n text-align: center;\n}\n.spreadsheet .spreadsheet-header table th,\n.spreadsheet .spreadsheet-body table th,\n.spreadsheet .spreadsheet-fixed table th,\n.spreadsheet .spreadsheet-header table td:first-child,\n.spreadsheet .spreadsheet-body table td:first-child,\n.spreadsheet .spreadsheet-fixed table td:first-child {\n font-size: 12px;\n background: #f4f5f8;\n font-weight: normal;\n color: #666;\n}\n.spreadsheet .spreadsheet-header table td:first-child,\n.spreadsheet .spreadsheet-body table td:first-child,\n.spreadsheet .spreadsheet-fixed table td:first-child,\n.spreadsheet .spreadsheet-header table th:first-child,\n.spreadsheet .spreadsheet-body table th:first-child,\n.spreadsheet .spreadsheet-fixed table th:first-child {\n border-left: 1px solid #e0e2e4;\n text-align: center;\n}\n.spreadsheet-editor {\n position: absolute;\n text-align: left;\n border: 2px solid #4b89ff;\n line-height: 0;\n z-index: 10;\n}\n.spreadsheet-editor textarea {\n box-sizing: content-box;\n border: none;\n padding: 0 3px;\n outline-width: 0;\n resize: none;\n text-align: start;\n overflow-y: hidden;\n font-family: inherit;\n font-size: inherit;\n color: inherit;\n white-space: normal;\n word-wrap: break-word;\n line-height: 22px;\n margin: 0;\n}\n.spreadsheet-suggest,\n.spreadsheet-contextmenu {\n position: absolute;\n box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);\n background: #fff;\n z-index: 100;\n}\n.spreadsheet-resizer {\n position: absolute;\n z-index: 11;\n}\n.spreadsheet-resizer.horizontal {\n cursor: row-resize;\n}\n.spreadsheet-resizer.vertical {\n cursor: col-resize;\n}\n.spreadsheet-resizer-line {\n position: absolute;\n z-index: 100;\n}\n.spreadsheet-resizer-line.horizontal {\n border-bottom: 2px dashed #4b89ff;\n}\n.spreadsheet-resizer-line.vertical {\n border-right: 2px dashed #4b89ff;\n}\n.spreadsheet-borders {\n box-sizing: content-box;\n}\n.spreadsheet-borders.dashed {\n border: 2px dashed #4b89ff;\n position: absolute;\n background: rgba(75, 137, 255, 0.03);\n}\n.spreadsheet-borders .left-border,\n.spreadsheet-borders .right-border,\n.spreadsheet-borders .bottom-border,\n.spreadsheet-borders .top-border,\n.spreadsheet-borders .area-border {\n position: absolute;\n font-size: 0;\n pointer-events: none;\n background: #4b89ff;\n}\n.spreadsheet-borders .area-border {\n background: rgba(75, 137, 255, 0.03);\n}\n.spreadsheet-borders .corner {\n cursor: crosshair;\n font-size: 0;\n height: 5px;\n width: 5px;\n border: 2px solid #ffffff;\n position: absolute;\n bottom: -6px;\n right: -6px;\n background: #4b89ff;\n}\n.spreadsheet-borders .copy-border {\n position: absolute;\n pointer-events: none;\n border: 1px dashed #4b89ff;\n background: rgba(75, 137, 255, 0.03);\n}\n.spreadsheet-paint-border {\n position: absolute;\n pointer-events: none;\n border: 1px dashed #4b89ff;\n background: rgba(75, 137, 255, 0.03);\n}\n.spreadsheet-bars .spreadsheet-toolbar {\n height: 40px;\n text-align: left;\n padding: 0 60px;\n border-bottom: 1px solid #e0e2e4;\n background: #f5f6f7;\n}\n.spreadsheet-bars .spreadsheet-toolbar > .spreadsheet-menu > .spreadsheet-item {\n margin: 7px 1px 0;\n}\n.spreadsheet-bars .spreadsheet-editor-bar {\n width: 100%;\n height: 26px;\n line-height: 26px;\n position: relative;\n background: #fff;\n padding: 0;\n}\n.spreadsheet-formula-bar {\n position: relative;\n height: 100%;\n}\n.spreadsheet-formula-bar .spreadsheet-formula-label {\n width: 60px;\n height: 100%;\n box-sizing: border-box;\n display: inline-block;\n text-align: center;\n border-right: 1px solid #e0e2e4;\n background-color: #fff;\n font-size: 12px;\n color: #777;\n user-select: none;\n float: left;\n vertical-align: middle;\n}\n.spreadsheet-formula-bar textarea {\n width: calc(100% - 60px);\n height: 100%;\n box-sizing: border-box;\n font-family: inherit;\n font-size: inherit;\n padding: 4px 10px;\n position: relative;\n float: left;\n resize: none;\n overflow-y: hidden;\n border: none;\n outline-width: 0;\n margin: 0;\n line-height: 1.2rem;\n}\n.spreadsheet-formula-bar-resizer {\n cursor: ns-resize;\n height: 4px;\n position: absolute;\n width: 100%;\n left: 0;\n bottom: 0;\n}\n.spreadsheet-menu.vertical > .spreadsheet-item-separator {\n background: #e0e2e4;\n height: 1px;\n margin: 5px 0;\n}\n.spreadsheet-menu.vertical > .spreadsheet-item {\n padding: 2px 10px;\n border-radius: 0;\n}\n.spreadsheet-menu.horizontal > .spreadsheet-item {\n display: inline-block;\n}\n.spreadsheet-menu.horizontal > .spreadsheet-item-separator {\n display: inline-block;\n background: #e0e2e4;\n width: 1px;\n vertical-align: middle;\n height: 18px;\n margin: 0 3px;\n}\n.spreadsheet-menu > .spreadsheet-item {\n border-radius: 2px;\n user-select: none;\n background: 0;\n border: 1px solid transparent;\n outline: none;\n height: 24px;\n color: rgba(0, 0, 0, 0.8);\n line-height: 24px;\n list-style: none;\n cursor: default;\n}\n.spreadsheet-menu > .spreadsheet-item.disabled {\n pointer-events: none;\n opacity: 0.5;\n}\n.spreadsheet-menu > .spreadsheet-item:not(.separator):hover,\n.spreadsheet-menu > .spreadsheet-item.active {\n background: rgba(0, 0, 0, 0.08);\n}\n.spreadsheet-menu > .spreadsheet-item:not(.separator):hover .spreadsheet-icon-img,\n.spreadsheet-menu > .spreadsheet-item.active .spreadsheet-icon-img {\n opacity: 0.7;\n}\n.spreadsheet-menu > .spreadsheet-item:not(.separator):hover .spreadsheet-dropdown-icon,\n.spreadsheet-menu > .spreadsheet-item.active .spreadsheet-dropdown-icon {\n background-color: rgba(0, 0, 0, 0.15);\n opacity: 0.6;\n}\n.spreadsheet-menu > .spreadsheet-item > .label {\n float: right;\n opacity: .8;\n}\n.spreadsheet-dropdown {\n position: relative;\n display: inline-block;\n width: auto!important;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-content {\n position: absolute;\n top: calc(100% + 5px);\n left: 0;\n z-index: 200;\n background: #fff;\n box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);\n width: auto;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-header .spreadsheet-dropdown-title {\n padding: 0 5px;\n display: inline-block;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-header .spreadsheet-dropdown-icon {\n display: inline-block;\n vertical-align: top;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-header .spreadsheet-dropdown-icon .spreadsheet-icon {\n width: 10px;\n}\n.spreadsheet-dropdown .spreadsheet-dropdown-header .spreadsheet-dropdown-icon .spreadsheet-icon .arrow-down {\n left: -130px;\n}\n.spreadsheet-color-panel {\n padding: 10px;\n width: 100%;\n}\n.spreadsheet-color-panel table {\n border-collapse: separate;\n border-spacing: 0;\n border: none;\n}\n.spreadsheet-color-panel table tr td {\n padding: 0;\n border: none;\n}\n.spreadsheet-color-panel .color-cell {\n width: 20px;\n height: 20px;\n margin: 3px;\n}\n.spreadsheet-color-panel .color-cell:hover {\n box-shadow: 0 0 2px rgba(0, 0, 0, 0.8);\n}\n.spreadsheet-icon {\n height: 18px;\n width: 18px;\n margin: 0px 4px 3px 3px;\n direction: ltr;\n text-align: left;\n user-select: none;\n vertical-align: middle;\n overflow: hidden;\n position: relative;\n display: inline-block;\n}\n.spreadsheet-icon-img {\n background-image: url("+i(s(21))+");\n position: absolute;\n width: 262px;\n height: 444px;\n opacity: 0.55;\n}\n.spreadsheet-icon-img.undo {\n left: 0;\n top: 0;\n}\n.spreadsheet-icon-img.redo {\n left: -18px;\n top: 0;\n}\n.spreadsheet-icon-img.print {\n left: -36px;\n top: 0;\n}\n.spreadsheet-icon-img.paintformat {\n left: -54px;\n top: 0;\n}\n.spreadsheet-icon-img.clearformat {\n left: -72px;\n top: 0;\n}\n.spreadsheet-icon-img.bold {\n left: -90px;\n top: 0;\n}\n.spreadsheet-icon-img.italic {\n left: -108px;\n top: 0;\n}\n.spreadsheet-icon-img.underline {\n left: -126px;\n top: 0;\n}\n.spreadsheet-icon-img.strikethrough {\n left: -144px;\n top: 0;\n}\n.spreadsheet-icon-img.text-color {\n left: -162px;\n top: 0;\n}\n.spreadsheet-icon-img.cell-color {\n left: -180px;\n top: 0;\n}\n.spreadsheet-icon-img.merge {\n left: -198px;\n top: 0;\n}\n.spreadsheet-icon-img.align-left {\n left: -216px;\n top: 0;\n}\n.spreadsheet-icon-img.align-center {\n left: -234px;\n top: 0;\n}\n.spreadsheet-icon-img.align-right {\n left: 0;\n top: -18px;\n}\n.spreadsheet-icon-img.valign-top {\n left: -18px;\n top: -18px;\n}\n.spreadsheet-icon-img.valign-middle {\n left: -36px;\n top: -18px;\n}\n.spreadsheet-icon-img.valign-bottom {\n left: -54px;\n top: -18px;\n}\n.spreadsheet-icon-img.textwrap {\n left: -72px;\n top: -18px;\n}\n.spreadsheet-icon-img.autofilter {\n left: -90px;\n top: -18px;\n}\n.spreadsheet-icon-img.formula {\n left: -108px;\n top: -18px;\n}\n.spreadsheet-icon-img.arrow-down {\n left: -126px;\n top: -18px;\n}\n.spreadsheet-icon-img.arrow-right {\n left: -144px;\n top: -18px;\n}\n",""])},function(e,t,s){var i=s(24);"string"==typeof i&&(i=[[e.i,i,""]]);var n={hmr:!0,transform:void 0,insertInto:void 0};s(20)(i,n);i.locals&&(e.exports=i.locals)},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});t.Select=class{constructor(e,t,s){this.start=e,this.stop=t,this.canMerge=s}forEach(e){const[t,s]=this.start,[i,n]=this.stop;for(let r=t;r<=i;r++)for(let o=s;o<=n;o++)e(r,o,r-t,o-s,i-t+1,n-s+1)}rowIndex(e){return this.start[0]+e%this.rowLen()}colIndex(e){return this.start[1]+e%this.colLen()}rowLen(){return this.stop[0]-this.start[0]+1}colLen(){return this.stop[1]-this.start[1]+1}cellLen(){return this.rowLen()*this.colLen()}contains(e,t){const[s,i]=this.start,[n,r]=this.stop;return s<=e&&n>=e&&i<=t&&r>=t}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.fonts=[{key:"Microsoft YaHei",title:"微软雅黑"},{key:"STFangsong",title:"华文仿宋"},{key:"Comic Sans MS",title:"Comic Sans MS"},{key:"Arial",title:"Arial"},{key:"Courier New",title:"Courier New"},{key:"Verdana",title:"Verdana"}]},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(8),n=s(27),r=s(7),o=s(5),l=s(6),h=s(26);class a{constructor(e){this.type=e,this.values=[]}add(e,t,s){this.values.push([e,t,s])}}t.History=a;t.Spreadsheet=class{constructor(e={}){if(this.histories=[],this.histories2=[],this.currentCellIndexes=[0,0],this.select=null,this.copySelect=null,this.cutSelect=null,this.change=(()=>{}),this.formats=e.formats||i.formats,this.fonts=e.fonts||n.fonts,this.formulas=e.formulas||r.formulas,this.data={rowHeight:22,colWidth:100,cell:o.defaultCell},e.data){const{data:t}=e;for(let e of["rowHeight","colWidth","rows","cols","cells"])t[e]&&(this.data[e]=t[e]);Object.assign(this.data.cell,t.cell||{})}}buildSelect(e,t){const s=f(e),i=f(t);let n=s.row,r=s.col,o=i.row,l=i.col;n>o&&(n=i.row,o=s.row),r>l&&(r=i.col,l=s.col);let[a,d]=g((e,t)=>this.getCell(e,t),n,o,r,l),[c,p]=b((e,t)=>this.getCell(e,t),a,d,r,l);for(;;){const[e,t]=g((e,t)=>this.getCell(e,t),a,d,c,p);let[s,i]=b((e,t)=>this.getCell(e,t),a,d,c,p);if(a===e&&d===t&&c===s&&p===i)break;a=e,d=t,c=s,p=i}const u=this.getCell(a,c);let m=a+(u&&u.rowspan||1)-1===d&&c+(u&&u.colspan||1)-1===p;return this.select=new h.Select([a,c],[d,p],!m),this.select}defaultRowHeight(){return this.data.rowHeight||22}defaultColWidth(){return this.data.colWidth||100}copy(){this.copySelect=this.select}cut(){this.cutSelect=this.select}paste(e,t,s){let i=this.copySelect;if(this.cutSelect&&(i=this.cutSelect,this.cutSelect=null),i&&this.select){const n=new a("cells");"copyformat"===t?this.select.forEach((r,o,l,h,a,d)=>{if(i){const a=i.rowIndex(l),d=i.colIndex(h),[c,p]=this.copyCell(a,d,r,o,t,e,s);n.add([r,o],c,p)}}):i.forEach((i,r,o,l,h,a)=>{if(this.select){const h=this.select.start[0]+o,a=this.select.start[1]+l,[d,c]=this.copyCell(i,r,h,a,t,e,s);n.add([h,a],d,c)}}),this.histories.push(n),this.change(this.data)}}insert(e,t,s){if(this.select){const{cells:t}=this.data,[i,n]=this.select.start;if(!t)return;const r=new a("cells");if("row"===e){const e={};Object.keys(t).forEach(n=>{let o=parseInt(n),l=t[o];i<=o&&Object.keys(l).forEach(e=>{let t=parseInt(e);s(o,t,{}),r.add([o,t],l[t],void 0),s(o+1,t,l[t]||{}),r.add([o+1,t],this.getCell(o+1,t),l[t])}),e[i<=o?o+1:o]=t[o]}),this.data.cells=e}else"col"===e&&Object.keys(t).forEach(e=>{let i=parseInt(e),o=t[i],l={};Object.keys(o).forEach(e=>{let t=parseInt(e);n<=t&&(s(i,t,{}),r.add([i,t],o[t],void 0),s(i,t+1,o[t]||{}),r.add([i,t+1],this.getCell(i,t+1),o[t])),l[n<=t?t+1:t]=o[t]}),t[i]=l});this.histories.push(r)}}batchPaste(e,t,s,i,n,r,o){if(this.select){const e=new a("cells");for(let l=t;l<=i;l++)for(let i=s;i<=n;i++){const n=this.select.rowIndex(l-t),h=this.select.colIndex(i-s),[a,d]=this.copyCell(n,h,l,i,r?"seqCopy":"copy",o,()=>{});e.add([l,i],a,d)}this.histories.push(e),this.change(this.data)}}copyCell(e,t,s,i,n,o,l){const h=this.getCell(e,t),a=s-e,d=i-t;if(h){let c=this.getCell(s,i);const p=Object.assign({},h);if(h.merge){const[e,t]=h.merge;p.merge=[e+a,t+d]}if("cut"===n&&l(e,t,this.cell(e,t,{})),"copyformat"===n)c&&c.text&&(p.text=c.text);else{const o=p.text;o&&!/^\s*$/.test(o)&&(/^\d*$/.test(o)&&"seqCopy"===n?p.text=parseInt(o)+(s-e)+(i-t)+"":-1!==o.indexOf("=")&&(p.text=r.formulaReplaceParam(o,a,d)))}return o(s,i,this.cell(s,i,p)),[c,p]}return[null,null]}isRedo(){return this.histories2.length>0}redo(e){const{histories:t,histories2:s}=this;if(s.length>0){const i=s.pop();i&&(this.resetByHistory(i,e,"redo"),t.push(i),this.change(this.data))}return this.isRedo()}isUndo(){return this.histories.length>0}undo(e){const{histories:t,histories2:s}=this;if(t.length>0){const i=t.pop();i&&(this.resetByHistory(i,e,"undo"),s.push(i),this.change(this.data))}return this.isUndo()}resetByHistory(e,t,s){e.values.forEach(([i,n,r])=>{if("cells"===e.type){const e="undo"===s?n:r,o=this.getCell(i[0],i[1]);if(o)if(3===i.length){const s={};s[i[2]]=e,t(i[0],i[1],e?this.cell(i[0],i[1],s,!0):this.cell(i[0],i[1],p(o,i[2])))}else t(i[0],i[1],this.cell(i[0],i[1],e||{}));else if(3===i.length){if(e){const s={};s[i[2]]=e,t(i[0],i[1],this.cell(i[0],i[1],s))}}else t(i[0],i[1],this.cell(i[0],i[1],e||{}))}})}clearformat(e){const{select:t}=this;if(null!==t){const s=new a("cells");t.forEach((t,i,n,r,o,l)=>{let h=this.getCell(t,i);h&&(s.add([t,i],h,{text:h.text}),h=this.cell(t,i,{text:h.text}),e(t,i,h))}),this.histories.push(s),this.change(this.data)}}merge(e,t,s){const{select:i}=this;if(null!==i&&i.cellLen()>1){const n=new a("cells");let r=0,o=[0,0];i.forEach((l,h,a,d,c,u)=>{if(0==r++){o=[l,h];let s={};if(c>1&&(s.rowspan=c),u>1&&(s.colspan=u),i.canMerge){n.add([l,h,"rowspan"],void 0,c),n.add([l,h,"colspan"],void 0,u);let t=this.cell(l,h,s,!0);e(l,h,t)}else{const e=this.getCell(l,h);if(null!==e){n.add([l,h,"rowspan"],e.rowspan,void 0),n.add([l,h,"colspan"],e.colspan,void 0);let s=this.cell(l,h,p(e,"rowspan","colspan","merge"));t(l,h,s)}}}else{let e={invisible:i.canMerge};if(i.canMerge){n.add([l,h,"invisible"],void 0,i.canMerge),e.merge=o;let t=this.cell(l,h,e,!0);s(l,h,t)}else{const e=this.getCell(l,h);if(null!==e){n.add([l,h,"invisible"],e.invisible,void 0);let t=this.cell(l,h,p(e,"rowspan","colspan","merge","invisible"));s(l,h,t)}}}}),this.histories.push(n),i.canMerge=!i.canMerge,this.change(this.data)}}cellAttr(e,t,s){let i={};i[e]=t;const n=t===this.data.cell[e];if(null!==this.select){const r=new a("cells");this.select.forEach((o,l)=>{const h=this.getCell(o,l);r.add([o,l,e],null!==h?h[e]:void 0,t);let a=this.cell(o,l,n?p(h,e):i,!n);s(o,l,a)}),this.histories.push(r)}this.change(this.data)}cellText(e,t){if(this.currentCellIndexes){const s=new a("cells"),[i,n]=this.currentCellIndexes,r=this.getCell(i,n);s.add([i,n,"text"],null!==r?r.text:void 0,e);const o=this.cell(i,n,{text:e},!0);return t(i,n,o),this.histories.push(s),this.change(this.data),o}return null}currentCell(e){void 0!==e&&(this.currentCellIndexes=e);const[t,s]=this.currentCellIndexes;return this.getCell(t,s)}cell(e,t,s,i=!1){return this.data.cells=this.data.cells||{},this.data.cells[e]=this.data.cells[e]||{},this.data.cells[e][t]=this.data.cells[e][t]||{},i?Object.assign(this.data.cells[e][t],s):s&&(this.data.cells[e][t]=s),this.data.cells[e][t]}getCell(e,t){return this.data.cells&&this.data.cells[e]&&this.data.cells[e][t]?this.data.cells[e][t]:null}getFont(e){return this.fonts.filter(t=>t.key===e)[0]}getFormat(e){return this.formats.filter(t=>t.key===e)[0]}row(e,t){const{data:s}=this;if(void 0!==t){const i=new a("rows");s.rows=s.rows||{},s.rows[e]=s.rows[e]||{},s.rows[e].height=t,i.add([e],null,s.rows[e]),this.histories.push(i)}return Object.assign({height:s.rowHeight},s.rows?s.rows[e]:{})}rows(e){const{data:t}=this;let s;return e?(s=10,this.data.cells&&(s=d(this.data.cells)+2)):s=c(100,t.rows),u(s,e=>this.row(e))}col(e,t){const{data:s}=this;if(void 0!==t){const i=new a("cols");s.cols=s.cols||{},s.cols[e]=s.cols[e]||{},s.cols[e].width=t,i.add([e],null,s.cols[e]),this.histories.push(i)}const i={width:s.colWidth,title:l.alphabet(e)};if(s.cols&&s.cols[e])for(let t in s.cols[e]){const n=s.cols[e];n[t]&&(i[t]=n[t])}return i}cols(){const{data:e}=this;let t=c(52,e.cols);return u(t,e=>this.col(e))}};const d=function(e){return Math.max(...Object.keys(e).map(e=>parseInt(e)))},c=function(e,t){if(t){const s=d(t);if(s>e)return s}return e},p=function(e,...t){const s={};return e&&Object.keys(e).forEach(i=>{-1===t.indexOf(i)&&(s[i]=e[i])}),s},u=function(e,t){const s=[];for(let i=0;i<e;i++)s.push(t(i));return s},f=e=>{const{offsetTop:t,offsetLeft:s,offsetHeight:i,offsetWidth:n}=e;return{row:parseInt(e.getAttribute("row-index")),col:parseInt(e.getAttribute("col-index")),rowspan:parseInt(e.getAttribute("rowspan")),colspan:parseInt(e.getAttribute("colspan")),left:s,top:t,width:n,height:i}},b=(e,t,s,i,n)=>{let r=i,o=n;for(let n=t;n<=s;n++){let t=i,s=e(n,t);s&&s.merge&&(t+=s.merge[1]-t),t<r&&(r=t);const l=(s=e(n,t=o))?s.colspan:1;if(parseInt(l)>1)t+=parseInt(l);else if(s&&s.merge){const[i,n]=s.merge;t+=e(i,n).colspan+(n-t)}t-1>o&&(o=t-1)}return[r,o]},g=(e,t,s,i,n)=>{let r=t,o=s;for(let s=i;s<=n;s++){let i=t,n=e(i,s);n&&n.merge&&(i+=n.merge[0]-i),i<r&&(r=i);const l=(n=e(i=o,s))?n.rowspan:1;if(parseInt(l)>1)i+=parseInt(l);else if(n&&n.merge){const[t,s]=n.merge;i+=e(t,s).rowspan+(t-i)}i-1>o&&(o=i-1)}return[r,o]}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(28);s(25);const n=s(18),r=s(12),o=s(9),l=s(0);t.LocalSpreadsheet=class{constructor(e,t={}){this.refs={},this.toolbar=null,this.editorbar=null,this._change=(()=>{}),this.bindEl=e,this.options=Object.assign({mode:"design"},t),this.bindEl&&(this.bindEl.innerHTML=""),this.ss=new i.Spreadsheet(t),"design"===this.options.mode&&(this.editorbar=new o.Editorbar,this.editorbar.change=(e=>this.editorbarChange(e)),this.toolbar=new r.Toolbar(this.ss),this.toolbar.change=((e,t)=>this.toolbarChange(e,t)),this.toolbar.undo=(()=>this.table.undo()),this.toolbar.redo=(()=>this.table.redo())),this.table=new n.Table(this.ss,Object.assign({height:()=>this.options.height?this.options.height():document.documentElement.clientHeight-24-41-26,width:()=>this.bindEl.offsetWidth,mode:this.options.mode})),this.table.change=(e=>{this.toolbar&&this.toolbar.setRedoAble(this.ss.isRedo()),this.toolbar&&this.toolbar.setUndoAble(this.ss.isUndo()),this._change(e)}),this.table.editorChange=(e=>this.editorChange(e)),this.table.clickCell=((e,t,s)=>this.clickCell(e,t,s)),this.render()}loadData(e){return setTimeout(()=>{this.ss.data=e,this.table.reload()},1),this}change(e){return this._change=e,this}render(){this.bindEl.appendChild(l.h().class("spreadsheet").children([l.h().class("spreadsheet-bars").children([this.toolbar&&this.toolbar.el||"",this.editorbar&&this.editorbar.el||""]),this.table.el]).el)}toolbarChange(e,t){"merge"!==e?"clearformat"!==e?"paintformat"!==e?this.table.setCellAttr(e,t):this.table.copyformat():this.table.clearformat():this.table.merge()}editorbarChange(e){this.table.setValueWithText(e)}editorChange(e){this.editorbar&&this.editorbar.setValue(e)}clickCell(e,t,s){const i=this.ss.cols();this.editorbar&&this.editorbar.set(`${i[t].title}${e+1}`,s),this.toolbar&&this.toolbar.set(this.table.td(e,t),s)}}},function(e,t,s){"use strict";Object.defineProperty(t,"__esModule",{value:!0});const i=s(29);function n(e,t){return new i.LocalSpreadsheet(e,t)}t.default=n,window.xspreadsheet=n}]);
//# sourceMappingURL=xspreadsheet.js.map
================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="spreadsheet.css"></link>
<script type="text/javascript" src="bundle.js"></script>
<script type="text/javascript">
window.onload = function () {
var data = {"rowHeight":22,"colWidth":100,"rows":{"1":{"height":35},"3":{"height":40},"4":{"height":53},"5":{"height":57}},"cols":{"0":{"width":74,"title":null},"2":{"width":79,"title":null},"3":{"width":75,"title":null},"5":{"width":58,"title":null},"6":{"width":59,"title":null},"8":{"width":89,"title":null},"9":{"width":80,"title":null},"10":{"width":53,"title":null},"11":{"width":54,"title":null},"12":{"width":51,"title":null},"13":{"width":52,"title":null},"14":{"width":53,"title":null},"15":{"width":52,"title":null},"16":{"width":51,"title":null},"17":{"width":52,"title":null}},"cell":{"font":"Microsoft YaHei","format":"normal","fontSize":14,"bold":false,"italic":false,"underline":false,"color":"#333","backgroundColor":"#fff","align":"left","valign":"middle","wordWrap":false,"invisible":false,"rowspan":1,"colspan":1,"text":""},"cells":{"1":{"2":{"colspan":19,"text":"2019-2021年中期财政规划(高速公路)","bold":true,"fontSize":16,"align":"center"},"3":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"4":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"5":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"6":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"7":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"8":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"9":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"10":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"11":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"12":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"13":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"14":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"15":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"16":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"17":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"18":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"19":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"},"20":{"invisible":true,"merge":[1,2],"bold":true,"fontSize":16,"align":"center"}},"3":{"0":{"rowspan":3,"text":"序号","align":"center"},"1":{"rowspan":3,"text":"单位名称","align":"center"},"2":{"colspan":2,"text":"项目所在地区","align":"center"},"3":{"invisible":true,"merge":[3,2],"align":"center"},"4":{"rowspan":3,"text":"项 目 名 称","align":"center"},"5":{"rowspan":3,"text":"项目所属集中连片特困地区","align":"center","wordWrap":true},"6":{"rowspan":3,"text":"项目所属革命老区","align":"center","wordWrap":true},"7":{"rowspan":3,"text":"贫困县类别(国贫、省贫、一般)","align":"center","wordWrap":true},"8":{"rowspan":3,"text":"线路性质","align":"center","wordWrap":true},"9":{"rowspan":3,"text":"建设性质","align":"center","wordWrap":true},"10":{"colspan":8,"text":"建设规模(公里)/(延米)","align":"center"},"11":{"invisible":true,"merge":[3,10],"align":"center"},"12":{"invisible":true,"merge":[3,10],"align":"center"},"13":{"invisible":true,"merge":[3,10],"align":"center"},"14":{"invisible":true,"merge":[3,10],"align":"center"},"15":{"invisible":true,"merge":[3,10],"align":"center"},"16":{"invisible":true,"merge":[3,10],"align":"center"},"17":{"invisible":true,"merge":[3,10],"align":"center"},"18":{"colspan":2,"text":"建设年限","align":"center"},"19":{"invisible":true,"merge":[3,18],"align":"center"}},"4":{"0":{"invisible":true,"merge":[3,0],"align":"center"},"1":{"invisible":true,"merge":[3,1],"align":"center"},"2":{"rowspan":2,"text":"市","align":"center"},"3":{"rowspan":2,"text":"县区","align":"center"},"4":{"invisible":true,"merge":[3,4],"align":"center"},"5":{"invisible":true,"merge":[3,5],"align":"center","wordWrap":true},"6":{"invisible":true,"merge":[3,6],"align":"center","wordWrap":true},"7":{"invisible":true,"merge":[3,7],"align":"center","wordWrap":true},"8":{"invisible":true,"merge":[3,8],"align":"center","wordWrap":true},"9":{"invisible":true,"merge":[3,9],"align":"center","wordWrap":true},"10":{"rowspan":2,"text":"合计","align":"center"},"11":{"rowspan":2,"text":"高速\n公路","align":"center","wordWrap":true},"12":{"rowspan":2,"text":"一级\n公路","align":"center","wordWrap":true},"13":{"rowspan":2,"text":"二级\n公路","align":"center","wordWrap":true},"14":{"rowspan":2,"text":"三级\n公路","align":"center","wordWrap":true},"15":{"rowspan":2,"text":"四级\n公路","align":"center","wordWrap":true},"16":{"rowspan":2,"text":"独立\n大桥","align":"center","wordWrap":true},"17":{"rowspan":2,"text":"独立\n隧道","align":"center","wordWrap":true},"18":{"rowspan":2,"text":"开工年","align":"center"},"19":{"rowspan":2,"text":"完工年","align":"center"}},"5":{"0":{"invisible":true,"merge":[3,0],"align":"center"},"1":{"invisible":true,"merge":[3,1],"align":"center"},"2":{"invisible":true,"merge":[4,2],"align":"center"},"3":{"invisible":true,"merge":[4,3],"align":"center"},"4":{"invisible":true,"merge":[3,4],"align":"center"},"5":{"invisible":true,"merge":[3,5],"align":"center","wordWrap":true},"6":{"invisible":true,"merge":[3,6],"align":"center","wordWrap":true},"7":{"invisible":true,"merge":[3,7],"align":"center","wordWrap":true},"8":{"invisible":true,"merge":[3,8],"align":"center","wordWrap":true},"9":{"invisible":true,"merge":[3,9],"align":"center","wordWrap":true},"10":{"invisible":true,"merge":[4,10],"align":"center"},"11":{"invisible":true,"merge":[4,11],"align":"center","wordWrap":true},"12":{"invisible":true,"merge":[4,12],"align":"center","wordWrap":true},"13":{"invisible":true,"merge":[4,13],"align":"center","wordWrap":true},"14":{"invisible":true,"merge":[4,14],"align":"center","wordWrap":true},"15":{"invisible":true,"merge":[4,15],"align":"center","wordWrap":true},"16":{"invisible":true,"merge":[4,16],"align":"center","wordWrap":true},"17":{"invisible":true,"merge":[4,17],"align":"center","wordWrap":true},"18":{"invisible":true,"merge":[4,18],"align":"center"},"19":{"invisible":true,"merge":[4,19],"align":"center"}}}};
xspreadsheet(document.getElementById('wrapper'), {mode: 'design'}).loadData(data)
}
</script>
<title>TypeScript with VSCode</title>
</head>
<body>
<div style="display: flex;">
<div style="width: 300px; flex: 0 0 auto;">
xxxxxx
</div>
<div style="flex: 1 1 auto;overflow: hidden;">
<div id="wrapper"></div>
</div>
</div>
</body>
</html>
================================================
FILE: package.json
================================================
{
"name": "xspreadsheet",
"version": "1.0.4",
"description": "a javascript spreadsheet",
"author": "myliang <liangyuliang0335@126.com>",
"private": false,
"main": "src/main.ts",
"types": "src/main.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/myliang/spreadsheet.git"
},
"scripts": {
"dev": "webpack-dev-server --color --inline --hot --config webpack.config.dev.js --open",
"build": "webpack --config webpack.config.js --progress --color"
},
"keywords": [
"excel",
"js",
"component",
"ui",
"spreadsheet"
],
"license": "MIT",
"devDependencies": {
"awesome-typescript-loader": "^5.2.0",
"css-loader": "^0.28.11",
"extract-text-webpack-plugin": "^4.0.0-beta.0",
"file-loader": "^1.1.11",
"less": "^3.0.1",
"less-loader": "^4.1.0",
"source-map-loader": "^0.2.3",
"style-loader": "^0.20.3",
"tslint-eslint-rules": "^5.2.0",
"typescript": "^2.9.2",
"webpack": "^4.5.0",
"webpack-cli": "^2.0.14",
"webpack-dev-server": "^3.1.3"
}
}
================================================
FILE: src/core/alphabet.d.ts
================================================
export declare function alphabet(index: number): string;
export declare function alphabetIndex(key: string): number;
================================================
FILE: src/core/alphabet.ts
================================================
const _alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']
export function alphabet(index: number): string {
const [a, b] = [parseInt(index / _alphabet.length + ''), index % _alphabet.length]
// console.log('a: ', a, '; b: ', b)
return a > 0 ? `${_alphabet[a - 1]}${_alphabet[b]}` : _alphabet[b]
}
export function alphabetIndex (key: string): number {
let ret = 0;
for (let i = 0; i < key.length; i++) {
// console.log(key.charCodeAt(i), key[i])
let cindex = key.charCodeAt(i) - 65;
ret += i * _alphabet.length + cindex;
}
return ret;
}
================================================
FILE: src/core/cell.d.ts
================================================
export interface Cell {
font?: string;
format?: string;
fontSize?: number;
bold?: boolean;
italic?: boolean;
underline?: boolean;
color?: string;
backgroundColor?: string;
align?: string;
valign?: string;
wordWrap?: boolean;
visable?: boolean;
rowspan?: number;
colspan?: number;
text?: string;
merge?: [number, number];
[key: string]: any;
}
export declare const defaultCell: Cell;
export declare function getStyleFromCell(cell: Cell | null): {
[key: string]: string;
};
================================================
FILE: src/core/cell.ts
================================================
export interface Cell {
font?: string;
format?: string;
fontSize?: number;
bold?: boolean;
italic?: boolean;
underline?: boolean;
color?: string;
backgroundColor?: string;
align?: string;
valign?: string;
wordWrap?: boolean;
visable?: boolean;
rowspan?: number;
colspan?: number;
text?: string;
merge?: [number, number];
[key: string]: any
}
export const defaultCell: Cell = {
font: 'Microsoft YaHei',
format: 'normal',
fontSize: 14,
bold: false,
italic: false,
underline: false,
color: '#333',
backgroundColor: '#fff',
align: 'left',
valign: 'middle',
wordWrap: false,
invisible: false,
rowspan: 1,
colspan: 1,
text: '',
}
export function getStyleFromCell (cell: Cell | null): {[key: string]: string} {
const map: {[key: string]: string} = {}
if (cell) {
if (cell.font) map['font-family'] = cell.font
if (cell.fontSize) map['font-size'] = `${cell.fontSize}px`
if (cell.bold) map['font-weight'] = 'bold'
if (cell.italic) map['font-style'] = 'italic'
if (cell.underline) map['text-decoration'] = 'underline'
if (cell.color) map['color'] = cell.color
if (cell.backgroundColor) map['background-color'] = cell.backgroundColor
if (cell.align) map['text-align'] = cell.align
if (cell.valign) map['vertical-align'] = cell.valign
if (cell.invisible) {
map['display'] = 'none'
}
if (cell.wordWrap) {
map['word-wrap'] = 'break-word'
map['white-space'] = 'normal'
}
}
return map
}
================================================
FILE: src/core/font.d.ts
================================================
export interface Font {
key: string;
title: string;
}
export declare const fonts: Array<Font>;
================================================
FILE: src/core/font.ts
================================================
export interface Font {
key: string;
title: string;
}
export const fonts: Array<Font> = [
{key: 'Microsoft YaHei', title: '微软雅黑'},
{key: 'STFangsong', title: '华文仿宋'},
{key: 'Comic Sans MS', title: 'Comic Sans MS'},
{key: 'Arial', title: 'Arial'},
{key: 'Courier New', title: 'Courier New'},
{key: 'Verdana', title: 'Verdana'}
]
================================================
FILE: src/core/format.d.ts
================================================
export interface Format {
key: string;
title: string;
label?: string;
render(txt: string): string;
}
export declare const formatRenderHtml: (key: string | undefined, txt: string | undefined) => string;
export declare const formats: Array<Format>;
================================================
FILE: src/core/format.ts
================================================
export interface Format {
key: string;
title: string;
label?: string;
render(txt: string): string;
}
export const formatRenderHtml = (key: string | undefined, txt: string | undefined) => {
for (let i = 0; i < formats.length; i++) {
if (formats[i].key === key) {
return formats[i].render(txt || '')
}
}
return txt || ''
}
const formatNumberRender = (v: string) => {
if (/^(-?\d*.?\d*)$/.test(v)) {
v = Number(v).toFixed(2).toString()
const parts = v.split('.')
parts[0] = parts[0].toString().replace(/(\d)(?=(\d{3})+(?!\d))/g, '$1' + ',')
return parts.join('.')
}
return v
}
const formatRender = (v: string) => v
export const formats: Array<Format> = [
{key: 'normal', title: 'Normal', render: formatRender},
{key: 'text', title: 'Text', render: formatRender},
{key: 'number', title: 'Number', label: '1,000.12', render: formatNumberRender},
{key: 'percent', title: 'Percent', label: '10.12%', render: (v) => `${formatNumberRender(v)}%`},
{key: 'RMB', title: 'RMB', label: '¥10.00', render: (v) => `¥${formatNumberRender(v)}`},
{key: 'USD', title: 'USD', label: '$10.00', render: (v) => `$${formatNumberRender(v)}`}
]
================================================
FILE: src/core/formula.d.ts
================================================
export interface Formula {
key: string;
title: string;
render(ary: Array<number>): number;
}
export declare const formulaFilterKey: (v: string, filter: (formula: Formula, param: string) => string) => string;
export declare const formulaRender: (v: string, renderCell: (rindex: number, cindex: number) => any) => string;
export declare const formulaReplaceParam: (param: string, rowDiff: number, colDiff: number) => string;
export declare const formulas: Array<Formula>;
================================================
FILE: src/core/formula.ts
================================================
import { alphabetIndex, alphabet } from "./alphabet";
export interface Formula {
key: string;
title: string;
render(ary: Array<number>): number
}
export const formulaFilterKey = (v: string, filter: (formula: Formula, param: string) => string) => {
if (v[0] === '=') {
const fx = v.substring(1, v.indexOf('('))
for (let formula of formulas) {
if (formula.key.toLowerCase() === fx.toLowerCase()) {
return filter(formula, v.substring(v.indexOf('(') + 1, v.lastIndexOf(')')))
}
}
}
return v
}
export const formulaRender = (v: string, renderCell: (rindex: number, cindex: number) => any) => {
return formulaFilterKey(v, (fx, param) => {
return fx.render(formulaParamToArray(param, renderCell)) + '';
})
}
export const formulaReplaceParam = (param: string, rowDiff: number, colDiff: number): string => {
return formulaFilterKey(param, (fx, params) => {
const replaceFormula = (_v: string):string => {
if (/^[0-9\-\+\*\/()\s]+$/.test(_v.trim())) {
return _v
}
const idx = /\d+/.exec(_v)
if (idx) {
let vc = _v.substring(0, idx.index).trim()
let vr = parseInt(_v.substring(idx.index).trim())
return `${alphabet(alphabetIndex(vc) + colDiff)}${vr + rowDiff}`
}
return _v;
}
if (params.indexOf(':') !== -1) {
params = params.split(':').map(replaceFormula).join(':')
} else {
params = params.split(',').map(replaceFormula).join(',')
}
return `=${fx.key}(${params})`
})
}
const formulaParamToArray = (param: string, renderCell: (rindex: number, cindex: number) => any) => {
let paramValues = []
try {
if (param.indexOf(':') !== -1) {
const [min, max] = param.split(':');
const idx = /\d+/.exec(min);
const maxIdx = /\d+/.exec(max);
if (idx && maxIdx) {
// idx = idx.index;
// maxIdx = maxIdx.index;
let minC = min.substring(0, idx.index).trim()
let minR = parseInt(min.substring(idx.index).trim())
let maxC = max.substring(0, maxIdx.index).trim()
let maxR = parseInt(max.substring(maxIdx.index).trim())
// console.log(min, max, minR, maxR, minC, maxC)
if (maxC === minC) {
for (let i = minR; i <= maxR; i++) {
// console.log('value:::', i-1, alphabetIndex(minC), renderCell(i - 1, alphabetIndex(minC)))
paramValues.push(renderCell(i - 1, alphabetIndex(minC)))
}
} else {
for (let i = alphabetIndex(minC); i <= alphabetIndex(maxC); i++) {
paramValues.push(renderCell(minR - 1, i))
}
}
}
} else {
paramValues = param.split(',').map(p => {
// console.log(/^[0-9\-\+\*\/() ]+$/.test(p), p)
if (/^[0-9\-\+\*\/()\s]+$/.test(p.trim())) {
try {
return eval(p)
} catch (e) {
return 0
}
}
const idx = /\d+/.exec(p)
if (idx) {
const c = p.substring(0, idx.index).trim()
const r = p.substring(idx.index).trim()
return renderCell(parseInt(r) - 1, alphabetIndex(c))
}
return 0
})
}
} catch (e) {
console.log('warning:', e)
}
return paramValues;
}
export const formulas: Array<Formula> = [
{key: 'SUM', title: '求和', render: (vv) => vv.reduce((a, b) => Number(a) + Number(b), 0)},
{key: 'AVERAGE', title: '平均值', render: (vv) => vv.reduce((a, b) => Number(a) + Number(b), 0) / vv.length},
{key: 'MAX', title: '最大值', render: (vv) => Math.max(...vv.map(v => Number(v)))},
{key: 'MIN', title: '最小值', render: (vv) => Math.min(...vv.map(v => Number(v)))}
]
================================================
FILE: src/core/index.d.ts
================================================
import { Format } from './format';
import { Font } from './font';
import { Formula } from './formula';
import { Cell } from './cell';
import { Select } from './select';
export interface Row {
height: number;
}
export interface Col {
title: string;
width: number;
}
export interface MapInt<T> {
[key: number]: T;
}
export declare class History {
type: 'rows' | 'cols' | 'cells';
values: Array<[Array<any>, any, any]>;
constructor(type: 'rows' | 'cols' | 'cells');
add(keys: Array<any>, oldValue: any, value: any): void;
}
export declare type StandardCallback = (rindex: number, cindex: number, cell: Cell) => void;
export interface SpreadsheetData {
rowHeight?: number;
colWidth?: number;
rows?: MapInt<Row>;
cols?: MapInt<Col>;
cell: Cell;
cells?: MapInt<MapInt<Cell>>;
[prop: string]: any;
}
export interface SpreadsheetOptions {
formats?: Array<Format>;
fonts?: Array<Font>;
formulas?: Array<Formula>;
data?: SpreadsheetData;
}
export declare class Spreadsheet {
formats: Array<Format>;
fonts: Array<Font>;
formulas: Array<Formula>;
data: SpreadsheetData;
private histories;
private histories2;
private currentCellIndexes;
select: Select | null;
private copySelect;
private cutSelect;
change: (data: SpreadsheetData) => void;
constructor(options?: SpreadsheetOptions);
buildSelect(startTarget: any, endTarget: any): Select;
defaultRowHeight(): number;
defaultColWidth(): number;
copy(): void;
cut(): void;
paste(cb: StandardCallback, state: 'copy' | 'cut' | 'copyformat', clear: StandardCallback): void;
insert(type: 'row' | 'col', amount: number, cb: StandardCallback): void;
batchPaste(arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number, seqCopy: boolean, cb: StandardCallback): void;
private copyCell;
isRedo(): boolean;
redo(cb: StandardCallback): boolean;
isUndo(): boolean;
undo(cb: StandardCallback): boolean;
resetByHistory(v: History, cb: StandardCallback, state: 'undo' | 'redo'): void;
clearformat(cb: StandardCallback): void;
merge(ok: StandardCallback, cancel: StandardCallback, other: StandardCallback): void;
cellAttr(key: keyof Cell, value: any, cb: StandardCallback): void;
cellText(value: any, cb: StandardCallback): Cell | null;
currentCell(indexes?: [number, number]): Cell | null;
cell(rindex: number, cindex: number, v: any, isCopy?: boolean): Cell;
getCell(rindex: number, cindex: number): Cell | null;
getFont(key: string | undefined): Font;
getFormat(key: string | undefined): Format;
row(index: number, v?: number): Row;
rows(isData: boolean): Array<Row>;
col(index: number, v?: number): Col;
cols(): Array<Col>;
}
================================================
FILE: src/core/index.ts
================================================
import { Format, formats } from './format'
import { Font, fonts } from './font'
import { Formula, formulas, formulaReplaceParam } from './formula'
import { Cell, defaultCell } from './cell'
import { alphabet } from './alphabet'
import { Select } from './select'
import { unbind } from '../local/event';
export interface Row {
height: number
}
export interface Col {
title: string
width: number
}
export interface MapInt<T> {
[key: number]: T
}
export class History {
values: Array<[Array<any>, any, any]> = [];
constructor (public type: 'rows' | 'cols' | 'cells') {}
add (keys: Array<any>, oldValue: any, value: any) {
this.values.push([keys, oldValue, value])
}
}
// types
export type StandardCallback = (rindex: number, cindex: number, cell: Cell) => void;
export interface SpreadsheetData {
rowHeight?: number;
colWidth?: number;
rows?: MapInt<Row>;
cols?: MapInt<Col>;
cell: Cell; // global default cell
cells?: MapInt<MapInt<Cell>>;
[prop: string]: any
}
export interface SpreadsheetOptions {
formats?: Array<Format>;
fonts?: Array<Font>;
formulas?: Array<Formula>;
data?: SpreadsheetData;
}
export class Spreadsheet {
formats: Array<Format>;
fonts: Array<Font>;
formulas: Array<Formula>;
data: SpreadsheetData;
private histories: Array<History> = [];
private histories2: Array<History> = [];
private currentCellIndexes: [number, number] = [0, 0];
select: Select | null = null;
private copySelect: Select | null = null;
private cutSelect: Select | null = null;
change: (data: SpreadsheetData) => void = () => {}
constructor (options: SpreadsheetOptions = {}) {
this.formats = options.formats || formats
this.fonts = options.fonts || fonts
this.formulas = options.formulas || formulas
// init data
this.data = {rowHeight: 22, colWidth: 100, cell: defaultCell}
if (options.data) {
const { data } = options;
for (let prop of ['rowHeight', 'colWidth', 'rows', 'cols', 'cells']) {
if (data[prop]) {
this.data[prop] = data[prop];
}
}
(<any>Object).assign(this.data.cell, data.cell || {});
}
}
// build select
buildSelect (startTarget: any, endTarget: any) {
const startAttrs = getElementAttrs(startTarget)
const endAttrs = getElementAttrs(endTarget)
// console.log(':::::::>>>', startAttrs, endAttrs)
let sRow = startAttrs.row
let sCol = startAttrs.col
let eRow = endAttrs.row
let eCol = endAttrs.col
if (sRow > eRow) {
sRow = endAttrs.row
eRow = startAttrs.row
}
if (sCol > eCol) {
sCol = endAttrs.col
eCol = startAttrs.col
}
// calc min, max of row
// console.log('s: ', sRow, sCol, ', e: ', eRow, eCol)
let [minRow, maxRow] = calcMinMaxRow((r: number, c: number) => this.getCell(r, c), sRow, eRow, sCol, eCol)
// console.log('minRow: ', minRow, ', maxRow: ', maxRow)
// calc min, max of col
let [minCol, maxCol] = calcMinMaxCol((r: number, c: number) => this.getCell(r, c), minRow, maxRow, sCol, eCol)
while (true) {
const [minr, maxr] = calcMinMaxRow((r: number, c: number) => this.getCell(r, c), minRow, maxRow, minCol, maxCol)
let [minc, maxc] = calcMinMaxCol((r: number, c: number) => this.getCell(r, c), minRow, maxRow, minCol, maxCol)
if (minRow === minr && maxRow === maxr && minCol === minc && maxCol === maxc) {
break
}
minRow = minr
maxRow = maxr
minCol = minc
maxCol = maxc
}
const firstCell = this.getCell(minRow, minCol)
// console.log('first => rowspan: ', firstCell.rowspan, ', colspan: ', firstCell.colspan)
let canotMerge = minRow + (firstCell && firstCell.rowspan || 1) - 1 === maxRow && minCol + (firstCell && firstCell.colspan || 1) - 1 === maxCol
// console.log('row: ', minRow, maxRow, ', col:', minCol, maxCol, canotMerge)
// 计算是否可以merge
this.select = new Select([minRow, minCol], [maxRow, maxCol], !canotMerge)
return this.select
}
defaultRowHeight (): number {
return this.data.rowHeight || 22
}
defaultColWidth (): number {
return this.data.colWidth || 100
}
copy (): void {
this.copySelect = this.select
}
cut (): void {
this.cutSelect = this.select
}
paste (cb: StandardCallback, state: 'copy' | 'cut' | 'copyformat', clear: StandardCallback): void {
let cselect = this.copySelect
if (this.cutSelect) {
cselect = this.cutSelect
this.cutSelect = null
}
if (cselect && this.select) {
const history = new History('cells')
if (state === 'copyformat') {
this.select.forEach((rindex, cindex, i, j, rowspan, colspan) => {
if (cselect) {
const srcRowIndex = cselect.rowIndex(i)
const srcColIndex = cselect.colIndex(j)
const [oldCell, newCell] = this.copyCell(srcRowIndex, srcColIndex, rindex, cindex, state, cb, clear)
history.add([rindex, cindex], oldCell, newCell)
}
})
} else {
cselect.forEach((rindex, cindex, i, j, rowspan, colspan) => {
if (this.select) {
const destRowIndex = this.select.start[0] + i
const destColIndex = this.select.start[1] + j
const [oldCell, newCell] = this.copyCell(rindex, cindex, destRowIndex, destColIndex, state, cb, clear)
history.add([destRowIndex, destColIndex], oldCell, newCell)
}
})
}
this.histories.push(history)
this.change(this.data)
}
}
insert (type: 'row' | 'col', amount: number, cb: StandardCallback) {
if (this.select) {
const { cells } = this.data
const [srindex, scindex] = this.select.start
if (!cells) return
// console.log('insert.before.data:', cells)
const history = new History('cells')
if (type === 'row') {
const newCells: MapInt<MapInt<Cell>> = {}
Object.keys(cells).forEach(key => {
let rindex = parseInt(key)
let values = cells[rindex]
if (srindex <= rindex) {
Object.keys(values).forEach(key1 => {
let cindex = parseInt(key1)
// clear current cell
cb(rindex, cindex, {})
history.add([rindex, cindex], values[cindex], undefined)
// set next cell is current celll
cb(rindex + 1, cindex, values[cindex] || {})
history.add([rindex + 1, cindex], this.getCell(rindex + 1, cindex), values[cindex])
})
}
newCells[srindex <= rindex ? rindex + 1 : rindex] = cells[rindex]
})
this.data.cells = newCells
} else if (type === 'col') {
Object.keys(cells).forEach(key => {
let rindex = parseInt(key)
let values = cells[rindex]
let newCell: MapInt<Cell> = {}
Object.keys(values).forEach(key1 => {
let cindex = parseInt(key1)
if (scindex <= cindex) {
// clear 当前cell
cb(rindex, cindex, {})
history.add([rindex, cindex], values[cindex], undefined)
// 设置下一个cell 等于当前的cell
cb(rindex, cindex + 1, values[cindex] || {})
history.add([rindex, cindex + 1], this.getCell(rindex, cindex + 1), values[cindex])
}
newCell[scindex <= cindex ? cindex + 1 : cindex] = values[cindex]
})
cells[rindex] = newCell
})
}
this.histories.push(history)
// console.log('insert.after.data:', this.data.cells)
}
}
batchPaste (arrow: 'bottom' | 'top' | 'left' | 'right',
startRow: number, startCol: number, stopRow: number, stopCol: number,
seqCopy: boolean,
cb: StandardCallback) {
if (this.select) {
const history = new History('cells')
for (let i = startRow; i <= stopRow; i++) {
for (let j = startCol; j <= stopCol; j++) {
const srcRowIndex = this.select.rowIndex(i - startRow)
const srcColIndex = this.select.colIndex(j - startCol)
const [oldDestCell, destCell] = this.copyCell(srcRowIndex, srcColIndex, i, j, seqCopy ? 'seqCopy' : 'copy', cb, () => {})
history.add([i, j], oldDestCell, destCell)
}
}
this.histories.push(history)
this.change(this.data)
}
}
private copyCell (srcRowIndex: number, srcColIndex: number, destRowIndex: number, destColIndex: number,
state: 'seqCopy' | 'copy' | 'cut' | 'copyformat', cb: StandardCallback, clear: StandardCallback): [Cell | null, Cell | null] {
const srcCell = this.getCell(srcRowIndex, srcColIndex)
const rowDiff = destRowIndex - srcRowIndex
const colDiff = destColIndex - srcColIndex
if (srcCell) {
let oldDestCell = this.getCell(destRowIndex, destColIndex)
// let destCell = cellCopy(srcCell, destRowIndex - srcRowIndex, destColIndex - srcColIndex, state === 'seqCopy')
const destCell = Object.assign({}, srcCell)
if (srcCell.merge) {
const [m1, m2] = srcCell.merge
destCell.merge = [m1 + rowDiff, m2 + colDiff];
}
if (state === 'cut') {
clear(srcRowIndex, srcColIndex, this.cell(srcRowIndex, srcColIndex, {}))
}
if (state === 'copyformat') {
if (oldDestCell && oldDestCell.text) {
destCell.text = oldDestCell.text
}
} else {
const txt = destCell.text
if (txt && !/^\s*$/.test(txt)) {
if (/^\d*$/.test(txt) && state === 'seqCopy') {
destCell.text = (parseInt(txt) + (destRowIndex - srcRowIndex) + (destColIndex - srcColIndex)) + ''
} else if (txt.indexOf('=') !== -1) {
// 如果text的内容是formula,那么需要需要修改表达式参数
destCell.text = formulaReplaceParam(txt, rowDiff, colDiff)
}
}
}
cb(destRowIndex, destColIndex, this.cell(destRowIndex, destColIndex, destCell))
return [oldDestCell, destCell];
}
return [null, null];
}
isRedo (): boolean {
return this.histories2.length > 0
}
redo (cb: StandardCallback): boolean {
const { histories, histories2 } = this
if (histories2.length > 0) {
const history = histories2.pop()
if (history) {
this.resetByHistory(history, cb, 'redo')
histories.push(history)
this.change(this.data)
}
}
return this.isRedo()
}
isUndo (): boolean {
return this.histories.length > 0
}
undo (cb: StandardCallback): boolean {
const { histories, histories2 } = this
// console.log('histories:', histories, histories2)
if (histories.length > 0) {
const history = histories.pop()
if (history) {
this.resetByHistory(history, cb, 'undo')
histories2.push(history)
this.change(this.data)
}
}
return this.isUndo()
}
resetByHistory (v: History, cb: StandardCallback, state: 'undo' | 'redo') {
// console.log('history: ', history)
v.values.forEach(([keys, oldValue, value]) => {
if (v.type === 'cells') {
const v = state === 'undo' ? oldValue : value
const oldCell = this.getCell(keys[0], keys[1])
if (!oldCell) {
if (keys.length === 3) {
if (v) {
const nValue: Cell = {}
nValue[keys[2]] = v
cb(keys[0], keys[1], this.cell(keys[0], keys[1], nValue))
}
} else {
cb(keys[0], keys[1], this.cell(keys[0], keys[1], v || {}))
}
} else {
if (keys.length === 3) {
const nValue: Cell = {}
nValue[keys[2]] = v
if (v) {
cb(keys[0], keys[1], this.cell(keys[0], keys[1], nValue, true))
} else {
cb(keys[0], keys[1], this.cell(keys[0], keys[1], mapIntFilter(oldCell, keys[2])))
}
} else {
cb(keys[0], keys[1], this.cell(keys[0], keys[1], v || {}))
}
}
} else {
// cols, rows
// const v = state === 'undo' ? oldValue : value
// if (v !== null) {
// this.data[v.type]
// }
}
// console.log('keys:', keys, ', oldValue:', oldValue, ', value:', value)
})
}
clearformat (cb: StandardCallback) {
const { select } = this
if (select !== null) {
const history = new History('cells')
select.forEach((rindex, cindex, i, j, rowspan, colspan) => {
let c = this.getCell(rindex, cindex);
if (c) {
history.add([rindex, cindex], c, {text: c.text})
c = this.cell(rindex, cindex, {text: c.text});
cb(rindex, cindex, c);
}
});
this.histories.push(history)
this.change(this.data)
}
}
/**
*
* @param ok 合并单元格第一个单元格(左上角)的回调函数
* @param cancel 取消合并单元格第一个单元格(左上角)的回调函数
* @param other 其他单元格的回调函数
*/
merge (ok: StandardCallback, cancel: StandardCallback, other: StandardCallback): void {
const { select } = this
// console.log('data.before: ', this.data)
if (select !== null && select.cellLen() > 1) {
// merge merge: [rows[0], cols[0]]
const history = new History('cells')
let index = 0
let firstXY: [number, number] = [0, 0]
select.forEach((rindex, cindex, i, j, rowspan, colspan) => {
if (index++ === 0) {
firstXY = [rindex, cindex]
let v: Cell = {}
if (rowspan > 1) v.rowspan = rowspan
if (colspan > 1) v.colspan = colspan
// console.log('rowspan:', rowspan, ', colspan:', colspan, select.canMerge)
if (select.canMerge) {
history.add([rindex, cindex, 'rowspan'], undefined, rowspan)
history.add([rindex, cindex, 'colspan'], undefined, colspan)
let cell = this.cell(rindex, cindex, v, true)
ok(rindex, cindex, cell)
} else {
const oldCell = this.getCell(rindex, cindex)
if (oldCell !== null) {
history.add([rindex, cindex, 'rowspan'], oldCell.rowspan, undefined)
history.add([rindex, cindex, 'colspan'], oldCell.colspan, undefined)
let cell = this.cell(rindex, cindex, mapIntFilter(oldCell, 'rowspan', 'colspan', 'merge'))
cancel(rindex, cindex, cell)
}
}
} else {
let v: Cell = {invisible: select.canMerge}
if (select.canMerge) {
history.add([rindex, cindex, 'invisible'], undefined, select.canMerge)
v.merge = firstXY
let cell = this.cell(rindex, cindex, v, true)
other(rindex, cindex, cell)
} else {
const oldCell = this.getCell(rindex, cindex)
if (oldCell !== null) {
history.add([rindex, cindex, 'invisible'], oldCell.invisible, undefined)
let cell = this.cell(rindex, cindex, mapIntFilter(oldCell, 'rowspan', 'colspan', 'merge', 'invisible'))
other(rindex, cindex, cell)
}
}
}
})
this.histories.push(history)
select.canMerge = !select.canMerge
this.change(this.data)
}
}
cellAttr (key: keyof Cell, value: any, cb: StandardCallback): void {
let v: Cell= {}
v[key] = value
const isDefault = value === this.data.cell[key]
if (this.select !== null) {
const history = new History('cells')
this.select.forEach((rindex, cindex) => {
const oldCell = this.getCell(rindex, cindex)
history.add([rindex, cindex, key], oldCell !== null ? oldCell[key] : undefined, value)
let cell = this.cell(rindex, cindex, isDefault ? mapIntFilter(oldCell, key) : v, !isDefault)
cb(rindex, cindex, cell)
})
this.histories.push(history)
}
this.change(this.data)
}
cellText (value: any, cb: StandardCallback): Cell | null {
if (this.currentCellIndexes) {
// this.addHistoryValues()
const history = new History('cells')
const [rindex, cindex] = this.currentCellIndexes
const oldCell = this.getCell(rindex, cindex)
history.add([rindex, cindex, 'text'], oldCell !== null ? oldCell.text : undefined, value)
const cell = this.cell(rindex, cindex, {text: value}, true)
cb(rindex, cindex, cell)
this.histories.push(history)
this.change(this.data)
return cell;
}
return null
}
currentCell (indexes?: [number, number]): Cell | null {
if (indexes !== undefined) {
this.currentCellIndexes = indexes
}
const [rindex, cindex] = this.currentCellIndexes
return this.getCell(rindex, cindex)
}
cell (rindex: number, cindex: number, v: any, isCopy = false): Cell {
this.data.cells = this.data.cells || {}
this.data.cells[rindex] = this.data.cells[rindex] || {}
this.data.cells[rindex][cindex] = this.data.cells[rindex][cindex] || {}
if (isCopy) {
(<any>Object).assign(this.data.cells[rindex][cindex], v)
} else if (v) {
this.data.cells[rindex][cindex] = v
}
return this.data.cells[rindex][cindex]
}
getCell (rindex: number, cindex: number): Cell | null {
if (this.data.cells && this.data.cells[rindex] && this.data.cells[rindex][cindex]) {
return this.data.cells[rindex][cindex];
}
return null;
}
getFont (key: string | undefined) {
return this.fonts.filter(it => it.key === key)[0]
}
getFormat (key: string | undefined) {
return this.formats.filter(it => it.key === key)[0]
}
row (index: number, v?: number): Row {
const { data } = this;
if (v !== undefined) {
const history = new History('rows')
data.rows = data.rows || {}
data.rows[index] = data.rows[index] || {}
data.rows[index].height = v
history.add([index], null, data.rows[index])
this.histories.push(history)
}
return (<any>Object).assign({height: data.rowHeight}, data.rows ? data.rows[index] : {})
}
// isData 是否返回数据的最大行数
rows (isData: boolean): Array<Row> {
const { data } = this;
let maxRow;
if (isData) {
maxRow = 10
if (this.data.cells) {
maxRow = mapIntMaxKey(this.data.cells) + 2
}
} else {
maxRow = mapIntMaxKeyWithDefault(100, data.rows)
}
return range(maxRow, (index) => this.row(index))
}
col (index: number, v?: number): Col {
const { data } = this;
if (v !== undefined) {
const history = new History('cols')
data.cols = data.cols || {}
data.cols[index] = data.cols[index] || {}
data.cols[index].width = v
history.add([index], null, data.cols[index])
this.histories.push(history)
}
const ret:any = {width: data.colWidth, title: alphabet(index)}
if (data.cols && data.cols[index]) {
for (let prop in data.cols[index]) {
const col:any = data.cols[index]
if (col[prop]) {
ret[prop] = col[prop]
}
}
}
return ret
}
cols (): Array<Col> {
const { data } = this;
let maxCol = mapIntMaxKeyWithDefault(26 * 2, data.cols);
return range(maxCol, (index) => this.col(index));
}
}
const mapIntMaxKey = function<T>(mapInt: MapInt<T>): number {
return Math.max(...Object.keys(mapInt).map(s => parseInt(s)))
}
// methods
const mapIntMaxKeyWithDefault = function<T>(max: number, mapInt: MapInt<T> | undefined): number {
if (mapInt) {
const m = mapIntMaxKey(mapInt)
if (m > max) return m;
}
return max;
}
const mapIntFilter = function(obj: any, ...keys: Array<any>): any {
const ret: any = {}
if (obj){
Object.keys(obj).forEach(e => {
if (keys.indexOf(e) === -1) {
ret[e] = obj[e]
}
})
}
return ret
}
const range = function<T>(stop:number, cb: (index: number) => T): Array<T> {
const ret = []
for (let i = 0; i < stop; i++) {
ret.push(cb(i))
}
return ret
}
const getElementAttrs = (target: any) => {
const { offsetTop, offsetLeft, offsetHeight, offsetWidth } = target
return {
row: parseInt(target.getAttribute('row-index')),
col: parseInt(target.getAttribute('col-index')),
rowspan: parseInt(target.getAttribute('rowspan')),
colspan: parseInt(target.getAttribute('colspan')),
left: offsetLeft,
top: offsetTop,
width: offsetWidth,
height: offsetHeight
}
}
const calcMinMaxCol = (cell: any, sRow: number, eRow: number, sCol: number, eCol: number) => {
let minCol = sCol
let maxCol = eCol
// console.log(':::::::;start: ', maxCol, minCol)
for (let j = sRow; j <= eRow; j++) {
let cCol = sCol
let dcell = cell(j, cCol)
if (dcell && dcell.merge) {
cCol += dcell.merge[1] - cCol
}
if (cCol < minCol) minCol = cCol
cCol = maxCol
dcell = cell(j, cCol)
// console.log(j, cCol, dcell && dcell.colspan || 1)
const cColspan = dcell ? dcell.colspan : 1
if (parseInt(cColspan) > 1) {
cCol += parseInt(cColspan)
} else {
if (dcell && dcell.merge) {
// console.log('merge::', maxCol, dcell.merge)
const [r, c] = dcell.merge
const rc = cell(r, c).colspan
cCol += rc + (c - cCol)
}
}
// console.log('cCol: ', cCol, ', maxCol: ', maxCol)
// console.log(':::::::;end: ', maxCol, minCol)
if (cCol - 1 > maxCol) maxCol = cCol - 1
}
return [minCol, maxCol]
}
const calcMinMaxRow = (cell: any, sRow: number, eRow: number, sCol: number, eCol: number) => {
let minRow = sRow
let maxRow = eRow
for (let j = sCol; j <= eCol; j++) {
let cRow = sRow
let dcell = cell(cRow, j)
if (dcell && dcell.merge) {
cRow += dcell.merge[0] - cRow
}
if (cRow < minRow) minRow = cRow
cRow = maxRow
dcell = cell(cRow, j)
// console.log('row: ', j, cRow, dcell.rowspan)
const cRowspan = dcell ? dcell.rowspan : 1
if (parseInt(cRowspan) > 1) {
cRow += parseInt(cRowspan)
} else {
if (dcell && dcell.merge) {
const [r, c] = dcell.merge
const rs = cell(r, c).rowspan
cRow += rs + (r - cRow)
}
}
if (cRow - 1 > maxRow) maxRow = cRow - 1
}
return [minRow, maxRow]
}
================================================
FILE: src/core/select.d.ts
================================================
export declare class Select {
start: [number, number];
stop: [number, number];
canMerge: boolean;
constructor(start: [number, number], stop: [number, number], canMerge: boolean);
forEach(cb: (r: number, c: number, rindex: number, cindex: number, rowspan: number, colspan: number) => void): void;
rowIndex(index: number): number;
colIndex(index: number): number;
rowLen(): number;
colLen(): number;
cellLen(): number;
contains(rindex: number, cindex: number): boolean;
}
================================================
FILE: src/core/select.ts
================================================
export class Select {
constructor(public start: [number, number], public stop: [number, number], public canMerge: boolean) {}
forEach (cb: (r:number, c: number, rindex: number, cindex: number, rowspan: number, colspan: number) => void): void {
const [sx, sy] = this.start
const [ex, ey] = this.stop
for (let i = sx; i <= ex; i++) {
for (let j = sy; j <= ey; j++) {
cb(i, j, i - sx, j - sy, ex - sx + 1, ey - sy + 1)
}
}
}
rowIndex (index: number) {
return this.start[0] + index % this.rowLen()
}
colIndex (index: number) {
return this.start[1] + index % this.colLen()
}
rowLen () {
return this.stop[0] - this.start[0] + 1
}
colLen () {
return this.stop[1] - this.start[1] + 1
}
cellLen () {
return this.rowLen() * this.colLen()
}
contains (rindex: number, cindex: number) {
const [sx, sy] = this.start
const [ex, ey] = this.stop
return sx <= rindex && ex >= rindex && sy <= cindex && ey >= cindex
}
}
// export function buildSelect (start: any, end: )
================================================
FILE: src/local/base/colorPanel.d.ts
================================================
import { Element } from "./element";
export declare class ColorPanel extends Element {
constructor(click: (color: string) => void);
}
export declare function buildColorPanel(click: (color: string) => void): ColorPanel;
================================================
FILE: src/local/base/colorPanel.ts
================================================
import { Element, h } from "./element";
const colorss = [
['#c00000', '#ff0000', '#ffc003', '#ffff00','#91d051', '#00af50', '#00b0f0', '#0070c0', '#002060', '#70309f'],
['#ffffff', '#000000', '#e7e6e6', '#44546a', '#4472c4', '#ed7d31', '#a5a5a5', '#ffc003', '#5b9bd5', '#70ad47'],
['#f4f5f8', '#848484', '#d0cece', '#d6dce4', '#d9e2f2', '#fae5d5', '#ededed', '#fff2cc', '#deebf6', '#e2efd9'],
['#d8d8d8', '#595959', '#afabab', '#adb9ca', '#b4c6e7', '#f7cbac', '#dbdbdb', '#fee598', '#bdd7ee', '#c5e0b3'],
['#bfbfbf', '#3f3f3f', '#757070', '#8496b0', '#8eaad8', '#f4b183', '#c9c9c9', '#ffd964', '#9dc2e5', '#a8d08d'],
['#a5a5a5', '#262626', '#3a3838', '#333f4f', '#2f5496', '#c55b11', '#7b7b7b', '#bf9001', '#2e75b5', '#538135'],
['#7e7e7e', '#0c0c0c', '#171616', '#232a35', '#1e3864', '#833d0b', '#525252', '#7e6000', '#1f4e79', '#375623']
]
export class ColorPanel extends Element {
constructor (click: (color: string) => void) {
super();
this.class('spreadsheet-color-panel')
.child(
h('table').child(
h('tbody').children(
colorss.map(colors => {
return h('tr').children(
colors.map(color => {
return h('td').child(
h()
.class('color-cell')
.on('click', click.bind(null, color))
.style('background-color', color)
)
})
)
})
)));
}
}
export function buildColorPanel (click: (color: string) => void) {
return new ColorPanel(click);
}
================================================
FILE: src/local/base/dropdown.d.ts
================================================
import { Element } from "./element";
export declare class Dropdown extends Element {
content: Element;
title: Element;
constructor(title: string | Element, width: string, contentChildren: Element[]);
toggleHandler(evt: Event): void;
}
export declare function buildDropdown(title: string | Element, width: string, contentChildren: Element[]): Dropdown;
================================================
FILE: src/local/base/dropdown.ts
================================================
import { Element, h } from "./element";
import { buildIcon } from "./icon";
export class Dropdown extends Element {
content: Element;
title: Element;
constructor (title: string | Element, width: string, contentChildren: Element[]) {
super();
this.class('spreadsheet-dropdown spreadsheet-item');
this.content = h().class('spreadsheet-dropdown-content')
.children(contentChildren)
.onClickOutside(() => this.deactive())
.on('click', (evt) => this.toggleHandler(evt))
.style('width', width).hide();
this.child(h().class('spreadsheet-dropdown-header').children([
this.title = typeof title === 'string' ? h().class('spreadsheet-dropdown-title').child(title) : title,
h().class('spreadsheet-dropdown-icon').on('click', (evt) => this.toggleHandler(evt)).child(buildIcon('arrow-down'))
])).child(this.content);
}
toggleHandler (evt: Event) {
if (this.content.isHide()){
this.content.show()
this.active()
} else {
this.content.hide()
this.deactive()
}
}
}
export function buildDropdown(title: string | Element, width: string, contentChildren: Element[]) {
return new Dropdown(title, width, contentChildren)
}
================================================
FILE: src/local/base/element.d.ts
================================================
export declare class Element {
tag: string;
el: HTMLElement;
_data: {
[key: string]: any;
};
_clickOutside: any;
constructor(tag?: string);
data(key: string, value?: any): any;
on(eventName: string, handler: (evt: any) => any): Element;
onClickOutside(cb: () => void): Element;
parent(): any;
class(name: string): Element;
attrs(map?: {
[key: string]: string;
}): Element;
attr(attr: string, value?: any): any;
removeAttr(attr: string): Element;
offset(): any;
clearStyle(): this;
styles(map?: {
[key: string]: string;
}, isClear?: boolean): Element;
style(key: string, value?: any): any;
contains(el: any): boolean;
removeStyle(key: string): void;
children(cs: Array<HTMLElement | string | Element>): Element;
child(c: HTMLElement | string | Element): Element;
html(html?: string): string | this;
val(v?: string): any;
clone(): any;
isHide(): boolean;
toggle(): void;
disabled(): Element;
able(): Element;
active(flag?: boolean): Element;
deactive(): Element;
isActive(): boolean;
addClass(cls: string): Element;
removeClass(cls: string): this;
hasClass(cls: string): boolean;
show(isRemove?: boolean): Element;
hide(): Element;
}
export declare function h(tag?: string): Element;
================================================
FILE: src/local/base/element.ts
================================================
import { bind, unbind } from '../event'
export class Element {
el: HTMLElement;
_data: {[key: string]: any} = {};
_clickOutside: any = null;
constructor (public tag = 'div') {
this.el = document.createElement(tag)
}
data (key: string, value?: any) {
if (value !== undefined) {
this._data[key] = value
}
return this._data[key]
}
on (eventName: string, handler: (evt: any) => any): Element {
const [first, ...others] = eventName.split('.')
// console.log('first:', first, ', others:', others)
this.el.addEventListener(first, (evt: any) => {
// console.log('>>>', others, evt.button)
for (let k of others) {
console.log('::::::::::', k)
if (k === 'left' && evt.button !== 0) {
return
} else if (k === 'right' && evt.button !== 2) {
return
} else if (k === 'stop') {
evt.stopPropagation()
}
}
// console.log('>>>>>>>>>>>>')
handler(evt)
})
return this;
}
onClickOutside (cb: () => void): Element {
this._clickOutside = cb
return this;
}
parent(): any {
return this.el.parentNode
}
class (name: string): Element {
this.el.className = name
return this;
}
attrs (map: {[key: string]: string} = {}): Element {
for (let key of Object.keys(map))
this.attr(key, map[key]);
return this;
}
attr (attr: string, value?: any): any {
if (value !== undefined) {
this.el.setAttribute(attr, value);
} else {
return this.el.getAttribute(attr)
}
return this;
}
removeAttr(attr: string): Element {
this.el.removeAttribute(attr);
return this;
}
offset (): any {
const { offsetTop, offsetLeft, offsetHeight, offsetWidth } = this.el
return {top: offsetTop, left: offsetLeft, height: offsetHeight, width: offsetWidth}
}
clearStyle () {
(<any>this.el).style = ''
return this;
}
styles (map: {[key: string]: string} = {}, isClear = false): Element {
if (isClear) {
this.clearStyle()
}
for (let key of Object.keys(map))
this.style(key, map[key]);
return this;
}
style (key: string, value?: any): any {
if (value !== undefined) {
this.el.style.setProperty(key, value);
} else {
return this.el.style.getPropertyValue(key)
}
return this;
}
contains (el: any) {
return this.el.contains(el)
}
removeStyle (key: string) {
this.el.style.removeProperty(key)
return ;
}
children (cs: Array<HTMLElement | string | Element>): Element {
for (let c of cs)
this.child(c);
return this;
}
child (c: HTMLElement | string | Element): Element {
if (typeof c === 'string') {
this.el.appendChild(document.createTextNode(c))
} else if (c instanceof Element) {
this.el.appendChild(c.el)
} else if (c instanceof HTMLElement) {
this.el.appendChild(c)
}
return this;
}
html (html?: string) {
if (html !== undefined) {
this.el.innerHTML = html
} else {
return this.el.innerHTML
}
return this;
}
val (v?: string) {
if (v !== undefined) {
// (<any>this.el).value = v
(<any>this.el).value = v
} else {
return (<any>this.el).value
}
return this;
}
clone (): any {
return this.el.cloneNode();
}
isHide () {
return this.style('display') === 'none'
}
toggle () {
if (this.isHide()) {
this.show()
} else {
this.hide()
}
}
disabled (): Element {
// this.removeClass('disabled')
this.addClass('disabled')
return this;
}
able (): Element {
this.removeClass('disabled')
return this;
}
active (flag = true): Element {
// this.el.className = this.el.className.split(' ').filter(c => c !== 'disabled').join(' ') + ' active'
// this.removeClass('disabled')
if (flag)
this.addClass('active')
else
this.deactive()
return this;
}
deactive (): Element {
return this.removeClass('active')
}
isActive (): boolean {
return this.hasClass('active');
}
addClass (cls: string): Element {
this.el.className = this.el.className.split(' ').concat(cls).join(' ')
return this;
}
removeClass (cls: string) {
// console.log('before.className: ', this.el.className)
this.el.className = this.el.className.split(' ').filter(c => c !== cls).join(' ')
// console.log('after.className: ', this.el.className)
return this;
}
hasClass (cls: string) {
return this.el.className.indexOf(cls) !== -1
}
show (isRemove = false): Element {
isRemove ? this.removeStyle('display') : this.style('display', 'block');
// clickoutside
if (this._clickOutside) {
this.data('_outsidehandler', (evt: Event) => {
if (this.contains(evt.target)) {
return false
}
this.hide()
unbind('click', this.data('_outsidehandler'))
this._clickOutside && this._clickOutside()
})
setTimeout(() => {
bind('click', this.data('_outsidehandler'))
}, 0)
}
return this;
}
hide (): Element {
this.style('display', 'none');
if (this._clickOutside) {
unbind('click', this.data('_outsidehandler'))
}
return this;
}
}
export function h (tag = 'div'): Element {
return new Element(tag)
}
================================================
FILE: src/local/base/icon.d.ts
================================================
import { Element } from "./element";
export declare class Icon extends Element {
img: Element;
constructor(name: string);
replace(name: string): void;
}
export declare function buildIcon(name: string): Icon;
================================================
FILE: src/local/base/icon.ts
================================================
import { Element, h } from "./element";
export class Icon extends Element{
img: Element;
constructor (name: string) {
super();
this.class('spreadsheet-icon').child(this.img = h().class(`spreadsheet-icon-img ${name}`));
}
replace (name: string) {
this.img.class(`spreadsheet-icon-img ${name}`)
}
}
export function buildIcon (name: string) {
return new Icon(name);
}
================================================
FILE: src/local/base/item.d.ts
================================================
import { Element } from "./element";
import { Icon } from "./icon";
export declare class Item extends Element {
iconEl: Icon | null;
static build(): Item;
constructor();
icon(name: string): this;
replaceIcon(name: string): void;
}
export declare function buildItem(): Item;
================================================
FILE: src/local/base/item.ts
================================================
import { Element } from "./element";
import { Icon, buildIcon } from "./icon";
export class Item extends Element {
iconEl: Icon | null = null;
static build (): Item {
return new Item()
}
constructor () {
super();
this.class('spreadsheet-item');
}
icon (name: string) {
this.child(this.iconEl = buildIcon(name))
return this;
}
replaceIcon (name: string) {
this.iconEl && this.iconEl.replace(name)
}
}
export function buildItem (): Item {
return new Item();
}
================================================
FILE: src/local/base/menu.d.ts
================================================
import { Element } from "./element";
export declare class Menu extends Element {
constructor(align?: string);
}
export declare function buildMenu(align?: string): Menu;
================================================
FILE: src/local/base/menu.ts
================================================
import { Element } from "./element";
export class Menu extends Element{
constructor (align = 'vertical') {
super();
this.class(`spreadsheet-menu ${align}`)
}
}
export function buildMenu (align = 'vertical') {
return new Menu(align);
}
================================================
FILE: src/local/base/suggest.d.ts
================================================
import { Element } from "./element";
export declare class Suggest extends Element {
list: Array<[string, string]>;
width: number;
filterList: Array<Element>;
currentIndex: number;
target: Element | null;
evtTarget: Element | null;
itemClick: (it: [string, string]) => void;
constructor(list: Array<[string, string]>, width: number);
private documentHandler;
private documentKeydownHandler;
private hideAndRemoveEvents;
private removeEvents;
private clickItemHandler;
search(target: Element, input: Element, word: string): void;
}
================================================
FILE: src/local/base/suggest.ts
================================================
import { Element, h } from "./element";
import { buildItem } from "./item";
import { buildMenu } from "./menu";
import { bind, unbind } from "../event";
export class Suggest extends Element {
filterList: Array<Element> = [];
currentIndex = 0;
target: Element | null = null;
evtTarget: Element | null = null;
itemClick: (it: [string, string]) => void = (it) => {}
constructor (public list: Array<[string, string]>, public width: number) {
super();
this.class('spreadsheet-suggest').hide()
}
private documentHandler (e: any) {
if (this.el.contains(e.target)) {
return false
}
this.hideAndRemoveEvents()
}
private documentKeydownHandler (e: any) {
console.log('keyCode: ', e)
if (this.filterList.length <= 0 && e.target.type !== 'textarea') return ;
switch (e.keyCode) {
case 37: // left
e.returnValue = false
break;
case 38: // up
this.filterList[this.currentIndex].deactive()
this.currentIndex--
if (this.currentIndex < 0) {
this.currentIndex = this.filterList.length - 1
}
this.filterList[this.currentIndex].active()
e.returnValue = false
e.stopPropagation();
break;
case 39: // right
e.returnValue = false
break;
case 40: // down
this.filterList[this.currentIndex].deactive()
this.currentIndex++
if (this.currentIndex > this.filterList.length - 1) {
this.currentIndex = 0
}
this.filterList[this.currentIndex].active()
e.returnValue = false
break;
case 13: // enter
this.filterList[this.currentIndex].el.click()
e.returnValue = false
break;
}
e.stopPropagation();
}
private hideAndRemoveEvents () {
this.hide()
this.removeEvents();
}
private removeEvents () {
if (this.evtTarget !== null) {
unbind('click', this.data('_outsidehandler'), this.evtTarget.el)
unbind('keydown', this.data('_keydownhandler'), this.evtTarget.el)
}
}
private clickItemHandler (it: [string, string]) {
// console.log('click.it: ', it)
this.itemClick(it)
this.hideAndRemoveEvents()
}
search (target: Element, input: Element, word: string) {
this.removeEvents()
this.target = target;
this.evtTarget = input;
const { left, top, width, height } = target.offset()
this.styles({left: `${left}px`, top: `${top + height + 2}px`, width: `${this.width}px`})
let lis: any = this.list
if (!/^\s*$/.test(word)) {
lis = this.list.filter(it => it[0].startsWith(word.toUpperCase()))
}
lis = lis.map((it: [string, string]) => {
const item = buildItem().on('click', (evt) => this.clickItemHandler(it)).child(it[0])
if (it[1]) {
item.child(h().class('label').html(it[1]))
}
return item
// return `<div class="spreadsheet-item" it-key="${it[0]}">${it[0]}${it[1] ? '<div class="label">'+it[1]+'</div>' : ''}</div>`
})
this.filterList = lis
this.currentIndex = 0
if (lis.length <= 0) {
lis = [buildItem().child('No Result')] // `<div class="spreadsheet-item disabled">No Result</div>`
} else {
lis[0].active()
// clickoutside
this.data('_outsidehandler', (evt: Event) => {
this.documentHandler(evt)
})
this.data('_keydownhandler', (evt: any) => this.documentKeydownHandler(evt))
setTimeout(() => {
if (this.evtTarget !== null) {
bind('click', this.data('_outsidehandler'), this.evtTarget.el)
bind('keydown', this.data('_keydownhandler'), this.evtTarget.el)
}
}, 0)
}
this.html(``)
this.child(buildMenu().children(lis)).show()
}
}
================================================
FILE: src/local/contextmenu.d.ts
================================================
import { Element } from "./base/element";
import { Table } from "./table";
export declare class ContextMenu {
table: Table;
el: Element;
constructor(table: Table);
set(evt: any): void;
}
================================================
FILE: src/local/contextmenu.ts
================================================
import { Element, h } from "./base/element";
import { buildItem } from "./base/item";
import { buildMenu } from "./base/menu";
import { Table } from "./table"
export class ContextMenu {
el: Element;
constructor (public table: Table) {
this.el = h().class('spreadsheet-contextmenu')
.style('width', '160px')
.on('click', (evt: any) => this.el.hide())
.children([
buildMenu().children([
buildItem().on('click', (evt) => table.copy()).children(['copy', h().class('label').html('ctrl + c')]),
buildItem().on('click', (evt) => table.cut()).children(['cut', h().class('label').html('ctrl + x')]),
buildItem().on('click', (evt) => table.paste()).children(['paste', h().class('label').html('ctrl + v')]),
// h().class('spreadsheet-item-separator'),
// buildItem().on('click', (evt) => table.insert('row', 1)).html('insert row'),
// buildItem().on('click', (evt) => table.insert('col', 1)).html('insert col')
])
]).onClickOutside(() => {}).hide()
// clickoutside
}
set (evt: any) {
const { offsetLeft, offsetTop } = evt.target
const elRect = this.el.el.getBoundingClientRect()
// cal left top
const { clientWidth, clientHeight } = document.documentElement
let top = offsetTop + evt.offsetY
let left = offsetLeft + evt.offsetX
if (evt.clientY > clientHeight / 1.5) {
top -= elRect.height
}
if (evt.clientX > clientWidth / 1.5) {
left -= elRect.width
}
this.el.style('left', `${left}px`).style('top', `${top}px`).show()
}
}
================================================
FILE: src/local/editor.d.ts
================================================
import { Element } from "./base/element";
import { Suggest } from "./base/suggest";
import { Cell } from "../core/cell";
import { Formula } from "../core/formula";
export declare class Editor {
defaultRowHeight: number;
formulas: Array<Formula>;
el: Element;
target: HTMLElement | null;
value: Cell | null;
editor: Element;
textarea: Element;
textline: Element;
suggest: Suggest;
change: (v: Cell) => void;
constructor(defaultRowHeight: number, formulas: Array<Formula>);
onChange(change: (v: Cell) => void): void;
set(target: HTMLElement, value: Cell | null): void;
setValue(value: Cell | null): string;
setStyle(value: Cell | null): void;
clear(): void;
private setTextareaRange;
private inputKeydown;
private inputChange;
private autocomplete;
reload(): void;
}
================================================
FILE: src/local/editor.ts
================================================
import { Element, h } from "./base/element";
import { Suggest } from "./base/suggest";
import { Cell, getStyleFromCell } from "../core/cell"
import { Formula } from "../core/formula";
export class Editor {
el: Element;
target: HTMLElement | null = null; // 选中的当前的element
value: Cell | null = null; // 选中的当前的cell
editor: Element;
textarea: Element;
textline: Element; // 计算输入文本的宽度用的element
suggest: Suggest; // autocomplete show
change: (v: Cell) => void = (v) => {};
constructor (public defaultRowHeight: number, public formulas : Array<Formula>) {
const suggestList: any = formulas.map(it => [it.key, it.title])
this.el = h().children([this.editor = h().class('spreadsheet-editor').children([
this.textarea = h('textarea')
.on('keydown', (evt: any) => this.inputKeydown(evt))
.on('input', (evt: Event) => this.inputChange(evt)),
this.textline = h().styles({visibility: 'hidden', overflow: 'hidden', position: 'fixed', top: '0', left: '0'})
])
, this.suggest = new Suggest(suggestList, 180)]).hide()
this.el.on('keydown', (evt: any) => {
if (evt.keyCode !== 13 && evt.keyCode !== 9) {
evt.stopPropagation();
}
})
this.suggest.itemClick = (it) => {
// console.log('>>>>>>>>>>>>', it)
const text = `=${it[0]}()`;
if (this.value) {
this.value.text = text
}
this.textarea.val(text);
this.textline.html(text);
this.setTextareaRange(text.length - 1)
// (<any>this.textarea.el).setSelectionRange(text.length + 1, text.length + 1);
// setTimeout(() => (<any>this.textarea.el).focus(), 10)
}
}
onChange (change: (v: Cell) => void) {
this.change = change
}
set (target: HTMLElement, value: Cell | null) {
// console.log('set::>>')
this.target = target;
const text = this.setValue(value)
this.el.show();
this.setTextareaRange(text.length)
// (<any>this.textarea.el).setSelectionRange(text.length, text.length);
// setTimeout(() => (<any>this.textarea.el).focus(), 10)
this.reload();
}
setValue (value: Cell | null): string {
this.setStyle(value);
if (value) {
this.value = value;
const text = value.text || '';
this.textarea.val(text);
this.textline.html(text);
return text
} else {
return '';
}
}
setStyle (value: Cell | null): void {
let attrs = {width: this.textarea.style('width'), height: this.textarea.style('height')}
this.textarea.styles(Object.assign(attrs, getStyleFromCell(value)), true)
}
clear () {
// console.log('clear:>>>')
this.el.hide();
this.target = null;
this.value = null;
this.textarea.val('')
this.textline.html('')
}
private setTextareaRange (position: number) {
setTimeout(() => {
(<any>this.textarea.el).setSelectionRange(position, position);
(<any>this.textarea.el).focus()
}, 10)
}
private inputKeydown (evt: any) {
if (evt.keyCode === 13) {
evt.preventDefault()
}
}
private inputChange (evt: any) {
const v = evt.target.value
if (this.value) {
this.value.text = v
} else {
this.value = {text: v}
}
this.change(this.value)
this.autocomplete(v);
this.textline.html(v);
this.reload()
}
private autocomplete (v: string) {
if (v[0] === '=') {
if (!v.includes('(')) {
const search = v.substring(1)
console.log(':::;search word:', search)
this.suggest.search(this.editor, this.textarea, search);
} else {
this.suggest.hide()
}
} else {
this.suggest.hide()
}
}
reload () {
// setTimeout(() => {
if (this.target) {
const { offsetTop, offsetLeft, offsetWidth, offsetHeight } = this.target
this.editor.styles({left: `${offsetLeft - 1}px`, top: `${offsetTop - 1}px`})
this.textarea.styles({width: `${offsetWidth - 8}px`, height: `${offsetHeight - 2}px`})
let ow = this.textline.offset().width + 16
// console.log(maxWidth, ow, '>>>>')
if (this.value) {
if (this.value.wordWrap) {
// 如果单元格自动换行,那么宽度固定,高度变化
// this.textarea.style('height', 'auto');
const h = (parseInt(ow / offsetWidth + '') + (ow % offsetWidth > 0 ? 1 : 0)) * this.defaultRowHeight;
if (h > offsetHeight) {
this.textarea.style('height', `${h}px`);
}
} else {
const clientWidth = document.documentElement.clientWidth
const maxWidth = clientWidth - offsetLeft - 24
if (ow > offsetWidth) {
if (ow > maxWidth) {
// console.log(':::::::::', ow, maxWidth)
const h = (parseInt(ow / maxWidth + '') + (ow % maxWidth > 0 ? 1 : 0)) * this.defaultRowHeight;
if (h > offsetHeight) {
this.textarea.style('height', `${h}px`)
} else {
this.textarea.style('height', `${offsetHeight}px`)
}
ow = maxWidth
}
this.textarea.style('width', `${ow}px`)
}
}
}
this.el.show()
}
// }, 0)
}
}
================================================
FILE: src/local/editorbar.d.ts
================================================
import { Element } from "./base/element";
import { Cell } from "../core/cell";
export declare class Editorbar {
el: Element;
value: Cell | null;
textarea: Element;
label: Element;
change: (v: Cell) => void;
constructor();
set(title: string, value: Cell | null): void;
setValue(value: Cell | null): void;
input(evt: any): void;
}
================================================
FILE: src/local/editorbar.ts
================================================
import { Element, h } from "./base/element";
import { Cell } from "../core/cell";
import { mouseMoveUp } from "./event"
export class Editorbar {
el: Element;
value: Cell | null = null; // 选中的当前的cell
textarea: Element;
label: Element;
change: (v: Cell) => void = (v) => {};
constructor () {
this.el = h().class('spreadsheet-editor-bar').children([
h().class('spreadsheet-formula-bar').children([
this.label = h().class('spreadsheet-formula-label'),
this.textarea = h('textarea').on('input', (evt) => this.input(evt))
]),
// h().class('spreadsheet-formular-bar-resizer').on('mousedown', this.mousedown)
])
}
set (title: string, value: Cell | null) {
this.label.html(title)
this.setValue(value)
}
setValue (value: Cell | null) {
this.value = value
this.textarea.val(value && value.text || '')
}
input (evt: any) {
const v = evt.target.value
if (this.value) {
this.value.text = v
} else {
this.value = {text: v}
}
this.change(this.value)
}
}
================================================
FILE: src/local/event.d.ts
================================================
export declare function bind<T extends Event>(name: string, fn: (evt: T) => void, target?: any): void;
export declare function unbind<T extends Event>(name: string, fn: (evt: T) => void, target?: any): void;
export declare function mouseMoveUp<T extends Event>(movefunc: (evt: T) => void, upfunc: (evt: T) => void): void;
================================================
FILE: src/local/event.ts
================================================
export function bind<T extends Event>(name: string, fn: (evt: T) => void, target: any = window) {
target.addEventListener(name, fn)
}
export function unbind<T extends Event>(name: string, fn: (evt: T) => void, target: any = window) {
target.removeEventListener(name, fn)
}
export function mouseMoveUp<T extends Event> (movefunc: (evt: T) => void, upfunc: (evt: T) => void) {
bind('mousemove', movefunc)
const up = (evt: T) => {
unbind('mousemove', movefunc)
unbind('mouseup', up)
upfunc(evt)
}
bind('mouseup', up)
}
================================================
FILE: src/local/index.d.ts
================================================
import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index';
import '../style/index.less';
import { Table } from './table';
import { Toolbar } from './toolbar';
import { Editorbar } from './editorbar';
export interface Options extends SpreadsheetOptions {
height?: () => number;
mode?: 'design' | 'write' | 'read';
}
export declare class LocalSpreadsheet {
ss: Spreadsheet;
refs: {
[key: string]: HTMLElement;
};
table: Table;
toolbar: Toolbar | null;
editorbar: Editorbar | null;
bindEl: HTMLElement;
options: Options;
_change: (data: SpreadsheetData) => void;
constructor(el: HTMLElement, options?: Options);
loadData(data: SpreadsheetData): LocalSpreadsheet;
change(cb: (data: SpreadsheetData) => void): LocalSpreadsheet;
private render;
private toolbarChange;
private editorbarChange;
private editorChange;
private clickCell;
}
================================================
FILE: src/local/index.ts
================================================
import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index'
import '../style/index.less'
import { Cell, getStyleFromCell } from '../core/cell';
import { Format } from '../core/format';
import { Font } from '../core/font';
import { Editor } from './editor';
import { Selector } from './selector';
import { Table } from './table';
import { Toolbar } from './toolbar';
import { Editorbar } from './editorbar';
import { h, Element } from './base/element'
export interface Options extends SpreadsheetOptions {
height?: () => number;
mode?: 'design' | 'write' | 'read';
}
export class LocalSpreadsheet {
ss: Spreadsheet;
refs: {[key: string]: HTMLElement} = {};
table: Table;
toolbar: Toolbar | null = null;
editorbar: Editorbar | null = null;
bindEl: HTMLElement
options: Options;
_change: (data: SpreadsheetData) => void = () => {}
constructor (el: HTMLElement, options: Options = {}) {
this.bindEl = el
this.options = Object.assign({mode: 'design'}, options)
// clear content in el
this.bindEl && (this.bindEl.innerHTML = '')
this.ss = new Spreadsheet(options);
// console.log('::::>>>select:', this.ss.select)
if (this.options.mode === 'design') {
this.editorbar = new Editorbar()
this.editorbar.change = (v) => this.editorbarChange(v)
this.toolbar = new Toolbar(this.ss);
this.toolbar.change = (key, v) => this.toolbarChange(key, v)
this.toolbar.undo = () => {
// console.log('undo::')
return this.table.undo()
}
this.toolbar.redo = () => {
// console.log('redo::')
return this.table.redo()
}
}
let bodyHeightFn = (): number => {
if (this.options.height) {
return this.options.height()
}
return document.documentElement.clientHeight - 24 - 41 - 26
}
let bodyWidthFn = (): number => {
return this.bindEl.offsetWidth
}
this.table = new Table(this.ss, Object.assign({height: bodyHeightFn, width: bodyWidthFn, mode: this.options.mode}));
this.table.change = (data) => {
this.toolbar && this.toolbar.setRedoAble(this.ss.isRedo())
this.toolbar && this.toolbar.setUndoAble(this.ss.isUndo())
this._change(data)
}
this.table.editorChange = (v) => this.editorChange(v)
this.table.clickCell = (rindex, cindex, cell) => this.clickCell(rindex, cindex, cell)
this.render();
}
loadData (data: SpreadsheetData): LocalSpreadsheet {
// reload until waiting main thread
setTimeout(() => {
this.ss.data = data
this.table.reload()
}, 1)
return this
}
change (cb: (data: SpreadsheetData) => void): LocalSpreadsheet {
this._change = cb
return this;
}
private render (): void {
this.bindEl.appendChild(h().class('spreadsheet').children([
h().class('spreadsheet-bars').children([
this.toolbar && this.toolbar.el || '',
this.editorbar && this.editorbar.el || '',
]),
this.table.el
]).el);
}
private toolbarChange (k: keyof Cell, v: any) {
if (k === 'merge') {
this.table.merge();
return;
} else if (k === 'clearformat') {
this.table.clearformat();
return ;
} else if (k === 'paintformat') {
this.table.copyformat();
return ;
}
this.table.setCellAttr(k, v);
}
private editorbarChange (v: Cell) {
this.table.setValueWithText(v)
}
private editorChange (v: Cell) {
this.editorbar && this.editorbar.setValue(v)
}
private clickCell (rindex: number, cindex: number, v: Cell | null) {
const cols = this.ss.cols()
this.editorbar && this.editorbar.set(`${cols[cindex].title}${rindex + 1}`, v)
this.toolbar && this.toolbar.set(this.table.td(rindex, cindex), v)
}
}
================================================
FILE: src/local/resizer.d.ts
================================================
import { Element } from "./base/element";
export declare class Resizer {
vertical: boolean;
change: (index: number, distance: number) => void;
el: Element;
resizer: Element;
resizerLine: Element;
moving: boolean;
index: number;
constructor(vertical: boolean, change: (index: number, distance: number) => void);
set(target: any, index: number, scroll: number): void;
mousedown(evt: any): void;
}
================================================
FILE: src/local/resizer.ts
================================================
import { Element, h } from "./base/element";
import { mouseMoveUp } from './event';
export class Resizer {
el: Element;
resizer: Element;
resizerLine: Element;
moving: boolean = false;
index: number = 0;
constructor (public vertical: boolean, public change: (index: number, distance: number) => void) {
this.el = h().class('spreadsheet-resizer-wrapper').children([
this.resizer = h().class(`spreadsheet-resizer ${vertical ? 'vertical' : 'horizontal'}`)
.on('mousedown', (evt: Event) => this.mousedown(evt)),
this.resizerLine = h().class(`spreadsheet-resizer-line ${vertical ? 'vertical' : 'horizontal'}`).hide()
])
}
set (target: any, index: number, scroll: number) {
if (this.moving) return ;
this.index = index
const { vertical } = this
const { offsetLeft, offsetTop, offsetHeight, offsetWidth, parentNode } = target
this.resizer.styles({
left: `${vertical ? offsetLeft + offsetWidth - 5 - scroll : offsetLeft}px`,
top: `${vertical ? offsetTop : offsetTop + offsetHeight - 5 + 24 - scroll}px`,
width: `${vertical ? 5 : offsetWidth}px`,
height: `${vertical ? offsetHeight : 5}px`
})
this.resizerLine.styles({
left: `${vertical ? offsetLeft + offsetWidth - scroll : offsetLeft}px`,
top: `${vertical ? offsetTop : offsetTop + offsetHeight + 24 - scroll}px`,
width: `${vertical ? 0 : parentNode.parentNode.parentNode.parentNode.parentNode.nextSibling.offsetWidth - 15}px`,
height: `${vertical ? parentNode.parentNode.parentNode.parentNode.nextSibling.offsetHeight + parentNode.offsetHeight : 0}px`
})
// this.el.show()
}
mousedown (evt: any) {
let startEvt = evt;
let distance = 0;
this.resizerLine.show()
mouseMoveUp((e: any) => {
this.moving = true
if (startEvt !== null && e.buttons === 1) {
if (this.vertical) {
const d = e.x - startEvt.x
distance += d
this.resizer.style('left', `${this.resizer.offset().left + d}px`)
this.resizerLine.style('left', `${this.resizerLine.offset().left + d}px`)
} else {
const d = e.y - startEvt.y
distance += d
this.resizer.style('top', `${this.resizer.offset().top + d}px`)
this.resizerLine.style('top', `${this.resizerLine.offset().top + d}px`)
}
startEvt = e
}
}, (e: any) => {
this.change(this.index, distance)
startEvt = null
this.resizerLine.hide()
distance = 0
this.moving = false
})
}
}
================================================
FILE: src/local/selector.d.ts
================================================
import { Element } from "./base/element";
import { Spreadsheet } from "../core/index";
import { Table } from './table';
export declare class Selector {
ss: Spreadsheet;
table: Table;
topEl: Element;
rightEl: Element;
bottomEl: Element;
leftEl: Element;
areaEl: Element;
cornerEl: Element;
copyEl: Element;
el: Element;
_offset: {
left: number;
top: number;
width: number;
height: number;
};
startTarget: any;
endTarget: any;
change: () => void;
changeCopy: (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) => void;
constructor(ss: Spreadsheet, table: Table);
mousedown(evt: any): void;
setCurrentTarget(target: HTMLElement): void;
private cornerMousedown;
reload(): void;
private setOffset;
private rowsHeight;
private colsWidth;
}
export declare class DashedSelector {
el: Element;
constructor();
set(selector: Selector): void;
hide(): void;
}
================================================
FILE: src/local/selector.ts
================================================
import { Element, h } from "./base/element";
import { bind, mouseMoveUp } from './event';
import { Spreadsheet } from "../core/index";
import { Table } from './table';
export class Selector {
topEl: Element;
rightEl: Element;
bottomEl: Element;
leftEl: Element;
areaEl: Element;
cornerEl: Element;
copyEl: Element;
el: Element;
_offset = {left: 0, top: 0, width: 0, height: 0};
startTarget: any;
endTarget: any;
change: () => void = () => {};
changeCopy: (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) => void
= (evt, arrow, startRow, startCol, stopRow, stopCol) => {};
constructor (public ss: Spreadsheet, public table: Table) {
this.topEl = h().class('top-border');
this.rightEl = h().class('right-border');
this.bottomEl = h().class('bottom-border');
this.leftEl = h().class('left-border');
this.areaEl = h().class('area-border');
this.cornerEl = h().class('corner').on('mousedown', (evt) => this.cornerMousedown(evt));
this.copyEl = h().class('copy-border');
this.el = h().class('spreadsheet-borders').children([
this.topEl,
this.rightEl,
this.bottomEl,
this.leftEl,
this.areaEl,
this.cornerEl,
this.copyEl.hide(),
]).hide()
}
mousedown (evt: any) {
// console.log('>>>>>>>>selector>>')
// console.log(this, evt, evt.type, evt.detail, evt.buttons, evt.button)
if (evt.detail === 1 && evt.target.getAttribute('type') === 'cell') {
// console.log(evt.shiftKey)
if (evt.shiftKey) {
this.endTarget = evt.target
this.setOffset()
return
}
// Object.assign(this, {startTarget: evt.target, endTarget: evt.target})
// this.setOffset()
this.setCurrentTarget(evt.target)
mouseMoveUp((e: any) => {
if (e.buttons === 1 && e.target.getAttribute('type') === 'cell') {
this.endTarget = e.target
this.setOffset()
}
}, (e) => { this.change() })
// show el
this.el.show()
}
}
setCurrentTarget (target: HTMLElement) {
Object.assign(this, {startTarget: target, endTarget: target})
this.setOffset()
}
private cornerMousedown (evt: any) {
const { select } = this.ss
if (select === null) {
return ;
}
const [stopRow, stopCol] = select.stop;
const [startRow, startCol] = select.start;
let boxRange:['bottom' | 'top' | 'left' | 'right', number, number, number, number] | null = null;
mouseMoveUp((e: any) => {
const rowIndex = e.target.getAttribute('row-index')
const colIndex = e.target.getAttribute('col-index')
if (rowIndex && colIndex) {
this.copyEl.show();
let rdiff = stopRow - rowIndex
let cdiff = stopCol - colIndex
let _rdiff = startRow - rowIndex
let _cdiff = startCol - colIndex
const {left, top, height, width} = this._offset;
// console.log(rdiff, cdiff, ',,,', _rdiff, _cdiff)
if (rdiff < 0) {
// bottom
// console.log('FCK=>bottom', this.rowsHeight(stopRow, stopRow + Math.abs(rdiff)), rdiff)
this.copyEl.styles({
left: `${left - 1}px`,
top: `${top - 1}px`,
width: `${width - 1}px`,
height: `${this.rowsHeight(stopRow - select.rowLen() + 1, stopRow + Math.abs(rdiff)) - 1}px`});
boxRange = ['bottom', stopRow + 1, startCol, stopRow + Math.abs(rdiff), stopCol]
} else if (cdiff < 0) {
// right
// console.log('FCK=>right')
this.copyEl.styles({
left: `${left - 1}px`,
top: `${top - 1}px`,
width: `${this.colsWidth(stopCol - select.colLen() + 1, stopCol + Math.abs(cdiff)) - 1}px`,
height: `${height - 1}px`});
boxRange = ['right', startRow, stopCol + 1, stopRow, stopCol + Math.abs(cdiff)]
} else if (_rdiff > 0) {
// top
// console.log('FCK=>top')
const h = this.rowsHeight(startRow - _rdiff, startRow - 1)
this.copyEl.styles({
left: `${left - 1}px`,
top: `${top - h - 1}px`,
width: `${width - 1}px`,
height: `${h - 1}px`});
boxRange = ['top', startRow - _rdiff, startCol, startRow - 1, stopCol]
} else if (_cdiff > 0) {
// left
// console.log('FCK=>left')
const w = this.colsWidth(startCol - _cdiff, startCol - 1)
this.copyEl.styles({
left: `${left - w - 1}px`,
top: `${top - 1}px`,
width: `${w - 1}px`,
height: `${height - 1}px`});
boxRange = ['left', startRow, startCol - _cdiff, stopRow, startCol - 1]
} else {
this.copyEl.styles({
left: `${left - 1}px`,
top: `${top - 1}px`,
width: `${width - 1}px`,
height: `${height - 1}px`});
boxRange = null
}
}
}, (e) => {
this.copyEl.hide()
if (boxRange !== null) {
const [arrow, startRow, startCol, stopRow, stopCol] = boxRange
this.changeCopy(e, arrow, startRow, startCol, stopRow, stopCol)
}
});
}
reload () {
this.setOffset()
}
private setOffset () {
if (this.startTarget === undefined) return ;
let { select } = this.ss
// console.log('select: ', select, this.table)
if (select) {
// console.log('clear>>>>>:::')
// clear
const [minRow, minCol] = select.start
const [maxRow, maxCol] = select.stop
_forEach(minRow, maxRow, this.table.firsttds, (e) => { e.deactive() })
_forEach(minCol, maxCol, this.table.ths, (e) => { e.deactive() })
}
select = this.ss.buildSelect(this.startTarget, this.endTarget)
const [minRow, minCol] = select.start
const [maxRow, maxCol] = select.stop
// let height = 0, width = 0;
const height = this.rowsHeight(minRow, maxRow, (e) => e.active())
// _forEach(minRow, maxRow, this.table.firsttds, (e) => {
// e.active()
// height += parseInt(e.offset().height)
// })
// height /= 2
const width = this.colsWidth(minCol, maxCol, (e) => e.active())
// _forEach(minCol, maxCol, this.table.ths, (e) => {
// e.active()
// width += parseInt(e.offset().width)
// })
// console.log('>>', minRow, minCol, maxRow, maxCol, height, width)
const td = this.table.td(minRow, minCol)
if (td) {
// console.log('td:', td)
const {left, top} = td.offset()
this._offset = {left, top, width, height};
this.topEl.styles({left: `${left - 1}px`, top: `${top - 1}px`, width: `${width + 1}px`, height: '2px'})
this.rightEl.styles({left: `${left + width - 1}px`, top: `${top - 1}px`, width: '2px', height: `${height}px`})
this.bottomEl.styles({left: `${left - 1}px`, top: `${top + height - 1}px`, width: `${width}px`, height: '2px'})
this.leftEl.styles({left: `${left - 1}px`, top: `${top - 1}px`, width: '2px', height: `${height}px`})
this.areaEl.styles({left: `${left}px`, top: `${top}px`, width: `${width - 2}px`, height: `${height - 2}px`})
this.cornerEl.styles({left: `${left + width - 5}px`, top: `${top + height - 5}px`})
}
}
private rowsHeight (minRow:number, maxRow:number, cb: (e: Element) => void = (e) => {}): number {
let height = 0
_forEach(minRow, maxRow, this.table.firsttds, (e) => {
cb(e)
height += parseInt(e.offset().height)
})
height /= 2
return height
}
private colsWidth (minCol: number, maxCol: number, cb: (e: Element) => void = (e) => {}): number {
let width = 0
_forEach(minCol, maxCol, this.table.ths, (e) => {
cb(e)
width += parseInt(e.offset().width)
})
return width
}
}
const _forEach = (start: number, stop: number, elements: {[key: string]: Array<Element> | Element}, cb: (e: Element) => void): void => {
for (let i = start; i <= stop; i++) {
const es = elements[i + ''];
if (es) {
if (es instanceof Element) {
cb(es)
} else {
es.forEach(e => cb(e))
}
}
}
}
export class DashedSelector {
el: Element;
constructor () {
this.el = h().class('spreadsheet-borders dashed').hide();
}
set (selector: Selector) {
if (selector._offset) {
const { left, top, width, height } = selector._offset;
this.el
.style('left', `${left - 2}px`)
.style('top', `${top - 2}px`)
.style('width', `${width}px`)
.style('height', `${height}px`)
.show();
}
}
hide () {
this.el.hide();
}
}
================================================
FILE: src/local/table.d.ts
================================================
import { Element } from "./base/element";
import { Spreadsheet, SpreadsheetData } from '../core/index';
import { Editor } from './editor';
import { Selector, DashedSelector } from './selector';
import { Resizer } from './resizer';
import { ContextMenu } from "./contextmenu";
import { Cell } from "../core/cell";
interface Map<T> {
[key: string]: T;
}
export interface TableOption {
height: () => number;
width: () => number;
mode: 'design' | 'write' | 'read';
}
export declare class Table {
options: TableOption;
cols: Map<Array<Element>>;
firsttds: Map<Array<Element>>;
tds: Map<Element>;
ths: Map<Element>;
ss: Spreadsheet;
formulaCellIndexs: Set<string>;
el: Element;
header: Element;
body: Element;
fixedLeftBody: Element | null;
editor: Editor | null;
rowResizer: Resizer | null;
colResizer: Resizer | null;
contextmenu: ContextMenu | null;
selector: Selector;
dashedSelector: DashedSelector;
state: 'copy' | 'cut' | 'copyformat' | null;
currentIndexs: [number, number] | null;
focusing: boolean;
change: (data: SpreadsheetData) => void;
editorChange: (v: Cell) => void;
clickCell: (rindex: number, cindex: number, v: Cell | null) => void;
constructor(ss: Spreadsheet, options: TableOption);
reload(): void;
private moveLeft;
private moveUp;
private moveDown;
private moveRight;
private moveSelector;
setValueWithText(v: Cell): void;
setTdWithCell(rindex: number, cindex: number, cell: Cell, autoWordWrap?: boolean): void;
setCellAttr(k: keyof Cell, v: any): void;
undo(): boolean;
redo(): boolean;
private setTdStylesAndAttrsAndText;
copy(): void;
cut(): void;
copyformat(): void;
paste(): void;
clearformat(): void;
merge(): void;
insert(type: 'row' | 'col', amount: number): void;
td(rindex: number, cindex: number): Element;
private selectorChange;
private selectorChangeCopy;
private renderCell;
private _renderCell;
private reRenderFormulaCells;
private setRowHeight;
private setTdStyles;
private setTdAttrs;
private changeRowHeight;
private changeRowResizer;
private changeColResizer;
private buildColGroup;
private buildFixedLeft;
private buildHeader;
private mousedownCell;
private editCell;
private buildBody;
private addRow;
private firsttdsPush;
}
export {};
================================================
FILE: src/local/table.ts
================================================
import { Element, h } from "./base/element";
import { Spreadsheet, SpreadsheetData } from '../core/index'
import { Editor } from './editor';
import { Selector, DashedSelector } from './selector';
import { Resizer } from './resizer';
import { Editorbar } from "./editorbar";
import { Toolbar } from "./toolbar";
import { ContextMenu } from "./contextmenu";
import { Cell, getStyleFromCell } from "../core/cell";
import { formatRenderHtml } from "../core/format";
import { formulaRender } from "../core/formula";
import { bind } from "./event";
interface Map<T> {
[key: string]: T
}
export interface TableOption {
height: () => number,
width: () => number,
mode: 'design' | 'write' | 'read';
}
export class Table {
cols: Map<Array<Element>> = {};
firsttds: Map<Array<Element>> = {};
tds: Map<Element> = {};
ths: Map<Element> = {};
ss: Spreadsheet;
formulaCellIndexs: Set<string> = new Set(); // 表达式单元格set
el: Element;
header: Element;
body: Element;
fixedLeftBody: Element | null = null;
editor: Editor | null = null;
rowResizer: Resizer | null = null;
colResizer: Resizer | null = null;
contextmenu: ContextMenu | null = null;
selector: Selector;
dashedSelector: DashedSelector;
state: 'copy' | 'cut' | 'copyformat' | null = null;
currentIndexs: [number, number] | null = null;
// 当前用户是否焦点再table上
focusing: boolean = false;
// change
change: (data: SpreadsheetData) => void = () => {}
editorChange: (v: Cell) => void = (v) => {}
clickCell: (rindex: number, cindex: number, v: Cell | null) => void = (rindex, cindex, v) => {}
constructor (ss: Spreadsheet, public options: TableOption) {
this.ss = ss;
this.ss.change = (data) => {
this.change(data)
}
if (options.mode !== 'read') {
this.editor = new Editor(ss.defaultRowHeight(), ss.formulas)
this.editor.change = (v: Cell) => this.editorChange(v)
}
if (options.mode === 'design') {
this.rowResizer = new Resizer(false, (index, distance) => this.changeRowResizer(index, distance))
this.colResizer = new Resizer(true, (index, distance) => this.changeColResizer(index, distance))
this.contextmenu = new ContextMenu(this)
}
this.selector = new Selector(this.ss, this);
this.selector.change = () => this.selectorChange();
this.selector.changeCopy = (e, arrow, startRow, startCol, stopRow, stopCol) => {
this.selectorChangeCopy(e, arrow, startRow, startCol, stopRow, stopCol);
}
this.dashedSelector = new DashedSelector();
this.el = h().class('spreadsheet-table').children([
this.colResizer && this.colResizer.el || '',
this.rowResizer && this.rowResizer.el || '',
this.buildFixedLeft(),
this.header = this.buildHeader(),
this.body = this.buildBody()
]).on('contextmenu', (evt) => {
evt.returnValue = false
evt.preventDefault();
});
bind('resize', (evt: any) => {
this.header.style('width', `${this.options.width()}px`)
this.body.style('width', `${this.options.width()}px`)
if (this.options.mode !== 'read') {
this.body.style('height', `${this.options.height()}px`)
}
})
bind('click', (evt: any) => {
// console.log('::::::::', this.el.contains(evt.target))
this.focusing = this.el.parent().contains(evt.target)
})
// bind ctrl + c, ctrl + x, ctrl + v
bind('keydown', (evt: any) => {
if (!this.focusing) {
return
}
// console.log('::::::::', evt)
if (!this.focusing) return;
// ctrlKey
if (evt.ctrlKey && evt.target.type !== 'textarea' && this.options.mode !== 'read') {
// ctrl + c
if (evt.keyCode === 67) {
this.copy();
evt.returnValue = false
}
// ctrl + x
if (evt.keyCode === 88) {
this.cut();
evt.returnValue = false
}
// ctrl + v
if (evt.keyCode === 86) {
this.paste();
evt.returnValue = false
}
} else {
// console.log('>>>>>>>>>>>>>>', evt)
switch (evt.keyCode) {
case 37: // left
this.moveLeft()
evt.returnValue = false
break;
case 38: // up
this.moveUp()
evt.returnValue = false
break;
case 39: // right
this.moveRight()
evt.returnValue = false
break;
case 40: // down
this.moveDown()
evt.returnValue = false
break;
case 9: // tab
this.moveRight();
evt.returnValue = false
break;
case 13:
this.moveDown();
evt.returnValue = false
break;
}
// 输入a-zA-Z1-9
if (this.options.mode !== 'read') {
if (evt.keyCode >= 65 && evt.keyCode <= 90 || evt.keyCode >= 48 && evt.keyCode <= 57 || evt.keyCode >= 96 && evt.keyCode <= 105 || evt.keyCode == 187) {
// if (this.currentIndexs) {
// console.log('::::::::', evt.target.type)
if (evt.target.type !== 'textarea') {
this.ss.cellText(evt.key, (rindex, cindex, cell) => {
if (this.editor) {
const td = this.td(rindex, cindex)
td.html(this.renderCell(rindex, cindex, cell))
this.editor.set(td.el, this.ss.currentCell())
}
})
}
}
}
}
});
}
reload () {
this.firsttds = {}
this.el.html('')
this.el.children([
this.colResizer && this.colResizer.el || '',
this.rowResizer && this.rowResizer.el || '',
this.buildFixedLeft(),
this.header = this.buildHeader(),
this.body = this.buildBody()
]);
}
private moveLeft () {
if (this.currentIndexs && this.currentIndexs[1] > 0) {
this.currentIndexs[1] -= 1
this.moveSelector('left')
}
}
private moveUp () {
if (this.currentIndexs && this.currentIndexs[0] > 0) {
this.currentIndexs[0] -= 1
this.moveSelector('up')
}
}
private moveDown () {
if (this.currentIndexs && this.currentIndexs[0] < this.ss.rows(this.options.mode === 'read').length) {
this.currentIndexs[0] += 1
this.moveSelector('down')
}
}
private moveRight () {
if (this.currentIndexs && this.currentIndexs[1] < this.ss.cols().length) {
this.currentIndexs[1] += 1
this.moveSelector('right')
}
}
// 移动选框
private moveSelector (direction: 'right' | 'left' | 'up' | 'down') {
if (this.currentIndexs) {
const [rindex, cindex] = this.currentIndexs
const td = this.td(rindex, cindex)
// console.log('move.td:', td)
if (td) {
this.selector.setCurrentTarget(td.el)
const bodyWidth = this.options.width()
const bodyHeight = this.options.height()
const {left, top, width, height} = td.offset()
// console.log(this.body.el.scrollLeft, ', body-width:', bodyWidth, ', left:', left, ', width=', width)
const leftDiff = left + width - bodyWidth
if (leftDiff > 0 && direction === 'right') {
this.body.el.scrollLeft = leftDiff + 15
}
if (direction === 'left' && this.body.el.scrollLeft + 60 > left) {
this.body.el.scrollLeft -= (this.body.el.scrollLeft + 60 - left)
}
if (direction === 'up' && this.body.el.scrollTop > top) {
this.body.el.scrollTop -= (this.body.el.scrollTop - top)
}
if (direction === 'down' && top + height - bodyHeight > 0) {
this.body.el.scrollTop = top + height - bodyHeight + 15;
}
this.mousedownCell(rindex, cindex)
}
}
}
setValueWithText (v: Cell) {
// console.log('setValueWithText: v = ', v)
if (this.currentIndexs) {
this.ss.cellText(v.text, (rindex, cindex, cell) => {
this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell))
})
}
this.editor && this.editor.setValue(v)
}
setTdWithCell (rindex: number, cindex: number, cell: Cell, autoWordWrap = true) {
this.setTdStyles(rindex, cindex, cell);
this.setRowHeight(rindex, cindex, autoWordWrap);
this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell));
}
setCellAttr (k: keyof Cell, v: any) {
// console.log('::k:', k, '::v:', v)
this.ss.cellAttr(k, v, (rindex, cindex, cell) => {
// console.log(':rindex:', rindex, '; cindex:', cindex, '; cell: ', cell)
this.setTdWithCell(rindex, cindex, cell, k === 'wordWrap' && v);
})
this.editor && this.editor.setStyle(this.ss.currentCell())
}
undo (): boolean {
return this.ss.undo((rindex, cindex, cell) => {
// console.log('>', rindex, ',', cindex, '::', cell)
this.setTdStylesAndAttrsAndText(rindex, cindex, cell)
})
}
redo (): boolean {
return this.ss.redo((rindex, cindex, cell) => {
this.setTdStylesAndAttrsAndText(rindex, cindex, cell)
})
}
private setTdStylesAndAttrsAndText (rindex: number, cindex: number, cell: Cell) {
let td = this.td(rindex, cindex);
this.setTdStyles(rindex, cindex, cell);
this.setTdAttrs(rindex, cindex, cell);
// console.log('txt>>>:', this.renderCell(rindex, cindex, cell))
td.html(this.renderCell(rindex, cindex, cell));
}
copy () {
this.ss.copy();
this.dashedSelector.set(this.selector);
this.state = 'copy';
}
cut () {
this.ss.cut();
this.dashedSelector.set(this.selector);
this.state = 'cut';
}
copyformat () {
this.ss.copy();
this.dashedSelector.set(this.selector);
this.state = 'copyformat';
}
paste () {
// console.log('state: ', this.state, this.ss.select)
if (this.state !== null && this.ss.select) {
this.ss.paste((rindex, cindex, cell) => {
// console.log('rindex: ', rindex, ', cindex: ', cindex);
let td = this.td(rindex, cindex);
this.setTdStyles(rindex, cindex, cell);
this.setTdAttrs(rindex, cindex, cell);
if (this.state === 'cut' || this.state === 'copy') {
td.html(this.renderCell(rindex, cindex, cell));
}
}, this.state, (rindex, cindex, cell) => {
let td = this.td(rindex, cindex);
this.setTdStyles(rindex, cindex, cell);
this.setTdAttrs(rindex, cindex, cell);
td.html('');
});
this.selector.reload();
}
if (this.state === 'copyformat') {
this.state = null;
} else if (this.state === 'cut') {
this.state = null;
} else if (this.state === 'copy') {
// this.ss.paste()
}
this.dashedSelector.hide();
}
clearformat () {
this.ss.clearformat((rindex, cindex, cell) => {
this.td(rindex, cindex)
.removeAttr('rowspan')
.removeAttr('colspan')
.styles({}, true)
.show(true);
})
}
merge () {
this.ss.merge((rindex, cindex, cell) => {
// console.log(rindex, cindex, '>>>', this.table.td(rindex, cindex))
this.setTdAttrs(rindex, cindex, cell).show(true)
}, (rindex, cindex, cell) => {
this.setTdAttrs(rindex, cindex, cell).show(true)
}, (rindex, cindex, cell) => {
let td = this.td(rindex, cindex)
!cell.invisible ? td.show(true) : td.hide()
})
}
// insert
insert (type: 'row' | 'col', amount: number) {
if (type === 'col') {
// insert col
} else if (type === 'row') {
// insert row
}
this.ss.insert(type, amount, (rindex, cindex, cell) => {
this.setTdStylesAndAttrsAndText(rindex, cindex, cell)
})
}
td (rindex: number, cindex: number): Element {
const td = this.tds[`${rindex}_${cindex}`]
return td
}
private selectorChange () {
if (this.state === 'copyformat') {
this.paste();
}
}
private selectorChangeCopy (evt: any, arrow: 'bottom' | 'top' | 'left' | 'right', startRow: number, startCol: number, stopRow: number, stopCol: number) {
this.ss.batchPaste(arrow, startRow, startCol, stopRow, stopCol, evt.ctrlKey, (rindex, cindex, cell) => {
this.setTdStyles(rindex, cindex, cell);
this.setTdAttrs(rindex, cindex, cell);
this.td(rindex, cindex).html(this.renderCell(rindex, cindex, cell));
})
}
private renderCell (rindex: number, cindex: number, cell: Cell | null): string {
if (cell) {
const setKey = `${rindex}_${cindex}`
// console.log('text:', setKey, cell.text && cell.text)
if (cell.text && cell.text[0] === '=') {
this.formulaCellIndexs.add(setKey)
} else {
if (this.formulaCellIndexs.has(setKey)) {
this.formulaCellIndexs.delete(setKey)
}
this.reRenderFormulaCells()
}
return formatRenderHtml(cell.format, this._renderCell(cell))
}
return '';
}
private _renderCell (cell: Cell | null): string {
if (cell) {
let text = cell.text || '';
return formulaRender(text, (rindex, cindex) => this._renderCell(this.ss.getCell(rindex, cindex)))
}
return '';
}
private reRenderFormulaCells () {
// console.log('formulaCellIndex: ', this.formulaCellIndexs)
this.formulaCellIndexs.forEach(it => {
let rcindexes = it.split('_')
const rindex = parseInt(rcindexes[0])
const cindex = parseInt(rcindexes[1])
// console.log('>>>', this.ss.data, this.ss.getCell(rindex, cindex))
const text = this.renderCell(rindex, cindex, this.ss.getCell(rindex, cindex))
this.td(rindex, cindex).html(text);
})
}
private setRowHeight (rindex: number, cindex: number, autoWordWrap: boolean) {
// console.log('rowHeight: ', this.td(rindex, cindex).offset().height, ', autoWordWrap:', autoWordWrap)
// 遍历rindex行的所有单元格,计算最大高度
if (autoWordWrap === false) {
return ;
}
const cols = this.ss.cols()
const td = this.td(rindex, cindex)
let h = td.offset().height
console.log('h:', h)
const tdRowspan = td.attr('rowspan')
if (tdRowspan) {
for (let i = 1; i < parseInt(tdRowspan); i++) {
let firsttds = this.firsttds[(rindex + i) +'']
firsttds && (h -= parseInt(firsttds[0].attr('height') || 0) + 1)
}
}
// console.log('after.h:', h)
this.changeRowHeight(rindex, h - 1);
}
private setTdStyles (rindex: number, cindex: number, cell: Cell): Element {
return this.td(rindex, cindex).styles(getStyleFromCell(cell), true)
}
private setTdAttrs (rindex: number, cindex: number, cell: Cell): Element {
return this.td(rindex, cindex)
.attr('rowspan', cell.rowspan || 1)
.attr('colspan', cell.colspan || 1);
}
private changeRowHeight (index: number, h: number) {
if (h <= this.ss.defaultRowHeight()) return
this.ss.row(index, h)
const firstTds = this.firsttds[index+'']
if (firstTds) {
firstTds.forEach(td => td.attr('height', h))
}
this.selector.reload()
this.editor && this.editor.reload()
}
private changeRowResizer (index: number, distance: number) {
const h = this.ss.row(index).height + distance
this.changeRowHeight(index, h);
}
private changeColResizer (index: number, distance: number) {
const w = this.ss.col(index).width + distance
if (w <= 50) return
this.ss.col(index, w)
const cols = this.cols[index+'']
if (cols) {
cols.forEach(col => col.attr('width', w))
}
this.selector.reload()
this.editor && this.editor.reload()
}
private buildColGroup (lastColWidth: number): Element {
const cols = this.ss.cols();
return h('colgroup').children([
h('col').attr('width', '60'),
...cols.map((col, index) => {
let c = h('col').attr('width', col.width)
this.cols[index+''] = this.cols[index+''] || []
this.cols[index+''].push(c)
return c;
}),
h('col').attr('width', lastColWidth)
])
}
private buildFixedLeft (): Element {
const rows = this.ss.rows(this.options.mode === 'read');
return h().class('spreadsheet-fixed')
.style('width', '60px')
.children([
h().class('spreadsheet-fixed-header').child(h('table').child(
h('thead').child(
h('tr').child(
h('th').child('-')
)
),
)),
this.fixedLeftBody =
h().class('spreadsheet-fixed-body')
.style('height', `${this.options.mode === 'read' ? 'auto' : this.options.height() - 18}px`)
.children([
h('table').child(
h('tbody').children(
rows.map((row, rindex) => {
let firstTd = h('td').attr('height', `${row.height}`).child(`${rindex + 1}`)
.on('mouseover', (evt: Event) => this.rowResizer && this.rowResizer.set(evt.target, rindex, this.body.el.scrollTop));
this.firsttdsPush(rindex, firstTd)
return h('tr').child(firstTd)
})
)
)
])
])
}
private buildHeader (): Element {
const cols = this.ss.cols();
const thead = h('thead').child(
h('tr').children([
h('th'),
...cols.map((col, index) => {
let th = h('th').child(col.title).on('mouseover', (evt: Event) => {
console.log(evt)
this.colResizer && this.colResizer.set(evt.target, index, this.body.el.scrollLeft)
});
this.ths[index + ''] = th;
return th;
}),
h('th')
]
))
return h().class('spreadsheet-header').style('width', `${this.options.width()}px`).children([
h('table').children([this.buildColGroup(15), thead])
])
}
private mousedownCell (rindex: number, cindex: number) {
if (this.editor) {
const editorValue = this.editor.value
if (this.currentIndexs && this.editor.target && editorValue) {
// console.log(':::editorValue:', editorValue)
const oldCell = this.ss.cellText(editorValue.text, (_rindex, _cindex, _cell: Cell) => {
this.td(_rindex, _cindex).html(this.renderCell(_rindex, _cindex, _cell))
});
// const oldTd = this.td(this.currentIndexs[0], this.currentIndexs[1]);
// oldTd.html(this.renderCell(editorValue))
if (oldCell) {
// 设置内容之后,获取高度设置行高
if (oldCell.wordWrap) {
this.setRowHeight(this.currentIndexs[0], this.currentIndexs[1], true)
}
// console.log('old.td.offset:', oldCell)
// this.editorChange(oldCell)
}
}
this.editor.clear()
}
this.currentIndexs = [rindex, cindex]
const cCell = this.ss.currentCell([rindex, cindex])
this.clickCell(rindex, cindex, cCell)
}
private editCell(rindex: number, cindex: number) {
const td = this.td(rindex, cindex)
this.editor && this.editor.set(td.el, this.ss.currentCell())
}
private buildBody () {
const rows = this.ss.rows(this.options.mode === 'read');
const cols = this.ss.cols();
const mousedown = (rindex: number, cindex: number, evt: any) => {
const {select} = this.ss
if (evt.button === 2) {
// show contextmenu
console.log(':::evt:', evt)
this.contextmenu && this.contextmenu.set(evt)
if (select && select.contains(rindex, cindex)) {
return
}
}
// left key
this.selector.mousedown(evt)
this.mousedownCell(rindex, cindex)
this.focusing = true
}
const dblclick = (rindex: number, cindex: number) => {
this.editCell(rindex, cindex)
}
const scrollFn = (evt: any) => {
this.header.el.scrollLeft = evt.target.scrollLeft
this.fixedLeftBody && (this.fixedLeftBody.el.scrollTop = evt.target.scrollTop)
// console.log('>>>>>>>>scroll...', this.header, evt.target.scrollLeft, evt.target.scrollHeight)
}
const tbody = h('tbody').children(rows.map((row, rindex) => {
let firstTd = h('td').attr('height', `${row.height}`).child(`${rindex + 1}`);
this.firsttdsPush(rindex, firstTd)
return h('tr').children([
firstTd,
...cols.map((col, cindex) => {
let cell = this.ss.getCell(rindex, cindex)
let td = h('td')
.child(this.renderCell(rindex, cindex, cell))
.attr('type', 'cell')
.attr('row-index', rindex + '')
.attr('col-index', cindex + '')
.attr('rowspan', cell && cell.rowspan || 1)
.attr('colspan', cell && cell.colspan || 1)
.styles(getStyleFromCell(cell), true)
.on('mousedown', (evt: any) => mousedown(rindex, cindex, evt))
.on('dblclick', dblclick.bind(null, rindex, cindex));
this.tds[`${rindex}_${cindex}`] = td
return td;
}),
h('td')
])
}));
return h().class('spreadsheet-body')
.on('scroll', scrollFn)
.style('height', `${this.options.mode === 'read' ? 'auto' : this.options.height()}px`)
.style('width', `${this.options.width()}px`)
.children([
h('table').children([this.buildColGroup(0), tbody]),
this.editor && this.editor.el || '',
this.selector.el,
this.contextmenu && this.contextmenu.el || '',
this.dashedSelector.el
]
)
}
// 向尾部添加行
private addRow (num = 1) {
if (num > 0) {
}
}
private firsttdsPush (index: number, el: Element) {
this.firsttds[`${index}`] = this.firsttds[`${index}`] || []
this.firsttds[`${index}`].push(el)
}
}
================================================
FILE: src/local/toolbar.d.ts
================================================
import { Element } from "./base/element";
import { Spreadsheet } from "../core/index";
import { Cell } from '../core/cell';
import { Dropdown } from './base/dropdown';
export declare class Toolbar {
ss: Spreadsheet;
el: Element;
defaultCell: Cell;
target: Element | null;
currentCell: Cell | null;
elUndo: Element;
elRedo: Element;
elPaintformat: Element;
elClearformat: Element;
elFormat: Dropdown;
elFont: Dropdown;
elFontSize: Dropdown;
elFontWeight: Element;
elFontStyle: Element;
elTextDecoration: Element;
elColor: Dropdown;
elBackgroundColor: Dropdown;
elMerge: Element;
elAlign: Dropdown;
elValign: Dropdown;
elWordWrap: Element;
change: (key: keyof Cell, v: any) => void;
redo: () => boolean;
undo: () => boolean;
constructor(ss: Spreadsheet);
set(target: Element, cell: Cell | null): void;
private setCell;
private setCellStyle;
setRedoAble(flag: boolean): void;
setUndoAble(flag: boolean): void;
private buildSeparator;
private buildAligns;
private buildValigns;
private buildWordWrap;
private buildFontWeight;
private buildFontStyle;
private buildTextDecoration;
private buildMerge;
private buildColor;
private buildBackgroundColor;
private buildUndo;
private buildRedo;
private buildPaintformat;
private buildClearformat;
private buildFormats;
private buildFonts;
private buildFontSizes;
}
================================================
FILE: src/local/toolbar.ts
================================================
import { Element, h } from "./base/element";
import { Spreadsheet } from "../core/index";
import { Cell, getStyleFromCell, defaultCell } from '../core/cell';
import { Table } from './table';
import { buildItem, Item } from './base/item';
import { buildIcon } from './base/icon';
import { buildDropdown, Dropdown } from './base/dropdown';
import { buildMenu } from './base/menu';
import { buildColorPanel } from './base/colorPanel';
import { Font } from "../core/font";
import { Format } from "../core/format";
export class Toolbar {
el: Element;
defaultCell: Cell;
target: Element | null = null;
currentCell: Cell | null = null;
elUndo: Element;
elRedo: Element;
elPaintformat: Element;
elClearformat: Element;
elFormat: Dropdown;
elFont: Dropdown;
elFontSize: Dropdown;
elFontWeight: Element;
elFontStyle: Element;
elTextDecoration: Element;
elColor: Dropdown;
elBackgroundColor: Dropdown;
elMerge: Element;
elAlign: Dropdown;
elValign: Dropdown;
elWordWrap: Element;
change: (key: keyof Cell, v: any) => void = (key, v) => {}
redo: () => boolean = () => false
undo: () => boolean = () => false
constructor (public ss: Spreadsheet) {
this.defaultCell = ss.data.cell
this.el = h().class('spreadsheet-toolbar').child(
buildMenu('horizontal').children([
this.elUndo = this.buildUndo(),
this.elRedo = this.buildRedo(),
this.elPaintformat = this.buildPaintformat(),
this.elClearformat = this.buildClearformat(),
this.elFormat = this.buildFormats(),
this.buildSeparator(),
this.elFont = this.buildFonts(),
this.elFontSize = this.buildFontSizes(),
this.buildSeparator(),
this.elFontWeight = this.buildFontWeight(),
this.elFontStyle = this.buildFontStyle(),
this.elTextDecoration = this.buildTextDecoration(),
this.elColor = this.buildColor(),
this.buildSeparator(),
this.elBackgroundColor = this.buildBackgroundColor(),
this.elMerge = this.buildMerge(),
this.buildSeparator(),
this.elAlign = this.buildAligns(),
this.elValign = this.buildValigns(),
this.elWordWrap = this.buildWordWrap()
])
)
;
}
set (target: Element, cell: Cell | null) {
this.target = target
this.setCell(cell)
}
private setCell (cell: Cell | null) {
this.currentCell = cell
this.setCellStyle()
}
private setCellStyle () {
const { target, currentCell, defaultCell, ss } = this
// console.log(':::', currentCell)
if (target) {
// target.clearStyle()
// target.styles(getStyleFromCell(currentCell))
this.elFormat.title.html(ss.getFormat(currentCell !== null && currentCell.format || defaultCell.format).title);
this.elFont.title.html(ss.getFont(currentCell !== null && currentCell.font || defaultCell.font).title);
this.elFontSize.title.html((currentCell !== null && currentCell.fontSize || defaultCell.fontSize) + '');
this.elFontWeight.active(currentCell !== null && currentCell.bold !== undefined && currentCell.bold !== defaultCell.bold);
this.elFontStyle.active(currentCell !== null && currentCell.italic !== undefined && currentCell.italic !== defaultCell.italic);
this.elTextDecoration.active(currentCell !== null && currentCell.underline !== undefined && currentCell.underline !== defaultCell.underline);
this.elColor.title.style('border-bottom-color', currentCell !== null && currentCell.color || defaultCell.color);
this.elBackgroundColor.title.style('border-bottom-color', currentCell !== null && currentCell.backgroundColor || defaultCell.backgroundColor);
(<any>this.elAlign.title).replace(`align-${currentCell !== null && currentCell.align || defaultCell.align}`);
(<any>this.elValign.title).replace(`valign-${currentCell !== null && currentCell.valign || defaultCell.valign}`);
this.elWordWrap.active(currentCell !== null && currentCell.wordWrap !== undefined && currentCell.wordWrap !== defaultCell.wordWrap);
// console.log('select:', currentCell)
if ((currentCell !== null && currentCell.rowspan && currentCell.rowspan > 1)
|| (currentCell !== null && currentCell.colspan && currentCell.colspan > 1)) {
this.elMerge.active(true);
} else {
this.elMerge.active(false);
}
}
}
setRedoAble (flag: boolean) {
flag ? this.elRedo.able() : this.elRedo.disabled()
}
setUndoAble (flag: boolean) {
flag ? this.elUndo.able() : this.elUndo.disabled()
}
private buildSeparator (): Element {
return h().class('spreadsheet-item-separator')
}
private buildAligns (): Dropdown {
const titleIcon = buildIcon(`align-${this.defaultCell.align}`)
const clickHandler = (it: string) => {
titleIcon.replace(`align-${it}`)
this.change('align', it)
}
return buildDropdown(titleIcon, '60px', [buildMenu().children(
['left', 'center', 'right'].map(it =>
buildItem()
.child(buildIcon(`align-${it}`).style('text-align', 'center'))
.on('click', clickHandler.bind(null, it))
)
)])
}
private buildValigns (): Dropdown {
const titleIcon = buildIcon(`valign-${this.defaultCell.valign}`)
const clickHandler = (it: string) => {
titleIcon.replace(`valign-${it}`)
this.change('valign', it)
}
return buildDropdown(titleIcon, '60px', [buildMenu().children(
['top', 'middle', 'bottom'].map(it =>
buildItem()
.child(buildIcon(`valign-${it}`).style('text-align', 'center'))
.on('click', clickHandler.bind(null, it))
)
)])
}
private buildWordWrap (): Element {
return buildIconItem('textwrap', (is) => this.change('wordWrap', is))
}
private buildFontWeight (): Element {
return buildIconItem('bold', (is) => this.change('bold', is))
}
private buildFontStyle (): Element {
return buildIconItem('italic', (is) => this.change('italic', is))
}
private buildTextDecoration (): Element {
return buildIconItem('underline', (is) => this.change('underline', is))
}
private buildMerge (): Element {
return buildIconItem('merge', (is) => this.change('merge', is))
}
private buildColor (): Dropdown {
const clickHandler = (color: string) => {
this.elColor.title.style('border-bottom-color', color)
this.change('color', color)
}
return buildDropdown(
buildIcon('text-color').styles({'border-bottom': `3px solid ${this.defaultCell.color}`, 'margin-top': '2px', height: '16px'}),
'auto',
[buildColorPanel(clickHandler)])
}
private buildBackgroundColor (): Dropdown {
const clickHandler = (color: string) => {
this.elBackgroundColor.title.style('border-bottom-color', color)
this.change('backgroundColor', color)
}
return buildDropdown(
buildIcon('cell-color').styles({'border-bottom': `3px solid ${this.defaultCell.backgroundColor}`, 'margin-top': '2px', height: '16px'}),
'auto',
[buildColorPanel(clickHandler)])
}
private buildUndo (): Element {
return buildItem().child(buildIcon('undo'))
.on('click', (evt) => {
this.undo() ? this.elUndo.able() : this.elUndo.disabled()
})
.disabled()
}
private buildRedo (): Element {
return buildItem().child(buildIcon('redo'))
.on('click', (evt) => {
this.redo() ? this.elRedo.able() : this.elRedo.disabled()
})
.disabled()
}
private buildPaintformat (): Element {
return buildIconItem('paintformat', (is) => {
this.change('paintformat', true);
this.elPaintformat.deactive();
})
}
private buildClearformat (): Element {
return buildIconItem('clearformat', (is) => {
this.change('clearformat', true);
this.elClearformat.deactive();
});
}
private buildFormats (): Dropdown {
const clickHandler = (it: Format) => {
this.elFormat.title.html(this.ss.getFormat(it.key).title);
this.change('format', it.key)
}
return buildDropdown(this.ss.getFormat(this.defaultCell.format).title, '250px', [buildMenu().children(
this.ss.formats.map(it =>
buildItem()
.children([it.title, h().class('label').child(it.label||'')])
.on('click', clickHandler.bind(null, it))
)
)])
}
private buildFonts (): Dropdown {
const clickHandler = (it: Font) => {
this.elFont.title.html(it.title)
this.change('font', it.key)
}
return buildDropdown(this.ss.getFont(this.defaultCell.font).title, '170px', [buildMenu().children(
this.ss.fonts.map(it => {
return buildItem()
.child(it.title)
.on('click', clickHandler.bind(null, it))
})
)])
}
private buildFontSizes (): Dropdown {
const clickHandler = (it: number) => {
this.elFontSize.title.html(`${it}`)
this.change('fontSize', it)
}
return buildDropdown(this.defaultCell.fontSize + '', '70px', [buildMenu().children(
[6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 30, 36].map(it => {
return buildItem()
.child(`${it}`)
.on('click', clickHandler.bind(null, it))
})
)])
}
}
const buildIconItem = (iconName: string, change: (flag: boolean) => void) => {
const el = buildItem().child(buildIcon(iconName))
el.on('click', (evt) => {
let is = el.isActive()
is ? el.deactive() : el.active()
change(!is)
})
return el;
}
================================================
FILE: src/main.d.ts
================================================
import { LocalSpreadsheet, Options } from './local/index';
export default function xspreadsheet(el: HTMLElement, options?: Options): LocalSpreadsheet;
declare global {
interface Window {
xspreadsheet: any;
}
}
================================================
FILE: src/main.ts
================================================
import { LocalSpreadsheet, Options } from './local/index';
export default function xspreadsheet (el: HTMLElement, options?: Options) {
return new LocalSpreadsheet(el, options)
}
declare global {
interface Window {
xspreadsheet: any;
}
}
window.xspreadsheet = xspreadsheet
================================================
FILE: src/style/index.less
================================================
@border-style: 1px solid #e0e2e4;
@icon-size: 18px;
body {
margin: 0;
}
.spreadsheet {
font-size: 14px;
line-height: normal;
user-select: none;
-moz-user-select: none;
font-family: Roboto, Helvetica, Arial, sans-serif;
box-sizing: content-box;
background: #fff;
.spreadsheet-table {
position: relative;
background: #fff;
}
.spreadsheet-fixed {
position: absolute;
top: 0;
left: 0;
z-index: 10;
background: #fff;
.spreadsheet-fixed-body {
overflow: hidden;
}
.spreadsheet-fixed-header {
overflow: hidden;
}
}
.spreadsheet-body {
overflow: scroll;
position: relative;
}
.spreadsheet-header {
overflow: hidden;
width: 100%;
}
.spreadsheet-header, .spreadsheet-body, .spreadsheet-fixed {
table {
table-layout: fixed;
text-align: left;
width: 100%;
border-collapse: separate;
borde
gitextract_n0gowviz/ ├── .gitignore ├── LICENSE ├── README.md ├── docs/ │ ├── index.html │ └── xspreadsheet.js ├── index.html ├── package.json ├── src/ │ ├── core/ │ │ ├── alphabet.d.ts │ │ ├── alphabet.ts │ │ ├── cell.d.ts │ │ ├── cell.ts │ │ ├── font.d.ts │ │ ├── font.ts │ │ ├── format.d.ts │ │ ├── format.ts │ │ ├── formula.d.ts │ │ ├── formula.ts │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── select.d.ts │ │ └── select.ts │ ├── local/ │ │ ├── base/ │ │ │ ├── colorPanel.d.ts │ │ │ ├── colorPanel.ts │ │ │ ├── dropdown.d.ts │ │ │ ├── dropdown.ts │ │ │ ├── element.d.ts │ │ │ ├── element.ts │ │ │ ├── icon.d.ts │ │ │ ├── icon.ts │ │ │ ├── item.d.ts │ │ │ ├── item.ts │ │ │ ├── menu.d.ts │ │ │ ├── menu.ts │ │ │ ├── suggest.d.ts │ │ │ └── suggest.ts │ │ ├── contextmenu.d.ts │ │ ├── contextmenu.ts │ │ ├── editor.d.ts │ │ ├── editor.ts │ │ ├── editorbar.d.ts │ │ ├── editorbar.ts │ │ ├── event.d.ts │ │ ├── event.ts │ │ ├── index.d.ts │ │ ├── index.ts │ │ ├── resizer.d.ts │ │ ├── resizer.ts │ │ ├── selector.d.ts │ │ ├── selector.ts │ │ ├── table.d.ts │ │ ├── table.ts │ │ ├── toolbar.d.ts │ │ └── toolbar.ts │ ├── main.d.ts │ ├── main.ts │ └── style/ │ └── index.less ├── tsconfig.json ├── tslint.json ├── webpack.config.dev.js └── webpack.config.js
SYMBOL INDEX (476 symbols across 47 files)
FILE: docs/xspreadsheet.js
function s (line 1) | function s(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{...
class n (line 1) | class n{constructor(e="div"){this.tag=e,this._data={},this._clickOutside...
method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
method parent (line 1) | parent(){return this.el.parentNode}
method class (line 1) | class(e){return this.el.className=e,this}
method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
method contains (line 1) | contains(e){return this.el.contains(e)}
method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
method children (line 1) | children(e){for(let t of e)this.child(t);return this}
method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
method clone (line 1) | clone(){return this.el.cloneNode()}
method isHide (line 1) | isHide(){return"none"===this.style("display")}
method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
method able (line 1) | able(){return this.removeClass("disabled"),this}
method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
method deactive (line 1) | deactive(){return this.removeClass("active")}
method isActive (line 1) | isActive(){return this.hasClass("active")}
method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
function i (line 1) | function i(e,t,s=window){s.addEventListener(e,t)}
function n (line 1) | function n(e,t,s=window){s.removeEventListener(e,t)}
method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
method parent (line 1) | parent(){return this.el.parentNode}
method class (line 1) | class(e){return this.el.className=e,this}
method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
method contains (line 1) | contains(e){return this.el.contains(e)}
method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
method children (line 1) | children(e){for(let t of e)this.child(t);return this}
method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
method clone (line 1) | clone(){return this.el.cloneNode()}
method isHide (line 1) | isHide(){return"none"===this.style("display")}
method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
method able (line 1) | able(){return this.removeClass("disabled"),this}
method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
method deactive (line 1) | deactive(){return this.removeClass("active")}
method isActive (line 1) | isActive(){return this.hasClass("active")}
method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
class n (line 1) | class n extends i.Element{constructor(e="vertical"){super(),this.class(`...
method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
method parent (line 1) | parent(){return this.el.parentNode}
method class (line 1) | class(e){return this.el.className=e,this}
method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
method contains (line 1) | contains(e){return this.el.contains(e)}
method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
method children (line 1) | children(e){for(let t of e)this.child(t);return this}
method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
method clone (line 1) | clone(){return this.el.cloneNode()}
method isHide (line 1) | isHide(){return"none"===this.style("display")}
method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
method able (line 1) | able(){return this.removeClass("disabled"),this}
method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
method deactive (line 1) | deactive(){return this.removeClass("active")}
method isActive (line 1) | isActive(){return this.hasClass("active")}
method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
class n (line 1) | class n extends i.Element{constructor(e){super(),this.class("spreadsheet...
method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
method parent (line 1) | parent(){return this.el.parentNode}
method class (line 1) | class(e){return this.el.className=e,this}
method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
method contains (line 1) | contains(e){return this.el.contains(e)}
method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
method children (line 1) | children(e){for(let t of e)this.child(t);return this}
method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
method clone (line 1) | clone(){return this.el.cloneNode()}
method isHide (line 1) | isHide(){return"none"===this.style("display")}
method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
method able (line 1) | able(){return this.removeClass("disabled"),this}
method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
method deactive (line 1) | deactive(){return this.removeClass("active")}
method isActive (line 1) | isActive(){return this.hasClass("active")}
method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
class r (line 1) | class r extends i.Element{constructor(){super(),this.iconEl=null,this.cl...
method constructor (line 1) | constructor(){super(),this.iconEl=null,this.class("spreadsheet-item")}
method build (line 1) | static build(){return new r}
method icon (line 1) | icon(e){return this.child(this.iconEl=n.buildIcon(e)),this}
method replaceIcon (line 1) | replaceIcon(e){this.iconEl&&this.iconEl.replace(e)}
method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-color-panel").child(i.h...
method constructor (line 1) | constructor(e,t,s){super(),this.class("spreadsheet-dropdown spreadshee...
method toggleHandler (line 1) | toggleHandler(e){this.content.isHide()?(this.content.show(),this.activ...
method constructor (line 1) | constructor(){this.value=null,this.change=(e=>{}),this.el=i.h().class("s...
method set (line 1) | set(e,t){this.label.html(e),this.setValue(t)}
method setValue (line 1) | setValue(e){this.value=e,this.textarea.val(e&&e.text||"")}
method input (line 1) | input(e){const t=e.target.value;this.value?this.value.text=t:this.value=...
class r (line 1) | class r extends i.Element{constructor(e){super(),this.class("spreadsheet...
method constructor (line 1) | constructor(){super(),this.iconEl=null,this.class("spreadsheet-item")}
method build (line 1) | static build(){return new r}
method icon (line 1) | icon(e){return this.child(this.iconEl=n.buildIcon(e)),this}
method replaceIcon (line 1) | replaceIcon(e){this.iconEl&&this.iconEl.replace(e)}
method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-color-panel").child(i.h...
method constructor (line 1) | constructor(e,t,s){super(),this.class("spreadsheet-dropdown spreadshee...
method toggleHandler (line 1) | toggleHandler(e){this.content.isHide()?(this.content.show(),this.activ...
class r (line 1) | class r extends i.Element{constructor(e,t,s){super(),this.class("spreads...
method constructor (line 1) | constructor(){super(),this.iconEl=null,this.class("spreadsheet-item")}
method build (line 1) | static build(){return new r}
method icon (line 1) | icon(e){return this.child(this.iconEl=n.buildIcon(e)),this}
method replaceIcon (line 1) | replaceIcon(e){this.iconEl&&this.iconEl.replace(e)}
method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-color-panel").child(i.h...
method constructor (line 1) | constructor(e,t,s){super(),this.class("spreadsheet-dropdown spreadshee...
method toggleHandler (line 1) | toggleHandler(e){this.content.isHide()?(this.content.show(),this.activ...
method constructor (line 1) | constructor(e){this.ss=e,this.target=null,this.currentCell=null,this.cha...
method set (line 1) | set(e,t){this.target=e,this.setCell(t)}
method setCell (line 1) | setCell(e){this.currentCell=e,this.setCellStyle()}
method setCellStyle (line 1) | setCellStyle(){const{target:e,currentCell:t,defaultCell:s,ss:i}=this;e&&...
method setRedoAble (line 1) | setRedoAble(e){e?this.elRedo.able():this.elRedo.disabled()}
method setUndoAble (line 1) | setUndoAble(e){e?this.elUndo.able():this.elUndo.disabled()}
method buildSeparator (line 1) | buildSeparator(){return i.h().class("spreadsheet-item-separator")}
method buildAligns (line 1) | buildAligns(){const e=r.buildIcon(`align-${this.defaultCell.align}`),t=t...
method buildValigns (line 1) | buildValigns(){const e=r.buildIcon(`valign-${this.defaultCell.valign}`),...
method buildWordWrap (line 1) | buildWordWrap(){return a("textwrap",e=>this.change("wordWrap",e))}
method buildFontWeight (line 1) | buildFontWeight(){return a("bold",e=>this.change("bold",e))}
method buildFontStyle (line 1) | buildFontStyle(){return a("italic",e=>this.change("italic",e))}
method buildTextDecoration (line 1) | buildTextDecoration(){return a("underline",e=>this.change("underline",e))}
method buildMerge (line 1) | buildMerge(){return a("merge",e=>this.change("merge",e))}
method buildColor (line 1) | buildColor(){return o.buildDropdown(r.buildIcon("text-color").styles({"b...
method buildBackgroundColor (line 1) | buildBackgroundColor(){return o.buildDropdown(r.buildIcon("cell-color")....
method buildUndo (line 1) | buildUndo(){return n.buildItem().child(r.buildIcon("undo")).on("click",e...
method buildRedo (line 1) | buildRedo(){return n.buildItem().child(r.buildIcon("redo")).on("click",e...
method buildPaintformat (line 1) | buildPaintformat(){return a("paintformat",e=>{this.change("paintformat",...
method buildClearformat (line 1) | buildClearformat(){return a("clearformat",e=>{this.change("clearformat",...
method buildFormats (line 1) | buildFormats(){const e=e=>{this.elFormat.title.html(this.ss.getFormat(e....
method buildFonts (line 1) | buildFonts(){const e=e=>{this.elFont.title.html(e.title),this.change("fo...
method buildFontSizes (line 1) | buildFontSizes(){const e=e=>{this.elFontSize.title.html(`${e}`),this.cha...
method constructor (line 1) | constructor(e){this.table=e,this.el=i.h().class("spreadsheet-contextmenu...
method set (line 1) | set(e){const{offsetLeft:t,offsetTop:s}=e.target,i=this.el.el.getBounding...
method constructor (line 1) | constructor(e,t){this.vertical=e,this.change=t,this.moving=!1,this.index...
method set (line 1) | set(e,t,s){if(this.moving)return;this.index=t;const{vertical:i}=this,{of...
method mousedown (line 1) | mousedown(e){let t=e,s=0;this.resizerLine.show(),n.mouseMoveUp(e=>{if(th...
method constructor (line 1) | constructor(e,t){this.ss=e,this.table=t,this._offset={left:0,top:0,width...
method mousedown (line 1) | mousedown(e){if(1===e.detail&&"cell"===e.target.getAttribute("type")){if...
method setCurrentTarget (line 1) | setCurrentTarget(e){Object.assign(this,{startTarget:e,endTarget:e}),this...
method cornerMousedown (line 1) | cornerMousedown(e){const{select:t}=this.ss;if(null===t)return;const[s,i]...
method reload (line 1) | reload(){this.setOffset()}
method setOffset (line 1) | setOffset(){if(void 0===this.startTarget)return;let{select:e}=this.ss;if...
method rowsHeight (line 1) | rowsHeight(e,t,s=(e=>{})){let i=0;return r(e,t,this.table.firsttds,e=>{s...
method colsWidth (line 1) | colsWidth(e,t,s=(e=>{})){let i=0;return r(e,t,this.table.ths,e=>{s(e),i+...
method constructor (line 1) | constructor(){this.el=i.h().class("spreadsheet-borders dashed").hide()}
method set (line 1) | set(e){if(e._offset){const{left:t,top:s,width:i,height:n}=e._offset;this...
method hide (line 1) | hide(){this.el.hide()}
method constructor (line 1) | constructor(e,t){super(),this.list=e,this.width=t,this.filterList=[],thi...
method documentHandler (line 1) | documentHandler(e){if(this.el.contains(e.target))return!1;this.hideAndRe...
method documentKeydownHandler (line 1) | documentKeydownHandler(e){if(console.log("keyCode: ",e),!(this.filterLis...
method hideAndRemoveEvents (line 1) | hideAndRemoveEvents(){this.hide(),this.removeEvents()}
method removeEvents (line 1) | removeEvents(){null!==this.evtTarget&&(o.unbind("click",this.data("_outs...
method clickItemHandler (line 1) | clickItemHandler(e){this.itemClick(e),this.hideAndRemoveEvents()}
method search (line 1) | search(e,t,s){this.removeEvents(),this.target=e,this.evtTarget=t;const{l...
method constructor (line 1) | constructor(e,t){this.defaultRowHeight=e,this.formulas=t,this.target=nul...
method onChange (line 1) | onChange(e){this.change=e}
method set (line 1) | set(e,t){this.target=e;const s=this.setValue(t);this.el.show(),this.setT...
method setValue (line 1) | setValue(e){if(this.setStyle(e),e){this.value=e;const t=e.text||"";retur...
method setStyle (line 1) | setStyle(e){let t={width:this.textarea.style("width"),height:this.textar...
method clear (line 1) | clear(){this.el.hide(),this.target=null,this.value=null,this.textarea.va...
method setTextareaRange (line 1) | setTextareaRange(e){setTimeout(()=>{this.textarea.el.setSelectionRange(e...
method inputKeydown (line 1) | inputKeydown(e){13===e.keyCode&&e.preventDefault()}
method inputChange (line 1) | inputChange(e){const t=e.target.value;this.value?this.value.text=t:this....
method autocomplete (line 1) | autocomplete(e){if("="===e[0])if(e.includes("("))this.suggest.hide();els...
method reload (line 1) | reload(){if(this.target){const{offsetTop:e,offsetLeft:t,offsetWidth:s,of...
method constructor (line 1) | constructor(e,t){this.options=t,this.cols={},this.firsttds={},this.tds={...
method reload (line 1) | reload(){this.firsttds={},this.el.html(""),this.el.children([this.colRes...
method moveLeft (line 1) | moveLeft(){this.currentIndexs&&this.currentIndexs[1]>0&&(this.currentInd...
method moveUp (line 1) | moveUp(){this.currentIndexs&&this.currentIndexs[0]>0&&(this.currentIndex...
method moveDown (line 1) | moveDown(){this.currentIndexs&&this.currentIndexs[0]<this.ss.rows("read"...
method moveRight (line 1) | moveRight(){this.currentIndexs&&this.currentIndexs[1]<this.ss.cols().len...
method moveSelector (line 1) | moveSelector(e){if(this.currentIndexs){const[t,s]=this.currentIndexs,i=t...
method setValueWithText (line 1) | setValueWithText(e){this.currentIndexs&&this.ss.cellText(e.text,(e,t,s)=...
method setTdWithCell (line 1) | setTdWithCell(e,t,s,i=!0){this.setTdStyles(e,t,s),this.setRowHeight(e,t,...
method setCellAttr (line 1) | setCellAttr(e,t){this.ss.cellAttr(e,t,(s,i,n)=>{this.setTdWithCell(s,i,n...
method undo (line 1) | undo(){return this.ss.undo((e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t...
method redo (line 1) | redo(){return this.ss.redo((e,t,s)=>{this.setTdStylesAndAttrsAndText(e,t...
method setTdStylesAndAttrsAndText (line 1) | setTdStylesAndAttrsAndText(e,t,s){let i=this.td(e,t);this.setTdStyles(e,...
method copy (line 1) | copy(){this.ss.copy(),this.dashedSelector.set(this.selector),this.state=...
method cut (line 1) | cut(){this.ss.cut(),this.dashedSelector.set(this.selector),this.state="c...
method copyformat (line 1) | copyformat(){this.ss.copy(),this.dashedSelector.set(this.selector),this....
method paste (line 1) | paste(){null!==this.state&&this.ss.select&&(this.ss.paste((e,t,s)=>{let ...
method clearformat (line 1) | clearformat(){this.ss.clearformat((e,t,s)=>{this.td(e,t).removeAttr("row...
method merge (line 1) | merge(){this.ss.merge((e,t,s)=>{this.setTdAttrs(e,t,s).show(!0)},(e,t,s)...
method insert (line 1) | insert(e,t){this.ss.insert(e,t,(e,t,s)=>{this.setTdStylesAndAttrsAndText...
method td (line 1) | td(e,t){return this.tds[`${e}_${t}`]}
method selectorChange (line 1) | selectorChange(){"copyformat"===this.state&&this.paste()}
method selectorChangeCopy (line 1) | selectorChangeCopy(e,t,s,i,n,r){this.ss.batchPaste(t,s,i,n,r,e.ctrlKey,(...
method renderCell (line 1) | renderCell(e,t,s){if(s){const i=`${e}_${t}`;return s.text&&"="===s.text[...
method _renderCell (line 1) | _renderCell(e){if(e){let t=e.text||"";return d.formulaRender(t,(e,t)=>th...
method reRenderFormulaCells (line 1) | reRenderFormulaCells(){this.formulaCellIndexs.forEach(e=>{let t=e.split(...
method setRowHeight (line 1) | setRowHeight(e,t,s){if(!1===s)return;this.ss.cols();const i=this.td(e,t)...
method setTdStyles (line 1) | setTdStyles(e,t,s){return this.td(e,t).styles(h.getStyleFromCell(s),!0)}
method setTdAttrs (line 1) | setTdAttrs(e,t,s){return this.td(e,t).attr("rowspan",s.rowspan||1).attr(...
method changeRowHeight (line 1) | changeRowHeight(e,t){if(t<=this.ss.defaultRowHeight())return;this.ss.row...
method changeRowResizer (line 1) | changeRowResizer(e,t){const s=this.ss.row(e).height+t;this.changeRowHeig...
method changeColResizer (line 1) | changeColResizer(e,t){const s=this.ss.col(e).width+t;if(s<=50)return;thi...
method buildColGroup (line 1) | buildColGroup(e){const t=this.ss.cols();return i.h("colgroup").children(...
method buildFixedLeft (line 1) | buildFixedLeft(){const e=this.ss.rows("read"===this.options.mode);return...
method buildHeader (line 1) | buildHeader(){const e=this.ss.cols(),t=i.h("thead").child(i.h("tr").chil...
method mousedownCell (line 1) | mousedownCell(e,t){if(this.editor){const e=this.editor.value;if(this.cur...
method editCell (line 1) | editCell(e,t){const s=this.td(e,t);this.editor&&this.editor.set(s.el,thi...
method buildBody (line 1) | buildBody(){const e=this.ss.rows("read"===this.options.mode),t=this.ss.c...
method addRow (line 1) | addRow(e=1){}
method firsttdsPush (line 1) | firsttdsPush(e,t){this.firsttds[`${e}`]=this.firsttds[`${e}`]||[],this.f...
function p (line 1) | function p(e,t){for(var s=0;s<e.length;s++){var i=e[s],n=r[i.id];if(n){n...
function u (line 1) | function u(e,t){for(var s=[],i={},n=0;n<e.length;n++){var r=e[n],o=t.bas...
function f (line 1) | function f(e,t){var s=l(e.insertInto);if(!s)throw new Error("Couldn't fi...
function b (line 1) | function b(e){if(null===e.parentNode)return!1;e.parentNode.removeChild(e...
function g (line 1) | function g(e){var t=document.createElement("style");return e.attrs.type=...
function m (line 1) | function m(e,t){Object.keys(t).forEach(function(s){e.setAttribute(s,t[s]...
function x (line 1) | function x(e,t){var s,i,n,r;if(t.transform&&e.css){if(!(r=t.transform(e....
function v (line 1) | function v(e,t,s,i){var n=s?"":i.css;if(e.styleSheet)e.styleSheet.cssTex...
method constructor (line 1) | constructor(e,t,s){this.start=e,this.stop=t,this.canMerge=s}
method forEach (line 1) | forEach(e){const[t,s]=this.start,[i,n]=this.stop;for(let r=t;r<=i;r++)fo...
method rowIndex (line 1) | rowIndex(e){return this.start[0]+e%this.rowLen()}
method colIndex (line 1) | colIndex(e){return this.start[1]+e%this.colLen()}
method rowLen (line 1) | rowLen(){return this.stop[0]-this.start[0]+1}
method colLen (line 1) | colLen(){return this.stop[1]-this.start[1]+1}
method cellLen (line 1) | cellLen(){return this.rowLen()*this.colLen()}
method contains (line 1) | contains(e,t){const[s,i]=this.start,[n,r]=this.stop;return s<=e&&n>=e&&i...
class a (line 1) | class a{constructor(e){this.type=e,this.values=[]}add(e,t,s){this.values...
method constructor (line 1) | constructor(e){this.type=e,this.values=[]}
method add (line 1) | add(e,t,s){this.values.push([e,t,s])}
method constructor (line 1) | constructor(e={}){if(this.histories=[],this.histories2=[],this.currentCe...
method buildSelect (line 1) | buildSelect(e,t){const s=f(e),i=f(t);let n=s.row,r=s.col,o=i.row,l=i.col...
method defaultRowHeight (line 1) | defaultRowHeight(){return this.data.rowHeight||22}
method defaultColWidth (line 1) | defaultColWidth(){return this.data.colWidth||100}
method copy (line 1) | copy(){this.copySelect=this.select}
method cut (line 1) | cut(){this.cutSelect=this.select}
method paste (line 1) | paste(e,t,s){let i=this.copySelect;if(this.cutSelect&&(i=this.cutSelect,...
method insert (line 1) | insert(e,t,s){if(this.select){const{cells:t}=this.data,[i,n]=this.select...
method batchPaste (line 1) | batchPaste(e,t,s,i,n,r,o){if(this.select){const e=new a("cells");for(let...
method copyCell (line 1) | copyCell(e,t,s,i,n,o,l){const h=this.getCell(e,t),a=s-e,d=i-t;if(h){let ...
method isRedo (line 1) | isRedo(){return this.histories2.length>0}
method redo (line 1) | redo(e){const{histories:t,histories2:s}=this;if(s.length>0){const i=s.po...
method isUndo (line 1) | isUndo(){return this.histories.length>0}
method undo (line 1) | undo(e){const{histories:t,histories2:s}=this;if(t.length>0){const i=t.po...
method resetByHistory (line 1) | resetByHistory(e,t,s){e.values.forEach(([i,n,r])=>{if("cells"===e.type){...
method clearformat (line 1) | clearformat(e){const{select:t}=this;if(null!==t){const s=new a("cells");...
method merge (line 1) | merge(e,t,s){const{select:i}=this;if(null!==i&&i.cellLen()>1){const n=ne...
method cellAttr (line 1) | cellAttr(e,t,s){let i={};i[e]=t;const n=t===this.data.cell[e];if(null!==...
method cellText (line 1) | cellText(e,t){if(this.currentCellIndexes){const s=new a("cells"),[i,n]=t...
method currentCell (line 1) | currentCell(e){void 0!==e&&(this.currentCellIndexes=e);const[t,s]=this.c...
method cell (line 1) | cell(e,t,s,i=!1){return this.data.cells=this.data.cells||{},this.data.ce...
method getCell (line 1) | getCell(e,t){return this.data.cells&&this.data.cells[e]&&this.data.cells...
method getFont (line 1) | getFont(e){return this.fonts.filter(t=>t.key===e)[0]}
method getFormat (line 1) | getFormat(e){return this.formats.filter(t=>t.key===e)[0]}
method row (line 1) | row(e,t){const{data:s}=this;if(void 0!==t){const i=new a("rows");s.rows=...
method rows (line 1) | rows(e){const{data:t}=this;let s;return e?(s=10,this.data.cells&&(s=d(th...
method col (line 1) | col(e,t){const{data:s}=this;if(void 0!==t){const i=new a("cols");s.cols=...
method cols (line 1) | cols(){const{data:e}=this;let t=c(52,e.cols);return u(t,e=>this.col(e))}
method constructor (line 1) | constructor(e,t={}){this.refs={},this.toolbar=null,this.editorbar=null,t...
method loadData (line 1) | loadData(e){return setTimeout(()=>{this.ss.data=e,this.table.reload()},1...
method change (line 1) | change(e){return this._change=e,this}
method render (line 1) | render(){this.bindEl.appendChild(l.h().class("spreadsheet").children([l....
method toolbarChange (line 1) | toolbarChange(e,t){"merge"!==e?"clearformat"!==e?"paintformat"!==e?this....
method editorbarChange (line 1) | editorbarChange(e){this.table.setValueWithText(e)}
method editorChange (line 1) | editorChange(e){this.editorbar&&this.editorbar.setValue(e)}
method clickCell (line 1) | clickCell(e,t,s){const i=this.ss.cols();this.editorbar&&this.editorbar.s...
function n (line 1) | function n(e,t){return new i.LocalSpreadsheet(e,t)}
method constructor (line 1) | constructor(e="div"){this.tag=e,this._data={},this._clickOutside=null,...
method data (line 1) | data(e,t){return void 0!==t&&(this._data[e]=t),this._data[e]}
method on (line 1) | on(e,t){const[s,...i]=e.split(".");return this.el.addEventListener(s,e...
method onClickOutside (line 1) | onClickOutside(e){return this._clickOutside=e,this}
method parent (line 1) | parent(){return this.el.parentNode}
method class (line 1) | class(e){return this.el.className=e,this}
method attrs (line 1) | attrs(e={}){for(let t of Object.keys(e))this.attr(t,e[t]);return this}
method attr (line 1) | attr(e,t){return void 0===t?this.el.getAttribute(e):(this.el.setAttrib...
method removeAttr (line 1) | removeAttr(e){return this.el.removeAttribute(e),this}
method offset (line 1) | offset(){const{offsetTop:e,offsetLeft:t,offsetHeight:s,offsetWidth:i}=...
method clearStyle (line 1) | clearStyle(){return this.el.style="",this}
method styles (line 1) | styles(e={},t=!1){t&&this.clearStyle();for(let t of Object.keys(e))thi...
method style (line 1) | style(e,t){return void 0===t?this.el.style.getPropertyValue(e):(this.e...
method contains (line 1) | contains(e){return this.el.contains(e)}
method removeStyle (line 1) | removeStyle(e){this.el.style.removeProperty(e)}
method children (line 1) | children(e){for(let t of e)this.child(t);return this}
method child (line 1) | child(e){return"string"==typeof e?this.el.appendChild(document.createT...
method html (line 1) | html(e){return void 0===e?this.el.innerHTML:(this.el.innerHTML=e,this)}
method val (line 1) | val(e){return void 0===e?this.el.value:(this.el.value=e,this)}
method clone (line 1) | clone(){return this.el.cloneNode()}
method isHide (line 1) | isHide(){return"none"===this.style("display")}
method toggle (line 1) | toggle(){this.isHide()?this.show():this.hide()}
method disabled (line 1) | disabled(){return this.addClass("disabled"),this}
method able (line 1) | able(){return this.removeClass("disabled"),this}
method active (line 1) | active(e=!0){return e?this.addClass("active"):this.deactive(),this}
method deactive (line 1) | deactive(){return this.removeClass("active")}
method isActive (line 1) | isActive(){return this.hasClass("active")}
method addClass (line 1) | addClass(e){return this.el.className=this.el.className.split(" ").conc...
method removeClass (line 1) | removeClass(e){return this.el.className=this.el.className.split(" ").f...
method hasClass (line 1) | hasClass(e){return-1!==this.el.className.indexOf(e)}
method show (line 1) | show(e=!1){return e?this.removeStyle("display"):this.style("display","...
method hide (line 1) | hide(){return this.style("display","none"),this._clickOutside&&i.unbin...
method constructor (line 1) | constructor(e="vertical"){super(),this.class(`spreadsheet-menu ${e}`)}
method constructor (line 1) | constructor(e){super(),this.class("spreadsheet-icon").child(this.img=i...
method replace (line 1) | replace(e){this.img.class(`spreadsheet-icon-img ${e}`)}
FILE: src/core/alphabet.ts
function alphabet (line 2) | function alphabet(index: number): string {
function alphabetIndex (line 8) | function alphabetIndex (key: string): number {
FILE: src/core/cell.d.ts
type Cell (line 1) | interface Cell {
FILE: src/core/cell.ts
type Cell (line 1) | interface Cell {
function getStyleFromCell (line 40) | function getStyleFromCell (cell: Cell | null): {[key: string]: string} {
FILE: src/core/font.d.ts
type Font (line 1) | interface Font {
FILE: src/core/font.ts
type Font (line 1) | interface Font {
FILE: src/core/format.d.ts
type Format (line 1) | interface Format {
FILE: src/core/format.ts
type Format (line 1) | interface Format {
FILE: src/core/formula.d.ts
type Formula (line 1) | interface Formula {
FILE: src/core/formula.ts
type Formula (line 3) | interface Formula {
FILE: src/core/index.d.ts
type Row (line 6) | interface Row {
type Col (line 9) | interface Col {
type MapInt (line 13) | interface MapInt<T> {
class History (line 16) | class History {
type StandardCallback (line 22) | type StandardCallback = (rindex: number, cindex: number, cell: Cell) => ...
type SpreadsheetData (line 23) | interface SpreadsheetData {
type SpreadsheetOptions (line 32) | interface SpreadsheetOptions {
class Spreadsheet (line 38) | class Spreadsheet {
FILE: src/core/index.ts
type Row (line 9) | interface Row {
type Col (line 12) | interface Col {
type MapInt (line 16) | interface MapInt<T> {
class History (line 19) | class History {
method constructor (line 21) | constructor (public type: 'rows' | 'cols' | 'cells') {}
method add (line 22) | add (keys: Array<any>, oldValue: any, value: any) {
type StandardCallback (line 27) | type StandardCallback = (rindex: number, cindex: number, cell: Cell) => ...
type SpreadsheetData (line 29) | interface SpreadsheetData {
type SpreadsheetOptions (line 39) | interface SpreadsheetOptions {
class Spreadsheet (line 46) | class Spreadsheet {
method constructor (line 60) | constructor (options: SpreadsheetOptions = {}) {
method buildSelect (line 78) | buildSelect (startTarget: any, endTarget: any) {
method defaultRowHeight (line 120) | defaultRowHeight (): number {
method defaultColWidth (line 124) | defaultColWidth (): number {
method copy (line 128) | copy (): void {
method cut (line 131) | cut (): void {
method paste (line 134) | paste (cb: StandardCallback, state: 'copy' | 'cut' | 'copyformat', cle...
method insert (line 165) | insert (type: 'row' | 'col', amount: number, cb: StandardCallback) {
method batchPaste (line 219) | batchPaste (arrow: 'bottom' | 'top' | 'left' | 'right',
method copyCell (line 237) | private copyCell (srcRowIndex: number, srcColIndex: number, destRowInd...
method isRedo (line 277) | isRedo (): boolean {
method redo (line 280) | redo (cb: StandardCallback): boolean {
method isUndo (line 293) | isUndo (): boolean {
method undo (line 296) | undo (cb: StandardCallback): boolean {
method resetByHistory (line 310) | resetByHistory (v: History, cb: StandardCallback, state: 'undo' | 'red...
method clearformat (line 350) | clearformat (cb: StandardCallback) {
method merge (line 373) | merge (ok: StandardCallback, cancel: StandardCallback, other: Standard...
method cellAttr (line 427) | cellAttr (key: keyof Cell, value: any, cb: StandardCallback): void {
method cellText (line 446) | cellText (value: any, cb: StandardCallback): Cell | null {
method currentCell (line 462) | currentCell (indexes?: [number, number]): Cell | null {
method cell (line 470) | cell (rindex: number, cindex: number, v: any, isCopy = false): Cell {
method getCell (line 482) | getCell (rindex: number, cindex: number): Cell | null {
method getFont (line 489) | getFont (key: string | undefined) {
method getFormat (line 492) | getFormat (key: string | undefined) {
method row (line 496) | row (index: number, v?: number): Row {
method rows (line 509) | rows (isData: boolean): Array<Row> {
method col (line 523) | col (index: number, v?: number): Col {
method cols (line 544) | cols (): Array<Col> {
FILE: src/core/select.d.ts
class Select (line 1) | class Select {
FILE: src/core/select.ts
class Select (line 1) | class Select {
method constructor (line 2) | constructor(public start: [number, number], public stop: [number, numb...
method forEach (line 3) | forEach (cb: (r:number, c: number, rindex: number, cindex: number, row...
method rowIndex (line 12) | rowIndex (index: number) {
method colIndex (line 15) | colIndex (index: number) {
method rowLen (line 18) | rowLen () {
method colLen (line 21) | colLen () {
method cellLen (line 24) | cellLen () {
method contains (line 27) | contains (rindex: number, cindex: number) {
FILE: src/local/base/colorPanel.d.ts
class ColorPanel (line 2) | class ColorPanel extends Element {
FILE: src/local/base/colorPanel.ts
class ColorPanel (line 13) | class ColorPanel extends Element {
method constructor (line 15) | constructor (click: (color: string) => void) {
function buildColorPanel (line 38) | function buildColorPanel (click: (color: string) => void) {
FILE: src/local/base/dropdown.d.ts
class Dropdown (line 2) | class Dropdown extends Element {
FILE: src/local/base/dropdown.ts
class Dropdown (line 4) | class Dropdown extends Element {
method constructor (line 8) | constructor (title: string | Element, width: string, contentChildren: ...
method toggleHandler (line 24) | toggleHandler (evt: Event) {
function buildDropdown (line 34) | function buildDropdown(title: string | Element, width: string, contentCh...
FILE: src/local/base/element.d.ts
class Element (line 1) | class Element {
FILE: src/local/base/element.ts
class Element (line 3) | class Element {
method constructor (line 8) | constructor (public tag = 'div') {
method data (line 12) | data (key: string, value?: any) {
method on (line 19) | on (eventName: string, handler: (evt: any) => any): Element {
method onClickOutside (line 40) | onClickOutside (cb: () => void): Element {
method parent (line 45) | parent(): any {
method class (line 49) | class (name: string): Element {
method attrs (line 54) | attrs (map: {[key: string]: string} = {}): Element {
method attr (line 60) | attr (attr: string, value?: any): any {
method removeAttr (line 68) | removeAttr(attr: string): Element {
method offset (line 73) | offset (): any {
method clearStyle (line 78) | clearStyle () {
method styles (line 83) | styles (map: {[key: string]: string} = {}, isClear = false): Element {
method style (line 92) | style (key: string, value?: any): any {
method contains (line 101) | contains (el: any) {
method removeStyle (line 105) | removeStyle (key: string) {
method children (line 110) | children (cs: Array<HTMLElement | string | Element>): Element {
method child (line 116) | child (c: HTMLElement | string | Element): Element {
method html (line 127) | html (html?: string) {
method val (line 136) | val (v?: string) {
method clone (line 146) | clone (): any {
method isHide (line 150) | isHide () {
method toggle (line 154) | toggle () {
method disabled (line 162) | disabled (): Element {
method able (line 167) | able (): Element {
method active (line 172) | active (flag = true): Element {
method deactive (line 181) | deactive (): Element {
method isActive (line 184) | isActive (): boolean {
method addClass (line 188) | addClass (cls: string): Element {
method removeClass (line 192) | removeClass (cls: string) {
method hasClass (line 198) | hasClass (cls: string) {
method show (line 202) | show (isRemove = false): Element {
method hide (line 221) | hide (): Element {
function h (line 230) | function h (tag = 'div'): Element {
FILE: src/local/base/icon.d.ts
class Icon (line 2) | class Icon extends Element {
FILE: src/local/base/icon.ts
class Icon (line 3) | class Icon extends Element{
method constructor (line 7) | constructor (name: string) {
method replace (line 12) | replace (name: string) {
function buildIcon (line 18) | function buildIcon (name: string) {
FILE: src/local/base/item.d.ts
class Item (line 3) | class Item extends Element {
FILE: src/local/base/item.ts
class Item (line 4) | class Item extends Element {
method build (line 8) | static build (): Item {
method constructor (line 12) | constructor () {
method icon (line 17) | icon (name: string) {
method replaceIcon (line 22) | replaceIcon (name: string) {
function buildItem (line 28) | function buildItem (): Item {
FILE: src/local/base/menu.d.ts
class Menu (line 2) | class Menu extends Element {
FILE: src/local/base/menu.ts
class Menu (line 3) | class Menu extends Element{
method constructor (line 5) | constructor (align = 'vertical') {
function buildMenu (line 12) | function buildMenu (align = 'vertical') {
FILE: src/local/base/suggest.d.ts
class Suggest (line 2) | class Suggest extends Element {
FILE: src/local/base/suggest.ts
class Suggest (line 6) | class Suggest extends Element {
method constructor (line 15) | constructor (public list: Array<[string, string]>, public width: numbe...
method documentHandler (line 20) | private documentHandler (e: any) {
method documentKeydownHandler (line 26) | private documentKeydownHandler (e: any) {
method hideAndRemoveEvents (line 64) | private hideAndRemoveEvents () {
method removeEvents (line 68) | private removeEvents () {
method clickItemHandler (line 75) | private clickItemHandler (it: [string, string]) {
method search (line 82) | search (target: Element, input: Element, word: string) {
FILE: src/local/contextmenu.d.ts
class ContextMenu (line 3) | class ContextMenu {
FILE: src/local/contextmenu.ts
class ContextMenu (line 6) | class ContextMenu {
method constructor (line 8) | constructor (public table: Table) {
method set (line 25) | set (evt: any) {
FILE: src/local/editor.d.ts
class Editor (line 5) | class Editor {
FILE: src/local/editor.ts
class Editor (line 6) | class Editor {
method constructor (line 16) | constructor (public defaultRowHeight: number, public formulas : Array<...
method onChange (line 46) | onChange (change: (v: Cell) => void) {
method set (line 50) | set (target: HTMLElement, value: Cell | null) {
method setValue (line 61) | setValue (value: Cell | null): string {
method setStyle (line 73) | setStyle (value: Cell | null): void {
method clear (line 78) | clear () {
method setTextareaRange (line 87) | private setTextareaRange (position: number) {
method inputKeydown (line 94) | private inputKeydown (evt: any) {
method inputChange (line 100) | private inputChange (evt: any) {
method autocomplete (line 115) | private autocomplete (v: string) {
method reload (line 129) | reload () {
FILE: src/local/editorbar.d.ts
class Editorbar (line 3) | class Editorbar {
FILE: src/local/editorbar.ts
class Editorbar (line 5) | class Editorbar {
method constructor (line 11) | constructor () {
method set (line 21) | set (title: string, value: Cell | null) {
method setValue (line 26) | setValue (value: Cell | null) {
method input (line 31) | input (evt: any) {
FILE: src/local/event.ts
function bind (line 1) | function bind<T extends Event>(name: string, fn: (evt: T) => void, targe...
function unbind (line 4) | function unbind<T extends Event>(name: string, fn: (evt: T) => void, tar...
function mouseMoveUp (line 7) | function mouseMoveUp<T extends Event> (movefunc: (evt: T) => void, upfun...
FILE: src/local/index.d.ts
type Options (line 6) | interface Options extends SpreadsheetOptions {
class LocalSpreadsheet (line 10) | class LocalSpreadsheet {
FILE: src/local/index.ts
type Options (line 13) | interface Options extends SpreadsheetOptions {
class LocalSpreadsheet (line 18) | class LocalSpreadsheet {
method constructor (line 30) | constructor (el: HTMLElement, options: Options = {}) {
method loadData (line 75) | loadData (data: SpreadsheetData): LocalSpreadsheet {
method change (line 84) | change (cb: (data: SpreadsheetData) => void): LocalSpreadsheet {
method render (line 89) | private render (): void {
method toolbarChange (line 99) | private toolbarChange (k: keyof Cell, v: any) {
method editorbarChange (line 114) | private editorbarChange (v: Cell) {
method editorChange (line 118) | private editorChange (v: Cell) {
method clickCell (line 122) | private clickCell (rindex: number, cindex: number, v: Cell | null) {
FILE: src/local/resizer.d.ts
class Resizer (line 2) | class Resizer {
FILE: src/local/resizer.ts
class Resizer (line 4) | class Resizer {
method constructor (line 10) | constructor (public vertical: boolean, public change: (index: number, ...
method set (line 18) | set (target: any, index: number, scroll: number) {
method mousedown (line 38) | mousedown (evt: any) {
FILE: src/local/selector.d.ts
class Selector (line 4) | class Selector {
class DashedSelector (line 34) | class DashedSelector {
FILE: src/local/selector.ts
class Selector (line 6) | class Selector {
method constructor (line 24) | constructor (public ss: Spreadsheet, public table: Table) {
method mousedown (line 43) | mousedown (evt: any) {
method setCurrentTarget (line 68) | setCurrentTarget (target: HTMLElement) {
method cornerMousedown (line 73) | private cornerMousedown (evt: any) {
method reload (line 149) | reload () {
method setOffset (line 153) | private setOffset () {
method rowsHeight (line 198) | private rowsHeight (minRow:number, maxRow:number, cb: (e: Element) => ...
method colsWidth (line 207) | private colsWidth (minCol: number, maxCol: number, cb: (e: Element) =>...
class DashedSelector (line 230) | class DashedSelector {
method constructor (line 232) | constructor () {
method set (line 236) | set (selector: Selector) {
method hide (line 248) | hide () {
FILE: src/local/table.d.ts
type Map (line 8) | interface Map<T> {
type TableOption (line 11) | interface TableOption {
class Table (line 16) | class Table {
FILE: src/local/table.ts
type Map (line 14) | interface Map<T> {
type TableOption (line 18) | interface TableOption {
class Table (line 24) | class Table {
method constructor (line 57) | constructor (ss: Spreadsheet, public options: TableOption) {
method reload (line 184) | reload () {
method moveLeft (line 196) | private moveLeft () {
method moveUp (line 202) | private moveUp () {
method moveDown (line 208) | private moveDown () {
method moveRight (line 214) | private moveRight () {
method moveSelector (line 222) | private moveSelector (direction: 'right' | 'left' | 'up' | 'down') {
method setValueWithText (line 253) | setValueWithText (v: Cell) {
method setTdWithCell (line 263) | setTdWithCell (rindex: number, cindex: number, cell: Cell, autoWordWra...
method setCellAttr (line 269) | setCellAttr (k: keyof Cell, v: any) {
method undo (line 278) | undo (): boolean {
method redo (line 284) | redo (): boolean {
method setTdStylesAndAttrsAndText (line 289) | private setTdStylesAndAttrsAndText (rindex: number, cindex: number, ce...
method copy (line 297) | copy () {
method cut (line 303) | cut () {
method copyformat (line 309) | copyformat () {
method paste (line 315) | paste () {
method clearformat (line 346) | clearformat () {
method merge (line 356) | merge () {
method insert (line 369) | insert (type: 'row' | 'col', amount: number) {
method td (line 380) | td (rindex: number, cindex: number): Element {
method selectorChange (line 385) | private selectorChange () {
method selectorChangeCopy (line 391) | private selectorChangeCopy (evt: any, arrow: 'bottom' | 'top' | 'left'...
method renderCell (line 399) | private renderCell (rindex: number, cindex: number, cell: Cell | null)...
method _renderCell (line 416) | private _renderCell (cell: Cell | null): string {
method reRenderFormulaCells (line 423) | private reRenderFormulaCells () {
method setRowHeight (line 435) | private setRowHeight (rindex: number, cindex: number, autoWordWrap: bo...
method setTdStyles (line 456) | private setTdStyles (rindex: number, cindex: number, cell: Cell): Elem...
method setTdAttrs (line 459) | private setTdAttrs (rindex: number, cindex: number, cell: Cell): Eleme...
method changeRowHeight (line 465) | private changeRowHeight (index: number, h: number) {
method changeRowResizer (line 475) | private changeRowResizer (index: number, distance: number) {
method changeColResizer (line 479) | private changeColResizer (index: number, distance: number) {
method buildColGroup (line 491) | private buildColGroup (lastColWidth: number): Element {
method buildFixedLeft (line 505) | private buildFixedLeft (): Element {
method buildHeader (line 535) | private buildHeader (): Element {
method mousedownCell (line 556) | private mousedownCell (rindex: number, cindex: number) {
method editCell (line 583) | private editCell(rindex: number, cindex: number) {
method buildBody (line 588) | private buildBody () {
method addRow (line 657) | private addRow (num = 1) {
method firsttdsPush (line 663) | private firsttdsPush (index: number, el: Element) {
FILE: src/local/toolbar.d.ts
class Toolbar (line 5) | class Toolbar {
FILE: src/local/toolbar.ts
class Toolbar (line 13) | class Toolbar {
method constructor (line 41) | constructor (public ss: Spreadsheet) {
method set (line 71) | set (target: Element, cell: Cell | null) {
method setCell (line 76) | private setCell (cell: Cell | null) {
method setCellStyle (line 81) | private setCellStyle () {
method setRedoAble (line 108) | setRedoAble (flag: boolean) {
method setUndoAble (line 112) | setUndoAble (flag: boolean) {
method buildSeparator (line 116) | private buildSeparator (): Element {
method buildAligns (line 119) | private buildAligns (): Dropdown {
method buildValigns (line 133) | private buildValigns (): Dropdown {
method buildWordWrap (line 147) | private buildWordWrap (): Element {
method buildFontWeight (line 150) | private buildFontWeight (): Element {
method buildFontStyle (line 153) | private buildFontStyle (): Element {
method buildTextDecoration (line 156) | private buildTextDecoration (): Element {
method buildMerge (line 159) | private buildMerge (): Element {
method buildColor (line 162) | private buildColor (): Dropdown {
method buildBackgroundColor (line 172) | private buildBackgroundColor (): Dropdown {
method buildUndo (line 182) | private buildUndo (): Element {
method buildRedo (line 189) | private buildRedo (): Element {
method buildPaintformat (line 196) | private buildPaintformat (): Element {
method buildClearformat (line 202) | private buildClearformat (): Element {
method buildFormats (line 208) | private buildFormats (): Dropdown {
method buildFonts (line 221) | private buildFonts (): Dropdown {
method buildFontSizes (line 234) | private buildFontSizes (): Dropdown {
FILE: src/main.d.ts
type Window (line 4) | interface Window {
FILE: src/main.ts
function xspreadsheet (line 3) | function xspreadsheet (el: HTMLElement, options?: Options) {
type Window (line 8) | interface Window {
Condensed preview — 60 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (221K chars).
[
{
"path": ".gitignore",
"chars": 22,
"preview": "node_modules/\n.vscode/"
},
{
"path": "LICENSE",
"chars": 1064,
"preview": "MIT License\n\nCopyright (c) 2017 myliang\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof"
},
{
"path": "README.md",
"chars": 1035,
"preview": "# XSpreadsheet\n\n[](https://www.npmjs.org/package/xspreadshe"
},
{
"path": "docs/index.html",
"chars": 673,
"preview": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n <head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\""
},
{
"path": "docs/xspreadsheet.js",
"chars": 66593,
"preview": "!function(e){var t={};function s(i){if(t[i])return t[i].exports;var n=t[i]={i:i,l:!1,exports:{}};return e[i].call(n.expo"
},
{
"path": "index.html",
"chars": 6952,
"preview": "<!DOCTYPE html>\n<html lang=\"zh-CN\">\n <head>\n <meta charset=\"utf-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\""
},
{
"path": "package.json",
"chars": 1064,
"preview": "{\n \"name\": \"xspreadsheet\",\n \"version\": \"1.0.4\",\n \"description\": \"a javascript spreadsheet\",\n \"author\": \"myliang <lia"
},
{
"path": "src/core/alphabet.d.ts",
"chars": 117,
"preview": "export declare function alphabet(index: number): string;\nexport declare function alphabetIndex(key: string): number;\n"
},
{
"path": "src/core/alphabet.ts",
"chars": 629,
"preview": "const _alphabet = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','"
},
{
"path": "src/core/cell.d.ts",
"chars": 544,
"preview": "export interface Cell {\n font?: string;\n format?: string;\n fontSize?: number;\n bold?: boolean;\n italic?: "
},
{
"path": "src/core/cell.ts",
"chars": 1515,
"preview": "export interface Cell {\n font?: string;\n format?: string;\n fontSize?: number;\n bold?: boolean;\n italic?: boolean;\n "
},
{
"path": "src/core/font.d.ts",
"chars": 103,
"preview": "export interface Font {\n key: string;\n title: string;\n}\nexport declare const fonts: Array<Font>;\n"
},
{
"path": "src/core/font.ts",
"chars": 344,
"preview": "export interface Font {\n key: string;\n title: string;\n}\n\nexport const fonts: Array<Font> = [\n {key: 'Microsoft YaHei'"
},
{
"path": "src/core/format.d.ts",
"chars": 263,
"preview": "export interface Format {\n key: string;\n title: string;\n label?: string;\n render(txt: string): string;\n}\nexp"
},
{
"path": "src/core/format.ts",
"chars": 1181,
"preview": "export interface Format {\n key: string;\n title: string;\n label?: string;\n render(txt: string): string;\n}\nexport cons"
},
{
"path": "src/core/formula.d.ts",
"chars": 482,
"preview": "export interface Formula {\n key: string;\n title: string;\n render(ary: Array<number>): number;\n}\nexport declare "
},
{
"path": "src/core/formula.ts",
"chars": 3661,
"preview": "import { alphabetIndex, alphabet } from \"./alphabet\";\n\nexport interface Formula {\n key: string;\n title: string;\n rend"
},
{
"path": "src/core/index.d.ts",
"chars": 2837,
"preview": "import { Format } from './format';\nimport { Font } from './font';\nimport { Formula } from './formula';\nimport { Cell } f"
},
{
"path": "src/core/index.ts",
"chars": 22064,
"preview": "import { Format, formats } from './format'\nimport { Font, fonts } from './font'\nimport { Formula, formulas, formulaRepla"
},
{
"path": "src/core/select.d.ts",
"chars": 514,
"preview": "export declare class Select {\n start: [number, number];\n stop: [number, number];\n canMerge: boolean;\n constr"
},
{
"path": "src/core/select.ts",
"chars": 1050,
"preview": "export class Select {\n constructor(public start: [number, number], public stop: [number, number], public canMerge: bool"
},
{
"path": "src/local/base/colorPanel.d.ts",
"chars": 223,
"preview": "import { Element } from \"./element\";\nexport declare class ColorPanel extends Element {\n constructor(click: (color: st"
},
{
"path": "src/local/base/colorPanel.ts",
"chars": 1573,
"preview": "import { Element, h } from \"./element\";\n\nconst colorss = [\n ['#c00000', '#ff0000', '#ffc003', '#ffff00','#91d051', '#00"
},
{
"path": "src/local/base/dropdown.d.ts",
"chars": 368,
"preview": "import { Element } from \"./element\";\nexport declare class Dropdown extends Element {\n content: Element;\n title: El"
},
{
"path": "src/local/base/dropdown.ts",
"chars": 1210,
"preview": "import { Element, h } from \"./element\";\nimport { buildIcon } from \"./icon\";\n\nexport class Dropdown extends Element {\n c"
},
{
"path": "src/local/base/element.d.ts",
"chars": 1362,
"preview": "export declare class Element {\n tag: string;\n el: HTMLElement;\n _data: {\n [key: string]: any;\n };\n "
},
{
"path": "src/local/base/element.ts",
"chars": 5360,
"preview": "import { bind, unbind } from '../event'\n\nexport class Element {\n el: HTMLElement;\n _data: {[key: string]: any} = {};\n "
},
{
"path": "src/local/base/icon.d.ts",
"chars": 220,
"preview": "import { Element } from \"./element\";\nexport declare class Icon extends Element {\n img: Element;\n constructor(name:"
},
{
"path": "src/local/base/icon.ts",
"chars": 394,
"preview": "import { Element, h } from \"./element\";\n\nexport class Icon extends Element{\n\n img: Element;\n\n constructor (name: strin"
},
{
"path": "src/local/base/item.d.ts",
"chars": 294,
"preview": "import { Element } from \"./element\";\nimport { Icon } from \"./icon\";\nexport declare class Item extends Element {\n icon"
},
{
"path": "src/local/base/item.ts",
"chars": 511,
"preview": "import { Element } from \"./element\";\nimport { Icon, buildIcon } from \"./icon\";\n\nexport class Item extends Element {\n\n i"
},
{
"path": "src/local/base/menu.d.ts",
"chars": 173,
"preview": "import { Element } from \"./element\";\nexport declare class Menu extends Element {\n constructor(align?: string);\n}\nexpo"
},
{
"path": "src/local/base/menu.ts",
"chars": 252,
"preview": "import { Element } from \"./element\";\n\nexport class Menu extends Element{\n\n constructor (align = 'vertical') {\n super"
},
{
"path": "src/local/base/suggest.d.ts",
"chars": 586,
"preview": "import { Element } from \"./element\";\nexport declare class Suggest extends Element {\n list: Array<[string, string]>;\n "
},
{
"path": "src/local/base/suggest.ts",
"chars": 3753,
"preview": "import { Element, h } from \"./element\";\nimport { buildItem } from \"./item\";\nimport { buildMenu } from \"./menu\";\nimport {"
},
{
"path": "src/local/contextmenu.d.ts",
"chars": 203,
"preview": "import { Element } from \"./base/element\";\nimport { Table } from \"./table\";\nexport declare class ContextMenu {\n table:"
},
{
"path": "src/local/contextmenu.ts",
"chars": 1566,
"preview": "import { Element, h } from \"./base/element\";\nimport { buildItem } from \"./base/item\";\nimport { buildMenu } from \"./base/"
},
{
"path": "src/local/editor.d.ts",
"chars": 849,
"preview": "import { Element } from \"./base/element\";\nimport { Suggest } from \"./base/suggest\";\nimport { Cell } from \"../core/cell\";"
},
{
"path": "src/local/editor.ts",
"chars": 5244,
"preview": "import { Element, h } from \"./base/element\";\nimport { Suggest } from \"./base/suggest\";\nimport { Cell, getStyleFromCell }"
},
{
"path": "src/local/editorbar.d.ts",
"chars": 365,
"preview": "import { Element } from \"./base/element\";\nimport { Cell } from \"../core/cell\";\nexport declare class Editorbar {\n el: "
},
{
"path": "src/local/editorbar.ts",
"chars": 1066,
"preview": "import { Element, h } from \"./base/element\";\nimport { Cell } from \"../core/cell\";\nimport { mouseMoveUp } from \"./event\"\n"
},
{
"path": "src/local/event.d.ts",
"chars": 322,
"preview": "export declare function bind<T extends Event>(name: string, fn: (evt: T) => void, target?: any): void;\nexport declare fu"
},
{
"path": "src/local/event.ts",
"chars": 539,
"preview": "export function bind<T extends Event>(name: string, fn: (evt: T) => void, target: any = window) {\n target.addEventListe"
},
{
"path": "src/local/index.d.ts",
"chars": 937,
"preview": "import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index';\nimport '../style/index.less';\nimport {"
},
{
"path": "src/local/index.ts",
"chars": 3774,
"preview": "import { Spreadsheet, SpreadsheetOptions, SpreadsheetData } from '../core/index'\nimport '../style/index.less'\nimport { C"
},
{
"path": "src/local/resizer.d.ts",
"chars": 435,
"preview": "import { Element } from \"./base/element\";\nexport declare class Resizer {\n vertical: boolean;\n change: (index: numb"
},
{
"path": "src/local/resizer.ts",
"chars": 2550,
"preview": "import { Element, h } from \"./base/element\";\nimport { mouseMoveUp } from './event';\n\nexport class Resizer {\n el: Elemen"
},
{
"path": "src/local/selector.d.ts",
"chars": 1065,
"preview": "import { Element } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Table } from './table';\n"
},
{
"path": "src/local/selector.ts",
"chars": 8648,
"preview": "import { Element, h } from \"./base/element\";\nimport { bind, mouseMoveUp } from './event';\nimport { Spreadsheet } from \"."
},
{
"path": "src/local/table.d.ts",
"chars": 2445,
"preview": "import { Element } from \"./base/element\";\nimport { Spreadsheet, SpreadsheetData } from '../core/index';\nimport { Editor "
},
{
"path": "src/local/table.ts",
"chars": 21460,
"preview": "import { Element, h } from \"./base/element\";\nimport { Spreadsheet, SpreadsheetData } from '../core/index'\nimport { Edito"
},
{
"path": "src/local/toolbar.d.ts",
"chars": 1491,
"preview": "import { Element } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Cell } from '../core/cel"
},
{
"path": "src/local/toolbar.ts",
"chars": 9507,
"preview": "import { Element, h } from \"./base/element\";\nimport { Spreadsheet } from \"../core/index\";\nimport { Cell, getStyleFromCel"
},
{
"path": "src/main.d.ts",
"chars": 226,
"preview": "import { LocalSpreadsheet, Options } from './local/index';\nexport default function xspreadsheet(el: HTMLElement, options"
},
{
"path": "src/main.ts",
"chars": 285,
"preview": "import { LocalSpreadsheet, Options } from './local/index';\n\nexport default function xspreadsheet (el: HTMLElement, optio"
},
{
"path": "src/style/index.less",
"chars": 9326,
"preview": "@border-style: 1px solid #e0e2e4;\n@icon-size: 18px;\n\nbody {\n margin: 0;\n}\n\n.spreadsheet {\n font-size: 14px;\n line-hei"
},
{
"path": "tsconfig.json",
"chars": 5192,
"preview": "{\n \"compilerOptions\": {\n /* Basic Options */\n \"target\": \"ES2015\", /* Specify ECMAScript "
},
{
"path": "tslint.json",
"chars": 217,
"preview": "{\n \"defaultSeverity\": \"error\",\n \"extends\": [\n \"tslint:recommended\",\n \"tslint-eslint-rules\"\n ],\n "
},
{
"path": "webpack.config.dev.js",
"chars": 1666,
"preview": "var ExtractTextPlugin = require('extract-text-webpack-plugin');\nmodule.exports = {\n entry: \"./src/main.ts\",\n output: {"
},
{
"path": "webpack.config.js",
"chars": 1396,
"preview": "var ExtractTextPlugin = require('extract-text-webpack-plugin');\nmodule.exports = {\n entry: \"./src/main.ts\",\n output: {"
}
]
About this extraction
This page contains the full source code of the myliang/xspreadsheet GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 60 files (204.8 KB), approximately 62.2k tokens, and a symbol index with 476 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.