| 1 | var PLUGIN_INFO = |
|---|
| 2 | <VimperatorPlugin> |
|---|
| 3 | <name>SBM Comments Viewer</name> |
|---|
| 4 | <description>List show Social Bookmark Comments</description> |
|---|
| 5 | <description lang="ja">ソーシャル・ブックマーク・コメントを表示します</description> |
|---|
| 6 | <version>0.1.1</version> |
|---|
| 7 | <minVersion>2.0pre</minVersion> |
|---|
| 8 | <maxVersion>2.3</maxVersion> |
|---|
| 9 | <updateURL>http://svn.coderepos.org/share/lang/javascript/vimperator-plugins/trunk/sbmcommentsviewer.js</updateURL> |
|---|
| 10 | <detail><![CDATA[ |
|---|
| 11 | == Usage == |
|---|
| 12 | >|| |
|---|
| 13 | viewSBMComments [url] [options] |
|---|
| 14 | url : 省略時は現在のURL |
|---|
| 15 | options: |
|---|
| 16 | -f, -format : 出力時のフォーマット(`,'区切りのリスト) |
|---|
| 17 | (default: id,timestamp,tags,comment) |
|---|
| 18 | let g:def_sbm_format = ... で指定可能 |
|---|
| 19 | -t, -type : 出力するSBMタイプ |
|---|
| 20 | (default: hdl) |
|---|
| 21 | let g:def_sbms = ... で指定可能 |
|---|
| 22 | -c, -count : ブックマーク件数のみ出力 |
|---|
| 23 | -b, -browser: バッファ・ウィンドウではなくブラウザに開く |
|---|
| 24 | TODO:まだ出来てない |
|---|
| 25 | ||< |
|---|
| 26 | |
|---|
| 27 | == 指定可能フォーマット == |
|---|
| 28 | id, timpstamp, tags, comment, tagsAndComment |
|---|
| 29 | |
|---|
| 30 | == SBMタイプ == |
|---|
| 31 | - h : hatena bookmark |
|---|
| 32 | - d : Delicious |
|---|
| 33 | - l : livedoor clip |
|---|
| 34 | - z : Buzzurl |
|---|
| 35 | - XXX:今後増やしていきたい |
|---|
| 36 | |
|---|
| 37 | >|| |
|---|
| 38 | e.g.) |
|---|
| 39 | :viewSBMComments http://d.hatena.ne.jp/teramako/ -t hdl -f id,comment -c |
|---|
| 40 | ||< |
|---|
| 41 | |
|---|
| 42 | == 備考 == |
|---|
| 43 | 一度取得したものは(30分ほど)キャッシュに貯めてますので何度も見直すことが可能です。 |
|---|
| 44 | 粋なコマンド名募集中 |
|---|
| 45 | ]]></detail> |
|---|
| 46 | </VimperatorPlugin>; |
|---|
| 47 | liberator.plugins.sbmCommentsViewer = (function(){ |
|---|
| 48 | |
|---|
| 49 | var isFilterNoComments = liberator.globalVariables.sbm_comments_viewer_filter_nocomments || false; |
|---|
| 50 | |
|---|
| 51 | /** |
|---|
| 52 | * SBMEntry Container {{{ |
|---|
| 53 | * @param {String} type |
|---|
| 54 | * @param {Number} count |
|---|
| 55 | * @param {Object} extra |
|---|
| 56 | * extra = { |
|---|
| 57 | * faviconURL, |
|---|
| 58 | * pageURL |
|---|
| 59 | * } |
|---|
| 60 | */ |
|---|
| 61 | function SBMContainer(type, count, extra){ //{{{ |
|---|
| 62 | this.type = type; |
|---|
| 63 | this.count = count || 0; |
|---|
| 64 | this.entries = []; |
|---|
| 65 | if (extra){ |
|---|
| 66 | this.faviconURL = extra.faviconURL || ''; |
|---|
| 67 | this.pageURL = extra.pageURL || ''; |
|---|
| 68 | } |
|---|
| 69 | } //}}} |
|---|
| 70 | SBMContainer.prototype = { //{{{ |
|---|
| 71 | add: function(id, timestamp, comment, tags, extra){ |
|---|
| 72 | this.entries.push(new SBMEntry( |
|---|
| 73 | id, timestamp, comment, tags, extra |
|---|
| 74 | )); |
|---|
| 75 | }, |
|---|
| 76 | toHTML: function(format, countOnly){ |
|---|
| 77 | var label = <> |
|---|
| 78 | {this.faviconURL ? <img src={this.faviconURL} width="16" height="16"/> : <></>} |
|---|
| 79 | {manager.type[this.type] + ' ' + this.count + '(' + this.entries.length + ')'} |
|---|
| 80 | {this.pageURL ? <a href="#">{this.pageURL}</a> : <></>} |
|---|
| 81 | </>; |
|---|
| 82 | if (countOnly){ |
|---|
| 83 | return label; |
|---|
| 84 | } else { |
|---|
| 85 | let xml = <table id="liberator-sbmcommentsviewer"> |
|---|
| 86 | <caption style="text-align:left" class="hl-Title">{label}</caption> |
|---|
| 87 | </table>; |
|---|
| 88 | let self = this; |
|---|
| 89 | xml.* += (function(){ |
|---|
| 90 | var thead = <tr/>; |
|---|
| 91 | format.forEach(function(colum){ thead.* += <th>{manager.format[colum] || '-'}</th>; }); |
|---|
| 92 | var tbody = <></>; |
|---|
| 93 | self.entries.forEach(function(e){ |
|---|
| 94 | if (isFilterNoComments && !e.comment) return; |
|---|
| 95 | tbody += e.toHTML(format); |
|---|
| 96 | }); |
|---|
| 97 | return thead + tbody; |
|---|
| 98 | })(); |
|---|
| 99 | return xml; |
|---|
| 100 | } |
|---|
| 101 | } |
|---|
| 102 | }; //}}} |
|---|
| 103 | // }}} |
|---|
| 104 | /** |
|---|
| 105 | * SBM Entry {{{ |
|---|
| 106 | * @param {String} id UserName |
|---|
| 107 | * @param {String|Date} timestamp |
|---|
| 108 | * @param {String} comment |
|---|
| 109 | * @param {String[]} tags |
|---|
| 110 | * @param {Object} extra |
|---|
| 111 | * extra = { |
|---|
| 112 | * userIcon |
|---|
| 113 | * link |
|---|
| 114 | * } |
|---|
| 115 | */ |
|---|
| 116 | function SBMEntry(id, timestamp, comment, tags, extra){ //{{{ |
|---|
| 117 | this.id = id || ''; |
|---|
| 118 | this.timeStamp = timestamp instanceof Date ? timestamp : null; |
|---|
| 119 | this.comment = comment || ''; |
|---|
| 120 | this.tags = tags || []; |
|---|
| 121 | if (extra){ |
|---|
| 122 | this.userIcon = extra.userIcon || null; |
|---|
| 123 | this.link = extra.link || null; |
|---|
| 124 | } |
|---|
| 125 | } //}}} |
|---|
| 126 | SBMEntry.prototype = { //{{{ |
|---|
| 127 | toHTML: function(format){ |
|---|
| 128 | var xml = <tr/>; |
|---|
| 129 | var self = this; |
|---|
| 130 | format.forEach(function(colum){ |
|---|
| 131 | switch(colum){ |
|---|
| 132 | case 'id': |
|---|
| 133 | xml.* += <td class="liberator-sbmcommentsviewer-id"> |
|---|
| 134 | {self.userIcon ? <><img src={self.userIcon} width="16" height="16"/> {self.id}</> : <span>{self.id}</span>} |
|---|
| 135 | </td>; |
|---|
| 136 | break; |
|---|
| 137 | case 'timestamp': |
|---|
| 138 | xml.* += <td class="liberator-sbmcommentsviewer-timestamp">{self.formatDate()}</td>; break; |
|---|
| 139 | case 'tags': |
|---|
| 140 | xml.* += <td class="liberator-sbmcommentsviewer-tags">{self.tags.join(',')}</td>; break; |
|---|
| 141 | case 'comment': |
|---|
| 142 | xml.* += <td class="liberator-sbmcommentsviewer-comment" style="white-space:normal;">{self.comment}</td>; break; |
|---|
| 143 | case 'tagsAndComment': |
|---|
| 144 | var tagString = self.tags.length ? '[' + self.tags.join('][') + ']':''; |
|---|
| 145 | xml.* += <td class="liberator-sbmcommentsviewer-tagsAndComment" style="white-space:normal;">{tagString + ' '+self.comment}</td>; |
|---|
| 146 | break; |
|---|
| 147 | default: |
|---|
| 148 | xml.* += <td>-</td>; |
|---|
| 149 | } |
|---|
| 150 | }); |
|---|
| 151 | return xml; |
|---|
| 152 | }, |
|---|
| 153 | formatDate: function(){ |
|---|
| 154 | if (!this.timeStamp) return ''; |
|---|
| 155 | var [year,month,day,hour,min,sec] = [ |
|---|
| 156 | this.timeStamp.getFullYear(), |
|---|
| 157 | this.timeStamp.getMonth()+1, |
|---|
| 158 | this.timeStamp.getDate(), |
|---|
| 159 | this.timeStamp.getHours(), |
|---|
| 160 | this.timeStamp.getMinutes(), |
|---|
| 161 | this.timeStamp.getSeconds() |
|---|
| 162 | ]; |
|---|
| 163 | return [ |
|---|
| 164 | year, '/', |
|---|
| 165 | (month < 10 ? '0'+month : month), '/', |
|---|
| 166 | (day < 10 ? '0'+day : day), ' ', |
|---|
| 167 | (hour < 10 ? '0'+hour : hour), ':', |
|---|
| 168 | (min < 10 ? '0'+min : min), ':', |
|---|
| 169 | (sec < 10 ? '0'+sec : sec) |
|---|
| 170 | ].join(''); |
|---|
| 171 | } |
|---|
| 172 | }; //}}} |
|---|
| 173 | //}}} |
|---|
| 174 | /** |
|---|
| 175 | * openSBM {{{ |
|---|
| 176 | * @param {String} url |
|---|
| 177 | * @param {String} type |
|---|
| 178 | * @param {String[]} format |
|---|
| 179 | * @param {Boolean} countOnly |
|---|
| 180 | * @param {Boolean} openToBrowser |
|---|
| 181 | */ |
|---|
| 182 | function openSBM(url, type, format, countOnly, openToBrowser){ |
|---|
| 183 | var sbmLabel = manager.type[type]; |
|---|
| 184 | var sbmURL = SBM[sbmLabel].getURL(url); |
|---|
| 185 | var xhr = new XMLHttpRequest(); |
|---|
| 186 | xhr.open('GET', sbmURL, true); |
|---|
| 187 | xhr.onreadystatechange = function(){ |
|---|
| 188 | if (xhr.readyState == 4){ |
|---|
| 189 | if (xhr.status == 200){ |
|---|
| 190 | let sbmContainer = SBM[sbmLabel].parser.call(this, xhr); |
|---|
| 191 | if (!sbmContainer) return; |
|---|
| 192 | cacheManager.add(sbmContainer, url, type); |
|---|
| 193 | if (openToBrowser) |
|---|
| 194 | manager.open(sbmContainer.toHTML(format,false)); |
|---|
| 195 | else |
|---|
| 196 | liberator.echo(sbmContainer.toHTML(format,countOnly), true); |
|---|
| 197 | } else { |
|---|
| 198 | liberator.echoerr(sbmURL + ' ' + xhr.status, true); |
|---|
| 199 | } |
|---|
| 200 | } |
|---|
| 201 | }; |
|---|
| 202 | xhr.send(null); |
|---|
| 203 | } //}}} |
|---|
| 204 | /** |
|---|
| 205 | * getURL と parser メソッドを供えること |
|---|
| 206 | * getURL は 取得先のURLを返すこと |
|---|
| 207 | * parser は SBMContainer オブジェクトを返すこと |
|---|
| 208 | */ |
|---|
| 209 | var SBM = { //{{{ |
|---|
| 210 | hatena: { //{{{ |
|---|
| 211 | getURL: function(url){ |
|---|
| 212 | var urlPrefix = 'http://b.hatena.ne.jp/entry/jsonlite/?url='; |
|---|
| 213 | return urlPrefix + encodeURIComponent(url.replace(/%23/g,'#')); |
|---|
| 214 | }, |
|---|
| 215 | parser: function(xhr){ |
|---|
| 216 | //var json = window.eval(xhr.responseText); |
|---|
| 217 | var json = jsonDecode(xhr.responseText, false); |
|---|
| 218 | var count = json.bookmarks.length; |
|---|
| 219 | var c = new SBMContainer('h', json.count, { |
|---|
| 220 | faviconURL:'http://b.hatena.ne.jp/favicon.ico', |
|---|
| 221 | pageURL: 'http://b.hatena.ne.jp/entry/' + json.url |
|---|
| 222 | }); |
|---|
| 223 | json.bookmarks.forEach(function(bm){ |
|---|
| 224 | c.add(bm.user, new Date(bm.timestamp), bm.comment, bm.tags, { |
|---|
| 225 | userIcon: 'http://www.hatena.ne.jp/users/' + bm.user.substring(0,2) + '/' + bm.user +'/profile_s.gif' |
|---|
| 226 | }); |
|---|
| 227 | }); |
|---|
| 228 | return c; |
|---|
| 229 | } |
|---|
| 230 | }, //}}} |
|---|
| 231 | delicious: { //{{{ |
|---|
| 232 | getURL: function(url){ |
|---|
| 233 | //var urlPrefix = 'http://del.icio.us/rss/url/'; |
|---|
| 234 | var urlPrefix = 'http://feeds.delicious.com/rss/url/'; |
|---|
| 235 | return urlPrefix + getMD5Hash(url); |
|---|
| 236 | }, |
|---|
| 237 | parser: function(xhr){ |
|---|
| 238 | var rss = xhr.responseXML; |
|---|
| 239 | if (!rss){ |
|---|
| 240 | liberator.echoerr('Delicious feed is none',true); |
|---|
| 241 | return; |
|---|
| 242 | } |
|---|
| 243 | var pageURL, items; |
|---|
| 244 | try { |
|---|
| 245 | pageURL = evaluateXPath(rss, '//rss:channel/rss:link')[0].textContent; |
|---|
| 246 | items = evaluateXPath(rss, '//rss:item'); |
|---|
| 247 | } catch(e){ |
|---|
| 248 | liberator.log(e); |
|---|
| 249 | } |
|---|
| 250 | var c = new SBMContainer('d', items.length, { |
|---|
| 251 | faviconURL: 'http://delicious.com/favicon.ico', |
|---|
| 252 | pageURL: pageURL |
|---|
| 253 | }); |
|---|
| 254 | items.forEach(function(item){ |
|---|
| 255 | var children = item.childNodes; |
|---|
| 256 | var [id,date,tags,comment,link] = ['','',[],'','']; |
|---|
| 257 | for (let i=0; i<children.length; i++){ |
|---|
| 258 | let node = children[i]; |
|---|
| 259 | if (node.nodeType == 1){ |
|---|
| 260 | switch (node.localName){ |
|---|
| 261 | case 'creator': id = node.textContent; break; |
|---|
| 262 | case 'link': link = node.textContent; break; |
|---|
| 263 | case 'date': |
|---|
| 264 | date = stringToDate(node.textContent); |
|---|
| 265 | break; |
|---|
| 266 | case 'description': comment = node.textContent; break; |
|---|
| 267 | case 'subject': tags = node.textContent.split(/\s+/); break; |
|---|
| 268 | } |
|---|
| 269 | } |
|---|
| 270 | } |
|---|
| 271 | c.add(id, date, comment, tags, {link: link}); |
|---|
| 272 | }); |
|---|
| 273 | return c; |
|---|
| 274 | } |
|---|
| 275 | }, //}}} |
|---|
| 276 | livedoorclip: { //{{{ |
|---|
| 277 | getURL: function(url){ |
|---|
| 278 | var urlPrefix = 'http://api.clip.livedoor.com/json/comments?link='; |
|---|
| 279 | return urlPrefix + encodeURIComponent(url.replace(/%23/g,'#')) + '&all=0'; |
|---|
| 280 | }, |
|---|
| 281 | parser: function(xhr){ |
|---|
| 282 | /* |
|---|
| 283 | var json = Components.classes['@mozilla.org/dom/json;1']. |
|---|
| 284 | getService(Components.interfaces.nsIJSON). |
|---|
| 285 | decode(xhr.responseText); |
|---|
| 286 | */ |
|---|
| 287 | var json = jsonDecode(xhr.responseText); |
|---|
| 288 | if (json && json.isSuccess){ |
|---|
| 289 | let c = new SBMContainer('l', json.total_clip_count, { |
|---|
| 290 | faviconURL: 'http://clip.livedoor.com/favicon.ico', |
|---|
| 291 | pageURL: 'http://clip.livedoor.com/page/' + json.link |
|---|
| 292 | }); |
|---|
| 293 | json.Comments.forEach(function(clip){ |
|---|
| 294 | c.add( clip.livedoor_id, new Date(clip.created_on * 1000), |
|---|
| 295 | clip.notes ? clip.notes : '', |
|---|
| 296 | clip.tags, |
|---|
| 297 | { |
|---|
| 298 | userIcon: 'http://image.clip.livedoor.com/profile/' + |
|---|
| 299 | '?viewer_id=[%%20member.livedoor_id%20Z%]&target_id=' + |
|---|
| 300 | clip.livedoor_id, |
|---|
| 301 | link: 'http://clip.livedoor.com/clips/' + clip.livedoor_id |
|---|
| 302 | } |
|---|
| 303 | ); |
|---|
| 304 | }); |
|---|
| 305 | return c; |
|---|
| 306 | } else { |
|---|
| 307 | liberator.log('Faild: LivedoorClip'); |
|---|
| 308 | } |
|---|
| 309 | } |
|---|
| 310 | }, //}}} |
|---|
| 311 | buzzurl: { //{{{ |
|---|
| 312 | getURL: function(url){ |
|---|
| 313 | var urlPrefix = 'http://api.buzzurl.jp/api/posts/get/v1/json/?url='; |
|---|
| 314 | return urlPrefix + encodeURIComponent(url.replace(/%23/g,'#')); |
|---|
| 315 | }, |
|---|
| 316 | parser: function(xhr){ |
|---|
| 317 | var url = 'http://buzzurl.jp/user/'; |
|---|
| 318 | var json = jsonDecode(xhr.responseText); |
|---|
| 319 | if (json && json[0] && json[0].user_num){ |
|---|
| 320 | let c = new SBMContainer('buzzurl', json[0].user_num, { |
|---|
| 321 | faviconURL: 'http://buzzurl.jp/favicon.ico', |
|---|
| 322 | pageURL: 'http://buzzurl.jp/entry/' + json[0].url |
|---|
| 323 | }); |
|---|
| 324 | json[0].posts.forEach(function(entry){ |
|---|
| 325 | c.add( entry.user_name, stringToDate(entry.date), |
|---|
| 326 | entry.comment ? entry.comment : '', (entry.keywords || '').split(','), |
|---|
| 327 | { |
|---|
| 328 | userIcon: url + entry.user_name + '/photo', |
|---|
| 329 | link: url + '/' + entry.user_name |
|---|
| 330 | } |
|---|
| 331 | ); |
|---|
| 332 | }); |
|---|
| 333 | return c; |
|---|
| 334 | } else { |
|---|
| 335 | liberator.log('Faild: Buzzurl'); |
|---|
| 336 | } |
|---|
| 337 | } |
|---|
| 338 | } //}}} |
|---|
| 339 | }; //}}} |
|---|
| 340 | |
|---|
| 341 | /** |
|---|
| 342 | * jsonDecode {{{ |
|---|
| 343 | * @param {String} str JSON String |
|---|
| 344 | * @param {Boolean} toRemove はてなブックマークのJSONの様に |
|---|
| 345 | * 前後に()が付いている場合に取り除くためのフラグ |
|---|
| 346 | */ |
|---|
| 347 | function jsonDecode(str, toRemove){ |
|---|
| 348 | var json = Components.classes['@mozilla.org/dom/json;1'].getService(Components.interfaces.nsIJSON); |
|---|
| 349 | if (toRemove) str = str.substring(1, str.length -1); |
|---|
| 350 | |
|---|
| 351 | return json.decode(str); |
|---|
| 352 | } |
|---|
| 353 | //}}} |
|---|
| 354 | /** |
|---|
| 355 | * getMD5Hash {{{ |
|---|
| 356 | * @param {String} str |
|---|
| 357 | * @return {String} MD5HashString |
|---|
| 358 | */ |
|---|
| 359 | function getMD5Hash(str){ |
|---|
| 360 | var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]. |
|---|
| 361 | createInstance(Components.interfaces.nsIScriptableUnicodeConverter); |
|---|
| 362 | converter.charset = 'UTF-8'; |
|---|
| 363 | var result = {}; |
|---|
| 364 | var data = converter.convertToByteArray(str, result); |
|---|
| 365 | var ch = Components.classes['@mozilla.org/security/hash;1'].createInstance(Components.interfaces.nsICryptoHash); |
|---|
| 366 | ch.init(ch.MD5); |
|---|
| 367 | ch.update(data, data.length); |
|---|
| 368 | var hash = ch.finish(false); |
|---|
| 369 | function toHexString(charCode){ |
|---|
| 370 | return ('0' + charCode.toString(16)).slice(-2); |
|---|
| 371 | } |
|---|
| 372 | var s = [i < hash.length ? toHexString(hash.charCodeAt(i)) : '' for (i in hash)].join(''); |
|---|
| 373 | return s; |
|---|
| 374 | } //}}} |
|---|
| 375 | /** |
|---|
| 376 | * stringToDate {{{ |
|---|
| 377 | * @param {String} Date String |
|---|
| 378 | * @return {Date} |
|---|
| 379 | */ |
|---|
| 380 | function stringToDate(str){ |
|---|
| 381 | let args = str.split(/[-T:Z]/,6).map(function (v) parseInt(v, 10)); |
|---|
| 382 | args[1]--; |
|---|
| 383 | return new Date(args[0], args[1], args[2], args[3], args[4], args[5]); |
|---|
| 384 | } //}}} |
|---|
| 385 | /** |
|---|
| 386 | * evaluateXPath {{{ |
|---|
| 387 | * @param {Element} aNode |
|---|
| 388 | * @param {String} aExpr XPath Expression |
|---|
| 389 | * @return {Element[]} |
|---|
| 390 | * @see http://developer.mozilla.org/ja/docs/Using_XPath |
|---|
| 391 | */ |
|---|
| 392 | function evaluateXPath(aNode, aExpr){ |
|---|
| 393 | var xpe = new XPathEvaluator(); |
|---|
| 394 | function nsResolver(prefix){ |
|---|
| 395 | var ns = { |
|---|
| 396 | xhtml: 'http://www.w3.org/1999/xhtml', |
|---|
| 397 | rdf: 'http://www.w3.org/1999/02/22-rdf-syntax-ns#', |
|---|
| 398 | dc: 'http://purl.org/dc/elements/1.1/', |
|---|
| 399 | rss: 'http://purl.org/rss/1.0/', |
|---|
| 400 | taxo: 'http://purl.org/rss/1.0/modules/taxonomy/', |
|---|
| 401 | content: 'http://purl.org/rss/1.0/modules/content/', |
|---|
| 402 | syn: 'http://purl.org/rss/1.0/modules/syndication/', |
|---|
| 403 | admin: 'http://webns.net/mvcb/' |
|---|
| 404 | }; |
|---|
| 405 | return ns[prefix] || null; |
|---|
| 406 | } |
|---|
| 407 | var result = xpe.evaluate(aExpr, aNode, nsResolver, 0, null); |
|---|
| 408 | var found = []; |
|---|
| 409 | var res; |
|---|
| 410 | while (res = result.iterateNext()) |
|---|
| 411 | found.push(res); |
|---|
| 412 | return found; |
|---|
| 413 | } //}}} |
|---|
| 414 | /** |
|---|
| 415 | * sbmCommentsView manager {{{ |
|---|
| 416 | * @alias liberator.plugins.sbmCommentsViewer |
|---|
| 417 | */ |
|---|
| 418 | var manager = { |
|---|
| 419 | type: { |
|---|
| 420 | h: 'hatena', |
|---|
| 421 | d: 'delicious', |
|---|
| 422 | l: 'livedoorclip', |
|---|
| 423 | z: 'buzzurl' |
|---|
| 424 | }, |
|---|
| 425 | format: { |
|---|
| 426 | id: 'ID', |
|---|
| 427 | comment: 'Comment', |
|---|
| 428 | timestamp: 'TimeStamp', |
|---|
| 429 | tags: 'Tags', |
|---|
| 430 | tagsAndComment: 'Tags&Comment' |
|---|
| 431 | }, |
|---|
| 432 | // for debug |
|---|
| 433 | convertMD5: function(str){ |
|---|
| 434 | return getMD5Hash(str); |
|---|
| 435 | }, |
|---|
| 436 | // for debug |
|---|
| 437 | getXML: function(url){ |
|---|
| 438 | var xhr = new XMLHttpRequest(); |
|---|
| 439 | xhr.open('GET',url,false); |
|---|
| 440 | xhr.send(null); |
|---|
| 441 | return xhr; |
|---|
| 442 | }, |
|---|
| 443 | // for debug |
|---|
| 444 | get cache(){ |
|---|
| 445 | return cacheManager; |
|---|
| 446 | }, |
|---|
| 447 | /** |
|---|
| 448 | * @param {String} str |
|---|
| 449 | * @param {Number} where |
|---|
| 450 | * TODO |
|---|
| 451 | */ |
|---|
| 452 | open: function(str, where){ |
|---|
| 453 | /* |
|---|
| 454 | getBrowser().addTab('data:text/html,'+str, null,null,null); |
|---|
| 455 | */ |
|---|
| 456 | } |
|---|
| 457 | }; //}}} |
|---|
| 458 | |
|---|
| 459 | var options = [ |
|---|
| 460 | [['-type','-t'], commands.OPTION_STRING, function(str) (new RegExp('^['+[t for(t in manager.type)].join('') + ']+$')).test(str)], |
|---|
| 461 | [['-format','-f'], commands.OPTION_LIST,null, [[f,manager.format[f]] for (f in manager.format)]], |
|---|
| 462 | [['-count','-c'], commands.OPTION_NOARG], |
|---|
| 463 | [['-browser','-b'],commands.OPTION_NORARG] |
|---|
| 464 | ]; |
|---|
| 465 | commands.addUserCommand(['viewSBMComments'], 'SBM Comments Viewer', //{{{ |
|---|
| 466 | function(arg){ //{{{ |
|---|
| 467 | var types = liberator.globalVariables.def_sbms || 'hdlz'; |
|---|
| 468 | var format = (liberator.globalVariables.def_sbm_format || 'id,timestamp,tags,comment').split(','); |
|---|
| 469 | var countOnly = false, openToBrowser = false; |
|---|
| 470 | var url = buffer.URL; |
|---|
| 471 | [ |
|---|
| 472 | let (v = arg['-' + name]) (v && f(v)) |
|---|
| 473 | for ([name, f] in Iterator({ |
|---|
| 474 | count: function () countOnly = true, |
|---|
| 475 | browser: function () openToBrowser = true, |
|---|
| 476 | type: function (v) (types = v), |
|---|
| 477 | format: function (v) (format = v), |
|---|
| 478 | arguments: function (v) (v.length > 0 && (url = v[0])) |
|---|
| 479 | })) |
|---|
| 480 | ] |
|---|
| 481 | |
|---|
| 482 | for (let i=0; i<types.length; i++){ |
|---|
| 483 | let type = types.charAt(i); |
|---|
| 484 | if ( manager.type[type] ){ |
|---|
| 485 | if ( cacheManager.isAvailable(url, type) ){ |
|---|
| 486 | liberator.log('cache avairable'); |
|---|
| 487 | if (openToBrowser) |
|---|
| 488 | // TODO |
|---|
| 489 | manager.open(cacheManager.get(url,type).toHTML(format,false), liberator.forceNewTab); |
|---|
| 490 | else |
|---|
| 491 | liberator.echo(cacheManager.get(url, type).toHTML(format,countOnly), true); |
|---|
| 492 | } else { |
|---|
| 493 | try { |
|---|
| 494 | openSBM(url, type, format, countOnly, openToBrowser); |
|---|
| 495 | } catch(e){ |
|---|
| 496 | liberator.log(e); |
|---|
| 497 | } |
|---|
| 498 | } |
|---|
| 499 | } |
|---|
| 500 | } |
|---|
| 501 | }, //}}} |
|---|
| 502 | { |
|---|
| 503 | argCount:"*", |
|---|
| 504 | options: options, |
|---|
| 505 | completer: function(context) completion.url(context, 'l') |
|---|
| 506 | }, |
|---|
| 507 | true |
|---|
| 508 | ); //}}} |
|---|
| 509 | |
|---|
| 510 | /** |
|---|
| 511 | * cacheManager {{{ |
|---|
| 512 | */ |
|---|
| 513 | var cacheManager = (function(){ |
|---|
| 514 | var cache = {}; |
|---|
| 515 | // min sec millisec |
|---|
| 516 | var threshold = 30 * 60 * 1000; |
|---|
| 517 | var interval = 10 * 60 * 1000; |
|---|
| 518 | var c_manager = { |
|---|
| 519 | get raw(){ |
|---|
| 520 | return cache; |
|---|
| 521 | }, |
|---|
| 522 | has: function(url){ |
|---|
| 523 | if (cache[url]) |
|---|
| 524 | return true; |
|---|
| 525 | else |
|---|
| 526 | return false; |
|---|
| 527 | }, |
|---|
| 528 | add: function(sbmComments, url, type){ |
|---|
| 529 | if (!cache[url]) cache[url] = {}; |
|---|
| 530 | cache[url][type] = [new Date(), sbmComments]; |
|---|
| 531 | }, |
|---|
| 532 | get: function(url, type){ |
|---|
| 533 | return cache[url][type][1]; |
|---|
| 534 | }, |
|---|
| 535 | delete: function(url, type) { |
|---|
| 536 | if (!cache[url]) return true; |
|---|
| 537 | if (!type) return delete cache[url]; |
|---|
| 538 | return delete cache[url][type]; |
|---|
| 539 | }, |
|---|
| 540 | garbage: function(){ |
|---|
| 541 | var date = new Date(); |
|---|
| 542 | for (let url in cache){ |
|---|
| 543 | for (let type in cache[url]){ |
|---|
| 544 | if (date - cache[url][type][0] > threshold) delete cache[url][type]; |
|---|
| 545 | } |
|---|
| 546 | } |
|---|
| 547 | }, |
|---|
| 548 | isAvailable: function(url, type){ |
|---|
| 549 | if (cache[url] && cache[url][type] && new Date() - cache[url][type][0] < threshold) |
|---|
| 550 | return true; |
|---|
| 551 | |
|---|
| 552 | return false; |
|---|
| 553 | } |
|---|
| 554 | }; |
|---|
| 555 | return c_manager; |
|---|
| 556 | })(); |
|---|
| 557 | //}}} |
|---|
| 558 | |
|---|
| 559 | return manager; |
|---|
| 560 | })(); |
|---|
| 561 | // vim: sw=4 ts=4 sts=0 et fdm=marker: |
|---|