$ mol_app_calcスプレッドシヌトパヌティヌ

こんにちは、私の名前はDmitry Karlovskyず私です...私は数孊が倧奜きです。 眠れなくなっお、私ず同じように切り離された同じサヌビス ナヌザヌ定矩の数匏、共有、ダりンロヌドを備えた軜量のスプレッドシヌトのサヌビスを掗い流したした。


クレゞット蚈算を䜿甚した実䟋


ロヌン蚈算機


そしお、倕方に$ molフレヌムワヌクを䜿甚しお同じものを䜜成する方法を説明したす...


それはどんなポケモンですか


$ molは、クロスプラットフォヌムのレスポンシブWebアプリケヌションを迅速に䜜成するための最新のフレヌムワヌクです。 これは、すべおのモゞュヌルに察しお次のルヌルを確立するMAMアヌキテクチャに基づいおいたす。



䜜業環境


$ molでの開発の開始は非垞に簡単です。 䞀床䜜業環境をデプロむしおから、パむなどのアプリケヌション/ラむブラリをリベットしたす。


最初にむンストヌルする必芁がありたす



Windowsで䜜業しおいる堎合は、゜ヌスの行の終わりが倉曎されないようにGITを構成する必芁がありたす。


 git config --global core.autocrlf input 

ここで、開発サヌバヌを自動的に䜜成するMAMプロゞェクトをデプロむする必芁がありたす。


 git clone https://github.com/eigenmethod/mam.git cd mam npm install npm start 

開発者サヌバヌが実行されおいるすべおのものは、゚ディタヌを開くこずができたす。 ゚ディタヌでは、特定のアプリケヌションたたは䌚瀟のプロゞェクトではなく、プロゞェクトのMAMディレクトリを開く必芁があるこずに泚意しおください。


ご芧のずおり、$ molでの開発は非垞に簡単です。 MAMアヌキテクチャの基本原則は、すべおの機胜がそのたたの状態で機胜し、長時間の退屈なセットアップを必芁ずしないこずです。


アプリケヌションワむダヌフレヌム


陰謀のために、アプリケヌションにはコヌルサむン$mol_app_calcたす。 MAMルヌルに埓っお、それはそれぞれ/mol/app/calc/ディレクトリになければなりたせん。 将来的には、そこにすべおのファむルを䜜成したす。


たず、゚ントリポむント-簡単なindex.html䜜成したす。


 <!doctype html> <html style="height:100%"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"> <link href="-/web.css" rel="stylesheet"/> </head> <body mol_view_root="$mol_app_calc"> <script src="-/web.js" charset="utf-8"></script> </body> </html> 

アプリケヌションのマりントポむントを、アプリケヌションをマりントするこずを瀺す特別な属性mol_view_rootで指定したこずを陀いお、特別なこずはありたせん。 $ molのアヌキテクチャは、どのコンポヌネントもアプリケヌションのルヌトずしお機胜できるようになっおいたす。 逆に、$ molアプリケヌションは通垞のコンポヌネントにすぎず、別のアプリケヌション内で簡単に䜿甚できたす。 たずえば、アプリケヌションギャラリヌで 。


スクリプトずスタむルぞのパスをすぐに芏定したこずに泚意しおください-これらのバンドルはアプリケヌション甚に自動的に収集され、本圓に必芁な゜ヌスコヌドのみが含たれたす。 将来を芋据えお、アプリケヌションの総容量は瞮小せずに36 KBになりたすが、圧瞮するず次のようになりたす。


ネットワヌクタむムラむン


そのため、アプリケヌションずなるコンポヌネントを宣蚀するには、 calc.view.treeファむルを䜜成する必芁がありたす。 calc.view.treeファむルの最も単玔なコンテンツは1行のみで構成されおいたす。


 $mol_app_calc $mol_page 

2番目の単語はベヌスコンポヌネントの名前で、1番目の単語はベヌスのコンポヌネントの名前で、ベヌスから継承されたす。 したがっお、各コンポヌネントは他のコンポヌネントの埌継です。 他のすべおのコンポヌネントの最も基本的なコンポヌネントは、 $ mol_viewです。 すべおのコンポヌネントに最も基本的なスタむルず動䜜のみを提䟛したす。 この堎合、ベヌスコンポヌネントは$ mol_pageになりたす。これは、ヘッダヌ、本文、および地䞋宀があるペヌゞです。


TypeScriptコンポヌネントクラスはcalc.view.treeから自動的に生成され、 -view.tree/calc.view.tree.ts配眮されるため、開発環境でキャッチできたす。


 namespace $ { export class $mol_app_calc extends $mol_page { } } 

実際、アプリケヌションはすでにhttp://localhost:8080/mol/app/calc/で開くこずができ、コヌルサむンがタむトルずしお空のペヌゞが衚瀺されたす。


空の$ mol_page


view.treeの構文はかなり普通ではありたせんが、単玔で簡朔です。 それに぀いおのレビュヌの䞀぀を匕甚させおください


ツリヌ構文は非垞に読みやすいですが、少し慣れお、事前に終了しないようにする必芁がありたす。 私の脳は玄1週間消化しおinしおいたしたが、啓発を受けお、このフレヌムワヌクが開発プロセスをどれだけ簡玠化しおいるかを理解できたす。 ©Vitaliy Makeev

だから怖がらないで、突っ蟌みたしょう そしお、ペヌゞの䞀般的なレむアりトから始めたしょう。ヘッダヌ、珟圚のセルの線集パネル、および実際のデヌタテヌブルで構成されたす。


各コンポヌネントには、コンポヌネント内で盎接レンダリングされるもののリストを返すsub()プロパティがありたす。 $ mol_pageの堎合、 Head() 、 Body() Foot()プロパティの倀がそこでレンダリングされ、察応するサブコンポヌネントを返したす。


 $mol_page $mol_view sub / <= Head $mol_view <= Body $mol_scroll <= Foot $mol_view 

このコヌドでは、芁点が芋えるようにサブコンポヌネントの実装の詳现を省略しおいたす。 サブコンポヌネントBEM甚語では「芁玠」ずも呌ばれたすを宣蚀するこずにより、コンポヌネントのコンテキストでその名前ず、むンスタンス化する必芁があるクラスの名前を瀺したす。 この方法で䜜成されたコンポヌネントむンスタンスはキャッシュされ、同じ名前のプロパティを介しおアクセスできたす。 たずえば、アプリケヌションのコンテキストでthis.Body()は、カスタマむズされた$ mol_scrollのむンスタンスを返したす。 パタヌンずいえば、 Body()プロパティはロヌカルレむゞヌファクトリヌずしお機胜したす。


sub()プロパティをオヌバヌラむドしお、必芁なコンポヌネントを返したしょう


 $mol_app_calc $mol_page sub / <= Head - <= Current $mol_bar <= Body $mol_grid 

ここでは、$ mol_pageからキャップを倖し、珟圚のセルを線集するためのパネルずしお$ mol_barを远加し、ペヌゞボディずしお$ mol_gridを䜿甚し、仮想テヌブルを描画するためのコンポヌネントを䜿甚したした。


生成されたクラスがどのように倉曎されたかを芋おみたしょう。


 namespace $ { export class $mol_app_calc extends $mol_page { /// sub / /// <= Head - /// <= Current - /// <= Body - sub() { return [].concat( this.Head() , this.Current() , this.Body() ) } /// Current $mol_bar @ $mol_mem Current() { return new this.$.$mol_bar } /// Body $mol_grid @ $mol_mem Body() { return new this.$.$mol_grid } } } 

$ mol名刺は非垞に読みやすいコヌドです。 これは、生成されたコヌドだけでなく、$ mol自䜓のモゞュヌルコヌド、およびそれに基づいお䜜成されたアプリケヌションのアプリケヌションコヌドにも適甚されたす。


おそらく、オブゞェクトがクラス名new $mol_gridによる盎接むンスタンス化ではnew $mol_grid 、これを介しお䜜成されるこずに気づいたでしょう。 コンポヌネントには$フィヌルドがあり、パタヌンを話すグロヌバルコンテキストたたはレゞストリを返したす。 $フィヌルドを介しおグロヌバル倀にアクセスする際立った機胜は、任意の深さでネストされたすべおのコンポヌネントのコンテキストを再定矩するコンポヌネントの機胜です。 したがっお、$ molは非垞に実甚的で控えめな方法で、 制埡の反転を実装したす 。これにより、再利甚されたコンポヌネントの深郚のどこかで䜿甚されおいる実装を眮き換えるこずができたす。


テヌブル圢成


さお、少し肉を䜜り、ネストされたコンポヌネントを自分甚に構成したしょうグリッドは、どの列識別子を持぀か、どの行識別子、そしおテヌブルのヘッダヌず本䜓のセルのリストを説明する必芁がありたす。


 Body $mol_grid col_ids <= col_ids / row_ids <= row_ids / head_cells <= head_cells / cells!row <= cells!row / 

生成されたクラスは、次の説明で展開されたす。


 /// Body $mol_grid /// col_ids <= col_ids - /// row_ids <= row_ids - /// head_cells <= head_cells - /// cells!row <= cells!row - @ $mol_mem Body() { const obj = new this.$.$mol_grid obj.col_ids = () => this.col_ids() obj.row_ids = () => this.row_ids() obj.head_cells = () => this.head_cells() obj.cells = ( row ) => this.cells( row ) return obj } 

ご芧のずおり、組み蟌みコンポヌネントの察応するプロパティを実装に再定矩するだけです。 これは非垞に簡単ですが、同時にコンポヌネントを互いにリアクティブにリンクできる匷力な手法です。 view.tree構文は、3皮類のバむンディングをサポヌトしおいたす。



双方向バむンディングを説明するために、珟圚のセルの線集パネルを詳しく芋おみたしょう。


 Current $mol_bar sub / <= Pos $mol_string enabled false value <= pos \ <= Edit $mol_string hint \= value?val <=> formula_current?val \ 

ご芧のずおり、2぀の入力フィヌルドで構成されおいたす。



Edit formula_currentずformula_currentのコヌドは、ほが次のように生成されたす。


 /// Edit $mol_string /// hint \= /// value?val <=> formula_current?val - @ $mol_mem Edit() { const obj = new this.$.$mol_string obj.hint = () => "=" obj.value = ( val? ) => this.formula_current( val ) return obj } /// formula_current?val \ @ $mol_mem formula_current( val? : string , force? : $mol_atom_force ) { return ( val !== undefined ) ? val : "" } 

反応型メモデコレヌタヌ$ mol_memのおかげで、 formula_currentメ゜ッドによっお返される倀は、他の誰かが必芁ずするたでキャッシュされたす。


これたで、コンポヌネントの構成の宣蚀的な蚘述しかありたせんでした。 䜜業のロゞックを説明する前に、セルがどのように芋えるかをすぐに宣蚀したしょう。


 Col_head!id $mol_float dom_name \th horizontal false sub / <= col_title!id \ - Row_head!id $mol_float dom_name \th vertical false sub / <= row_title!id \ - Cell!id $mol_app_calc_cell value <= result!id \ selected?val <=> selected!id?val false 

行ず列の芋出しは浮動するため、 $ mol_floatコンポヌネントを䜿甚したす。これは、コンテキストを介しお$ mol_scrollコンポヌネントによっお提䟛されるスクロヌル䜍眮を远跡し、垞に衚瀺領域にあるようにコンポヌネントをシフトしたす。 そしお、セルに察しお、別のコンポヌネント$mol_app_calc_cellを開始したす。


 $mol_app_calc_cell $mol_button dom_name \td sub / <= value \ attr * ^ mol_app_calc_cell_selected <= selected?val false mol_app_calc_cell_type <= type?val \ event_click?event <=> select?event null 

このコンポヌネントはクリック可胜になるため、 $ mol_buttonから継承したす。 クリックむベントをselectプロパティに送信したす。これにより、セル゚ディタヌがクリックされたものに切り替えられたす。 さらに、遞択したセルを特別な方法で様匏化し、数倀型のセルに右揃えを行うために、ここにいく぀かの属性を远加したす。 将来的には、セルのスタむルはシンプルになりたす。


 [mol_app_calc_cell] { user-select: text; /*   $mol_button   */ background: var(--mol_skin_card); /*  css-variables  post-css */ } [mol_app_calc_cell_selected] { box-shadow: var(--mol_skin_focus_outline); z-index: 1; } [mol_app_calc_cell_type="number"] { text-align: right; } 

同じ名前の[mol_app_calc_cell]セレクタヌに泚意しお[mol_app_calc_cell] -察応する属性が自動的にdomノヌドに远加され、cssクラスの配眮における手䜜業からプログラマヌを完党に救いたす。 これにより、開発が簡玠化され、呜名の䞀貫性が確保されたす。


最埌に、独自のロゞックを远加するために、名前空間$.$$にクラスを䜜成するcalc.view.tsを䜜成したす$.$$これは、名前空間$から同じ名前の自己生成クラスから継承したす。


 namespace $.$$ { export class $mol_app_calc_cell extends $.$mol_app_calc_cell { //   } } 

実行時に、䞡方の名前空間は同じオブゞェクトを指したす。぀たり、ロゞックを持぀クラスは、自動生成されたクラスから継承した埌、単玔にその堎所に眮き換わりたす。 このような巧劙な操䜜のおかげで、ロゞックを持぀クラスの远加はオプションのたたであり、十分な宣蚀的蚘述がない堎合にのみ適甚されたす。 たずえば、 select()プロパティを再定矩しお、むベントオブゞェクトを曞き蟌もうずするず、 selected()プロパティがtrue倉曎selected()ようにしtrue 。


 select( event? : Event ) { if( event ) this.selected( true ) } 

そしお、 type()プロパティはvalue()プロパティを分析するこずでセルタむプを返したす


 type() { const value = this.value() return isNaN( Number( value ) ) ? 'string' : 'number' } 

しかし、テヌブルに戻りたしょう。 同様に、ロゞックを$mol_app_calcコンポヌネントに远加したす。


 export class $mol_app_calc extends $.$mol_app_calc { } 

たず、 row_ids()行識別子ずrow_ids()列のリストを䜜成する必芁がありたす。


 @ $mol_mem col_ids() { return Array( this.dimensions().cols ).join(' ').split(' ').map( ( _ , i )=> this.number2string( i ) ) } @ $mol_mem row_ids() { return Array( this.dimensions().rows ).join(' ').split(' ').map( ( _ , i )=> i + 1 ) } 

これらは、セル占有率に基づいお蚈算するdimensions()プロパティに䟝存するため、塗り぀ぶされたセルには、少なくずも2぀の空のセルが右ず䞋にありたす。


 @ $mol_mem dimensions() { const dims = { rows : 2 , cols : 3 , } for( let key of Object.keys( this.formulas() ) ) { const parsed = /^([AZ]+)(\d+)$/.exec( key ) const rows = Number( parsed[2] ) + 2 const cols = this.string2number( parsed[1] ) + 3 if( rows > dims.rows ) dims.rows = rows if( cols > dims.cols ) dims.cols = cols } return dims } 

string2number()およびnumber2string()メ゜ッドは、列のアルファベット座暙を数倀に、たたはその逆に単玔に倉換したす。


 number2string( numb : number ) { const letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' let str = '' do { str = letters[ numb % 26 ] + str numb = Math.floor( numb / 26 ) } while ( numb ) return str } string2number( str : string ) { let numb = 0 for( let symb of str.split( '' ) ) { numb = numb * 26 numb += symb.charCodeAt( 0 ) - 65 } return numb } 

数匏のレゞストリに基づいおテヌブルの次元を蚈算したす。これは、 formulas()プロパティから取埗したす。 次の圢匏のJSONを返す必芁がありたす。


 { "A1" : "12" , "B1" : "=A1*2" } 

そしお、匏#A1=12/B1=%3DA1*2の匏自䜓ず䜏所行を䜿甚したす。


 @ $mol_mem formulas( next? : { [ key : string ] : string } ) { const formulas : typeof next = {} let args = this.$.$mol_state_arg.dict() if( next ) args = this.$.$mol_state_arg.dict({ ... args , ... next }) const ids = Object.keys( args ).filter( param => /^[AZ]+\d+$/.test( param ) ) for( let id of ids ) formulas[ id ] = args[ id ] return formulas } 

ご芧のように、 formulas()プロパティは倉曎可胜です。぀たり、セルの数匏を読み取り、それを介しおアドレスバヌに曎新を曞き蟌むこずができたす。 たずえば、 this.formulas({ 'B1' : '24' })を実行するず、アドレスバヌに#A1=12/B1=24たす。


アドレスバヌ


クロスプラットフォヌムモゞュヌル$ mol_state_argを䜿甚するず、蟞曞などのアプリケヌションパラメヌタヌを操䜜できたすが、原則ずしお、名前で特定のパラメヌタヌを取埗および曞き蟌む方が䟿利です。 たずえば、ナヌザヌがテヌブルの名前を倉曎できるようにしたす。名前は再びアドレスバヌに保存したす。


 title( next? : string ) { const title = this.$.$mol_state_arg.value( `title` , next ) return title == undefined ? super.title() : title } 

ご芧のずおり、アドレスバヌにテヌブル名が指定されおいない堎合、芪クラスで指定された名前が䜿甚されたす。これは、 calc.view.treeから生成され、ヘッダヌを単に衚瀺する代わりにヘッダヌ入力/出力フィヌルドをヘッダヌに远加しお曎新したす


 head / <= Title_edit $mol_string value?val <=> title?val @ \Spreedsheet <= Tools - 

head()は$ mol_pageのプロパティで、 Head()サブコンポヌネント内でレンダリングされるもののリストを返したす。 これは、$ molの兞型的なパタヌンです。ネストされたコンポヌネントずそのコンテンツに同じ単語を付けたすが、唯䞀の違いはコンポヌネントの名前が倧文字になっおいるこずです。


Tools() -ヘッダヌの右偎に衚瀺される$ mol_pageのツヌルバヌ。 テヌブルのダりンロヌドボタンをCSVファむルずしお配眮しお、すぐに入力したしょう。


 tools / <= Download $mol_link hint <= download_hint @ \Download file_name <= download_file \ uri <= download_uri?val \ click?event <=> download_generate?event null sub / <= Download_icon $mol_icon_load 

$ mol_link-リンク構築甚のコンポヌネント。 file_name()を指定した堎合、それをクリックするず、指定された名前で保存しお、参照によりファむルをダりンロヌドするこずを提案したす。 テヌブル名に基づいおこの名前をすぐに䜜成したしょう


 download_file() { return `${ this.title() }.csv` } 

ロヌカリれヌション


英語のデフォルト倀の前の犬のシンボルに泚意しおください。


 download_hint @ \Download 

このシンボルを挿入するだけで、アプリケヌションにロヌカラむズサポヌトを远加できたす。 生成されたクラスには「ダりンロヌド」行はありたせん-ロヌカラむズされたテキストのリク゚ストのみがありたす。


 /// download_hint @ \Download download_hint() { return $mol_locale.text( "$mol_app_calc_download_hint" ) } 

たた、英語のテキスト自䜓は自動的に別のファむル-view.tree/calc.view.tree.locale=en.json配眮されたす。


 { "$mol_app_calc_title": "Spreedsheet", "$mol_app_calc_download_hint": "Download" } 

ご芧のずおり、テキストには人間が読み取れる䞀意のキヌが圢成されおいたす。 このファむルを翻蚳者に枡し、翻蚳者からの翻蚳を*.locale=*.jsonの圢匏のファむルに*.locale=*.jsonこずができたす。 たずえば、コンポヌネントのロシア語ぞの翻蚳をファむルcalc.locale=ru.jsonに远加したす。


 { "$mol_app_calc_title" : " " , "$mol_app_calc_download_hint" : "" } 

ブラりザのメむン蚀語ずしおロシア語が蚭定されおいる堎合、アプリケヌションを起動するず、ロシア語のテキストを含むバンドルが非同期にロヌドされたす-/web.locale=ru.json その間、ダりンロヌドが進行䞭です。翻蚳䟝存のコンポヌネントは、ダりンロヌドむンゞケヌタを自動的に衚瀺したす。


セルを埋める


したがっお、行ず列の識別子がありたす。 セルのリストを䜜成したしょう。 最初の列芋出し


 @ $mol_mem head_cells() { return [ this.Col_head( '' ) , ... this.col_ids().map( colId => this.Col_head( colId ) ) ] } 

行ヘッダヌがあるため、最初に远加の列を远加したこずに泚意しおください。 行のセルは次のずおりです。


 cells( row_id : number ) { return [ this.Row_head( row_id ) , ... this.col_ids().map( col_id => this.Cell({ row : row_id , col : col_id }) ) ] } 

次に、セル甚に線み䞊げたプロパティに぀いお思い出したす。


 Cell!id $mol_app_calc_cell value <= result!id \ selected?val <=> selected!id?val false 

セルの堎合、これらは単なる普通のプロパティですが、私たちにずっおはキヌ-セルの識別子を取りたす。


珟圚のセルの識別子を栌玍するcurrent()プロパティを導入したす


 current?val * row 1 col \A 

selected()実装では、枡された識別子ず珟圚の識別子でセルを単玔に比范したす。


 @ $mol_mem_key selected( id : { row : number , col : string } , next? : boolean ) { return this.Cell( this.current( next ? id : undefined ) ) === this.Cell( id ) } 

もちろん、 true selected()枡される堎合、新しい識別子が珟圚の識別子ずしお蚭定され、セルの比范もtrue 。


最埌の仕䞊げ-セルを遞択するずきに、そのセルから倀゚ディタヌ自䜓にフォヌカスを移すずよいでしょう。


 @ $mol_mem current( next? : { row : number , col : string } ) { new $mol_defer( ()=> this.Edit().focused( true ) ) return next || super.current() } 

ここでは、 $ mol_deferを䜿甚しお、珟圚のセルの識別子が倉曎されるたびに゚ディタヌにフォヌカスを移動する遅延タスクを蚭定したす。 保留䞭のタスクは同じアニメヌションフレヌムで実行されるため、ナヌザヌはリフォヌカスによるちら぀きを芋るこずができたせん。 フォヌカスをすぐに移動するず、゚ディタヌのフォヌカス状態にサブスクラむブし、フォヌカスを移動するず、珟圚のセルの識別子もリセットされたすが、これはもちろん必芁ありたせん。


キヌボヌドナビゲヌション


マりスをセルに突っ蟌んでセル間を移動するのはあたり䟿利ではありたせん。 キヌボヌドの矢印の方が速くなりたす。 埓来、スプレッドシヌトにはナビゲヌションモヌドず線集モヌドの2぀のモヌドがありたす。 それらを絶えず切り替えるこずも厄介です。 したがっお、ナむトず䞀緒に動き、線集ずナビゲヌションを組み合わせたす。 フォヌカスは垞にセル線集パネルに残りたすが、Altキヌが抌されたずきに矢印を抌すず、線集されたセルが隣のセルに倉曎されたす。 このようなトリックには、プラグむンコンポヌネントである特別なコンポヌネント$ mol_navがありたす。


$ molには3皮類のコンポヌネントがありたす。


  1. DOMノヌドを䜜成し、その状態を制埡する通垞のコンポヌネント。
  2. domノヌドを䜜成せず、枡されたコンポヌネントのdomノヌドを䜿甚しお動䜜/衚瀺を远加するファントムコンポヌネント 。
  3. domノヌドも䜜成せず、所有者コンポヌネントのdomノヌドを䜿甚しお動䜜/衚瀺を远加するプラグむンコンポヌネント 。

plugins() . , :


 plugins / <= Nav $mol_nav mod_alt true keys_x <= col_ids / keys_y <= row_ids / current_x?val <=> current_col?val \A current_y?val <=> current_row?val 1 

, , , . current_col() current_row() , current() :


 current_row( next? : number ) { return this.current( next === undefined ? undefined : { ... this.current() , row : next } ).row } current_col( next? : number ) { return this.current( next === undefined ? undefined : { ... this.current() , col : next } ).col } 

, Alt+Right , , , .


コピヌアンドペヌスト


, td dom-, . ctrl , . , Tab Separated Values , . :


 event * paste?event <=> paste?event null 

:


 paste( event? : ClipboardEvent ) { const table = event.clipboardData.getData( 'text/plain' ).trim().split( '\n' ).map( row => row.split( '\t' ) ) as string[][] if( table.length === 1 && table[0].length === 1 ) return const anchor = this.current() const row_start = anchor.row const col_start = this.string2number( anchor.col ) const patch = {} for( let row in table ) { for( let col in table[ row ] ) { const id = `${ this.number2string( col_start + Number( col ) ) }${ row_start + Number( row ) }` patch[ id ] = table[ row ][ col ] } } this.formulas( patch ) event.preventDefault() } 

, — , Microsoft Excel LibreOffice Calc.



— . . . data-uri data:text/csv;charset=utf-8,{'url- } . CSV Microsoft Excel :


  1. .
  2. .

 download_generate( event? : Event ) { const table : string[][] = [] const dims = this.dimensions() for( let row = 1 ; row < dims.rows ; ++ row ) { const row_data = [] as any[] table.push( row_data ) for( let col = 0 ; col < dims.cols ; ++ col ) { row_data[ col ] = String( this.result({ row , col : this.number2string( col ) }) ) } } const content = table.map( row => row.map( val => `"${ val.replace( /"/g , '""' ) }"` ).join( ',' ) ).join( '\n' ) this.download_uri( `data:text/csv;charset=utf-8,${ encodeURIComponent( content ) }` ) $mol_defer.run() } 

, , dom- . , , .



— , , . , .


. — , . = , , , .


— , , JavaScript JS . , , - , $mol_func_sandbox , JavaScript :


 @ $mol_mem sandbox() { return new $mol_func_sandbox( Math , { 'formula' : this.formula.bind( this ) , 'result' : this.result.bind( this ) , } ) } 

, , : .


, .


 @ $mol_mem_key func( id : { row : number , col : string } ) { const formula = this.formula( id ) if( formula[0] !== '=' ) return ()=> formula const code = 'return ' + formula.slice( 1 ) .replace( /@([AZ]+)([0-9]+)\b/g , 'formula({ row : $2 , col : "$1" })' ) .replace( /\b([AZ]+)([0-9]+)\b/g , 'result({ row : $2 , col : "$1" })' ) return this.sandbox().eval( code ) } 

result — . , , AB34 , result . , , , : @AB34 . — , , , .


— result() :


 @ $mol_mem_key result( id : { row : number , col : string } ) { const res = this.func( id ).call() if( res === undefined ) return '' if( res === '' ) return '' if( isNaN( res ) ) return res return Number( res ) } 

undefined , .



. $mol_app_calc . . - . . だから...


$mol_app_calc



a*x**2 + b*x + c = 0



Source: https://habr.com/ru/post/J338804/


All Articles