diff --git a/LICENSE b/LICENSE index 02da5f51c..e79c58b2d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* appchan x - Version 2.2.2 - 2013-08-05 +* appchan x - Version 2.2.2 - 2013-08-06 * * Licensed under the MIT license. * https://github.com/zixaphir/appchan-x/blob/master/LICENSE diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 44df79589..1f7c82496 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -19,7 +19,7 @@ // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwAgMAAAAqbBEUAAAACVBMVEUAAGcAAABmzDNZt9VtAAAAAXRSTlMAQObYZgAAAHFJREFUKFOt0LENACEIBdBv4Qju4wgWanEj3D6OcIVMKaitYHEU/jwTCQj8W75kiVCSBvdQ5/AvfVHBin11BgdRq3ysBgfwBDRrj3MCIA+oAQaku/Q1cNctrAmyDl577tOThYt/Y1RBM4DgOHzM0HFTAyLukH/cmRnqAAAAAElFTkSuQmCC // ==/UserScript== /* -* 4chan X - Version 1.2.25 - 2013-08-05 +* 4chan X - Version 1.2.25 - 2013-08-06 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -1787,9 +1787,9 @@ top = post.getBoundingClientRect().top; if (Conf['Fixed Header'] && !Conf['Bottom Header']) { headRect = Header.bar.getBoundingClientRect(); - top += -headRect.top - headRect.height; + top -= headRect.top + headRect.height; } - return doc.scrollTop += top; + return window.scrollBy(0, top); }, addShortcut: function(el) { var shortcut; @@ -2351,8 +2351,8 @@ $.add(Header.hover, menu); mRect = menu.getBoundingClientRect(); bRect = button.getBoundingClientRect(); - bTop = doc.scrollTop + d.body.scrollTop + bRect.top; - bLeft = doc.scrollLeft + d.body.scrollLeft + bRect.left; + bTop = window.scrollY + bRect.top; + bLeft = window.scrollX + bRect.left; cHeight = doc.clientHeight; cWidth = doc.clientWidth; _ref1 = bRect.top + bRect.height + mRect.height < cHeight ? [bRect.bottom, null] : [null, cHeight - bRect.top], top = _ref1[0], bottom = _ref1[1]; @@ -6283,7 +6283,7 @@ } }, toggle: function(post) { - var headRect, node, rect, root, thumb, top; + var headRect, rect, root, thumb, x, y; thumb = post.file.thumb; if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) { @@ -6291,35 +6291,31 @@ return; } ImageExpand.contract(post); - node = post.nodes.root; - rect = Conf['Advance on contract'] ? (function() { - while (node.nextElementSibling) { - if (!(node = node.nextElementSibling)) { - return post.nodes.root; - } - if (!$.hasClass(node, 'postContainer')) { + root = post.nodes.root; + rect = (Conf['Advance on contract'] ? (function() { + var next; + + next = root; + while (next = $.x("following::div[contains(@class,'postContainer')][1]", next)) { + if ($('.stub', next) || next.offsetHeight === 0) { continue; } - if (node.offsetHeight > 0 && !$('.stub', node)) { - break; - } + return next; } - return node.getBoundingClientRect(); - })() : post.nodes.root.getBoundingClientRect(); - if (!(rect.top <= 0 || rect.left <= 0)) { - return; - } - top = rect.top; - if (Conf['Fixed Header'] && !Conf['Bottom Header']) { - headRect = Header.bar.getBoundingClientRect(); - top += -headRect.top - headRect.height; - } - root = doc; + return root; + })() : root).getBoundingClientRect(); if (rect.top < 0) { - root.scrollTop += top; + y = rect.top; + if (Conf['Fixed Header'] && !Conf['Bottom Header']) { + headRect = Header.bar.getBoundingClientRect(); + y -= headRect.top + headRect.height; + } } if (rect.left < 0) { - return root.scrollLeft = 0; + x = -window.scrollX; + } + if (x || y) { + return window.scrollBy(x, y); } }, contract: function(post) { @@ -6370,16 +6366,15 @@ } prev = post.nodes.root.getBoundingClientRect(); return $.queueTask(function() { - var curr, root; + var curr; $.addClass(post.nodes.root, 'expanded-image'); $.rmClass(post.file.thumb, 'expanding'); if (!(prev.top + prev.height <= 0)) { return; } - root = doc; curr = post.nodes.root.getBoundingClientRect(); - return root.scrollTop += curr.height - prev.height + curr.top - prev.top; + return window.scrollBy(0, curr.height - prev.height + curr.top - prev.top); }); }, error: function() { @@ -7613,7 +7608,7 @@ } if (scroll) { if (Conf['Bottom Scroll']) { - doc.scrollTop = d.body.clientHeight; + window.scrollTo(0, d.body.clientHeight); } else { if (root) { Header.scrollToPost(root); @@ -8612,34 +8607,34 @@ }); }, node: function() { - var a, span; + var a, files, posts, span, _ref; - if (!(span = $('.summary', this.OP.nodes.root.parentNode))) { + if (!(span = $.x('following-sibling::span[contains(@class,"summary")][1]', this.OP.nodes.root))) { return; } + _ref = span.textContent.match(/\d+/g), posts = _ref[0], files = _ref[1]; a = $.el('a', { - textContent: "+ " + span.textContent, + textContent: ExpandThread.text('+', posts, files), className: 'summary', href: 'javascript:;' }); $.on(a, 'click', ExpandThread.cbToggle); return $.replace(span, a); }, + text: function(status, posts, files) { + return ("" + status + " " + posts + " post" + (posts > 1 ? 's' : '')) + (+files ? " and " + files + " image repl" + (files > 1 ? 'ies' : 'y') : "") + (" " + (status === '-' ? 'shown' : 'omitted') + "."); + }, cbToggle: function() { - var op; - - op = Get.postFromRoot(this.previousElementSibling); - return ExpandThread.toggle(op.thread); + return ExpandThread.toggle(Get.threadFromRoot(this.parentNode)); }, toggle: function(thread) { - var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + var a, files, filesCount, inlined, num, post, posts, postsCount, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3, _ref4; threadRoot = thread.OP.nodes.root.parentNode; a = $('.summary', threadRoot); switch (thread.isExpanded) { case false: case void 0: - thread.isExpanded = 'loading'; _ref = $$('.thread > .postContainer', threadRoot); for (_i = 0, _len = _ref.length; _i < _len; _i++) { post = _ref[_i]; @@ -8650,7 +8645,8 @@ return; } thread.isExpanded = 'loading'; - a.textContent = a.textContent.replace('+', '...'); + _ref1 = a.textContent.match(/\d+/g), posts = _ref1[0], files = _ref1[1]; + a.textContent = ExpandThread.text('...', posts, files); $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() { return ExpandThread.parse(this, thread, a); }); @@ -8660,84 +8656,99 @@ if (!a) { return; } - a.textContent = a.textContent.replace('...', '+'); + _ref2 = a.textContent.match(/\d+/g), posts = _ref2[0], files = _ref2[1]; + a.textContent = ExpandThread.text('+', posts, files); break; case true: thread.isExpanded = false; - if (a) { - a.textContent = a.textContent.replace('-', '+').replace('hide', 'view').replace('expanded', 'omitted'); - num = (function() { - if (thread.isSticky) { - return 1; - } else { - switch (g.BOARD.ID) { - case 'b': - case 'vg': - case 'q': - return 3; - case 't': - return 1; - default: - return 5; - } + num = (function() { + if (thread.isSticky) { + return 1; + } else { + switch (g.BOARD.ID) { + case 'b': + case 'vg': + case 'q': + return 3; + case 't': + return 1; + default: + return 5; } - })(); - replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num); - for (_j = 0, _len1 = replies.length; _j < _len1; _j++) { - reply = replies[_j]; - if (Conf['Quote Inlining']) { - while (inlined = $('.inlined', reply)) { - inlined.click(); - } - } - $.rm(reply); } - } - _ref1 = $$('.thread > .postContainer', threadRoot); - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - post = _ref1[_k]; + })(); + posts = $$(".thread > .replyContainer", threadRoot); + _ref3 = [thread.OP.nodes.root].concat(posts.slice(-num)); + for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { + post = _ref3[_j]; ExpandComment.contract(Get.postFromRoot(post)); } + if (!a) { + return; + } + postsCount = 0; + filesCount = 0; + _ref4 = posts.slice(0, -num); + for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) { + reply = _ref4[_k]; + if (Conf['Quote Inlining']) { + while (inlined = $('.inlined', reply)) { + inlined.click(); + } + } + postsCount++; + if ('file' in Get.postFromRoot(reply)) { + filesCount++; + } + $.rm(reply); + } + a.textContent = ExpandThread.text('+', postsCount, filesCount); } }, parse: function(req, thread, a) { - var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len; + var filesCount, link, post, posts, postsCount, postsObj, postsRoot, reply, root, spoilerRange, _i, _len; if (a.textContent[0] === '+') { return; } - status = req.status; - if (![200, 304].contains(status)) { - a.textContent = "Error " + req.statusText + " (" + status + ")"; - $.off(a, 'click', ExpandThread.cb.toggle); + if (![200, 304].contains(req.status)) { + a.textContent = "Error " + req.statusText + " (" + req.status + ")"; + $.off(a, 'click', ExpandThread.cbToggle); return; } thread.isExpanded = true; - a.textContent = a.textContent.replace('...', '-').replace('view', 'hide').replace('omitted', 'expanded'); posts = JSON.parse(req.response).posts; - if (spoilerRange = posts[0].custom_spoiler) { - Build.spoilerRange[g.BOARD] = spoilerRange; + if (spoilerRange = posts.shift().custom_spoiler) { + Build.spoilerRange[thread.board] = spoilerRange; } - replies = posts.slice(1); - posts = []; - nodes = []; - for (_i = 0, _len = replies.length; _i < _len; _i++) { - reply = replies[_i]; + postsObj = []; + postsRoot = []; + filesCount = 0; + for (_i = 0, _len = posts.length; _i < _len; _i++) { + reply = posts[_i]; if (post = thread.posts[reply.no]) { - nodes.push(post.nodes.root); + if ('file' in post) { + filesCount++; + } + postsRoot.push(post.nodes.root); continue; } - node = Build.postFromObject(reply, thread.board.ID); - post = new Post(node, thread, thread.board); - link = $('a[title="Highlight this post"]', node); + root = Build.postFromObject(reply, thread.board.ID); + post = new Post(root, thread, thread.board); + link = $('a[title="Highlight this post"]', root); link.href = "res/" + thread + "#p" + post; link.nextSibling.href = "res/" + thread + "#q" + post; - posts.push(post); - nodes.push(node); + if ('file' in post) { + filesCount++; + } + postsObj.push(post); + postsRoot.push(root); } - Main.callbackNodes(Post, posts); - $.after(a, nodes); - return Fourchan.parseThread(thread.ID, 1, nodes.length); + Main.callbackNodes(Post, postsObj); + $.after(a, postsRoot); + postsCount = postsRoot.length; + a.textContent = ExpandThread.text('-', postsCount, filesCount); + return Fourchan.parseThread(thread.ID, 1, postsCount); } }; diff --git a/builds/appchan-x.user.js b/builds/appchan-x.user.js index a353d21fb..3a8309f84 100644 --- a/builds/appchan-x.user.js +++ b/builds/appchan-x.user.js @@ -18,7 +18,7 @@ // ==/UserScript== /* -* appchan x - Version 2.2.2 - 2013-08-05 +* appchan x - Version 2.2.2 - 2013-08-06 * * Licensed under the MIT license. * https://github.com/zixaphir/appchan-x/blob/master/LICENSE @@ -4082,9 +4082,9 @@ top = post.getBoundingClientRect().top; if (Conf['Fixed Header'] && !Conf['Bottom Header']) { headRect = Header.bar.getBoundingClientRect(); - top += -headRect.top - headRect.height; + top -= headRect.top + headRect.height; } - return doc.scrollTop += top; + return window.scrollBy(0, top); }, addShortcut: function(el) { var shortcut; @@ -4638,8 +4638,8 @@ $.add(Header.hover, menu); mRect = menu.getBoundingClientRect(); bRect = button.getBoundingClientRect(); - bTop = doc.scrollTop + d.body.scrollTop + bRect.top; - bLeft = doc.scrollLeft + d.body.scrollLeft + bRect.left; + bTop = window.scrollY + bRect.top; + bLeft = window.scrollX + bRect.left; cHeight = doc.clientHeight; cWidth = doc.clientWidth; _ref1 = bRect.top + bRect.height + mRect.height < cHeight ? [bRect.bottom, null] : [null, cHeight - bRect.top], top = _ref1[0], bottom = _ref1[1]; @@ -8612,7 +8612,7 @@ } }, toggle: function(post) { - var headRect, node, rect, root, thumb, top; + var headRect, rect, root, thumb, x, y; thumb = post.file.thumb; if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) { @@ -8620,35 +8620,31 @@ return; } ImageExpand.contract(post); - node = post.nodes.root; - rect = Conf['Advance on contract'] ? (function() { - while (node.nextElementSibling) { - if (!(node = node.nextElementSibling)) { - return post.nodes.root; - } - if (!$.hasClass(node, 'postContainer')) { + root = post.nodes.root; + rect = (Conf['Advance on contract'] ? (function() { + var next; + + next = root; + while (next = $.x("following::div[contains(@class,'postContainer')][1]", next)) { + if ($('.stub', next) || next.offsetHeight === 0) { continue; } - if (node.offsetHeight > 0 && !$('.stub', node)) { - break; - } + return next; } - return node.getBoundingClientRect(); - })() : post.nodes.root.getBoundingClientRect(); - if (!(rect.top <= 0 || rect.left <= 0)) { - return; - } - top = rect.top; - if (Conf['Fixed Header'] && !Conf['Bottom Header']) { - headRect = Header.bar.getBoundingClientRect(); - top += -headRect.top - headRect.height; - } - root = doc; + return root; + })() : root).getBoundingClientRect(); if (rect.top < 0) { - root.scrollTop += top; + y = rect.top; + if (Conf['Fixed Header'] && !Conf['Bottom Header']) { + headRect = Header.bar.getBoundingClientRect(); + y -= headRect.top + headRect.height; + } } if (rect.left < 0) { - return root.scrollLeft = 0; + x = -window.scrollX; + } + if (x || y) { + return window.scrollBy(x, y); } }, contract: function(post) { @@ -8699,16 +8695,15 @@ } prev = post.nodes.root.getBoundingClientRect(); return $.queueTask(function() { - var curr, root; + var curr; $.addClass(post.nodes.root, 'expanded-image'); $.rmClass(post.file.thumb, 'expanding'); if (!(prev.top + prev.height <= 0)) { return; } - root = doc; curr = post.nodes.root.getBoundingClientRect(); - return root.scrollTop += curr.height - prev.height + curr.top - prev.top; + return window.scrollBy(0, curr.height - prev.height + curr.top - prev.top); }); }, error: function() { @@ -9958,7 +9953,7 @@ } if (scroll) { if (Conf['Bottom Scroll']) { - doc.scrollTop = d.body.clientHeight; + window.scrollTo(0, d.body.clientHeight); } else { if (root) { Header.scrollToPost(root); @@ -12452,34 +12447,34 @@ }); }, node: function() { - var a, span; + var a, files, posts, span, _ref; - if (!(span = $('.summary', this.OP.nodes.root.parentNode))) { + if (!(span = $.x('following-sibling::span[contains(@class,"summary")][1]', this.OP.nodes.root))) { return; } + _ref = span.textContent.match(/\d+/g), posts = _ref[0], files = _ref[1]; a = $.el('a', { - textContent: "+ " + span.textContent, + textContent: ExpandThread.text('+', posts, files), className: 'summary', href: 'javascript:;' }); $.on(a, 'click', ExpandThread.cbToggle); return $.replace(span, a); }, + text: function(status, posts, files) { + return ("" + status + " " + posts + " post" + (posts > 1 ? 's' : '')) + (+files ? " and " + files + " image repl" + (files > 1 ? 'ies' : 'y') : "") + (" " + (status === '-' ? 'shown' : 'omitted') + "."); + }, cbToggle: function() { - var op; - - op = Get.postFromRoot(this.previousElementSibling); - return ExpandThread.toggle(op.thread); + return ExpandThread.toggle(Get.threadFromRoot(this.parentNode)); }, toggle: function(thread) { - var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + var a, files, filesCount, inlined, num, post, posts, postsCount, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3, _ref4; threadRoot = thread.OP.nodes.root.parentNode; a = $('.summary', threadRoot); switch (thread.isExpanded) { case false: case void 0: - thread.isExpanded = 'loading'; _ref = $$('.thread > .postContainer', threadRoot); for (_i = 0, _len = _ref.length; _i < _len; _i++) { post = _ref[_i]; @@ -12490,7 +12485,8 @@ return; } thread.isExpanded = 'loading'; - a.textContent = a.textContent.replace('+', '...'); + _ref1 = a.textContent.match(/\d+/g), posts = _ref1[0], files = _ref1[1]; + a.textContent = ExpandThread.text('...', posts, files); $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() { return ExpandThread.parse(this, thread, a); }); @@ -12500,84 +12496,99 @@ if (!a) { return; } - a.textContent = a.textContent.replace('...', '+'); + _ref2 = a.textContent.match(/\d+/g), posts = _ref2[0], files = _ref2[1]; + a.textContent = ExpandThread.text('+', posts, files); break; case true: thread.isExpanded = false; - if (a) { - a.textContent = a.textContent.replace('-', '+').replace('hide', 'view').replace('expanded', 'omitted'); - num = (function() { - if (thread.isSticky) { - return 1; - } else { - switch (g.BOARD.ID) { - case 'b': - case 'vg': - case 'q': - return 3; - case 't': - return 1; - default: - return 5; - } + num = (function() { + if (thread.isSticky) { + return 1; + } else { + switch (g.BOARD.ID) { + case 'b': + case 'vg': + case 'q': + return 3; + case 't': + return 1; + default: + return 5; } - })(); - replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num); - for (_j = 0, _len1 = replies.length; _j < _len1; _j++) { - reply = replies[_j]; - if (Conf['Quote Inlining']) { - while (inlined = $('.inlined', reply)) { - inlined.click(); - } - } - $.rm(reply); } - } - _ref1 = $$('.thread > .postContainer', threadRoot); - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - post = _ref1[_k]; + })(); + posts = $$(".thread > .replyContainer", threadRoot); + _ref3 = [thread.OP.nodes.root].concat(posts.slice(-num)); + for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { + post = _ref3[_j]; ExpandComment.contract(Get.postFromRoot(post)); } + if (!a) { + return; + } + postsCount = 0; + filesCount = 0; + _ref4 = posts.slice(0, -num); + for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) { + reply = _ref4[_k]; + if (Conf['Quote Inlining']) { + while (inlined = $('.inlined', reply)) { + inlined.click(); + } + } + postsCount++; + if ('file' in Get.postFromRoot(reply)) { + filesCount++; + } + $.rm(reply); + } + a.textContent = ExpandThread.text('+', postsCount, filesCount); } }, parse: function(req, thread, a) { - var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len; + var filesCount, link, post, posts, postsCount, postsObj, postsRoot, reply, root, spoilerRange, _i, _len; if (a.textContent[0] === '+') { return; } - status = req.status; - if (![200, 304].contains(status)) { - a.textContent = "Error " + req.statusText + " (" + status + ")"; - $.off(a, 'click', ExpandThread.cb.toggle); + if (![200, 304].contains(req.status)) { + a.textContent = "Error " + req.statusText + " (" + req.status + ")"; + $.off(a, 'click', ExpandThread.cbToggle); return; } thread.isExpanded = true; - a.textContent = a.textContent.replace('...', '-').replace('view', 'hide').replace('omitted', 'expanded'); posts = JSON.parse(req.response).posts; - if (spoilerRange = posts[0].custom_spoiler) { - Build.spoilerRange[g.BOARD] = spoilerRange; + if (spoilerRange = posts.shift().custom_spoiler) { + Build.spoilerRange[thread.board] = spoilerRange; } - replies = posts.slice(1); - posts = []; - nodes = []; - for (_i = 0, _len = replies.length; _i < _len; _i++) { - reply = replies[_i]; + postsObj = []; + postsRoot = []; + filesCount = 0; + for (_i = 0, _len = posts.length; _i < _len; _i++) { + reply = posts[_i]; if (post = thread.posts[reply.no]) { - nodes.push(post.nodes.root); + if ('file' in post) { + filesCount++; + } + postsRoot.push(post.nodes.root); continue; } - node = Build.postFromObject(reply, thread.board.ID); - post = new Post(node, thread, thread.board); - link = $('a[title="Highlight this post"]', node); + root = Build.postFromObject(reply, thread.board.ID); + post = new Post(root, thread, thread.board); + link = $('a[title="Highlight this post"]', root); link.href = "res/" + thread + "#p" + post; link.nextSibling.href = "res/" + thread + "#q" + post; - posts.push(post); - nodes.push(node); + if ('file' in post) { + filesCount++; + } + postsObj.push(post); + postsRoot.push(root); } - Main.callbackNodes(Post, posts); - $.after(a, nodes); - return Fourchan.parseThread(thread.ID, 1, nodes.length); + Main.callbackNodes(Post, postsObj); + $.after(a, postsRoot); + postsCount = postsRoot.length; + a.textContent = ExpandThread.text('-', postsCount, filesCount); + return Fourchan.parseThread(thread.ID, 1, postsCount); } }; diff --git a/builds/crx/script.js b/builds/crx/script.js index 0c36aab39..80ba0c336 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* appchan x - Version 2.2.2 - 2013-08-05 +* appchan x - Version 2.2.2 - 2013-08-06 * * Licensed under the MIT license. * https://github.com/zixaphir/appchan-x/blob/master/LICENSE @@ -4095,9 +4095,9 @@ top = post.getBoundingClientRect().top; if (Conf['Fixed Header'] && !Conf['Bottom Header']) { headRect = Header.bar.getBoundingClientRect(); - top += -headRect.top - headRect.height; + top -= headRect.top + headRect.height; } - return d.body.scrollTop += top; + return window.scrollBy(0, top); }, addShortcut: function(el) { var shortcut; @@ -4651,8 +4651,8 @@ $.add(Header.hover, menu); mRect = menu.getBoundingClientRect(); bRect = button.getBoundingClientRect(); - bTop = doc.scrollTop + d.body.scrollTop + bRect.top; - bLeft = doc.scrollLeft + d.body.scrollLeft + bRect.left; + bTop = window.scrollY + bRect.top; + bLeft = window.scrollX + bRect.left; cHeight = doc.clientHeight; cWidth = doc.clientWidth; _ref1 = bRect.top + bRect.height + mRect.height < cHeight ? [bRect.bottom, null] : [null, cHeight - bRect.top], top = _ref1[0], bottom = _ref1[1]; @@ -8594,7 +8594,7 @@ } }, toggle: function(post) { - var headRect, node, rect, root, thumb, top; + var headRect, rect, root, thumb, x, y; thumb = post.file.thumb; if (!(post.file.isExpanded || $.hasClass(thumb, 'expanding'))) { @@ -8602,35 +8602,31 @@ return; } ImageExpand.contract(post); - node = post.nodes.root; - rect = Conf['Advance on contract'] ? (function() { - while (node.nextElementSibling) { - if (!(node = node.nextElementSibling)) { - return post.nodes.root; - } - if (!$.hasClass(node, 'postContainer')) { + root = post.nodes.root; + rect = (Conf['Advance on contract'] ? (function() { + var next; + + next = root; + while (next = $.x("following::div[contains(@class,'postContainer')][1]", next)) { + if ($('.stub', next) || next.offsetHeight === 0) { continue; } - if (node.offsetHeight > 0 && !$('.stub', node)) { - break; - } + return next; } - return node.getBoundingClientRect(); - })() : post.nodes.root.getBoundingClientRect(); - if (!(rect.top <= 0 || rect.left <= 0)) { - return; - } - top = rect.top; - if (Conf['Fixed Header'] && !Conf['Bottom Header']) { - headRect = Header.bar.getBoundingClientRect(); - top += -headRect.top - headRect.height; - } - root = d.body; + return root; + })() : root).getBoundingClientRect(); if (rect.top < 0) { - root.scrollTop += top; + y = rect.top; + if (Conf['Fixed Header'] && !Conf['Bottom Header']) { + headRect = Header.bar.getBoundingClientRect(); + y -= headRect.top + headRect.height; + } } if (rect.left < 0) { - return root.scrollLeft = 0; + x = -window.scrollX; + } + if (x || y) { + return window.scrollBy(x, y); } }, contract: function(post) { @@ -8681,16 +8677,15 @@ } prev = post.nodes.root.getBoundingClientRect(); return $.queueTask(function() { - var curr, root; + var curr; $.addClass(post.nodes.root, 'expanded-image'); $.rmClass(post.file.thumb, 'expanding'); if (!(prev.top + prev.height <= 0)) { return; } - root = d.body; curr = post.nodes.root.getBoundingClientRect(); - return root.scrollTop += curr.height - prev.height + curr.top - prev.top; + return window.scrollBy(0, curr.height - prev.height + curr.top - prev.top); }); }, error: function() { @@ -9940,7 +9935,7 @@ } if (scroll) { if (Conf['Bottom Scroll']) { - d.body.scrollTop = d.body.clientHeight; + window.scrollTo(0, d.body.clientHeight); } else { if (root) { Header.scrollToPost(root); @@ -12439,34 +12434,34 @@ }); }, node: function() { - var a, span; + var a, files, posts, span, _ref; - if (!(span = $('.summary', this.OP.nodes.root.parentNode))) { + if (!(span = $.x('following-sibling::span[contains(@class,"summary")][1]', this.OP.nodes.root))) { return; } + _ref = span.textContent.match(/\d+/g), posts = _ref[0], files = _ref[1]; a = $.el('a', { - textContent: "+ " + span.textContent, + textContent: ExpandThread.text('+', posts, files), className: 'summary', href: 'javascript:;' }); $.on(a, 'click', ExpandThread.cbToggle); return $.replace(span, a); }, + text: function(status, posts, files) { + return ("" + status + " " + posts + " post" + (posts > 1 ? 's' : '')) + (+files ? " and " + files + " image repl" + (files > 1 ? 'ies' : 'y') : "") + (" " + (status === '-' ? 'shown' : 'omitted') + "."); + }, cbToggle: function() { - var op; - - op = Get.postFromRoot(this.previousElementSibling); - return ExpandThread.toggle(op.thread); + return ExpandThread.toggle(Get.threadFromRoot(this.parentNode)); }, toggle: function(thread) { - var a, inlined, num, post, replies, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + var a, files, filesCount, inlined, num, post, posts, postsCount, reply, threadRoot, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3, _ref4; threadRoot = thread.OP.nodes.root.parentNode; a = $('.summary', threadRoot); switch (thread.isExpanded) { case false: case void 0: - thread.isExpanded = 'loading'; _ref = $$('.thread > .postContainer', threadRoot); for (_i = 0, _len = _ref.length; _i < _len; _i++) { post = _ref[_i]; @@ -12477,7 +12472,8 @@ return; } thread.isExpanded = 'loading'; - a.textContent = a.textContent.replace('+', '...'); + _ref1 = a.textContent.match(/\d+/g), posts = _ref1[0], files = _ref1[1]; + a.textContent = ExpandThread.text('...', posts, files); $.cache("//api.4chan.org/" + thread.board + "/res/" + thread + ".json", function() { return ExpandThread.parse(this, thread, a); }); @@ -12487,84 +12483,99 @@ if (!a) { return; } - a.textContent = a.textContent.replace('...', '+'); + _ref2 = a.textContent.match(/\d+/g), posts = _ref2[0], files = _ref2[1]; + a.textContent = ExpandThread.text('+', posts, files); break; case true: thread.isExpanded = false; - if (a) { - a.textContent = a.textContent.replace('-', '+').replace('hide', 'view').replace('expanded', 'omitted'); - num = (function() { - if (thread.isSticky) { - return 1; - } else { - switch (g.BOARD.ID) { - case 'b': - case 'vg': - case 'q': - return 3; - case 't': - return 1; - default: - return 5; - } + num = (function() { + if (thread.isSticky) { + return 1; + } else { + switch (g.BOARD.ID) { + case 'b': + case 'vg': + case 'q': + return 3; + case 't': + return 1; + default: + return 5; } - })(); - replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num); - for (_j = 0, _len1 = replies.length; _j < _len1; _j++) { - reply = replies[_j]; - if (Conf['Quote Inlining']) { - while (inlined = $('.inlined', reply)) { - inlined.click(); - } - } - $.rm(reply); } - } - _ref1 = $$('.thread > .postContainer', threadRoot); - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - post = _ref1[_k]; + })(); + posts = $$(".thread > .replyContainer", threadRoot); + _ref3 = [thread.OP.nodes.root].concat(posts.slice(-num)); + for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { + post = _ref3[_j]; ExpandComment.contract(Get.postFromRoot(post)); } + if (!a) { + return; + } + postsCount = 0; + filesCount = 0; + _ref4 = posts.slice(0, -num); + for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) { + reply = _ref4[_k]; + if (Conf['Quote Inlining']) { + while (inlined = $('.inlined', reply)) { + inlined.click(); + } + } + postsCount++; + if ('file' in Get.postFromRoot(reply)) { + filesCount++; + } + $.rm(reply); + } + a.textContent = ExpandThread.text('+', postsCount, filesCount); } }, parse: function(req, thread, a) { - var link, node, nodes, post, posts, replies, reply, spoilerRange, status, _i, _len; + var filesCount, link, post, posts, postsCount, postsObj, postsRoot, reply, root, spoilerRange, _i, _len; if (a.textContent[0] === '+') { return; } - status = req.status; - if (![200, 304].contains(status)) { - a.textContent = "Error " + req.statusText + " (" + status + ")"; - $.off(a, 'click', ExpandThread.cb.toggle); + if (![200, 304].contains(req.status)) { + a.textContent = "Error " + req.statusText + " (" + req.status + ")"; + $.off(a, 'click', ExpandThread.cbToggle); return; } thread.isExpanded = true; - a.textContent = a.textContent.replace('...', '-').replace('view', 'hide').replace('omitted', 'expanded'); posts = JSON.parse(req.response).posts; - if (spoilerRange = posts[0].custom_spoiler) { - Build.spoilerRange[g.BOARD] = spoilerRange; + if (spoilerRange = posts.shift().custom_spoiler) { + Build.spoilerRange[thread.board] = spoilerRange; } - replies = posts.slice(1); - posts = []; - nodes = []; - for (_i = 0, _len = replies.length; _i < _len; _i++) { - reply = replies[_i]; + postsObj = []; + postsRoot = []; + filesCount = 0; + for (_i = 0, _len = posts.length; _i < _len; _i++) { + reply = posts[_i]; if (post = thread.posts[reply.no]) { - nodes.push(post.nodes.root); + if ('file' in post) { + filesCount++; + } + postsRoot.push(post.nodes.root); continue; } - node = Build.postFromObject(reply, thread.board.ID); - post = new Post(node, thread, thread.board); - link = $('a[title="Highlight this post"]', node); + root = Build.postFromObject(reply, thread.board.ID); + post = new Post(root, thread, thread.board); + link = $('a[title="Highlight this post"]', root); link.href = "res/" + thread + "#p" + post; link.nextSibling.href = "res/" + thread + "#q" + post; - posts.push(post); - nodes.push(node); + if ('file' in post) { + filesCount++; + } + postsObj.push(post); + postsRoot.push(root); } - Main.callbackNodes(Post, posts); - $.after(a, nodes); - return Fourchan.parseThread(thread.ID, 1, nodes.length); + Main.callbackNodes(Post, postsObj); + $.after(a, postsRoot); + postsCount = postsRoot.length; + a.textContent = ExpandThread.text('-', postsCount, filesCount); + return Fourchan.parseThread(thread.ID, 1, postsCount); } }; diff --git a/src/General/Header.coffee b/src/General/Header.coffee index 33b3b1da7..b715ebe5f 100644 --- a/src/General/Header.coffee +++ b/src/General/Header.coffee @@ -246,8 +246,8 @@ Header = {top} = post.getBoundingClientRect() if Conf['Fixed Header'] and not Conf['Bottom Header'] headRect = Header.bar.getBoundingClientRect() - top += - headRect.top - headRect.height - <% if (type === 'crx') { %>d.body<% } else { %>doc<% } %>.scrollTop += top + top -= headRect.top + headRect.height + window.scrollBy 0, top addShortcut: (el) -> shortcut = $.el 'span', diff --git a/src/General/UI.coffee b/src/General/UI.coffee index 91beaa2c4..9b99440ac 100644 --- a/src/General/UI.coffee +++ b/src/General/UI.coffee @@ -67,8 +67,8 @@ UI = do -> # Position mRect = menu.getBoundingClientRect() bRect = button.getBoundingClientRect() - bTop = doc.scrollTop + d.body.scrollTop + bRect.top - bLeft = doc.scrollLeft + d.body.scrollLeft + bRect.left + bTop = window.scrollY + bRect.top + bLeft = window.scrollX + bRect.left cHeight = doc.clientHeight cWidth = doc.clientWidth [top, bottom] = if bRect.top + bRect.height + mRect.height < cHeight diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index 64bec990f..a442ab73b 100644 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -63,27 +63,28 @@ ImageExpand = ImageExpand.expand post return ImageExpand.contract post - node = post.nodes.root - rect = if Conf['Advance on contract'] then do -> - # FIXME does not work with Quote Threading - while node.nextElementSibling - return post.nodes.root unless node = node.nextElementSibling - continue unless $.hasClass node, 'postContainer' - break if node.offsetHeight > 0 and not $ '.stub', node - node.getBoundingClientRect() - else - post.nodes.root.getBoundingClientRect() - return unless rect.top <= 0 or rect.left <= 0 + # Scroll back to the thumbnail when contracting the image + # to avoid being left miles away from the relevant post. + {root} = post.nodes + rect = (if Conf['Advance on contract'] then do -> + next = root + while next = $.x "following::div[contains(@class,'postContainer')][1]", next + continue if $('.stub', next) or next.offsetHeight is 0 + return next + root + else + root + ).getBoundingClientRect() - {top} = rect - if Conf['Fixed Header'] and not Conf['Bottom Header'] - headRect = Header.bar.getBoundingClientRect() - top += - headRect.top - headRect.height + if rect.top < 0 + y = rect.top + if Conf['Fixed Header'] and not Conf['Bottom Header'] + headRect = Header.bar.getBoundingClientRect() + y -= headRect.top + headRect.height - root = <% if (type === 'crx') { %>d.body<% } else { %>doc<% } %> - - root.scrollTop += top if rect.top < 0 - root.scrollLeft = 0 if rect.left < 0 + if rect.left < 0 + x = -window.scrollX + window.scrollBy x, y if x or y contract: (post) -> $.rmClass post.nodes.root, 'expanded-image' @@ -123,9 +124,8 @@ ImageExpand = $.addClass post.nodes.root, 'expanded-image' $.rmClass post.file.thumb, 'expanding' return unless prev.top + prev.height <= 0 - root = <% if (type === 'crx') { %>d.body<% } else { %>doc<% } %> curr = post.nodes.root.getBoundingClientRect() - root.scrollTop += curr.height - prev.height + curr.top - prev.top + window.scrollBy 0, curr.height - prev.height + curr.top - prev.top error: -> post = Get.postFromNode @ diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index 764d201ab..3f3a7c19a 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -5,18 +5,24 @@ ExpandThread = Thread::callbacks.push name: 'Thread Expansion' cb: @node + node: -> - return unless span = $ '.summary', @OP.nodes.root.parentNode + return unless span = $.x 'following-sibling::span[contains(@class,"summary")][1]', @OP.nodes.root + [posts, files] = span.textContent.match /\d+/g a = $.el 'a', - textContent: "+ #{span.textContent}" + textContent: ExpandThread.text '+', posts, files className: 'summary' href: 'javascript:;' $.on a, 'click', ExpandThread.cbToggle $.replace span, a + text: (status, posts, files) -> + "#{status} #{posts} post#{if posts > 1 then 's' else ''}" + + (if +files then " and #{files} image repl#{if files > 1 then 'ies' else 'y'}" else "") + + " #{if status is '-' then 'shown' else 'omitted'}." + cbToggle: -> - op = Get.postFromRoot @previousElementSibling - ExpandThread.toggle op.thread + ExpandThread.toggle Get.threadFromRoot @parentNode toggle: (thread) -> threadRoot = thread.OP.nodes.root.parentNode @@ -24,74 +30,82 @@ ExpandThread = switch thread.isExpanded when false, undefined - thread.isExpanded = 'loading' for post in $$ '.thread > .postContainer', threadRoot ExpandComment.expand Get.postFromRoot post unless a thread.isExpanded = true return thread.isExpanded = 'loading' - a.textContent = a.textContent.replace '+', '...' + [posts, files] = a.textContent.match /\d+/g + a.textContent = ExpandThread.text '...', posts, files $.cache "//api.4chan.org/#{thread.board}/res/#{thread}.json", -> ExpandThread.parse @, thread, a when 'loading' thread.isExpanded = false return unless a - a.textContent = a.textContent.replace '...', '+' + [posts, files] = a.textContent.match /\d+/g + a.textContent = ExpandThread.text '+', posts, files when true thread.isExpanded = false - if a - a.textContent = a.textContent.replace('-', '+').replace('hide', 'view').replace('expanded', 'omitted') - #goddamit moot - num = if thread.isSticky - 1 - else switch g.BOARD.ID - # XXX boards config - when 'b', 'vg', 'q' then 3 - when 't' then 1 - else 5 - replies = $$('.thread > .replyContainer', threadRoot)[...-num] - for reply in replies - if Conf['Quote Inlining'] - # rm clones - inlined.click() while inlined = $ '.inlined', reply - $.rm reply - for post in $$ '.thread > .postContainer', threadRoot + #goddamit moot + num = if thread.isSticky + 1 + else switch g.BOARD.ID + # XXX boards config + when 'b', 'vg', 'q' then 3 + when 't' then 1 + else 5 + posts = $$ ".thread > .replyContainer", threadRoot + for post in [thread.OP.nodes.root].concat posts[-num..] ExpandComment.contract Get.postFromRoot post + return unless a + postsCount = 0 + filesCount = 0 + for reply in posts[...-num] + if Conf['Quote Inlining'] + # rm clones + inlined.click() while inlined = $ '.inlined', reply + postsCount++ + filesCount++ if 'file' of Get.postFromRoot reply + $.rm reply + a.textContent = ExpandThread.text '+', postsCount, filesCount return parse: (req, thread, a) -> return if a.textContent[0] is '+' - {status} = req - unless [200, 304].contains status - a.textContent = "Error #{req.statusText} (#{status})" - $.off a, 'click', ExpandThread.cb.toggle + unless [200, 304].contains req.status + a.textContent = "Error #{req.statusText} (#{req.status})" + $.off a, 'click', ExpandThread.cbToggle return thread.isExpanded = true - a.textContent = a.textContent.replace('...', '-').replace('view', 'hide').replace('omitted', 'expanded') - posts = JSON.parse(req.response).posts - if spoilerRange = posts[0].custom_spoiler - Build.spoilerRange[g.BOARD] = spoilerRange + {posts} = JSON.parse req.response + if spoilerRange = posts.shift().custom_spoiler + Build.spoilerRange[thread.board] = spoilerRange - replies = posts[1..] - posts = [] - nodes = [] - for reply in replies + postsObj = [] + postsRoot = [] + filesCount = 0 + for reply in posts if post = thread.posts[reply.no] - nodes.push post.nodes.root + filesCount++ if 'file' of post + postsRoot.push post.nodes.root continue - node = Build.postFromObject reply, thread.board.ID - post = new Post node, thread, thread.board - link = $ 'a[title="Highlight this post"]', node + root = Build.postFromObject reply, thread.board.ID + post = new Post root, thread, thread.board + link = $ 'a[title="Highlight this post"]', root link.href = "res/#{thread}#p#{post}" link.nextSibling.href = "res/#{thread}#q#{post}" - posts.push post - nodes.push node - Main.callbackNodes Post, posts - $.after a, nodes + filesCount++ if 'file' of post + postsObj.push post + postsRoot.push root + Main.callbackNodes Post, postsObj + $.after a, postsRoot - Fourchan.parseThread thread.ID, 1, nodes.length + postsCount = postsRoot.length + a.textContent = ExpandThread.text '-', postsCount, filesCount + + Fourchan.parseThread thread.ID, 1, postsCount diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index 3444cb377..115bea3f1 100644 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -294,7 +294,6 @@ ThreadUpdater = unless count ThreadUpdater.set 'status', null, null ThreadUpdater.outdateCount++ - else ThreadUpdater.set 'status', "+#{count}", 'new' ThreadUpdater.outdateCount = 0 @@ -320,7 +319,7 @@ ThreadUpdater = if scroll if Conf['Bottom Scroll'] - <% if (type === 'crx') { %>d.body<% } else { %>doc<% } %>.scrollTop = d.body.clientHeight + window.scrollTo 0, d.body.clientHeight else Header.scrollToPost root if root