Changeset 16976 for lang/javascript/userscripts
- Timestamp:
- 08/02/08 17:43:44 (4 months ago)
- Files:
-
- 1 modified
Legend:
- Unmodified
- Added
- Removed
-
lang/javascript/userscripts/hatena.haiku.expandrepliestree.user.js
r16974 r16976 6 6 // ==/UserScript== 7 7 8 (function (unsafeWindow) { with (D()) { 8 location.href = "javascript:"+encodeURIComponent(uneval(function () { 9 10 (function (Global) { with (D()) { 9 11 const WAIT = 1; 10 const LEVEL = 9;12 const LEVEL = 1; 11 13 const ICON = [ 12 14 "data:image/png;base64,", … … 18 20 ].join(""); 19 21 20 21 GM_addStyle([ 22 var loading = false; 23 24 25 addStyle([ 22 26 "div.info .expand a {", 23 27 "background: transparent url('",ICON,"') no-repeat scroll 0 65%;", … … 25 29 "margin: 0 0 0 3px", 26 30 "}", 27 ] .join(""));31 ]); 28 32 29 33 function applyJavaScript (entry) { … … 39 43 }); 40 44 41 unsafeWindow.Hatena.Haiku.Pager.dispatchEvent('loadedEntries', entry.parentNode.wrappedJSObject || entry.parentNode);45 Global.Hatena.Haiku.Pager.dispatchEvent('loadedEntries', entry.parentNode.wrappedJSObject || entry.parentNode); 42 46 return entry; 43 47 } … … 45 49 function expandReplies (entry, level) { 46 50 if (typeof level == "undefined") level = LEVEL; 47 if (level < 1) return next();48 51 log("level:" + level); 49 50 var a = $X("./div[@class='list-body']/div/a[img[@src='/images/icon-replylink.gif']]", entry)[0]; 51 var raw_href = $X("string(@href)", a); 52 var es = $X("//div[@class='entry' and .//span[@class='timestamp']/a[@href = '"+raw_href+"']]"); 53 54 if (a) a.style.opacity = "0.6"; 55 56 $X(".//span[@class='expand']", entry).forEach(function (e) { 57 e.innerHTML = "Loading..."; 58 }); 52 if (entry._expanded) return next(); 53 54 if (level < 1) { 55 // 深すぎるので、さらに展開するためのリンクをつけたうえで終了する。 56 return next(function (i) { 57 log("level too deep. Please click the link to expand more."); 58 addExpandLink(entry, function () { 59 log("expand more -> child"); 60 return expandReplies(entry, LEVEL); 61 }); 62 }); 63 } 64 65 entry._expanded = true; 66 59 67 return parallel([ 60 expandChildReplies(entry, level - 1), 61 !a ? next() : es.length ? appendAndLoadNext(es[0]) : xhttp.get(a.href).next(function (data) { 68 expandChildReplies(entry, level), 69 expandParent(entry, level) 70 ]); 71 72 function expandParent (entry, level) { 73 log(["expandParent", entry, level]); 74 75 var a = $X("./div[@class='list-body']/div/a[img[@src='/images/icon-replylink.gif']]", entry)[0]; 76 var raw_href = $X("string(@href)", a); 77 var es = $X("//div[@class='entry' and ./div/div/span[@class='timestamp']/a[@href = '"+raw_href+"']]"); 78 79 if (a) a.style.opacity = "0.6"; 80 81 return !a ? next() : es.length ? appendAndLoadNext(es[0]) : http.get(a.href).next(function (data) { 62 82 var t = h(data.responseText.replace(/<\/?(?:script|i?frame)[^>]*>/g, "")); 63 83 return parallel($X(".//div[@class='entries']/div[@class='entry']", t).map(appendAndLoadNext)); 64 }),65 ]).66 next(function () {67 $X(".//span[@class='expand']", entry).forEach(function (e) {68 e.parentNode.removeChild(e);69 84 }); 70 }); 71 72 function appendAndLoadNext (e) { 73 if (a) a.style.opacity = "0.2"; 74 e = applyJavaScript(e); 75 var body = $X("./div[@class='list-body']", e)[0]; 76 entry.parentNode.insertBefore(e, entry); 77 body.appendChild(entry); 78 return wait(WAIT).next(function () { 79 return call(expandReplies, e, level - 1); 80 }); 85 86 function appendAndLoadNext (e) { 87 if (e._expanded) return next(); 88 89 if (a) a.style.opacity = "0.2"; 90 e = applyJavaScript(e); 91 var body = $X("./div[@class='list-body']", e)[0]; 92 entry.parentNode.insertBefore(e, entry); 93 body.appendChild(entry); 94 return wait(WAIT).next(function () { 95 return call(expandReplies, e, level - 1); 96 }); 97 } 81 98 } 82 99 83 100 function expandChildReplies (entry, level) { 84 log("level:" + level); 85 if (level < 1) return next(); 101 log(["expandChildReplies", entry, level]); 86 102 87 103 var body = $X("./div[@class='list-body']", entry)[0]; … … 98 114 var es = $X("//div[@class='entry' and .//span[@class='timestamp']/a[@href = '"+raw_href+"']]"); 99 115 if (es.length) return appendAndLoadNext(es[0]); 100 return xhttp.get(a.href).next(function (data) {116 return http.get(a.href).next(function (data) { 101 117 // remove unnecessary tags 102 118 var t = h(data.responseText.replace(/<\/?(?:script|i?frame)[^>]*>/g, "")); … … 117 133 118 134 return wait(WAIT).next(function () { 119 return call(expand ChildReplies, e, level - 1);135 return call(expandReplies, e, level - 1); 120 136 }); 121 137 } … … 125 141 } 126 142 143 function addExpandLink (e, handler) { 144 if (e._gm_expandreplies_applied) return; 145 e._gm_expandreplies_applied = true; 146 147 var info = $X("./div/div[@class='info']", e)[0]; 148 var link = dom("<span class='expand'><a href='javascript:void(156)'>Expand</a></span>", info).root; 149 link.addEventListener("click", function () { 150 if (window.getSelection().toString()) return; 151 if (e._loading) return; 152 e._loading = true; 153 log("Loading..."); 154 link.innerHTML = "loading"; 155 handler().next(function () { 156 link.parentNode.removeChild(link); 157 }).error(function (e) { alert(e) }); 158 }, false); 159 } 160 127 161 // observe pagerize 128 162 var num = 0; 129 163 next(function () { 164 if (loading) return wait(WAIT).next(arguments.callee); 165 130 166 var n = $X("count(//div[@class='entries']/div[@class='entry'])"); 131 167 if (num < n) { … … 133 169 loop(entries.length, function (n) { 134 170 var e = entries[n].wrappedJSObject || entries[n]; 135 if (e._gm_expandreplies_applied) return; 136 e._gm_expandreplies_applied = true; 137 var handler = function () { 138 if (window.getSelection().toString()) return; 139 if (e._loading) return; 140 e._loading = true; 141 log("Loading..."); 142 expandReplies(e).next(function () { 171 addExpandLink(e, function () { 172 return expandReplies(e). 173 next(function () { 143 174 if (log.element) { 144 175 log.element.parentNode.removeChild(log.element); 145 176 log.element = null; 146 177 } 147 }).error(function (e) { 178 }). 179 error(function (e) { 148 180 alert("Error"+e); 149 181 }); 150 }; 151 // $X("div/div[@class='body']", e)[0].addEventListener("click", handler, false); 152 153 var info = $X("./div/div[@class='info']", e)[0]; 154 info.appendChild(h("<span class='expand'><a href='javascript:void(156)'>Expand</a></span>").firstChild); 155 info.addEventListener("click", handler, false); 182 }); 156 183 }); 157 184 … … 174 201 } 175 202 203 function addStyle (a) { 204 dom("<style type='text/css'>#{css}</style>", document.body, { css : a.join("") }); 205 } 206 207 208 function dom (str, cur, txt) { 209 var t, ret = {}, stack = [cur = cur || document.createElement("div")]; 210 while (str.length) { 211 if (str.indexOf("<") == 0) { 212 if (t = str.match(/^\s*<(\/?[^\s>\/]+)([^>]+?)?(\/)?>/)) { 213 var tag = t[1], attrs = t[2], isempty = !!t[3]; 214 if (tag.indexOf("/") == -1) { 215 child = document.createElement(tag); 216 if (attrs) attrs.replace(/([a-z]+)=(?:'([^']+)'|"([^"]+)")/gi, 217 function (m, name, v1, v2) { 218 var v = text(v1 || v2); 219 if (name == "class") ret[v] = child; 220 child.setAttribute(name, v); 221 } 222 ); 223 cur.appendChild(ret.root ? child : (ret.root = child)); 224 if (!isempty) { 225 stack.push(cur); 226 cur = child; 227 } 228 } else cur = stack.pop(); 229 } else throw("Parse Error: " + str); 230 } else { 231 if (t = str.match(/^([^<]+)/)) cur.appendChild(document.createTextNode(text(t[0]))); 232 } 233 str = str.substring(t[0].length); 234 } 235 return ret; 236 237 function text (str) { 238 return str 239 .replace(/&(#(x)?)?([^;]+);/g, function (_, isNumRef, isHex, ref) { 240 return isNumRef ? String.fromCharCode(parseInt(ref, isHex ? 16 : 10)): 241 {"lt":"<","gt":"<","amp":"&"}[ref]; 242 }) 243 .replace(/#\{([^}]+)\}/, function (_, name) { 244 return txt[name]; 245 }); 246 } 247 } 248 249 176 250 function log (m) { 177 unsafeWindow.console.log(uneval(m));251 Global.console.log(m); 178 252 179 253 if (!arguments.callee.element) { … … 263 337 264 338 // Usage:: with (D()) { your code } 265 // JSDefe ered 0.2.0(c) Copyright (c) 2007 cho45 ( www.lowreal.net )339 // JSDeferred 0.2.1 (c) Copyright (c) 2007 cho45 ( www.lowreal.net ) 266 340 // See http://coderepos.org/share/wiki/JSDeferred 267 341 function D () { … … 314 388 Deferred.parallel = function (dl) { 315 389 var ret = new Deferred(), values = {}, num = 0; 316 for (var i in dl) { 317 if (!dl.hasOwnProperty(i)) continue; 390 for (var i in dl) if (dl.hasOwnProperty(i)) { 318 391 (function (d, i) { 319 392 d.next(function (v) { … … 333 406 } 334 407 if (!num) Deferred.next(function () { ret.call() }); 408 ret.canceller = function () { 409 for (var i in dl) if (dl.hasOwnProperty(i)) { 410 dl[i].cancel(); 411 } 412 }; 335 413 return ret; 336 414 }; … … 341 419 clearTimeout(id); 342 420 d.call((new Date).getTime() - t.getTime()); 343 }, n * 1000) 344 d.canceller = function () { try { clearTimeout(id) } catch (e) {} };421 }, n * 1000); 422 d.canceller = function () { try { clearTimeout(id) } catch (e) {} }; 345 423 return d; 346 424 }; … … 350 428 var id = setTimeout(function () { clearTimeout(id); d.call() }, 0); 351 429 if (fun) d.callback.ok = fun; 352 d.canceller = function () { try { clearTimeout(id) } catch (e) {} };430 d.canceller = function () { try { clearTimeout(id) } catch (e) {} }; 353 431 return d; 354 432 }; … … 365 443 var o = { 366 444 begin : n.begin || 0, 367 end : n.end || (n - 1),445 end : (typeof n.end == "number") ? n.end : n - 1, 368 446 step : n.step || 1, 369 447 last : false, … … 392 470 } 393 471 } 394 return Deferred.call(_loop, o.begin);472 return (o.begin <= o.end) ? Deferred.call(_loop, o.begin) : null; 395 473 }); 396 474 }; … … 436 514 d.fail(res); 437 515 }; 438 GM_xmlhttpRequest(opts); 516 setTimeout(function () { 517 GM_xmlhttpRequest(opts); 518 }, 0); 439 519 return d; 440 520 } 441 xhttp.get = function (url) { return xhttp({method:"get", url:url}) }442 xhttp.post = function (url, data) { return xhttp({method:"post", url:url, data:data, headers:{"Content-Type":"application/x-www-form-urlencoded"}}) } 521 xhttp.get = function (url) { return xhttp({method:"get", url:url}) }; 522 xhttp.post = function (url, data) { return xhttp({method:"post", url:url, data:data, headers:{"Content-Type":"application/x-www-form-urlencoded"}}) }; 443 523 444 524 … … 447 527 var req = new XMLHttpRequest(); 448 528 req.open(opts.method, opts.url, true); 529 if (opts.headers) { 530 for (var k in opts.headers) if (opts.headers.hasOwnProperty(k)) { 531 req.setRequestHeader(k, opts.headers[k]); 532 } 533 } 449 534 req.onreadystatechange = function () { 450 535 if (req.readyState == 4) d.call(req); 451 536 }; 452 537 req.send(opts.data || null); 538 d.xhr = req; 453 539 return d; 454 540 } 455 http.get = function (url) { return http({method:"get", url:url}) } 456 http.post = function (url, data) { return http({method:"post", url:url, data:data}) } 541 http.get = function (url) { return http({method:"get", url:url}) }; 542 http.post = function (url, data) { return http({method:"post", url:url, data:data, headers:{"Content-Type":"application/x-www-form-urlencoded"}}) }; 543 http.jsonp = function (url, params) { 544 if (!params) params = {}; 545 546 var Global = (function () { return this })(); 547 var d = Deferred(); 548 var cbname = params["callback"]; 549 if (!cbname) do { 550 cbname = "callback" + String(Math.random()).slice(2); 551 } while (typeof(Global[cbname]) != "undefined"); 552 553 params["callback"] = cbname; 554 555 url += (url.indexOf("?") == -1) ? "?" : "&"; 556 557 for (var name in params) if (params.hasOwnProperty(name)) { 558 url = url + encodeURIComponent(name) + "=" + encodeURIComponent(params[name]) + "&"; 559 } 560 561 var script = document.createElement('script'); 562 script.type = "text/javascript"; 563 script.charset = "utf-8"; 564 script.src = url; 565 document.body.appendChild(script); 566 567 Global[cbname] = function callback (data) { 568 delete Global[cbname]; 569 document.body.removeChild(script); 570 d.call(data); 571 }; 572 return d; 573 }; 457 574 458 575 Deferred.Deferred = Deferred; … … 462 579 }// End of JSDeferred 463 580 464 })(this .unsafeWindow || this);465 466 581 })(this); 582 583 }))+"()";
![(please configure the [header_logo] section in trac.ini)](/share/chrome/site/your_project_logo.png)