途中だけどうpっておく
簡単なURLとUser名だけで、好きなページにwiki形式でメモするツールがほしかったので作った。
TODO
- authorを認証にする
- parseが微妙に失敗したりするので直す
- 文字コード不明なページ上で処理すると文字化けする
- 長い文字列の場合はgetの都合に合わせて適当に分割する(ここ、途中で眠くなった)
- なんか2回ずつリクエスト飛ばすのが気持ち悪い
- とりあえず・・・とりあえず・・・
appengine側
#!/usr/bin/env python2.5 # -*- coding: utf-8 -*- import cgi, codecs from google.appengine.api import users from google.appengine.ext import webapp from google.appengine.ext.webapp.util import run_wsgi_app from google.appengine.ext import db class Data(db.Model): author = db.StringProperty(required = True) url = db.StringProperty(required = True) content = db.StringProperty(multiline = True) date = db.DateTimeProperty(auto_now_add = True) class Display(webapp.RequestHandler): def get(self): if self.request.get('url') and self.request.get('author'): datas = db.GqlQuery("SELECT * FROM Data WHERE url = '%s' AND author = '%s' ORDER BY date DESC LIMIT 1" % (self.request.get('url'), self.request.get('author'))) for data in datas: if data.content: self.response.out.write('jWiki.display({"result":"%s","error":null,"id":"0"})' % data.content.encode('utf-8')) else: self.response.out.write('jWiki.display({"result":null,"error":"parameter error","id":"0"})' % data.content.encode('utf-8')) class Save(webapp.RequestHandler): def get(self): if self.request.get('content') and self.request.get('url') and self.request.get('author'): data = Data(content = self.request.get('content'), url = self.request.get('url'), author = self.request.get('author')) data.put() datas = db.GqlQuery("SELECT * FROM Data WHERE url = '%s' ORDER BY date DESC LIMIT 1" % (self.request.get('url'), self.request.get('author'))) for data in datas: self.response.out.write('jWiki.save({"result":"success content=%s url=%s","error":null,"id":"1"})' %(guess_charset(data.content), data.url)) return True self.response.out.write('jWiki.save({"result":null,"error":"cannot save your data","id":"1"})') else: self.response.out.write('jWiki.save({"result":null,"error":"parameter error","id":"1"})') application = webapp.WSGIApplication( [('/jWiki/display', Display), ('/jWiki/save', Save)], debug = True) def main(): run_wsgi_app(application) if __name__ == '__main__': main() def guess_charset(data): f = lambda d, enc: d.decode(enc) and enc try: return f(data, 'utf-8') except: pass try: return f(data, 'shift-jis') except: pass try: return f(data, 'euc-jp') except: pass try: return f(data, 'iso2022-jp') except: pass return None
js側
/************************************************************ * NAME : jWiki.js * AUTHOR : muddydixon@gmail.com * VERSION : 0.0.0 * DESCRIPTION : どこででもwikiを書いておけるようにする付箋ツールのようなもの * DATE : 2009/10/09 create */ (function(){ /************************************************************ * 設定 */ if(!window.jWiki) window.jWiki; var cfg = { baseurl : 'http://localhost', codeckey : '--*--' }; var codec = new RegExp(cfg.codeckey); /************************************************************ * 共通関数 */ var showLoading = function(){ }; var hideLoading = function(){ }; var translate = function(data){ var O = function(){this.initialize.apply(this, arguments)}; O.prototype = { initialize: function(parent, elm, data){ this.elm = elm; this.data = data; this.parent = parent; }, push: function(child){ if(!this.child) this.child = []; this.child.push(child); }, makeText: function(){ if(this.data){ return '<'+this.elm+'>'+this.data+'</'+this.elm+'>'; }else{ var tmp = []; if(this.child){ for(var i = 0, l = this.child.length; i < l; i++){ tmp.push(this.child[i].makeText()); } return '<'+this.elm+'>'+tmp.join('')+'</'+this.elm+'>'; } return ''; } } }; var rv = new O(null, 'div', false); var p = rv; var idt = 0; window.RV = rv; for(var i = 0, l = data.length; i < l; i++){ var match = data[i].match(/^(\s+)(\*|.\.)\s+(.+)$/); if(!match){ if(data[i].match(/^[\s]*$/)){ if(p.parent){ p = p.parent; idt = 0; } }else{ p.push(new O(p, 'p', data[i])); } }else{ if(match[2]){ var elm = (match[2] === '*' ? 'ul' : 'ol'); if(idt < match[1].length){ idt = match[1].length; var o = new O(p, elm, false); p.push(o); p = o; }else if(idt > match[1].length){ idt = match[1].length; p = p.parent; }else if(p.elm !== elm){ p = p.parent; var o = new O(p, elm, false); p.push(o); p = o; } p.push(new O(p, 'li', match[3])); } } } return rv.makeText(); }; var execute = function(action, data){ var sendRequest = function(action, param){ alert(param); //データが大きい場合は分割して個別にidをつけてリクエストを飛ばす必要がある var s = document.createElement('scr'+'ipt'); s.setAttribute('type', 'text/javascript'); s.setAttribute('src', cfg.baseurl+'/jWiki/'+action+(param.length > 0 ? '?'+param.join('&'): '')+'&id='+i); document.body.appendChild(s); } var param = []; if(data.content && typeof data.content === 'string'){ var content = data.content; delete data.content; var match = content.match(/.{10}/g); for(var i = 0, l = match.length; i < l; i++){ param = []; for(var i in data){ if(data.hasOwnProperty(i)){ param.push(i+'='+data[i]); } } alert(match[i]); param.push('content='+match[i]); sendRequest(action, param); } }else{ for(var i in data){ if(data.hasOwnProperty(i)){ param.push(i+'='+data[i]); } } sendRequest(action, param); } }; var showJWiki = function(){ document.getElementById('jwiki_head').style.display = ''; document.getElementById('jwiki_body').style.display = ''; document.getElementById('jwiki_foot').style.display = ''; document.getElementById('jwiki_close_foot').style.display = 'none'; document.getElementById('jwiki').className = ''; }; var hideJWiki = function(){ document.getElementById('jwiki_head').style.display = 'none'; document.getElementById('jwiki_body').style.display = 'none'; document.getElementById('jwiki_foot').style.display = 'none'; document.getElementById('jwiki_close_foot').style.display = ''; document.getElementById('jwiki').className = 'close'; }; Object.prototype.show = function(){ if(this.style.display) this.style.display = '';}; Object.prototype.hide = function(){ alert(this); if(this.style.display) this.style.display = 'none';}; Observe = function(elm, ev, fn, cap){ if(elm.addEventListener){ elm.addEventListener(ev, fn, cap); }else if(elm.attachEvent){ elm.attachEvent('on'+ev, fn); } }; var jWikiPane = document.createElement('div'); jWikiPane.id = 'jwiki'; jWikiPane.innerHTML = '<div id="jwiki_head"></div>'+ '<div id="jwiki_body"><div id="jwiki_body_display"></div><textarea id="jwiki_body_text"></textarea></div>'+ '<div id="jwiki_foot"><span id="jwiki_close" class="jwiki_button">[x]</span><br clear="both"/></div>'+ '<div id="jwiki_close_foot"><span id="jwiki_open" class="jwiki_button">[open]</span><br clear="both"/></div>'; /************************************************************ * 初期化 */ var initialize = function(){ if(document.getElementById('jWiki')) return false; var css = document.createElement('link'); css.setAttribute('type', 'text/css'); css.setAttribute('rel', 'stylesheet'); css.setAttribute('href', cfg.baseurl+'/css/jWiki.css'); var h = document.getElementsByTagName('head')[0]; h.appendChild(css); document.body.appendChild(jWikiPane); document.getElementById('jwiki_close_foot').style.display = 'none'; document.getElementById('jwiki_body_text').style.display = 'none'; Observe(document.getElementById('jwiki_body_display'), 'click', edit, false); Observe(document.getElementById('jwiki_body_text'), 'blur', save, false); Observe(document.getElementById('jwiki_close'), 'click', hideJWiki, false); Observe(document.getElementById('jwiki_open'), 'click', showJWiki, false); execute('display', {url: location.href, author: 'muddydixon'}); }; /************************************************************ * 各種イベントハンドラ */ var edit = function(){ document.getElementById('jwiki_body_display').style.display = 'none'; document.getElementById('jwiki_body_text').style.display = ''; document.getElementById('jwiki_body_text').focus(); } var save = function(){ document.getElementById('jwiki_body_display').style.display = ''; document.getElementById('jwiki_body_text').style.display = 'none'; var text = document.getElementById('jwiki_body_text').value.replace(/\n/g, cfg.codeckey); execute('save', {author:'muddydixon', url:location.href, content:text}); jWiki.display({"result":text, "error":null, "id": -1}); } /************************************************************ * イベントコールバック */ jWiki = { display : function(data){ if(data.error){ return false; } // var text = decodeURI(data.result).split(cfg.codeckey); var text = data.result.split(cfg.codeckey); document.getElementById('jwiki_body_text').value = text.join('\n'); document.getElementById('jwiki_body_display').innerHTML = translate(text); }, save : function(data){ if(data.error){ return false; } } } /************************************************************ * 実行 */ initialize(); })();