Add Thread Expansion.

This commit is contained in:
Nicolas Stepien 2013-02-17 00:13:55 +01:00
parent b8db488591
commit 5e03439960
3 changed files with 194 additions and 2 deletions

View File

@ -20,7 +20,7 @@
// @icon data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAIALAAAAAAQABAAAAIxlI+pq+D9DAgUoFkPDlbs7lGiI2bSVnKglnJMOL6omczxVZK3dH/41AG6Lh7i6qUoAAA7 // @icon data:image/gif;base64,R0lGODlhEAAQAKECAAAAAGbMM////////yH5BAEKAAIALAAAAAAQABAAAAIxlI+pq+D9DAgUoFkPDlbs7lGiI2bSVnKglnJMOL6omczxVZK3dH/41AG6Lh7i6qUoAAA7
// ==/UserScript== // ==/UserScript==
/* 4chan X Alpha - Version 3.0.0 - 2013-02-16 /* 4chan X Alpha - Version 3.0.0 - 2013-02-17
* http://mayhemydg.github.com/4chan-x/ * http://mayhemydg.github.com/4chan-x/
* *
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com> * Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
@ -43,7 +43,7 @@
*/ */
(function() { (function() {
var $, $$, Anonymize, ArchiveLink, AutoGIF, Board, Build, Clone, Conf, Config, DeleteLink, DownloadLink, ExpandComment, Favicon, FileInfo, Filter, Get, Header, ImageExpand, ImageHover, Main, Menu, Notification, Polyfill, Post, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Recursive, Redirect, RelativeDates, ReplyHiding, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, Time, UI, Unread, d, doc, g, var $, $$, Anonymize, ArchiveLink, AutoGIF, Board, Build, Clone, Conf, Config, DeleteLink, DownloadLink, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, Get, Header, ImageExpand, ImageHover, Main, Menu, Notification, Polyfill, Post, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Recursive, Redirect, RelativeDates, ReplyHiding, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, Time, UI, Unread, d, doc, g,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__hasProp = {}.hasOwnProperty, __hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }; __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; };
@ -3971,6 +3971,114 @@
} }
}; };
ExpandThread = {
init: function() {
if (g.VIEW !== 'index' || !Conf['Thread Expansion']) {
return;
}
return Thread.prototype.callbacks.push({
name: 'Thread Expansion',
cb: this.node
});
},
node: function() {
var a, op, span;
op = this.posts[this];
if (!(span = $('.summary', op.nodes.root.parentNode))) {
return;
}
a = $.el('a', {
textContent: "+ " + span.textContent,
className: 'summary',
href: 'javascript:;'
});
$.on(a, 'click', ExpandThread.cbToggle);
return $.replace(span, a);
},
cbToggle: function() {
var op;
op = Get.postFromRoot(this.previousElementSibling);
return ExpandThread.toggle(op.thread);
},
toggle: function(thread) {
var a, inlined, num, replies, reply, text, threadRoot, url, _i, _len;
threadRoot = thread.posts[thread].nodes.root.parentNode;
url = "//api.4chan.org/" + thread.board + "/res/" + thread + ".json";
a = $('.summary', threadRoot);
text = a.textContent;
switch (text[0]) {
case '+':
a.textContent = text.replace('+', '× Loading...');
$.cache(url, function() {
return ExpandThread.parse(this, thread, a);
});
break;
case '×':
a.textContent = text.replace('× Loading...', '+');
break;
case '-':
a.textContent = text.replace('-', '+');
num = (function() {
switch (g.BOARD) {
case 'b':
case 'vg':
case 'q':
return 3;
case 't':
return 1;
default:
return 5;
}
})();
replies = $$('.thread > .replyContainer', threadRoot).slice(0, -num);
for (_i = 0, _len = replies.length; _i < _len; _i++) {
reply = replies[_i];
if (Conf['Quote Inline']) {
while (inlined = $('.inlined', reply)) {
inlined.click();
}
}
$.rm(reply);
}
}
},
parse: function(req, thread, a) {
var link, node, nodes, post, posts, replies, reply, spoilerRange, _i, _len;
if (a.textContent[0] === '+') {
return;
}
if (req.status !== 200) {
a.textContent = "Error " + req.statusText + " (" + req.status + ")";
$.off(a, 'click', ExpandThread.cb.toggle);
return;
}
a.textContent = a.textContent.replace('× Loading...', '-');
posts = JSON.parse(req.response).posts;
if (spoilerRange = posts[0].custom_spoiler) {
Build.spoilerRange[g.BOARD] = spoilerRange;
}
replies = posts.slice(1);
posts = [];
nodes = [];
for (_i = 0, _len = replies.length; _i < _len; _i++) {
reply = replies[_i];
if (post = thread.posts[reply.no]) {
nodes.push(post.nodes.root);
continue;
}
node = Build.postFromObject(reply, thread.board);
post = new Post(node, thread, thread.board);
link = $('a[title="Highlight this post"]', node);
link.href = "res/" + thread + "#p" + post;
link.nextSibling.href = "res/" + thread + "#q" + post;
posts.push(post);
nodes.push(node);
}
Main.callbackNodes(Post, posts);
return $.after(a, nodes);
}
};
ThreadExcerpt = { ThreadExcerpt = {
init: function() { init: function() {
if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) { if (g.VIEW !== 'thread' || !Conf['Thread Excerpt']) {
@ -5827,6 +5935,7 @@
initFeature('Auto-GIF', AutoGIF); initFeature('Auto-GIF', AutoGIF);
initFeature('Image Hover', ImageHover); initFeature('Image Hover', ImageHover);
initFeature('Comment Expansion', ExpandComment); initFeature('Comment Expansion', ExpandComment);
initFeature('Thread Expansion', ExpandThread);
initFeature('Thread Excerpt', ThreadExcerpt); initFeature('Thread Excerpt', ThreadExcerpt);
initFeature('Favicon', Favicon); initFeature('Favicon', Favicon);
initFeature('Unread', Unread); initFeature('Unread', Unread);

View File

@ -2478,6 +2478,88 @@ ExpandComment =
$.rm comment $.rm comment
$.after prev, comment $.after prev, comment
ExpandThread =
init: ->
return if g.VIEW isnt 'index' or !Conf['Thread Expansion']
Thread::callbacks.push
name: 'Thread Expansion'
cb: @node
node: ->
op = @posts[@]
return unless span = $ '.summary', op.nodes.root.parentNode
a = $.el 'a',
textContent: "+ #{span.textContent}"
className: 'summary'
href: 'javascript:;'
$.on a, 'click', ExpandThread.cbToggle
$.replace span, a
cbToggle: ->
op = Get.postFromRoot @previousElementSibling
ExpandThread.toggle op.thread
toggle: (thread) ->
threadRoot = thread.posts[thread].nodes.root.parentNode
url = "//api.4chan.org/#{thread.board}/res/#{thread}.json"
a = $ '.summary', threadRoot
text = a.textContent
switch text[0]
when '+'
a.textContent = text.replace '+', '× Loading...'
$.cache url, -> ExpandThread.parse @, thread, a
when '×'
a.textContent = text.replace '× Loading...', '+'
when '-'
a.textContent = text.replace '-', '+'
#goddamit moot
num = switch g.BOARD
# 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 Inline']
# rm clones
inlined.click() while inlined = $ '.inlined', reply
$.rm reply
return
parse: (req, thread, a) ->
return if a.textContent[0] is '+'
if req.status isnt 200
a.textContent = "Error #{req.statusText} (#{req.status})"
$.off a, 'click', ExpandThread.cb.toggle
return
a.textContent = a.textContent.replace '× Loading...', '-'
posts = JSON.parse(req.response).posts
if spoilerRange = posts[0].custom_spoiler
Build.spoilerRange[g.BOARD] = spoilerRange
replies = posts[1..]
posts = []
nodes = []
for reply in replies
if post = thread.posts[reply.no]
nodes.push post.nodes.root
continue
node = Build.postFromObject reply, thread.board
post = new Post node, thread, thread.board
link = $ 'a[title="Highlight this post"]', node
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
ThreadExcerpt = ThreadExcerpt =
init: -> init: ->
return if g.VIEW isnt 'thread' or !Conf['Thread Excerpt'] return if g.VIEW isnt 'thread' or !Conf['Thread Excerpt']

View File

@ -337,6 +337,7 @@ Main =
initFeature 'Auto-GIF', AutoGIF initFeature 'Auto-GIF', AutoGIF
initFeature 'Image Hover', ImageHover initFeature 'Image Hover', ImageHover
initFeature 'Comment Expansion', ExpandComment initFeature 'Comment Expansion', ExpandComment
initFeature 'Thread Expansion', ExpandThread
initFeature 'Thread Excerpt', ThreadExcerpt initFeature 'Thread Excerpt', ThreadExcerpt
initFeature 'Favicon', Favicon initFeature 'Favicon', Favicon
initFeature 'Unread', Unread initFeature 'Unread', Unread