UNPKG

ethercalc

Version:

Multi-User Spreadsheet Server

330 lines (303 loc) 11.6 kB
<!DOCTYPE html> <html manifest="manifest.appcache"> <head> <title>EtherCalc</title> <meta charset="utf-8" /> <meta content="IE=edge" http-equiv="X-UA-Compatible"/> <script>try { window.history.pushState({}, '', './') } catch (e) {}</script> <link href="./static/start.css" rel="stylesheet" type="text/css"> </head> <body id="framedpagebody" class="home"> <div id="top"> <div id="topnav_wrap"> <div id="navigation"></div> </div> <div id="intro-left"> <h1>EtherCalc</h1> <h2><a target="_blank" style="border: none" title="Read the story of this project" href="https://ethercalc.net/">EtherCalc is a web spreadsheet.</a></h2> <p>Your data is saved on the web, and people can edit the same document at the same time. Everybody's changes are instantly reflected on all screens.</p> <p>Work together on inventories, survey forms, list management, brainstorming sessions and more!</p> <div id="intro-links"> <a id="newpadbutton" href="./_new" alt="Create Spreadsheet"><span>Create Spreadsheet</span><br> <small>No sign-up, start editing instantly</small></a> </div> <a id="restore" target="_blank" href="https://ethercalc.org/log/" title="View &amp; Restore Backups" class="btn btn-primary btn-fab btn-raised mdi-action-restore" style="visibility: hidden; width: 28px; height: 28px; margin-left: 270px; margin-top: 10px"></a> </div> </div> <a href="https://github.com/audreyt/ethercalc"><img style="z-order: 9999; position: absolute; top: 0; right: 0; border: 0" src="./static/img/right-graphite@2x.png" alt="Fork me on GitHub" width="120" height="120"></a> <script src="./static/jszip.js"></script> <script src="./static/xlsx.js"></script> <script src="./static/shim.js"></script> <script src="./static/jquery.js"></script> <div id="drop">Drop a .csv, .ods, or a .xlsx file here to import it<div style="display:block;font-size:60%;padding-top:0.5ex"><label style="cursor:pointer"><input type='checkbox' id='rename_sheet' name='rename_sheet'>Rename sheet(s) after upload</label></div></div> <style> #drop { display: block; clear: both; margin-top: 40px; background: #eee; border:2px dashed #bbb; -moz-border-radius:5px; -webkit-border-radius:5px; border-radius:5px; padding:20px; text-align:center; font:20pt bold,"Vollkorn";color:#bbb } </style> <script> if (/^(?:www\.)?ethercalc\.(?:org|com)$/.test(location.host)) { $("head").append("<link rel='stylesheet' type='text/css' href='https://ethercalc.org/log/css/material.min.css' />"); $("#restore").css('visibility', 'visible'); } var rABS = typeof FileReader !== "undefined" && typeof FileReader.prototype !== "undefined" && typeof FileReader.prototype.readAsBinaryString !== "undefined"; function fixdata(data) { var o = "", l = 0, w = 10240; for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,new Uint8Array(data.slice(l*w,l*w+w))); o+=String.fromCharCode.apply(null, new Uint8Array(data.slice(o.length))); return o; } // cb is typically process_wb function xlsxworker(data, cb, id) { var worker = new Worker('./static/xlsxworker.js'); worker.onmessage = function(e) { switch(e.data.t) { case 'ready': break; case 'e': console.error(e.data.d); break; case 'xlsx': cb(JSON.parse(e.data.d), id); break; } }; var arr = rABS ? data : btoa(fixdata(data)); worker.postMessage({d:arr,b:rABS}); } function get_radio_value( radioName ) { var radios = document.getElementsByName( radioName ); for( var i = 0; i < radios.length; i++ ) { if( radios[i].checked ) { return radios[i].value; } } } function to_csv(workbook) { var result = []; workbook.SheetNames.forEach(function(sheetName) { var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]); if(csv.length > 0){ result.push("SHEET: " + sheetName); result.push(""); result = []; result.push(csv); } }); return result.join("\n").replace(/,+\n/g, '\n').replace(/[\s]+$/, '\n'); } /* xlsx2socialcalc.js (C) 2014 SheetJS -- http://sheetjs.com */ /* License: Apache 2.0 */ /* vim: set ts=2: */ var sheet_to_socialcalc = (function() { var header = [ "socialcalc:version:1.5", "MIME-Version: 1.0", "Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave" ].join("\n"); var sep = [ "--SocialCalcSpreadsheetControlSave", "Content-type: text/plain; charset=UTF-8", "" ].join("\n"); /* TODO: the other parts */ var meta = [ "# SocialCalc Spreadsheet Control Save", "part:sheet" ].join("\n"); var end = "--SocialCalcSpreadsheetControlSave--"; var scencode = function(s) { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); } var scsave = function scsave(ws) { if(!ws || !ws['!ref']) return ""; var o = [], oo = [], cell, coord; var r = XLSX.utils.decode_range(ws['!ref']); for(var R = r.s.r; R <= r.e.r; ++R) { for(var C = r.s.c; C <= r.e.c; ++C) { coord = XLSX.utils.encode_cell({r:R,c:C}); if(!(cell = ws[coord]) || cell.v == null) continue; oo = ["cell", coord, 't']; switch(cell.t) { case 's': case 'str': oo.push(scencode(cell.v)); break; case 'n': if(cell.f) { oo[2] = 'vtf'; oo.push('n'); oo.push(cell.v); oo.push(scencode(cell.f)); } else { oo[2] = 'v'; oo.push(cell.v); } break; } o.push(oo.join(":")); } } o.push("sheet:c:" + (r.e.c - r.s.c + 1) + ":r:" + (r.e.r - r.s.r + 1) + ":tvf:1"); o.push("valueformat:1:text-wiki"); o.push("copiedfrom:" + ws['!ref']); return o.join("\n"); }; return function socialcalcify(ws, opts) { return [header, sep, meta, sep, scsave(ws), end].join("\n"); //return ["version:1.5", scsave(ws)].join("\n"); }; })(); function process_wb(wb, id) { var output = ""; if (wb.SheetNames.length > 1) { var toc = '"#url","#title"\n'; var names = [].concat(wb.SheetNames); var idx = 0; var res = []; var sheetsToIdx = {} for (var i = 0; i < names.length; i++) { sheetsToIdx[names[i]] = i+1; res.push(names[i].replace(/'/g, "''").replace(/(\W)/g, '\\$1')); } var step = function(){ if (names.length) { idx++; var k = names.shift(); output = sheet_to_socialcalc(wb.Sheets[k]); toc += '"/' + id + '.' + idx + '",'; toc += '"' + k.replace(/"/g, '""') + '"\n'; output = output.replace( RegExp('(\'?)\\b(' + res.join('|') + ')\\1!', 'g'), function(_0, _1, ref){ return "'" + id + "." + sheetsToIdx[ref.replace(/''/g, "'")] + "'!"; } ); $.ajax({ url: './_/' + id + '.' + idx, method: 'PUT', contentType: 'text/x-socialcalc; charset=utf-8', processData: false, data: output, success: function(data, msg, xhr) { step(); } }); } else { $.ajax({ url: './_/' + id, method: 'PUT', contentType: 'text/csv; charset=utf-8', processData: false, data: toc, success: function(data, msg, xhr) { location.href = './=' + id } }); } }; step(); return; } output = sheet_to_socialcalc(wb.Sheets[wb.SheetNames[0]]); $.ajax({ url: './_/' + id, method: 'PUT', contentType: 'text/x-socialcalc; charset=utf-8', processData: false, data: output, success: function(data, msg, xhr) { location.href = './' + id } }); } function post_csv (csv, id) { $.ajax({ url: './_/' + id, method: 'PUT', contentType: 'text/csv', processData: false, data: csv, success: function(data, msg, xhr) { location.href = './' + id } }); } var BASE64URICHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_'.split(''); function newId (len, radix) { var chars = BASE64URICHARS, newId = [], i=0; radix = radix || chars.length; len = len || 22; for (i = 0; i < len; i++) newId[i] = chars[0 | Math.random()*radix]; return newId.join(''); }; function get_id(file, checked) { var id = null; if (checked) { id = prompt("Enter a spreadsheet name for " + file + " (alphanumeric only)", ""); id = id.trim().toLowerCase().replace(/\s/g, "_"); } if (id === null) { id = newId(10, 36).toLowerCase(); } return id; } var drop = document.getElementById('drop'); var renameSheetCheckbox = document.getElementById('rename_sheet'); function handleDrop(e) { e.stopPropagation(); e.preventDefault(); var toggle = function(){ $(drop).fadeOut('fast', function(){ $(drop).fadeIn('fast', toggle) }); } var files = e.dataTransfer.files; var i,f; $(drop).text('Working...'); for (i = 0, f = files[i]; i != files.length; ++i) { var reader = new FileReader(); var name = f.name; var id = get_id(name, $(renameSheetCheckbox).is(":checked")); reader.onload = function(e) { var data = e.target.result; if (!/^PK\u0003\u0004/.test(data) && /^[^\n]+,(?:[^\n]+)*\n/.test(data)) { return post_csv(data, id); } if(typeof Worker !== 'undefined') { xlsxworker(data, process_wb, id); } else { var wb; if(rABS) { wb = XLSX.read(data, {type: 'binary'}); } else { var arr = fixdata(data); wb = XLSX.read(btoa(arr), {type: 'base64'}); } process_wb(wb, id); } }; if(rABS) { reader.readAsBinaryString(f); } else { reader.readAsArrayBuffer(f); } } } function handleDragover(e) { e.stopPropagation(); e.preventDefault(); e.dataTransfer.dropEffect = 'copy'; } if(drop.addEventListener) { drop.addEventListener('dragenter', handleDragover, false); drop.addEventListener('dragover', handleDragover, false); drop.addEventListener('drop', handleDrop, false); } </script> </body> </html>