localStorage Demo GeckoTang Follow 2010-08-05 11:17:01 License: see code comments Fork2 Fav6 View1665 localStrageのデモとしてメモ帳のようなものを。 * Strageに入れたjsonをダウンロードさせる為に * 以下を使用させていただきました。 * * js内で無圧縮ZIPを作ってData URIを生成するライブラリ * http://d.hatena.ne.jp/amachang/20081130/1228029751 Play Stop Reload Fullscreen Smart Phone Fork tree Readme JavaScript 605 lines HTML 22 lines CSS 77 lines localStrageのデモとしてメモ帳のようなものを。 * Strageに入れたjsonをダウンロードさせる為に * 以下を使用させていただきました。 * * js内で無圧縮ZIPを作ってData URIを生成するライブラリ * http://d.hatena.ne.jp/amachang/20081130/1228029751 localStorage Demo jQuery v1.4.2 /* * localStrageのデモとしてメモ帳のようなものを。 * Strageに入れたjsonをダウンロードさせる為に * 以下を使用させていただきました。 * * js内で無圧縮ZIPを作ってData URIを生成するライブラリ * http://d.hatena.ne.jp/amachang/20081130/1228029751 */ var model = { id : "diary", serialize : function(){ return JSON.stringify(this); }, deserialize : function(jsonstr){ var data = eval("(" + jsonstr + ")"); for(var key in data){ this[key] = data[key]; } return this; } }; $(function(){ loadlib(); var storage = window.localStorage; if(storage){ var jsonStr = storage.getItem(model.id); var jsonObj = model.deserialize(jsonStr); if(!jsonObj.data){ jsonObj.data={}; } if(!jsonObj.data.items){ jsonObj.data.items=[]; } createTable(jsonObj.data); var todo_submit = $("#todo_submit"); var todo_title = $("#todo_title"); var todo_msg = $("#todo_msg"); var todo_allclear = $("#todo_allclear"); var info = $("#info"); todo_submit.click(function(){todoSet();}); todo_allclear.click(function(){todoAllClear();}); } // create table function createTable(json){ var result = $("#result"); var html = []; if(json.items.length>0){ //download zip file $("#dlArea").show(); var zip = new Zip; zip.addString(model.serialize(), 'localstrage.js'); var dataURI = zip.getDataURI(); $("#ziplink").attr("href",dataURI); //create html html.push('<table>'); html.push('<thead><tr><th> タイトル</th><td>本文</td><td>時間</td></tr></thead>'); html.push('<tbody>'); for(var i=0;i<json.items.length;i++){ html.push('<tr id="local_strage_'+model.id+'_'+i+'">'); html.push('<th>'+json.items[i].title+'</th>'); html.push('<td>'+json.items[i].msg+'</td>'); html.push('<td>'+json.items[i].date+'</td>'); html.push('</tr>'); } html.push('</tbody>'); html.push('</table>'); result.html(html.join('\n')); }else{ $("#dlArea").hide(); result.html("データがありません。"); } } // clear function todoAllClear(){ model.data.items = []; storage.setItem(model.id,model.serialize()); createTable(model.data); } // set function todoSet(){ var jsonStr = storage.getItem(model.id); var jsonObj = model.deserialize(jsonStr); if(!jsonObj.data){ jsonObj.data = {}; } if(!jsonObj.data.items){ jsonObj.data.items = []; } var data = jsonObj.data; var tVal = todo_title.val(); var mVal = todo_msg.val(); var dt = new Date(); var dateStr = dt.getFullYear()+"-"+(dt.getMonth()+1)+"-"+dt.getDate()+" "+dt.getHours()+":"+dt.getMinutes()+":"+ dt.getSeconds(); if(tVal && mVal){ data.items.push({"title" : tVal, "msg":mVal, "date":dateStr}); model.data = data; storage.setItem(model.id,model.serialize()); createTable(data); todo_title.val(''); todo_msg.val(''); info.html("保存しました。"); }else{ info.html("タイトル・本文を入力してください。"); } } }); //unload window.onunload = function(){ var storage = window.localStorage; if(storage){ var jsonStr = model.serialize(); storage.setItem(model.id,jsonStr); } }; function loadlib(){ /* * $Id: base64.js,v 0.2 2008/06/18 08:01:50 dankogai Exp dankogai $ */ (function() { var b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var b64charcodes = function() { var a = []; var codeA = 'A'.charCodeAt(0); var codea = 'a'.charCodeAt(0); var code0 = '0'.charCodeAt(0); for (var i = 0; i < 26; i ++) a.push(codeA + i); for (var i = 0; i < 26; i ++) a.push(codea + i); for (var i = 0; i < 10; i ++) a.push(code0 + i); a.push('+'.charCodeAt(0)); a.push('/'.charCodeAt(0)); return a; }(); var b64tab = function(bin) { var t = {}; for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; return t; }(b64chars); var stringToArray = function(s) { var a = []; for (var i = 0, l = s.length; i < l; i ++) a[i] = s.charCodeAt(i); return a; }; var convertUTF8ArrayToBase64 = function(bin) { var padlen = 0; while (bin.length % 3) { bin.push(0); padlen++; }; var b64 = []; for (var i = 0, l = bin.length; i < l; i += 3) { var c0 = bin[i], c1 = bin[i+1], c2 = bin[i+2]; if (c0 >= 256 || c1 >= 256 || c2 >= 256) throw 'unsupported character found'; var n = (c0 << 16) | (c1 << 8) | c2; b64.push( b64charcodes[ n >>> 18], b64charcodes[(n >>> 12) & 63], b64charcodes[(n >>> 6) & 63], b64charcodes[ n & 63] ); } while (padlen--) b64[b64.length - padlen - 1] = '='.charCodeAt(0); return String.fromCharCode.apply(String, b64); }; var convertBase64ToUTF8Array = function(b64) { b64 = b64.replace(/[^A-Za-z0-9+\/]+/g, ''); var bin = []; var padlen = b64.length % 4; for (var i = 0, l = b64.length; i < l; i += 4) { var n = ((b64tab[b64.charAt(i )] || 0) << 18) | ((b64tab[b64.charAt(i+1)] || 0) << 12) | ((b64tab[b64.charAt(i+2)] || 0) << 6) | ((b64tab[b64.charAt(i+3)] || 0)); bin.push( ( n >> 16 ), ( (n >> 8) & 0xff ), ( n & 0xff ) ); } bin.length -= [0,0,2,1][padlen]; return bin; }; var convertUTF16ArrayToUTF8Array = function(uni) { var bin = []; for (var i = 0, l = uni.length; i < l; i++) { var n = uni[i]; if (n < 0x80) bin.push(n); else if (n < 0x800) bin.push( 0xc0 | (n >>> 6), 0x80 | (n & 0x3f)); else bin.push( 0xe0 | ((n >>> 12) & 0x0f), 0x80 | ((n >>> 6) & 0x3f), 0x80 | (n & 0x3f)); } return bin; }; var convertUTF8ArrayToUTF16Array = function(bin) { var uni = []; for (var i = 0, l = bin.length; i < l; i++) { var c0 = bin[i]; if (c0 < 0x80) { uni.push(c0); } else { var c1 = bin[++i]; if (c0 < 0xe0) { uni.push(((c0 & 0x1f) << 6) | (c1 & 0x3f)); } else { var c2 = bin[++i]; uni.push( ((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f) ); } } } return uni; }; var convertUTF8StringToBase64 = function(bin) { return convertUTF8ArrayToBase64(stringToArray(bin)); }; var convertBase64ToUTF8String = function(b64) { return String.fromCharCode.apply(String, convertBase64ToUTF8Array(b64)); }; var convertUTF8StringToUTF16Array = function(bin) { return convertUTF8ArrayToUTF16Array(stringToArray(bin)); }; var convertUTF8ArrayToUTF16String = function(bin) { return String.fromCharCode.apply(String, convertUTF8ArrayToUTF16Array(bin)); }; var convertUTF8StringToUTF16String = function(bin) { return String.fromCharCode.apply(String, convertUTF8ArrayToUTF16Array(stringToArray(bin))); }; var convertUTF16StringToUTF8Array = function(uni) { return convertUTF16ArrayToUTF8Array(stringToArray(uni)); }; var convertUTF16ArrayToUTF8String = function(uni) { return String.fromCharCode.apply(String, convertUTF16ArrayToUTF8Array(uni)); }; var convertUTF16StringToUTF8String = function(uni) { return String.fromCharCode.apply(String, convertUTF16ArrayToUTF8Array(stringToArray(uni))); }; if (window.btoa) { var btoa = window.btoa; var convertUTF16StringToBase64 = function (uni) { return btoa(convertUTF16StringToUTF8String(uni)); }; } else { var btoa = convertUTF8StringToBase64; var convertUTF16StringToBase64 = function (uni) { return convertUTF8ArrayToBase64(convertUTF16StringToUTF8Array(uni)); }; } if (window.atob) { var atob = window.atob; var convertBase64ToUTF16String = function (b64) { return convertUTF8StringToUTF16String(atob(b64)); }; } else { var atob = convertBase64ToUTF8String; var convertBase64ToUTF16String = function (b64) { return convertUTF8ArrayToUTF16String(convertBase64ToUTF8Array(b64)); }; } window.Base64 = { convertUTF8ArrayToBase64:convertUTF8ArrayToBase64, convertByteArrayToBase64:convertUTF8ArrayToBase64, convertBase64ToUTF8Array:convertBase64ToUTF8Array, convertBase64ToByteArray:convertBase64ToUTF8Array, convertUTF16ArrayToUTF8Array:convertUTF16ArrayToUTF8Array, convertUTF16ArrayToByteArray:convertUTF16ArrayToUTF8Array, convertUTF8ArrayToUTF16Array:convertUTF8ArrayToUTF16Array, convertByteArrayToUTF16Array:convertUTF8ArrayToUTF16Array, convertUTF8StringToBase64:convertUTF8StringToBase64, convertBase64ToUTF8String:convertBase64ToUTF8String, convertUTF8StringToUTF16Array:convertUTF8StringToUTF16Array, convertUTF8ArrayToUTF16String:convertUTF8ArrayToUTF16String, convertByteArrayToUTF16String:convertUTF8ArrayToUTF16String, convertUTF8StringToUTF16String:convertUTF8StringToUTF16String, convertUTF16StringToUTF8Array:convertUTF16StringToUTF8Array, convertUTF16StringToByteArray:convertUTF16StringToUTF8Array, convertUTF16ArrayToUTF8String:convertUTF16ArrayToUTF8String, convertUTF16StringToUTF8String:convertUTF16StringToUTF8String, convertUTF16StringToBase64:convertUTF16StringToBase64, convertBase64ToUTF16String:convertBase64ToUTF16String, fromBase64:convertBase64ToUTF8String, toBase64:convertUTF8StringToBase64, atob:atob, btoa:btoa, utob:convertUTF16StringToUTF8String, btou:convertUTF8StringToUTF16String, encode:convertUTF16StringToBase64, encodeURI:function(u) { return convertUTF16StringToBase64(u).replace(/[+\/]/g, function(m0) { return m0 == '+' ? '-' : '_'; }).replace(/=+$/, ''); }, decode:function(a) { return convertBase64ToUTF16String(a.replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/'; })); } }; })(); // This source code is in the public domain. (function() { function Zip() { this.members = []; } Zip.prototype = { mimeType: 'application/zip', addMember: function(member) { this.members.push(member); return member; }, addString: function(string, name) { return this.addMember(new StringMember(string, name)); }, addDirectory: function(name) { if (!/\/$/.test(name)) { name += '/'; } return this.addMember(new DirectoryMember(name)); }, addFile: function(url, name) { if (!name) { var paths = url.split(/\/+/); name = paths.pop(); } var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.send(null); return this.addMember(new StringMember(xhr.responseText, name)); }, addFileAsync: function(url, name, callback, errorback) { if (!name) { var paths = url.split(/\/+/); name = paths.pop(); } var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200 || xhr.status == 0) callback(this.addMember(new StringMember(xhr.responseText, name)), xhr); else errorback(this.addMember(new StringMember(xhr.responseText, name)), xhr); } }; xhr.open('GET', url); xhr.send(null); }, getByteArray: function() { var members = this.members; var bin = new ByteArray; var push = Array.prototype.push; var offsets = []; for (var i = 0; i < members.length; i++) { offsets.push(bin.length); push.apply(bin, members[i].getLocalFileHeader()); push.apply(bin, members[i].getData()); } var centralDirectoryOffset = bin.length; for (var i = 0; i < members.length; i++) { push.apply(bin, members[i].getCentralDirectoryFileHeader(offsets[i])); } var endOfCentralDirectoryOffset = bin.length; // end of central dir signature 4 bytes (0x06054b50) bin.append(0x06054b50, 4); // number of this disk 2 bytes bin.append(0, 2); // number of the disk with the // start of the central directory 2 bytes bin.append(0, 2); // total number of entries in the // central directory on this disk 2 bytes bin.append(members.length, 2); // total number of entries in // the central directory 2 bytes bin.append(members.length, 2); // size of the central directory 4 bytes bin.append(endOfCentralDirectoryOffset - centralDirectoryOffset, 4); // offset of start of central // directory with respect to // the starting disk number 4 bytes bin.append(centralDirectoryOffset, 4); // .ZIP file comment length 2 bytes bin.append(0, 2); // .ZIP file comment (variable size) // Array.prototype.push.apply(bin, []); return bin; }, getDataURI: function() { return ['data:', this.mimeType, ';base64,', Base64.convertByteArrayToBase64(this.getByteArray())].join(''); }, constructor: Zip }; var crc32table = function() { var poly = 0xEDB88320, u, table = []; for (var i = 0; i < 256; i ++) { u = i; for (var j = 0; j < 8; j++) { if (u & 1) u = (u >>> 1) ^ poly; else u = u >>> 1; } table[i] = u; } return table; } (); var getCrc32 = function(bin) { var result = 0xFFFFFFFF; for (var i = 0; i < bin.length; i ++) result = (result >>> 8) ^ crc32table[bin[i] ^ (result & 0xFF)]; return ~result; }; function ByteArray() { var self = []; var proto = ByteArray.prototype; for (var name in proto) self[name] = proto[name]; return self; } ByteArray.prototype = { append: function(value, bytes) { for (var i = 0; i < bytes; i ++) this.push(value >> (i * 8) & 0xFF); }, constructor: ByteArray }; function Member() { } Member.prototype = { initDateTime: function(dt) { this.date = ((dt.getFullYear() - 1980) << 9) | ((dt.getMonth() + 1) << 5) | (dt.getDate()); this.time = (dt.getHours() << 5) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1); }, getLocalFileHeader: function() { var bin = new ByteArray(); // local file header signature 4 bytes (0x04034b50) bin.append(0x04034b50, 4); // version needed to extract 2 bytes bin.append(10, 2); // general purpose bit flag 2 bytes bin.append(0, 2); // compression method 2 bytes bin.append(0, 2); // last mod file time 2 bytes bin.append(this.time, 2); // last mod file date 2 bytes bin.append(this.date, 2); // crc-32 4 bytes bin.append(this.crc32, 4); // compressed size 4 bytes bin.append(this.data.length, 4); // uncompressed size 4 bytes bin.append(this.data.length, 4); // file name length 2 bytes bin.append(this.name.length, 2); // extra field length 2 bytes bin.append(this.extra.localFile.length, 2); // file name (variable size) Array.prototype.push.apply(bin, this.name); // extra field (variable size) Array.prototype.push.apply(bin, this.extra.localFile); return bin; }, getData: function() { return this.data; }, getCentralDirectoryFileHeader: function(offset) { var bin = new ByteArray(); // central file header signature 4 bytes (0x02014b50) bin.append(0x02014b50, 4); // version made by 2 bytes bin.append(0x0317, 2); // version needed to extract 2 bytes bin.append(10, 2); // general purpose bit flag 2 bytes bin.append(0, 2); // compression method 2 bytes bin.append(0, 2); // last mod file time 2 bytes bin.append(this.time, 2); // last mod file date 2 bytes bin.append(this.date, 2); // crc-32 4 bytes bin.append(this.crc32, 4); // compressed size 4 bytes bin.append(this.data.length, 4); // uncompressed size 4 bytes bin.append(this.data.length, 4); // file name length 2 bytes bin.append(this.name.length, 2); // extra field length 2 bytes bin.append(this.extra.centralDirectory.length, 2); // file comment length 2 bytes bin.append(0, 2); // disk number start 2 bytes bin.append(0, 2); // internal file attributes 2 bytes bin.append(0, 2); // external file attributes 4 bytes bin.append(this.externalFileAttributes, 4); // relative offset of local header 4 bytes bin.append(offset, 4); // file name (variable size) Array.prototype.push.apply(bin, this.name); // extra field (variable size) Array.prototype.push.apply(bin, this.extra.centralDirectory); // file comment (variable size) // Array.prototype.push.apply(bin, []); return bin; }, constructor: Member }; function Extra() { this.localFile = new ByteArray; this.centralDirectory = new ByteArray; } Extra.prototype = { append: function(field) { Array.prototype.push.apply( this.localFile, field.localFile ); Array.prototype.push.apply( this.centralDirectory, field.centralDirectory ); }, contructor: ExtraField }; function ExtraField(magic) { this.magic = magic; } function StringMember(string, name) { this.name = Base64.convertUTF16StringToByteArray(name); this.data = Base64.convertUTF16StringToByteArray(string); this.crc32 = getCrc32(this.data); this.externalFileAttributes = 0100644 << 16; this.initDateTime(new Date); this.extra = new Extra; } StringMember.prototype = new Member(); StringMember.constructor = StringMember; function DirectoryMember(name) { this.name = Base64.convertUTF16StringToByteArray(name); this.data = []; this.crc32 = getCrc32(this.data); this.externalFileAttributes = (040755 << 16) | 0x10; // 0x10 bit for Windows Explorer's Directory this.initDateTime(new Date); this.extra = new Extra; } DirectoryMember.prototype = new Member(); DirectoryMember.constructor = DirectoryMember; window.Zip = Zip; })(); }; <h1>localStorage Demo</h1> <div id="dlArea"> <h2>jsonをzipでdl</h2> <p><a id="ziplink" href="#">download</a><br/>Alt+Clickでダウンロード</p> </div> <form action="javascript:void(0);" method="post"> <div id="info">タイトル・本文を入力してください。</div> <dl> <dt>タイトル</dt> <dd><input type="text" id="todo_title" name="todo" value=""/></dd> <dt>本文</dt> <dd><textarea id="todo_msg" name="todo"></textarea></dd> <dt>保存する</dt> <dd><input type="button" id="todo_submit" name="todo_submit" value="submit"/></dd> <dt>すべて削除する</dt> <dd><input type="button" id="todo_allclear" name="todo_allclear" value="all clear"/></dd> <dt>メモされたもの</dt> <dd id="result"></dd> </dl> </form> localStorage Demo body { background-color: #DDDDDD; font: 12px sans-serif; } #dlArea{ position:absolute; top:5px; right:5px; width:150px; padding:5px 0px 0; background:#fff; color:#333; text-align:center; -webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; -moz-box-shadow: 0 0 5px #000; -webkit-box-shadow: 0 0 5px #000; box-shadow: 0 0 5px #000; } #dlArea h2{ font-size:12px; margin:0; padding:0; } #ziplink{ display:inline-block; padding:5px 10px; margin-bottom:10px; color:#fff; -webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; background: #539e01; background: -moz-linear-gradient(top, #a1e649, #539e01); background: -webkit-gradient(linear, left top, left bottom, from(#a1e649), to(#539e01)); filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#a1e649,EndColorStr=#539e01); -moz-box-shadow: 0 0 5px #000; -webkit-box-shadow: 0 0 5px #000; box-shadow: 0 0 5px #000; } #ziplink:hover{ background: #a1e649; background: -moz-linear-gradient(top, #539e01, #a1e649); background: -webkit-gradient(linear, left top, left bottom, from(#539e01), to(#a1e649)); filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#539e01,EndColorStr=#a1e649); } #info{ width:262px; border:1px solid #333; padding:5px; } input[type=text], textarea{ width:100%; } table { width:100%; border-collapse:collapse; border-top:1px solid #000; border-left:1px solid #000; } table th{width:30%;} table td:nth-child(2){width:50%;} table td:nth-child(3){width:20%;} table td,table th{ padding:0px 5px; border-bottom:1px solid #000; border-right:1px solid #000; } dt{ border-bottom:1px solid #fff; padding-bottom:2px; margin-bottom:5px; } dd{ padding-bottom:5px; } localStrageのデモとしてメモ帳のようなものを。 * Strageに入れたjsonをダウンロードさせる為に * 以下を使用させていただきました。 * * js内で無圧縮ZIPを作ってData URIを生成するライブラリ * http://d.hatena.ne.jp/amachang/20081130/1228029751 /* * localStrageのデモとしてメモ帳のようなものを。 * Strageに入れたjsonをダウンロードさせる為に * 以下を使用させていただきました。 * * js内で無圧縮ZIPを作ってData URIを生成するライブラリ * http://d.hatena.ne.jp/amachang/20081130/1228029751 */ var model = { id : "diary", serialize : function(){ return JSON.stringify(this); }, deserialize : function(jsonstr){ var data = eval("(" + jsonstr + ")"); for(var key in data){ this[key] = data[key]; } return this; } }; $(function(){ loadlib(); var storage = window.localStorage; if(storage){ var jsonStr = storage.getItem(model.id); var jsonObj = model.deserialize(jsonStr); if(!jsonObj.data){ jsonObj.data={}; } if(!jsonObj.data.items){ jsonObj.data.items=[]; } createTable(jsonObj.data); var todo_submit = $("#todo_submit"); var todo_title = $("#todo_title"); var todo_msg = $("#todo_msg"); var todo_allclear = $("#todo_allclear"); var info = $("#info"); todo_submit.click(function(){todoSet();}); todo_allclear.click(function(){todoAllClear();}); } // create table function createTable(json){ var result = $("#result"); var html = []; if(json.items.length>0){ //download zip file $("#dlArea").show(); var zip = new Zip; zip.addString(model.serialize(), 'localstrage.js'); var dataURI = zip.getDataURI(); $("#ziplink").attr("href",dataURI); //create html html.push('<table>'); html.push('<thead><tr><th> タイトル</th><td>本文</td><td>時間</td></tr></thead>'); html.push('<tbody>'); for(var i=0;i<json.items.length;i++){ html.push('<tr id="local_strage_'+model.id+'_'+i+'">'); html.push('<th>'+json.items[i].title+'</th>'); html.push('<td>'+json.items[i].msg+'</td>'); html.push('<td>'+json.items[i].date+'</td>'); html.push('</tr>'); } html.push('</tbody>'); html.push('</table>'); result.html(html.join('\n')); }else{ $("#dlArea").hide(); result.html("データがありません。"); } } // clear function todoAllClear(){ model.data.items = []; storage.setItem(model.id,model.serialize()); createTable(model.data); } // set function todoSet(){ var jsonStr = storage.getItem(model.id); var jsonObj = model.deserialize(jsonStr); if(!jsonObj.data){ jsonObj.data = {}; } if(!jsonObj.data.items){ jsonObj.data.items = []; } var data = jsonObj.data; var tVal = todo_title.val(); var mVal = todo_msg.val(); var dt = new Date(); var dateStr = dt.getFullYear()+"-"+(dt.getMonth()+1)+"-"+dt.getDate()+" "+dt.getHours()+":"+dt.getMinutes()+":"+ dt.getSeconds(); if(tVal && mVal){ data.items.push({"title" : tVal, "msg":mVal, "date":dateStr}); model.data = data; storage.setItem(model.id,model.serialize()); createTable(data); todo_title.val(''); todo_msg.val(''); info.html("保存しました。"); }else{ info.html("タイトル・本文を入力してください。"); } } }); //unload window.onunload = function(){ var storage = window.localStorage; if(storage){ var jsonStr = model.serialize(); storage.setItem(model.id,jsonStr); } }; function loadlib(){ /* * $Id: base64.js,v 0.2 2008/06/18 08:01:50 dankogai Exp dankogai $ */ (function() { var b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; var b64charcodes = function() { var a = []; var codeA = 'A'.charCodeAt(0); var codea = 'a'.charCodeAt(0); var code0 = '0'.charCodeAt(0); for (var i = 0; i < 26; i ++) a.push(codeA + i); for (var i = 0; i < 26; i ++) a.push(codea + i); for (var i = 0; i < 10; i ++) a.push(code0 + i); a.push('+'.charCodeAt(0)); a.push('/'.charCodeAt(0)); return a; }(); var b64tab = function(bin) { var t = {}; for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; return t; }(b64chars); var stringToArray = function(s) { var a = []; for (var i = 0, l = s.length; i < l; i ++) a[i] = s.charCodeAt(i); return a; }; var convertUTF8ArrayToBase64 = function(bin) { var padlen = 0; while (bin.length % 3) { bin.push(0); padlen++; }; var b64 = []; for (var i = 0, l = bin.length; i < l; i += 3) { var c0 = bin[i], c1 = bin[i+1], c2 = bin[i+2]; if (c0 >= 256 || c1 >= 256 || c2 >= 256) throw 'unsupported character found'; var n = (c0 << 16) | (c1 << 8) | c2; b64.push( b64charcodes[ n >>> 18], b64charcodes[(n >>> 12) & 63], b64charcodes[(n >>> 6) & 63], b64charcodes[ n & 63] ); } while (padlen--) b64[b64.length - padlen - 1] = '='.charCodeAt(0); return String.fromCharCode.apply(String, b64); }; var convertBase64ToUTF8Array = function(b64) { b64 = b64.replace(/[^A-Za-z0-9+\/]+/g, ''); var bin = []; var padlen = b64.length % 4; for (var i = 0, l = b64.length; i < l; i += 4) { var n = ((b64tab[b64.charAt(i )] || 0) << 18) | ((b64tab[b64.charAt(i+1)] || 0) << 12) | ((b64tab[b64.charAt(i+2)] || 0) << 6) | ((b64tab[b64.charAt(i+3)] || 0)); bin.push( ( n >> 16 ), ( (n >> 8) & 0xff ), ( n & 0xff ) ); } bin.length -= [0,0,2,1][padlen]; return bin; }; var convertUTF16ArrayToUTF8Array = function(uni) { var bin = []; for (var i = 0, l = uni.length; i < l; i++) { var n = uni[i]; if (n < 0x80) bin.push(n); else if (n < 0x800) bin.push( 0xc0 | (n >>> 6), 0x80 | (n & 0x3f)); else bin.push( 0xe0 | ((n >>> 12) & 0x0f), 0x80 | ((n >>> 6) & 0x3f), 0x80 | (n & 0x3f)); } return bin; }; var convertUTF8ArrayToUTF16Array = function(bin) { var uni = []; for (var i = 0, l = bin.length; i < l; i++) { var c0 = bin[i]; if (c0 < 0x80) { uni.push(c0); } else { var c1 = bin[++i]; if (c0 < 0xe0) { uni.push(((c0 & 0x1f) << 6) | (c1 & 0x3f)); } else { var c2 = bin[++i]; uni.push( ((c0 & 0x0f) << 12) | ((c1 & 0x3f) << 6) | (c2 & 0x3f) ); } } } return uni; }; var convertUTF8StringToBase64 = function(bin) { return convertUTF8ArrayToBase64(stringToArray(bin)); }; var convertBase64ToUTF8String = function(b64) { return String.fromCharCode.apply(String, convertBase64ToUTF8Array(b64)); }; var convertUTF8StringToUTF16Array = function(bin) { return convertUTF8ArrayToUTF16Array(stringToArray(bin)); }; var convertUTF8ArrayToUTF16String = function(bin) { return String.fromCharCode.apply(String, convertUTF8ArrayToUTF16Array(bin)); }; var convertUTF8StringToUTF16String = function(bin) { return String.fromCharCode.apply(String, convertUTF8ArrayToUTF16Array(stringToArray(bin))); }; var convertUTF16StringToUTF8Array = function(uni) { return convertUTF16ArrayToUTF8Array(stringToArray(uni)); }; var convertUTF16ArrayToUTF8String = function(uni) { return String.fromCharCode.apply(String, convertUTF16ArrayToUTF8Array(uni)); }; var convertUTF16StringToUTF8String = function(uni) { return String.fromCharCode.apply(String, convertUTF16ArrayToUTF8Array(stringToArray(uni))); }; if (window.btoa) { var btoa = window.btoa; var convertUTF16StringToBase64 = function (uni) { return btoa(convertUTF16StringToUTF8String(uni)); }; } else { var btoa = convertUTF8StringToBase64; var convertUTF16StringToBase64 = function (uni) { return convertUTF8ArrayToBase64(convertUTF16StringToUTF8Array(uni)); }; } if (window.atob) { var atob = window.atob; var convertBase64ToUTF16String = function (b64) { return convertUTF8StringToUTF16String(atob(b64)); }; } else { var atob = convertBase64ToUTF8String; var convertBase64ToUTF16String = function (b64) { return convertUTF8ArrayToUTF16String(convertBase64ToUTF8Array(b64)); }; } window.Base64 = { convertUTF8ArrayToBase64:convertUTF8ArrayToBase64, convertByteArrayToBase64:convertUTF8ArrayToBase64, convertBase64ToUTF8Array:convertBase64ToUTF8Array, convertBase64ToByteArray:convertBase64ToUTF8Array, convertUTF16ArrayToUTF8Array:convertUTF16ArrayToUTF8Array, convertUTF16ArrayToByteArray:convertUTF16ArrayToUTF8Array, convertUTF8ArrayToUTF16Array:convertUTF8ArrayToUTF16Array, convertByteArrayToUTF16Array:convertUTF8ArrayToUTF16Array, convertUTF8StringToBase64:convertUTF8StringToBase64, convertBase64ToUTF8String:convertBase64ToUTF8String, convertUTF8StringToUTF16Array:convertUTF8StringToUTF16Array, convertUTF8ArrayToUTF16String:convertUTF8ArrayToUTF16String, convertByteArrayToUTF16String:convertUTF8ArrayToUTF16String, convertUTF8StringToUTF16String:convertUTF8StringToUTF16String, convertUTF16StringToUTF8Array:convertUTF16StringToUTF8Array, convertUTF16StringToByteArray:convertUTF16StringToUTF8Array, convertUTF16ArrayToUTF8String:convertUTF16ArrayToUTF8String, convertUTF16StringToUTF8String:convertUTF16StringToUTF8String, convertUTF16StringToBase64:convertUTF16StringToBase64, convertBase64ToUTF16String:convertBase64ToUTF16String, fromBase64:convertBase64ToUTF8String, toBase64:convertUTF8StringToBase64, atob:atob, btoa:btoa, utob:convertUTF16StringToUTF8String, btou:convertUTF8StringToUTF16String, encode:convertUTF16StringToBase64, encodeURI:function(u) { return convertUTF16StringToBase64(u).replace(/[+\/]/g, function(m0) { return m0 == '+' ? '-' : '_'; }).replace(/=+$/, ''); }, decode:function(a) { return convertBase64ToUTF16String(a.replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/'; })); } }; })(); // This source code is in the public domain. (function() { function Zip() { this.members = []; } Zip.prototype = { mimeType: 'application/zip', addMember: function(member) { this.members.push(member); return member; }, addString: function(string, name) { return this.addMember(new StringMember(string, name)); }, addDirectory: function(name) { if (!/\/$/.test(name)) { name += '/'; } return this.addMember(new DirectoryMember(name)); }, addFile: function(url, name) { if (!name) { var paths = url.split(/\/+/); name = paths.pop(); } var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.send(null); return this.addMember(new StringMember(xhr.responseText, name)); }, addFileAsync: function(url, name, callback, errorback) { if (!name) { var paths = url.split(/\/+/); name = paths.pop(); } var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (xhr.readyState == 4) { if (xhr.status == 200 || xhr.status == 0) callback(this.addMember(new StringMember(xhr.responseText, name)), xhr); else errorback(this.addMember(new StringMember(xhr.responseText, name)), xhr); } }; xhr.open('GET', url); xhr.send(null); }, getByteArray: function() { var members = this.members; var bin = new ByteArray; var push = Array.prototype.push; var offsets = []; for (var i = 0; i < members.length; i++) { offsets.push(bin.length); push.apply(bin, members[i].getLocalFileHeader()); push.apply(bin, members[i].getData()); } var centralDirectoryOffset = bin.length; for (var i = 0; i < members.length; i++) { push.apply(bin, members[i].getCentralDirectoryFileHeader(offsets[i])); } var endOfCentralDirectoryOffset = bin.length; // end of central dir signature 4 bytes (0x06054b50) bin.append(0x06054b50, 4); // number of this disk 2 bytes bin.append(0, 2); // number of the disk with the // start of the central directory 2 bytes bin.append(0, 2); // total number of entries in the // central directory on this disk 2 bytes bin.append(members.length, 2); // total number of entries in // the central directory 2 bytes bin.append(members.length, 2); // size of the central directory 4 bytes bin.append(endOfCentralDirectoryOffset - centralDirectoryOffset, 4); // offset of start of central // directory with respect to // the starting disk number 4 bytes bin.append(centralDirectoryOffset, 4); // .ZIP file comment length 2 bytes bin.append(0, 2); // .ZIP file comment (variable size) // Array.prototype.push.apply(bin, []); return bin; }, getDataURI: function() { return ['data:', this.mimeType, ';base64,', Base64.convertByteArrayToBase64(this.getByteArray())].join(''); }, constructor: Zip }; var crc32table = function() { var poly = 0xEDB88320, u, table = []; for (var i = 0; i < 256; i ++) { u = i; for (var j = 0; j < 8; j++) { if (u & 1) u = (u >>> 1) ^ poly; else u = u >>> 1; } table[i] = u; } return table; } (); var getCrc32 = function(bin) { var result = 0xFFFFFFFF; for (var i = 0; i < bin.length; i ++) result = (result >>> 8) ^ crc32table[bin[i] ^ (result & 0xFF)]; return ~result; }; function ByteArray() { var self = []; var proto = ByteArray.prototype; for (var name in proto) self[name] = proto[name]; return self; } ByteArray.prototype = { append: function(value, bytes) { for (var i = 0; i < bytes; i ++) this.push(value >> (i * 8) & 0xFF); }, constructor: ByteArray }; function Member() { } Member.prototype = { initDateTime: function(dt) { this.date = ((dt.getFullYear() - 1980) << 9) | ((dt.getMonth() + 1) << 5) | (dt.getDate()); this.time = (dt.getHours() << 5) | (dt.getMinutes() << 5) | (dt.getSeconds() >> 1); }, getLocalFileHeader: function() { var bin = new ByteArray(); // local file header signature 4 bytes (0x04034b50) bin.append(0x04034b50, 4); // version needed to extract 2 bytes bin.append(10, 2); // general purpose bit flag 2 bytes bin.append(0, 2); // compression method 2 bytes bin.append(0, 2); // last mod file time 2 bytes bin.append(this.time, 2); // last mod file date 2 bytes bin.append(this.date, 2); // crc-32 4 bytes bin.append(this.crc32, 4); // compressed size 4 bytes bin.append(this.data.length, 4); // uncompressed size 4 bytes bin.append(this.data.length, 4); // file name length 2 bytes bin.append(this.name.length, 2); // extra field length 2 bytes bin.append(this.extra.localFile.length, 2); // file name (variable size) Array.prototype.push.apply(bin, this.name); // extra field (variable size) Array.prototype.push.apply(bin, this.extra.localFile); return bin; }, getData: function() { return this.data; }, getCentralDirectoryFileHeader: function(offset) { var bin = new ByteArray(); // central file header signature 4 bytes (0x02014b50) bin.append(0x02014b50, 4); // version made by 2 bytes bin.append(0x0317, 2); // version needed to extract 2 bytes bin.append(10, 2); // general purpose bit flag 2 bytes bin.append(0, 2); // compression method 2 bytes bin.append(0, 2); // last mod file time 2 bytes bin.append(this.time, 2); // last mod file date 2 bytes bin.append(this.date, 2); // crc-32 4 bytes bin.append(this.crc32, 4); // compressed size 4 bytes bin.append(this.data.length, 4); // uncompressed size 4 bytes bin.append(this.data.length, 4); // file name length 2 bytes bin.append(this.name.length, 2); // extra field length 2 bytes bin.append(this.extra.centralDirectory.length, 2); // file comment length 2 bytes bin.append(0, 2); // disk number start 2 bytes bin.append(0, 2); // internal file attributes 2 bytes bin.append(0, 2); // external file attributes 4 bytes bin.append(this.externalFileAttributes, 4); // relative offset of local header 4 bytes bin.append(offset, 4); // file name (variable size) Array.prototype.push.apply(bin, this.name); // extra field (variable size) Array.prototype.push.apply(bin, this.extra.centralDirectory); // file comment (variable size) // Array.prototype.push.apply(bin, []); return bin; }, constructor: Member }; function Extra() { this.localFile = new ByteArray; this.centralDirectory = new ByteArray; } Extra.prototype = { append: function(field) { Array.prototype.push.apply( this.localFile, field.localFile ); Array.prototype.push.apply( this.centralDirectory, field.centralDirectory ); }, contructor: ExtraField }; function ExtraField(magic) { this.magic = magic; } function StringMember(string, name) { this.name = Base64.convertUTF16StringToByteArray(name); this.data = Base64.convertUTF16StringToByteArray(string); this.crc32 = getCrc32(this.data); this.externalFileAttributes = 0100644 << 16; this.initDateTime(new Date); this.extra = new Extra; } StringMember.prototype = new Member(); StringMember.constructor = StringMember; function DirectoryMember(name) { this.name = Base64.convertUTF16StringToByteArray(name); this.data = []; this.crc32 = getCrc32(this.data); this.externalFileAttributes = (040755 << 16) | 0x10; // 0x10 bit for Windows Explorer's Directory this.initDateTime(new Date); this.extra = new Extra; } DirectoryMember.prototype = new Member(); DirectoryMember.constructor = DirectoryMember; window.Zip = Zip; })(); }; <h1>localStorage Demo</h1> <div id="dlArea"> <h2>jsonをzipでdl</h2> <p><a id="ziplink" href="#">download</a><br/>Alt+Clickでダウンロード</p> </div> <form action="javascript:void(0);" method="post"> <div id="info">タイトル・本文を入力してください。</div> <dl> <dt>タイトル</dt> <dd><input type="text" id="todo_title" name="todo" value=""/></dd> <dt>本文</dt> <dd><textarea id="todo_msg" name="todo"></textarea></dd> <dt>保存する</dt> <dd><input type="button" id="todo_submit" name="todo_submit" value="submit"/></dd> <dt>すべて削除する</dt> <dd><input type="button" id="todo_allclear" name="todo_allclear" value="all clear"/></dd> <dt>メモされたもの</dt> <dd id="result"></dd> </dl> </form> body { background-color: #DDDDDD; font: 12px sans-serif; } #dlArea{ position:absolute; top:5px; right:5px; width:150px; padding:5px 0px 0; background:#fff; color:#333; text-align:center; -webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; -moz-box-shadow: 0 0 5px #000; -webkit-box-shadow: 0 0 5px #000; box-shadow: 0 0 5px #000; } #dlArea h2{ font-size:12px; margin:0; padding:0; } #ziplink{ display:inline-block; padding:5px 10px; margin-bottom:10px; color:#fff; -webkit-border-radius:5px; -moz-border-radius:5px; border-radius:5px; background: #539e01; background: -moz-linear-gradient(top, #a1e649, #539e01); background: -webkit-gradient(linear, left top, left bottom, from(#a1e649), to(#539e01)); filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#a1e649,EndColorStr=#539e01); -moz-box-shadow: 0 0 5px #000; -webkit-box-shadow: 0 0 5px #000; box-shadow: 0 0 5px #000; } #ziplink:hover{ background: #a1e649; background: -moz-linear-gradient(top, #539e01, #a1e649); background: -webkit-gradient(linear, left top, left bottom, from(#539e01), to(#a1e649)); filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#539e01,EndColorStr=#a1e649); } #info{ width:262px; border:1px solid #333; padding:5px; } input[type=text], textarea{ width:100%; } table { width:100%; border-collapse:collapse; border-top:1px solid #000; border-left:1px solid #000; } table th{width:30%;} table td:nth-child(2){width:50%;} table td:nth-child(3){width:20%;} table td,table th{ padding:0px 5px; border-bottom:1px solid #000; border-right:1px solid #000; } dt{ border-bottom:1px solid #fff; padding-bottom:2px; margin-bottom:5px; } dd{ padding-bottom:5px; } use an iframe compat browser, deer Tweet QR code Embed Design view Code view <script type="text/javascript" src="http://jsdo.it/blogparts/x2bO/js?view=design"></script><p class="ttlBpJsdoit" style="width: 465px; margin: 0; text-align: right; font-size: 11px;"><a href="http://jsdo.it/GeckoTang/x2bO" title="localStorage Demo">localStorage Demo - jsdo.it - share JavaScript, HTML5 and CSS</a></p> zip tags json localstorage memo zip Tweet twitter Tags CSS3 HTML5 json localstorage memo zip Favorite by dentaq termat ub-pnr gutti38: CSS3HTML5localstoragejson yasu0519: CSS3HTML5jsonlocalstorage holydesign: 参考になるなぁ~。 早く普通に使えるようになってほしいな。 Forked sort new page view favorite forked forked: localStorage Demo tuna.mayonna.. 00 47views 606/22/77 json localstorage memo zip TEST gutti38 00 377views 113/54/84 forked from: localStorage Demo.. narikei1030 00 198views 94/18/27