root/lang/javascript/vimperator-plugins/trunk/_libly.js

Revision 37393, 27.9 kB (checked in by anekos, 4 months ago)

Fix a typo

  • Property svn:executable set to *
Line 
1/*** BEGIN LICENSE BLOCK {{{
2    Copyright (c) 2008 suVene<suvene@zeromemory.info>
3
4    distributable under the terms of an MIT-style license.
5    http://www.opensource.jp/licenses/mit-license.html
6}}}  END LICENSE BLOCK ***/
7// PLUGIN_INFO//{{{
8var PLUGIN_INFO =
9<VimperatorPlugin>
10    <name>libly(filename _libly.js)</name>
11    <description>Vimperator plugins library?</description>
12    <description lang="ja">適当なライブラリっぽいものたち。</description>
13    <author mail="suvene@zeromemory.info" homepage="http://zeromemory.sblo.jp/">suVene</author>
14    <license>MIT</license>
15    <version>0.1.33</version>
16    <minVersion>2.3pre</minVersion>
17    <maxVersion>2.3</maxVersion>
18    <updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/_libly.js</updateURL>
19    <detail><![CDATA[
20== Objects ==
21- liberator.plugins.libly.$U
22- liberator.plugins.libly.Request
23- liberator.plugins.libly.Response
24- liberator.plugins.libly.Wedata
25
26== Logger ==
27getLogger(prefix):
28    log(msg, level), echo(msg, flg), echoerr(msg)
29    のメソッドを持つ logger インスタンスを取得します。
30    ログの書式は prefix + ': ' + yyyy/MM/dd + msg となります。
31
32== Object Utility ==
33extend(dst, src):
34    オブジェクトを拡張します。
35A(iterable):
36    オブジェクトを配列にします。
37around(obj, name, func, autoRestore):
38  obj がもつ name 関数を、func に置き換えます。
39  func は
40    function (next, args) {...}
41  という形で呼ばれます。
42  next はオリジナルの関数を呼び出すための関数、
43  args はオリジナルの引数列です。
44  通常、next には引数を渡す必要はありません。
45  (任意の引数を渡したい場合は配列で渡します。)
46  また、autoRestore が真であれば、プラグインの再ロードなどで around が再実行されたときに、関数の置き換え前にオリジナル状態に書き戻します。
47  (多重に置き換えられなくなるので、auto_source.js などを使ったプラグイン開発で便利です)
48  返値は以下のオブジェクトです
49  >||
50  {
51    original: オリジナルの関数
52    current: 現在の関数
53    restore: 元に戻すための関数
54  }
55  ||<
56bind(obj, func):
57    func に obj を bind します。
58    func内からは this で obj が参照できるようになります。
59eval(text):
60    Sandbox による、window.eval を極力利用するようにします。
61    Snadbox が利用できない場合は、unsafe な window の eval が直接利用されます。
62evalJson(str, toRemove):
63    str を decode します。
64    toRemove が true の場合、文字列の前後を1文字削除します。
65    "(key:value)" 形式の場合などに true を指定して下さい。
66dateFormat(dtm, fmt):
67    Date型インスタンスを、指定されたフォーマットで文字列に変換します。
68    fmt を省略した場合、"%y/%M/%d %h:%m:%s" となります。
69runnable(generator):
70    gererator を実行し、再帰的に resume する為の引数を渡します。
71
72==  Browser ==
73getSelectedString:
74    window の選択文字列を返却します。
75getUserAndPassword(hostname, formSubmitURL, username):
76    login-manager から [username, password] を取得します。
77    引数の username が省略された場合、検索された 1件目を返却します。
78    データが存在しない場合は、null を返却します。
79
80== System ==
81readDirectory(path, fileter, func):
82    path で指定したディレクトリから、filter で指定された正規表現に match する場合、
83    func をファイル名を引数にコールバックします。
84    filter は Function を指定することも可能です。
85
86== HTML, XML, DOM, E4X ==
87pathToURL(a, baseURL, doc):
88    相対パスを絶対パスに変換します。
89getHTMLFragment(html):
90    <html>※1</html>
91    ※1 の文字列を取得します。
92stripTags(str, tags):
93    str から tags で指定されたタグを取り除いて返却します。
94    tags は文字列、または配列で指定して下さい。
95createHTMLDocument(str, xmlns):
96    引数 str より、HTMLFragment を作成します。
97getFirstNodeFromXPath(xpath, context):
98    xpath を評価しオブジェクトをを返却します。
99getNodesFromXPath(xpath, context, callback, thisObj):
100    xpath を評価し snapshot の配列を返却します。
101xmlSerialize(xml):
102    xml を文字列化します。
103xmlToDom(node, doc, nodes):
104    for vimperator1.2.
105    @see vimperator2.0pre util.
106getElementPosition(elem):
107    elem の offset を返却します。
108    return {top: 0, left: 0}
109toStyleText(style):
110    スタイルが格納されているオブジェクトを
111    >||
112        position: fixed;
113        left: 10px;
114    ||<
115    のような文字列に変換します。
116
117== Object Request ==
118Request(url, headers, options):
119    コンストラクタ
120    url:
121        HTTPリクエスト先のURL
122    headers:
123        以下のようにHTTPヘッダの値を指定できる(省略可)
124        >||
125        {
126            'Referer' : 'http://example.com/'
127        }
128        ||<
129        以下の値はデフォルトで設定される('Content-type'はPOST時のみ)
130        >||
131        {
132            'Accept': 'text/javascript, application/javascript, text/html, application/xhtml+xml, application/xml, text/xml, */*;q=0.1',
133            'Content-type': 'application/x-www-form-urlencoded; charset=' + options.encodingの値
134        }
135        ||<
136
137    options:
138        オプションとして以下のようなオブジェクトを指定できる(省略可)
139        asynchronous:
140            true: 同期モード/false: 非同期モード(デフォルト:true)
141        encoding:
142            エンコーディング(デフォルト: 'UTF-8')
143        username:
144            BASIC認証時のuser名
145        password:
146            BASIC認証時のパスワード
147        postBody:
148            POSTメソッドにより送信するbody
149addEventListener(name, func):
150    イベントリスナを登録する。
151    name:
152        'onSuccess':
153            成功時
154        'onFailure':
155            失敗を表すステータスコードが返ってきた時
156        'onException':
157            例外発生時
158    func:
159        イベント発火時の処理
160        引数として以下Responseオブジェクトが渡される
161get():
162    GETメソッドによりHTTPリクエストを発行する。
163post():
164    POSTメソッドによりHTTPリクエストを発行する。
165
166== Object Response ==
167HTTPレスポンスを表すオブジェクト
168req:
169    レスポンスと対となるRequestオブジェクト
170doc:
171    レスポンスから生成されたHTMLDocumentオブジェクト
172isSuccess():
173    ステータスコードが成功を表していればtrue、失敗であればfalse
174getStatus():
175    ステータスコードを取得する
176getStatusText():
177    ステータを表す文字列を取得する
178getHTMLDocument(xpath, xmlns, ignoreTags, callback, thisObj):
179    レスポンスからHTMLDocumentオブジェクトを生成し、xpath を評価した結果の snapshot の配列を返す
180
181== Object Wedata ==
182~/vimperator/info/profile_name/plugins-libly-wedata-?????
183に store されます。
184getItems(expire, itemCallback, finalCallback):
185    インスタンス作成時に指定した dbname から、item を読込みます。
186=== TODO ===
187clearCache:
188  wedata 読込み成功したら、強制的にキャッシュと置き換えるの作って!
189
190    ]]></detail>
191</VimperatorPlugin>;
192//}}}
193//if (!liberator.plugins.libly) {
194
195liberator.plugins.libly = {};
196var libly = liberator.plugins.libly;
197
198libly.$U = {//{{{
199    // Logger {{{
200    getLogger: function(prefix) {
201        return new function() {
202            this.log = function(msg, level) {
203                if (typeof msg == 'object') msg = util.objectToString(msg);
204                liberator.log(libly.$U.dateFormat(new Date()) + ': ' + (prefix || '') + ': ' + msg, (level || 0));
205            };
206            this.echo = function(msg, flg) {
207                flg = flg || commandline.FORCE_MULTILINE;
208                // this.log(msg);
209                liberator.echo(msg, flg);
210            };
211            this.echoerr = function(msg) {
212                this.log('error: ' + msg);
213                liberator.echoerr(msg);
214            };
215        }
216    },
217    // }}}
218    // Object Utility {{{
219    extend: function(dst, src) {
220        for (let prop in src)
221            dst[prop] = src[prop];
222        return dst;
223    },
224    A: function(iterable) {
225        var ret = [];
226        if (!iterable) return ret;
227        if (typeof iterable == 'string') return [iterable];
228        if (!(typeof iterable == 'function' && iterable == '[object NodeList]') &&
229            iterable.toArray) return iterable.toArray();
230        if (typeof iterable.length != 'undefined') {
231            for (let i = 0, len = iterable.length; i < len; ret.push(iterable[i++]));
232        } else {
233            for each (let item in iterable) ret.push(item);
234        }
235        return ret;
236    },
237    around: (function () {
238        function getPluginPath () {
239          let pluginPath;
240          Error('hoge').stack.split(/\n/).some(
241            function (s)
242              let (m = s.match(/^\(\)@chrome:\/\/liberator\/content\/liberator\.js -> (.+):\d+$/))
243                (m && (pluginPath = m[1]))
244          );
245          return pluginPath;
246        }
247
248        let restores = {};
249
250        return function (obj, name, func, autoRestore) {
251            let original;
252            let restore = function () obj[name] = original;
253            if (autoRestore) {
254                let pluginPath = getPluginPath();
255                if (pluginPath) {
256                    restores[pluginPath] =
257                        (restores[pluginPath] || []).filter(
258                            function (res) (
259                                res.object != obj ||
260                                res.name != name ||
261                                (res.restore() && false)
262                            )
263                        );
264                    restores[pluginPath].push({
265                        object: obj,
266                        name: name,
267                        restore: restore
268                    });
269                } else {
270                    liberator.echoerr('getPluginPath failed');
271                }
272            }
273            original = obj[name];
274            let current = obj[name] = function () {
275                let self = this, args = arguments;
276                return func.call(self, function (_args) original.apply(self, _args || args), args);
277            };
278            libly.$U.extend(current, {original: original.original || original, restore: restore});
279            return libly.$U.extend({
280                original: original,
281                current: current,
282                restore: restore
283            }, [original, current]);
284        };
285    })(),
286    bind: function(obj, func) {
287        return function() {
288            return func.apply(obj, arguments);
289        }
290    },
291    eval: function(text) {
292        var fnc = window.eval;
293        var sandbox;
294        try {
295            sandbox = new Components.utils.Sandbox("about:blank");
296            if (Components.utils.evalInSandbox('true', sandbox) === true) {
297                fnc = function(text) { return Components.utils.evalInSandbox(text, sandbox); };
298            }
299        } catch (e) { liberator.log('warning: _libly.js is working with unsafe sandbox.'); }
300
301        return fnc(text);
302    },
303    evalJson: function(str, toRemove) {
304        var json;
305        try {
306            json = Components.classes['@mozilla.org/dom/json;1'].getService(Components.interfaces.nsIJSON);
307            if (toRemove) str = str.substring(1, str.length - 1);
308            return json.decode(str);
309        } catch (e) { return null; }
310    },
311    dateFormat: function(dtm, fmt) {
312        var d = {
313            y: dtm.getFullYear(),
314            M: dtm.getMonth() + 1,
315            d: dtm.getDate(),
316            h: dtm.getHours(),
317            m: dtm.getMinutes(),
318            s: dtm.getSeconds(),
319            '%': '%'
320        };
321        for (let [n, v] in Iterator(d)) {
322            if (v < 10)
323                d[n] = '0' + v;
324        }
325        return (fmt || '%y/%M/%d %h:%m:%s').replace(/%([yMdhms%])/g, function (_, n) d[n]);
326    },
327    /**
328     * example)
329     *  $U.runnable(function(resume) {
330     *      // execute asynchronous function.
331     *      // goto next yield;
332     *      var val = yield setTimeout(function() { resume('value!'), 1000) });
333     *      alert(val);  // value!
334     *      yield;
335     *  });
336     */
337    runnable: function(generator) {
338        var it = generator(function(value) {
339                    try { it.send(value); } catch (e) {}
340                 });
341        it.next();
342    },
343    // }}}
344    // Browser {{{
345    getSelectedString: function() {
346         return (new XPCNativeWrapper(window.content.window)).getSelection().toString();
347    },
348    getUserAndPassword: function(hostname, formSubmitURL, username) {
349        var passwordManager, logins;
350        try {
351            passwordManager = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
352            logins = passwordManager.findLogins({}, hostname, formSubmitURL, null);
353            if (logins.length) {
354                if (username) {
355                    for (let i = 0, len = logins.lengh; i < len; i++) {
356                        if (logins[i].username == username)
357                            return [logins[i].username, logins[i].password]
358                    }
359                    liberator.log(this.dateFormat(new Date()) +': [getUserAndPassword] username notfound');
360                    //throw 'username notfound.';
361                    return [];
362                } else {
363                    return [logins[0].username, logins[0].password];
364                }
365            } else {
366                liberator.log(this.dateFormat(new Date()) + ': [getUserAndPassword] account notfound');
367                return [];
368            }
369        } catch (e) {
370            liberator.log(this.dateFormat(new Date()) + ': [getUserAndPassword] error: ' + e, 0);
371            return null;
372        }
373    },
374    // }}}
375    // System {{{
376    readDirectory: function(path, filter, func) {
377        var d = io.File(path);
378        if (d.exists() && d.isDirectory()) {
379            let enm = d.directoryEntries;
380            let flg = false;
381            while (enm.hasMoreElements()) {
382                let item = enm.getNext();
383                item.QueryInterface(Components.interfaces.nsIFile);
384                flg = false;
385                if (typeof filter == 'string') {
386                    if ((new RegExp(filter)).test(item.leafName)) flg = true;
387                } else if (typeof filter == 'function') {
388                    flg = filter(item);
389                }
390                if (flg) func(item);
391            }
392        }
393    },
394    // }}}
395    // HTML, XML, DOM, E4X {{{
396    pathToURL: function(a, baseURL, doc) {
397        if (!a) return '';
398        var XHTML_NS = "http://www.w3.org/1999/xhtml";
399        var XML_NS   = "http://www.w3.org/XML/1998/namespace";
400        //var path = (a.href || a.getAttribute('src') || a.action || a.value || a);
401        var path = (a.getAttribute('href') || a.getAttribute('src') || a.action || a.value || a);
402        if (/^https?:\/\//.test(path)) return path;
403        var link = (doc || window.content.documtent).createElementNS(XHTML_NS, 'a');
404        link.setAttributeNS(XML_NS, 'xml:base', baseURL);
405        link.href = path;
406        return link.href;
407    },
408    getHTMLFragment: function(html) {
409        if (!html) return html;
410        return html.replace(/^[\s\S]*?<html(?:[ \t\n\r][^>]*)?>|<\/html[ \t\r\n]*>[\S\s]*$/ig, '');
411    },
412    stripTags: function(str, tags) {
413        var ignoreTags = '(?:' + [].concat(tags).join('|') + ')';
414        return str.replace(new RegExp('<' + ignoreTags + '(?:[ \\t\\n\\r][^>]*|/)?>([\\S\\s]*?)<\/' + ignoreTags + '[ \\t\\r\\n]*>', 'ig'), '');
415    },
416    createHTMLDocument: function(str, xmlns, doc) {
417        let root = document.createElementNS("http://www.w3.org/1999/xhtml", "html");
418        let uhService = Cc["@mozilla.org/feed-unescapehtml;1"].getService(Ci.nsIScriptableUnescapeHTML);
419        let text = str.replace(/^[\s\S]*?<body([ \t\n\r][^>]*)?>[\s]*|<\/body[ \t\r\n]*>[\S\s]*$/ig, '');
420        let fragment = uhService.parseFragment(text, false, null, root);
421        let doctype = document.implementation.createDocumentType('html', '-//W3C//DTD HTML 4.01//EN', 'http://www.w3.org/TR/html4/strict.dtd');
422        let htmlFragment = document.implementation.createDocument(null, 'html', doctype);
423        htmlFragment.documentElement.appendChild(htmlFragment.importNode(fragment,true));
424        return htmlFragment;
425        /* うまく動いていない場合はこちらに戻してください
426        doc = doc || window.content.document;
427        var htmlFragment = doc.implementation.createDocument(null, 'html', null);
428        var range = doc.createRange();
429        range.setStartAfter(doc.body);
430        htmlFragment.documentElement.appendChild(htmlFragment.importNode(range.createContextualFragment(str), true));
431        return htmlFragment;
432        */
433    },
434    getFirstNodeFromXPath: function(xpath, context) {
435        if (!xpath) return null;
436        context = context || window.content.document;
437        var result = (context.ownerDocument || context).evaluate(xpath, context, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null);
438        return result.singleNodeValue || null;
439    },
440    getNodesFromXPath: function(xpath, context, callback, thisObj) {
441        var ret = [];
442        if (!xpath) return ret;
443        context = context || window.content.document;
444        var nodesSnapshot = (context.ownerDocument || context).evaluate(xpath, context, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
445        for (let i = 0, l = nodesSnapshot.snapshotLength; i < l; i++) {
446            if (typeof callback == 'function') callback.call(thisObj, nodesSnapshot.snapshotItem(i), i);
447            ret.push(nodesSnapshot.snapshotItem(i));
448        }
449        return ret;
450    },
451    xmlSerialize: function(xml) {
452        try {
453            return (new XMLSerializer()).serializeToString(xml)
454                                        .replace(/<!--(?:[^-]|-(?!->))*-->/g, '')
455                                        .replace(/<\s*\/?\s*\w+/g, function(all) all.toLowerCase());
456        } catch (e) { return '' }
457    },
458    xmlToDom: function xmlToDom(node, doc, nodes)
459    {
460        XML.prettyPrinting = false;
461        switch (node.nodeKind())
462        {
463            case "text":
464                return doc.createTextNode(node);
465            case "element":
466                let domnode = doc.createElementNS(node.namespace(), node.localName());
467                for each (let attr in node.@*)
468                    domnode.setAttributeNS(attr.name() == "highlight" ? NS.uri : attr.namespace(), attr.name(), String(attr));
469                for each (let child in node.*)
470                    domnode.appendChild(arguments.callee(child, doc, nodes));
471                if (nodes && node.@key)
472                    nodes[node.@key] = domnode;
473                return domnode;
474        }
475    },
476    getElementPosition: function(elem) {
477        var offsetTrail = elem;
478        var offsetLeft  = 0;
479        var offsetTop   = 0;
480        while (offsetTrail) {
481            offsetLeft += offsetTrail.offsetLeft;
482            offsetTop  += offsetTrail.offsetTop;
483            offsetTrail = offsetTrail.offsetParent;
484        }
485        offsetTop = offsetTop || null;
486        offsetLeft = offsetLeft || null;
487        return {top: offsetTop, left: offsetLeft};
488    },
489    toStyleText: function(style) {
490        var result = '';
491        for (let name in style) {
492            result += name.replace(/[A-Z]/g, function (c) ('-' + c.toLowerCase())) +
493                      ': ' +
494                      style[name] +
495                      ';\n';
496        }
497        return result;
498    }
499    // }}}
500};
501//}}}
502
503libly.Request = function() {//{{{
504    this.initialize.apply(this, arguments);
505};
506libly.Request.EVENTS = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
507libly.Request.requestCount = 0;
508libly.Request.prototype = {
509    initialize: function(url, headers, options) {
510        this.url = url;
511        this.headers = headers || {};
512        this.options = libly.$U.extend({
513            asynchronous: true,
514            encoding: 'UTF-8'
515        }, options || {});
516        this.observers = {};
517    },
518    addEventListener: function(name, func) {
519        try {
520            if (typeof this.observers[name] == 'undefined') this.observers[name] = [];
521            this.observers[name].push(func);
522        } catch (e) {
523            if (!this.fireEvent('onException', new libly.Response(this), e)) throw e;
524        }
525    },
526    fireEvent: function(name, args, asynchronous) {
527        if (!(this.observers[name] instanceof Array)) return false;
528        this.observers[name].forEach(function(event) {
529            if (asynchronous) {
530                setTimeout(event, 10, args);
531            } else {
532                event(args);
533            }
534        });
535        return true;
536    },
537    _complete: false,
538    _request: function(method) {
539
540        try {
541            libly.Request.requestCount++;
542
543            this.method = method;
544            this.transport = new XMLHttpRequest();
545            this.transport.open(method, this.url, this.options.asynchronous, this.options.username, this.options.password);
546
547            this.transport.onreadystatechange = libly.$U.bind(this, this._onStateChange);
548            this.setRequestHeaders();
549            this.transport.overrideMimeType('text/html; charset=' + this.options.encoding);
550
551            this.body = this.method == 'POST' ? this.options.postBody : null;
552
553            this.transport.send(this.body);
554
555            // Force Firefox to handle ready state 4 for synchronous requests
556            if (!this.options.asynchronous && this.transport.overrideMimeType)
557                this._onStateChange();
558
559        } catch (e) {
560            if (!this.fireEvent('onException', new libly.Response(this), e)) throw e;
561        }
562    },
563    _onStateChange: function() {
564        var readyState = this.transport.readyState;
565        if (readyState > 1 && !(readyState == 4 && this._complete))
566            this.respondToReadyState(this.transport.readyState);
567    },
568    getStatus: function() {
569        try {
570            return this.transport.status || 0;
571        } catch (e) { return 0; }
572    },
573    isSuccess: function() {
574        var status = this.getStatus();
575        return !status || (status >= 200 && status < 300);
576    },
577    respondToReadyState: function(readyState) {
578        var state = libly.Request.EVENTS[readyState];
579        var res = new libly.Response(this);
580
581        if (state == 'Complete') {
582            libly.Request.requestCount--;
583            try {
584                this._complete = true;
585                this.fireEvent('on' + (this.isSuccess() ? 'Success' : 'Failure'), res, this.options.asynchronous);
586            } catch (e) {
587                if (!this.fireEvent('onException', res, e)) throw e;
588            }
589        }
590    },
591    setRequestHeaders: function() {
592        var headers = {
593            'Accept': 'text/javascript, application/javascript, text/html, application/xhtml+xml, application/xml, text/xml, */*;q=0.1'
594        };
595
596        if (this.method == 'POST') {
597            headers['Content-type'] = 'application/x-www-form-urlencoded' +
598                (this.options.encoding ? '; charset=' + this.options.encoding : '');
599
600            if (this.transport.overrideMimeType) {
601                let year = parseInt((navigator.userAgent.match(/\bGecko\/(\d{4})/) || [0, 2005])[1], 10);
602                if (0 < year && year < 2005)
603                     headers['Connection'] = 'close';
604            }
605        }
606
607        for (let key in this.headers)
608            if (this.headers.hasOwnProperty(key)) headers[key] = this.headers[key];
609
610        for (let name in headers)
611            this.transport.setRequestHeader(name, headers[name]);
612    },
613    get: function() {
614        this._request('GET');
615    },
616    post: function() {
617        this._request('POST');
618    }
619};//}}}
620
621libly.Response = function() {//{{{
622    this.initialize.apply(this, arguments);
623};
624libly.Response.prototype = {
625    initialize: function(req) {
626        this.req = req;
627        this.transport = req.transport;
628        this.isSuccess = req.isSuccess;
629        this.readyState = this.transport.readyState;
630
631        if (this.readyState == 4) {
632            this.status = this.getStatus();
633            this.statusText = this.getStatusText();
634            this.responseText = (this.transport.responseText == null) ? '' : this.transport.responseText;
635        }
636
637        this.doc = null;
638        this.htmlFragmentstr = '';
639    },
640    status: 0,
641    statusText: '',
642    getStatus: libly.Request.prototype.getStatus,
643    getStatusText: function() {
644        try {
645            return this.transport.statusText || '';
646        } catch (e) { return ''; }
647    },
648    getHTMLDocument: function(xpath, xmlns, ignoreTags, callback, thisObj) {
649        if (!this.doc) {
650            //if (doc.documentElement.nodeName != 'HTML') {
651            //    return new DOMParser().parseFromString(str, 'application/xhtml+xml');
652            //}
653            this.htmlFragmentstr = libly.$U.getHTMLFragment(this.responseText);
654            this.htmlStripScriptFragmentstr = libly.$U.stripTags(this.htmlFragmentstr, ignoreTags);
655            this.doc = libly.$U.createHTMLDocument(this.htmlStripScriptFragmentstr, xmlns);
656        }
657        if (!xpath) xpath = '//*';
658        return libly.$U.getNodesFromXPath(xpath, this.doc, callback, thisObj);
659    }
660};
661//}}}
662
663libly.Wedata = function(dbname) { // {{{
664    this.initialize.apply(this, arguments);
665};
666libly.Wedata.prototype = {
667    initialize: function(dbname) {
668        this.HOST_NAME = 'http://wedata.net/';
669        this.dbname = dbname;
670        this.logger = libly.$U.getLogger('libly.Wedata');
671    },
672    getItems: function(expire, itemCallback, finalCallback) {
673
674        var logger = this.logger;
675        var STORE_KEY = 'plugins-libly-wedata-' + this.dbname + '-items';
676        var store = storage.newMap(STORE_KEY, true);
677        var cache = store && store.get('data');
678
679        if (store && cache && new Date(store.get('expire')) > new Date()) {
680            logger.log('return cache. ');
681            cache.forEach(function(item) { if (typeof itemCallback == 'function') itemCallback(item); });
682            if (typeof finalCallback == 'function')
683                finalCallback(true, cache);
684            return;
685        }
686
687        expire = expire || 0;
688
689        function errDispatcher(msg, cache) {
690            if (cache) {
691                logger.log('return cache. -> ' + msg);
692                cache.forEach(function(item) { if (typeof itemCallback == 'function') itemCallback(item); });
693                if (typeof finalCallback == 'function')
694                    finalCallback(true, cache);
695            } else {
696                logger.log(msg + ': cache notfound.');
697                if (typeof finalCallback == 'function')
698                    finalCallback(false, msg);
699            }
700        }
701
702        var req = new libly.Request(this.HOST_NAME + 'databases/' + this.dbname + '/items.json');
703        req.addEventListener('onSuccess', libly.$U.bind(this, function(res) {
704            var text = res.responseText;
705            if (!text) {
706                errDispatcher('response is null.', cache);
707                return;
708            }
709            var json = libly.$U.evalJson(text);
710            if (!json) {
711                errDispatcher('failed eval json.', cache);
712                return;
713            }
714            logger.log('success get wedata.');
715            store.set('expire', new Date(new Date().getTime() + expire).toString());
716            store.set('data', json);
717            store.save();
718            json.forEach(function(item) { if (typeof itemCallback == 'function') itemCallback(item); });
719            if (typeof finalCallback == 'function')
720                finalCallback(true, json);
721        }));
722        req.addEventListener('onFailure', function() errDispatcher('onFailure', cache));
723        req.addEventListener('onException', function() errDispatcher('onException', cache));
724        req.get();
725    }
726};
727//}}}
728
729//}
730// vim: set fdm=marker sw=4 ts=4 sts=0 et:
731
Note: See TracBrowser for help on using the browser.