Merge branch 'v3'

Conflicts:
	LICENSE
	builds/appchan-x.user.js
	builds/crx/script.js
This commit is contained in:
Zixaphir 2014-03-11 14:56:57 -07:00
commit 3dd84a69ac
7 changed files with 361 additions and 210 deletions

View File

@ -3274,6 +3274,7 @@
this.thread.OP = this; this.thread.OP = this;
this.thread.isSticky = !!$('.stickyIcon', info); this.thread.isSticky = !!$('.stickyIcon', info);
this.thread.isClosed = !!$('.closedIcon', info); this.thread.isClosed = !!$('.closedIcon', info);
root.parentElement.dataset.fullID = this.fullID;
} }
this.info = {}; this.info = {};
if (subject = $('.subject', info)) { if (subject = $('.subject', info)) {
@ -4951,10 +4952,14 @@
return $.event('change', null, Index.selectMode); return $.event('change', null, Index.selectMode);
}, },
cycleSortType: function() { cycleSortType: function() {
var i, type, types, _i, _len; var i, option, type, types, _i, _len;
types = __slice.call(Index.selectSort.options).filter(function(option) { types = [];
return !option.disabled; i = 0;
}); while (option = Index.selectSort.options[i++]) {
if (!option.disabled) {
types.push(option);
}
}
for (i = _i = 0, _len = types.length; _i < _len; i = ++_i) { for (i = _i = 0, _len = types.length; _i < _len; i = ++_i) {
type = types[i]; type = types[i];
if (type.selected) { if (type.selected) {
@ -4965,13 +4970,15 @@
return $.event('change', null, Index.selectSort); return $.event('change', null, Index.selectSort);
}, },
catalogSwitch: function() { catalogSwitch: function() {
var hash; return $.get('JSON Navigation', true, function(items) {
if (!Conf['JSON Navigation']) { var hash;
return; if (!items['JSON Navigation']) {
} return;
$.set('Index Mode', 'catalog'); }
hash = window.location.hash; $.set('Index Mode', 'catalog');
return window.location = './' + hash; hash = window.location.hash;
return window.location = './' + hash;
});
}, },
searchTest: function() { searchTest: function() {
var hash, match; var hash, match;
@ -5061,20 +5068,18 @@
return Index.buildIndex(); return Index.buildIndex();
}, },
target: function() { target: function() {
var thread, threadID, thumb, _ref; return g.BOARD.threads.forEach(function(thread) {
_ref = g.BOARD.threads; var thumb;
for (threadID in _ref) {
thread = _ref[threadID];
if (!thread.catalogView) { if (!thread.catalogView) {
continue; return;
} }
thumb = thread.catalogView.nodes.thumb; thumb = thread.catalogView.nodes.thumb;
if (Conf['Open threads in a new tab']) { if (Conf['Open threads in a new tab']) {
thumb.target = '_blank'; return thumb.target = '_blank';
} else { } else {
thumb.removeAttribute('target'); return thumb.removeAttribute('target');
} }
} });
}, },
replies: function() { replies: function() {
Index.buildThreads(); Index.buildThreads();
@ -5429,12 +5434,11 @@
return $.event('IndexRefresh'); return $.event('IndexRefresh');
}, },
buildHRs: function(threadRoots) { buildHRs: function(threadRoots) {
var node, nodes, _i, _len; var i, node, nodes;
nodes = []; nodes = [];
for (_i = 0, _len = threadRoots.length; _i < _len; _i++) { i = 0;
node = threadRoots[_i]; while (node = threadRoots[i++]) {
nodes.push(node); nodes.push(node, $.el('hr'));
nodes.push($.el('hr'));
} }
return nodes; return nodes;
}, },
@ -5479,7 +5483,7 @@
return Main.callbackNodes(Post, posts); return Main.callbackNodes(Post, posts);
}, },
buildCatalogViews: function() { buildCatalogViews: function() {
var catalogThreads, thread, _i, _len, _ref; var catalogThreads, i, nodes, thread, _i, _len, _ref;
catalogThreads = []; catalogThreads = [];
_ref = Index.sortedThreads; _ref = Index.sortedThreads;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@ -5489,9 +5493,12 @@
} }
} }
Main.callbackNodes(CatalogThread, catalogThreads); Main.callbackNodes(CatalogThread, catalogThreads);
return Index.sortedThreads.map(function(thread) { nodes = [];
return thread.catalogView.nodes.root; i = 0;
}); while (thread = Index.sortedThreads[i++]) {
nodes.push(thread.catalogView.nodes.root);
}
return nodes;
}, },
sizeCatalogViews: function(nodes) { sizeCatalogViews: function(nodes) {
var height, node, ratio, size, thumb, width, _i, _len, _ref; var height, node, ratio, size, thumb, width, _i, _len, _ref;
@ -5509,13 +5516,16 @@
} }
}, },
sort: function() { sort: function() {
var sortedThreadIDs; var i, sortedThreadIDs, sortedThreads, thread, threadID;
switch (Conf['Index Sort']) { sortedThreads = [];
case 'bump': sortedThreadIDs = [];
sortedThreadIDs = Index.liveThreadIDs; ({
break; 'bump': function() {
case 'lastreply': return sortedThreadIDs = Index.liveThreadIDs;
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { },
'lastreply': function() {
var data, i, liveData;
liveData = __slice.call(Index.liveThreadData).sort(function(a, b) {
var _ref, _ref1; var _ref, _ref1;
if ('last_replies' in a) { if ('last_replies' in a) {
_ref = a.last_replies, a = _ref[_ref.length - 1]; _ref = a.last_replies, a = _ref[_ref.length - 1];
@ -5524,34 +5534,49 @@
_ref1 = b.last_replies, b = _ref1[_ref1.length - 1]; _ref1 = b.last_replies, b = _ref1[_ref1.length - 1];
} }
return b.no - a.no; return b.no - a.no;
}).map(function(data) {
return data.no;
}); });
break; i = 0;
case 'birth': while (data = liveData[i++]) {
sortedThreadIDs = __slice.call(Index.liveThreadIDs).sort(function(a, b) { sortedThreadIDs.push(data.no);
}
},
'birth': function() {
return sortedThreadIDs = __slice.call(Index.liveThreadIDs).sort(function(a, b) {
return b - a; return b - a;
}); });
break; },
case 'replycount': 'replycount': function() {
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { var data, i, liveData;
liveData = __slice.call(Index.liveThreadData).sort(function(a, b) {
return b.replies - a.replies; return b.replies - a.replies;
}).map(function(data) {
return data.no;
}); });
break; i = 0;
case 'filecount': while (data = liveData[i++]) {
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { sortedThreadIDs.push(data.no);
}
},
'filecount': function() {
var data, i, liveData;
liveData = __slice.call(Index.liveThreadData).sort(function(a, b) {
return b.images - a.images; return b.images - a.images;
}).map(function(data) {
return data.no;
}); });
i = 0;
while (data = liveData[i++]) {
sortedThreadIDs.push(data.no);
}
}
})[Conf['Index Sort']]();
i = 0;
while (threadID = sortedThreadIDs[i++]) {
sortedThreads.push(g.BOARD.threads[threadID]);
}
Index.sortedThreads = [];
i = 0;
while (thread = sortedThreads[i++]) {
if (thread.isHidden === Index.showHiddenThreads) {
Index.sortedThreads.push(thread);
}
} }
Index.sortedThreads = sortedThreadIDs.map(function(threadID) {
return g.BOARD.threads[threadID];
}).filter(function(thread) {
return thread.isHidden === Index.showHiddenThreads;
});
if (Index.isSearching) { if (Index.isSearching) {
Index.sortedThreads = Index.querySearch(Index.searchInput.value) || Index.sortedThreads; Index.sortedThreads = Index.querySearch(Index.searchInput.value) || Index.sortedThreads;
} }
@ -5574,7 +5599,7 @@
} }
}, },
buildIndex: function(infinite) { buildIndex: function(infinite) {
var nodes, pageNum, threads, threadsPerPage; var nodes, pageNum, thread, threads, threadsPerPage, _i, _j, _len, _len1, _ref;
switch (Conf['Index Mode']) { switch (Conf['Index Mode']) {
case 'paged': case 'paged':
case 'infinite': case 'infinite':
@ -5585,9 +5610,11 @@
} }
threadsPerPage = Index.getThreadsNumPerPage(); threadsPerPage = Index.getThreadsNumPerPage();
threads = Index.sortedThreads.slice(threadsPerPage * pageNum, threadsPerPage * (pageNum + 1)); threads = Index.sortedThreads.slice(threadsPerPage * pageNum, threadsPerPage * (pageNum + 1));
nodes = threads.map(function(thread) { nodes = [];
return thread.OP.nodes.root.parentNode; for (_i = 0, _len = threads.length; _i < _len; _i++) {
}); thread = threads[_i];
nodes.push(thread.OP.nodes.root.parentNode);
}
Index.buildReplies(threads); Index.buildReplies(threads);
nodes = Index.buildHRs(nodes); nodes = Index.buildHRs(nodes);
Index.buildPagelist(); Index.buildPagelist();
@ -5598,9 +5625,12 @@
Index.sizeCatalogViews(nodes); Index.sizeCatalogViews(nodes);
break; break;
default: default:
nodes = Index.sortedThreads.map(function(thread) { nodes = [];
return thread.OP.nodes.root.parentNode; _ref = Index.sortedThreads;
}); for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
thread = _ref[_j];
nodes.push(thread.OP.nodes.root.parentNode);
}
Index.buildReplies(Index.sortedThreads); Index.buildReplies(Index.sortedThreads);
nodes = Index.buildHRs(nodes); nodes = Index.buildHRs(nodes);
} }
@ -5650,9 +5680,16 @@
return Index.search(keywords); return Index.search(keywords);
}, },
search: function(keywords) { search: function(keywords) {
return Index.sortedThreads.filter(function(thread) { var filtered, i, sortedThreads, thread;
return Index.searchMatch(thread, keywords); filtered = [];
}); i = 0;
sortedThreads = Index.sortedThreads;
while (thread = sortedThreads[i++]) {
if (Index.searchMatch(thread, keywords)) {
filtered.push(thread);
}
}
return Index.sortedThreads = filtered;
}, },
searchMatch: function(thread, keywords) { searchMatch: function(thread, keywords) {
var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1; var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1;
@ -5964,7 +6001,7 @@
return "/" + thread.board + "/ - " + excerpt; return "/" + thread.board + "/ - " + excerpt;
}, },
threadFromRoot: function(root) { threadFromRoot: function(root) {
return g.threads["" + g.BOARD + "." + root.id.slice(1)]; return g.threads[root.dataset.fullID];
}, },
threadFromNode: function(node) { threadFromNode: function(node) {
return Get.threadFromRoot($.x('ancestor::div[@class="thread"]', node)); return Get.threadFromRoot($.x('ancestor::div[@class="thread"]', node));
@ -5982,9 +6019,7 @@
return Get.postFromRoot($.x('ancestor::div[contains(@class,"postContainer")][1]', node)); return Get.postFromRoot($.x('ancestor::div[contains(@class,"postContainer")][1]', node));
}, },
contextFromNode: function(node) { contextFromNode: function(node) {
var snapshot; return Get.postFromRoot($.x('ancestor::div[@class="thread"]', node).firstElementChild);
snapshot = $.X('ancestor::div[contains(@class,"postContainer")]', node);
return Get.postFromRoot(snapshot.snapshotItem(snapshot.length - 1));
}, },
postDataFromLink: function(link) { postDataFromLink: function(link) {
var boardID, path, postID, threadID, _ref; var boardID, path, postID, threadID, _ref;
@ -7366,7 +7401,7 @@
return $.add(this.nodes.info, container); return $.add(this.nodes.info, container);
}, },
buildBacklink: function(quoted, quoter) { buildBacklink: function(quoted, quoter) {
var a, frag, text; var a, frag, hash, text;
frag = QuoteBacklink.frag.cloneNode(true); frag = QuoteBacklink.frag.cloneNode(true);
a = frag.lastElementChild; a = frag.lastElementChild;
a.href = "/" + quoter.board + "/res/" + quoter.thread + "#p" + quoter; a.href = "/" + quoter.board + "/res/" + quoter.thread + "#p" + quoter;
@ -7384,7 +7419,14 @@
if (Conf['Quote Inlining']) { if (Conf['Quote Inlining']) {
$.on(a, 'click', QuoteInline.toggle); $.on(a, 'click', QuoteInline.toggle);
if (Conf['Quote Hash Navigation']) { if (Conf['Quote Hash Navigation']) {
QuoteInline.qiQuote(a, quoter.isHidden); hash = QuoteInline.qiQuote(a, quoter.isHidden);
}
}
if (Conf['JSON Navigation']) {
if (hash) {
Navigate.singleQuoteLink(hash);
} else if (!Conf['Quote Inlining']) {
Navigate.singleQuoteLink(a);
} }
} }
return frag; return frag;
@ -16223,22 +16265,28 @@
return $.on(replyLink, 'click', Navigate.navigate); return $.on(replyLink, 'click', Navigate.navigate);
}, },
post: function() { post: function() {
var boardID, hashlink, postID, postlink, threadID, _i, _len, _ref, _ref1; var linktype;
if (Conf['Quote Hash Navigation']) { if (!(g.VIEW === 'thread' && this.thread.ID === g.THREADID)) {
_ref = $$('.hashlink', this.nodes.comment); $.on($('a[title="Highlight this post"]', this.nodes.info), 'click', Navigate.navigate);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
hashlink = _ref[_i];
_ref1 = Get.postDataFromLink(hashlink), boardID = _ref1.boardID, threadID = _ref1.threadID, postID = _ref1.postID;
if (boardID !== g.BOARD.ID || (threadID !== g.THREADID)) {
$.on(hashlink, 'click', Navigate.navigate);
}
}
} }
if (g.VIEW === 'thread' && this.thread.ID === g.THREADID) { if (!(linktype = Conf['Quote Inlining'] && Conf['Quote Hash Navigation'] ? '.hashlink' : !Conf['Quote Inlining'] ? '.quotelink' : null)) {
return; return;
} }
postlink = $('a[title="Highlight this post"]', this.nodes.info); return Navigate.quoteLink($$(linktype, this.nodes.comment));
return $.on(postlink, 'click', Navigate.navigate); },
quoteLink: function(links) {
var link, _i, _len;
for (_i = 0, _len = links.length; _i < _len; _i++) {
link = links[_i];
Navigate.singleQuoteLink(link);
}
},
singleQuoteLink: function(link) {
var boardID, threadID, _ref;
_ref = Get.postDataFromLink(link), boardID = _ref.boardID, threadID = _ref.threadID;
if (g.VIEW === 'index' || boardID !== g.BOARD.ID || threadID !== g.THREADID) {
return $.on(link, 'click', Navigate.navigate);
}
}, },
clean: function() { clean: function() {
g.threads.forEach(function(thread) { g.threads.forEach(function(thread) {

View File

@ -3327,6 +3327,7 @@
this.thread.OP = this; this.thread.OP = this;
this.thread.isSticky = !!$('.stickyIcon', info); this.thread.isSticky = !!$('.stickyIcon', info);
this.thread.isClosed = !!$('.closedIcon', info); this.thread.isClosed = !!$('.closedIcon', info);
root.parentElement.dataset.fullID = this.fullID;
} }
this.info = {}; this.info = {};
if (subject = $('.subject', info)) { if (subject = $('.subject', info)) {
@ -5009,10 +5010,14 @@
return $.event('change', null, Index.selectMode); return $.event('change', null, Index.selectMode);
}, },
cycleSortType: function() { cycleSortType: function() {
var i, type, types, _i, _len; var i, option, type, types, _i, _len;
types = __slice.call(Index.selectSort.options).filter(function(option) { types = [];
return !option.disabled; i = 0;
}); while (option = Index.selectSort.options[i++]) {
if (!option.disabled) {
types.push(option);
}
}
for (i = _i = 0, _len = types.length; _i < _len; i = ++_i) { for (i = _i = 0, _len = types.length; _i < _len; i = ++_i) {
type = types[i]; type = types[i];
if (type.selected) { if (type.selected) {
@ -5023,13 +5028,15 @@
return $.event('change', null, Index.selectSort); return $.event('change', null, Index.selectSort);
}, },
catalogSwitch: function() { catalogSwitch: function() {
var hash; return $.get('JSON Navigation', true, function(items) {
if (!Conf['JSON Navigation']) { var hash;
return; if (!items['JSON Navigation']) {
} return;
$.set('Index Mode', 'catalog'); }
hash = window.location.hash; $.set('Index Mode', 'catalog');
return window.location = './' + hash; hash = window.location.hash;
return window.location = './' + hash;
});
}, },
searchTest: function() { searchTest: function() {
var hash, match; var hash, match;
@ -5119,20 +5126,18 @@
return Index.buildIndex(); return Index.buildIndex();
}, },
target: function() { target: function() {
var thread, threadID, thumb, _ref; return g.BOARD.threads.forEach(function(thread) {
_ref = g.BOARD.threads; var thumb;
for (threadID in _ref) {
thread = _ref[threadID];
if (!thread.catalogView) { if (!thread.catalogView) {
continue; return;
} }
thumb = thread.catalogView.nodes.thumb; thumb = thread.catalogView.nodes.thumb;
if (Conf['Open threads in a new tab']) { if (Conf['Open threads in a new tab']) {
thumb.target = '_blank'; return thumb.target = '_blank';
} else { } else {
thumb.removeAttribute('target'); return thumb.removeAttribute('target');
} }
} });
}, },
replies: function() { replies: function() {
Index.buildThreads(); Index.buildThreads();
@ -5487,12 +5492,11 @@
return $.event('IndexRefresh'); return $.event('IndexRefresh');
}, },
buildHRs: function(threadRoots) { buildHRs: function(threadRoots) {
var node, nodes, _i, _len; var i, node, nodes;
nodes = []; nodes = [];
for (_i = 0, _len = threadRoots.length; _i < _len; _i++) { i = 0;
node = threadRoots[_i]; while (node = threadRoots[i++]) {
nodes.push(node); nodes.push(node, $.el('hr'));
nodes.push($.el('hr'));
} }
return nodes; return nodes;
}, },
@ -5537,7 +5541,7 @@
return Main.callbackNodes(Post, posts); return Main.callbackNodes(Post, posts);
}, },
buildCatalogViews: function() { buildCatalogViews: function() {
var catalogThreads, thread, _i, _len, _ref; var catalogThreads, i, nodes, thread, _i, _len, _ref;
catalogThreads = []; catalogThreads = [];
_ref = Index.sortedThreads; _ref = Index.sortedThreads;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@ -5547,9 +5551,12 @@
} }
} }
Main.callbackNodes(CatalogThread, catalogThreads); Main.callbackNodes(CatalogThread, catalogThreads);
return Index.sortedThreads.map(function(thread) { nodes = [];
return thread.catalogView.nodes.root; i = 0;
}); while (thread = Index.sortedThreads[i++]) {
nodes.push(thread.catalogView.nodes.root);
}
return nodes;
}, },
sizeCatalogViews: function(nodes) { sizeCatalogViews: function(nodes) {
var height, node, ratio, size, thumb, width, _i, _len, _ref; var height, node, ratio, size, thumb, width, _i, _len, _ref;
@ -5567,13 +5574,16 @@
} }
}, },
sort: function() { sort: function() {
var sortedThreadIDs; var i, sortedThreadIDs, sortedThreads, thread, threadID;
switch (Conf['Index Sort']) { sortedThreads = [];
case 'bump': sortedThreadIDs = [];
sortedThreadIDs = Index.liveThreadIDs; ({
break; 'bump': function() {
case 'lastreply': return sortedThreadIDs = Index.liveThreadIDs;
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { },
'lastreply': function() {
var data, i, liveData;
liveData = __slice.call(Index.liveThreadData).sort(function(a, b) {
var _ref, _ref1; var _ref, _ref1;
if ('last_replies' in a) { if ('last_replies' in a) {
_ref = a.last_replies, a = _ref[_ref.length - 1]; _ref = a.last_replies, a = _ref[_ref.length - 1];
@ -5582,34 +5592,49 @@
_ref1 = b.last_replies, b = _ref1[_ref1.length - 1]; _ref1 = b.last_replies, b = _ref1[_ref1.length - 1];
} }
return b.no - a.no; return b.no - a.no;
}).map(function(data) {
return data.no;
}); });
break; i = 0;
case 'birth': while (data = liveData[i++]) {
sortedThreadIDs = __slice.call(Index.liveThreadIDs).sort(function(a, b) { sortedThreadIDs.push(data.no);
}
},
'birth': function() {
return sortedThreadIDs = __slice.call(Index.liveThreadIDs).sort(function(a, b) {
return b - a; return b - a;
}); });
break; },
case 'replycount': 'replycount': function() {
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { var data, i, liveData;
liveData = __slice.call(Index.liveThreadData).sort(function(a, b) {
return b.replies - a.replies; return b.replies - a.replies;
}).map(function(data) {
return data.no;
}); });
break; i = 0;
case 'filecount': while (data = liveData[i++]) {
sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { sortedThreadIDs.push(data.no);
}
},
'filecount': function() {
var data, i, liveData;
liveData = __slice.call(Index.liveThreadData).sort(function(a, b) {
return b.images - a.images; return b.images - a.images;
}).map(function(data) {
return data.no;
}); });
i = 0;
while (data = liveData[i++]) {
sortedThreadIDs.push(data.no);
}
}
})[Conf['Index Sort']]();
i = 0;
while (threadID = sortedThreadIDs[i++]) {
sortedThreads.push(g.BOARD.threads[threadID]);
}
Index.sortedThreads = [];
i = 0;
while (thread = sortedThreads[i++]) {
if (thread.isHidden === Index.showHiddenThreads) {
Index.sortedThreads.push(thread);
}
} }
Index.sortedThreads = sortedThreadIDs.map(function(threadID) {
return g.BOARD.threads[threadID];
}).filter(function(thread) {
return thread.isHidden === Index.showHiddenThreads;
});
if (Index.isSearching) { if (Index.isSearching) {
Index.sortedThreads = Index.querySearch(Index.searchInput.value) || Index.sortedThreads; Index.sortedThreads = Index.querySearch(Index.searchInput.value) || Index.sortedThreads;
} }
@ -5632,7 +5657,7 @@
} }
}, },
buildIndex: function(infinite) { buildIndex: function(infinite) {
var nodes, pageNum, threads, threadsPerPage; var nodes, pageNum, thread, threads, threadsPerPage, _i, _j, _len, _len1, _ref;
switch (Conf['Index Mode']) { switch (Conf['Index Mode']) {
case 'paged': case 'paged':
case 'infinite': case 'infinite':
@ -5643,9 +5668,11 @@
} }
threadsPerPage = Index.getThreadsNumPerPage(); threadsPerPage = Index.getThreadsNumPerPage();
threads = Index.sortedThreads.slice(threadsPerPage * pageNum, threadsPerPage * (pageNum + 1)); threads = Index.sortedThreads.slice(threadsPerPage * pageNum, threadsPerPage * (pageNum + 1));
nodes = threads.map(function(thread) { nodes = [];
return thread.OP.nodes.root.parentNode; for (_i = 0, _len = threads.length; _i < _len; _i++) {
}); thread = threads[_i];
nodes.push(thread.OP.nodes.root.parentNode);
}
Index.buildReplies(threads); Index.buildReplies(threads);
nodes = Index.buildHRs(nodes); nodes = Index.buildHRs(nodes);
Index.buildPagelist(); Index.buildPagelist();
@ -5656,9 +5683,12 @@
Index.sizeCatalogViews(nodes); Index.sizeCatalogViews(nodes);
break; break;
default: default:
nodes = Index.sortedThreads.map(function(thread) { nodes = [];
return thread.OP.nodes.root.parentNode; _ref = Index.sortedThreads;
}); for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
thread = _ref[_j];
nodes.push(thread.OP.nodes.root.parentNode);
}
Index.buildReplies(Index.sortedThreads); Index.buildReplies(Index.sortedThreads);
nodes = Index.buildHRs(nodes); nodes = Index.buildHRs(nodes);
} }
@ -5708,9 +5738,16 @@
return Index.search(keywords); return Index.search(keywords);
}, },
search: function(keywords) { search: function(keywords) {
return Index.sortedThreads.filter(function(thread) { var filtered, i, sortedThreads, thread;
return Index.searchMatch(thread, keywords); filtered = [];
}); i = 0;
sortedThreads = Index.sortedThreads;
while (thread = sortedThreads[i++]) {
if (Index.searchMatch(thread, keywords)) {
filtered.push(thread);
}
}
return Index.sortedThreads = filtered;
}, },
searchMatch: function(thread, keywords) { searchMatch: function(thread, keywords) {
var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1; var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1;
@ -6022,7 +6059,7 @@
return "/" + thread.board + "/ - " + excerpt; return "/" + thread.board + "/ - " + excerpt;
}, },
threadFromRoot: function(root) { threadFromRoot: function(root) {
return g.threads["" + g.BOARD + "." + root.id.slice(1)]; return g.threads[root.dataset.fullID];
}, },
threadFromNode: function(node) { threadFromNode: function(node) {
return Get.threadFromRoot($.x('ancestor::div[@class="thread"]', node)); return Get.threadFromRoot($.x('ancestor::div[@class="thread"]', node));
@ -6040,9 +6077,7 @@
return Get.postFromRoot($.x('ancestor::div[contains(@class,"postContainer")][1]', node)); return Get.postFromRoot($.x('ancestor::div[contains(@class,"postContainer")][1]', node));
}, },
contextFromNode: function(node) { contextFromNode: function(node) {
var snapshot; return Get.postFromRoot($.x('ancestor::div[@class="thread"]', node).firstElementChild);
snapshot = $.X('ancestor::div[contains(@class,"postContainer")]', node);
return Get.postFromRoot(snapshot.snapshotItem(snapshot.length - 1));
}, },
postDataFromLink: function(link) { postDataFromLink: function(link) {
var boardID, path, postID, threadID, _ref; var boardID, path, postID, threadID, _ref;
@ -7417,7 +7452,7 @@
return $.add(this.nodes.info, container); return $.add(this.nodes.info, container);
}, },
buildBacklink: function(quoted, quoter) { buildBacklink: function(quoted, quoter) {
var a, frag, text; var a, frag, hash, text;
frag = QuoteBacklink.frag.cloneNode(true); frag = QuoteBacklink.frag.cloneNode(true);
a = frag.lastElementChild; a = frag.lastElementChild;
a.href = "/" + quoter.board + "/res/" + quoter.thread + "#p" + quoter; a.href = "/" + quoter.board + "/res/" + quoter.thread + "#p" + quoter;
@ -7435,7 +7470,14 @@
if (Conf['Quote Inlining']) { if (Conf['Quote Inlining']) {
$.on(a, 'click', QuoteInline.toggle); $.on(a, 'click', QuoteInline.toggle);
if (Conf['Quote Hash Navigation']) { if (Conf['Quote Hash Navigation']) {
QuoteInline.qiQuote(a, quoter.isHidden); hash = QuoteInline.qiQuote(a, quoter.isHidden);
}
}
if (Conf['JSON Navigation']) {
if (hash) {
Navigate.singleQuoteLink(hash);
} else if (!Conf['Quote Inlining']) {
Navigate.singleQuoteLink(a);
} }
} }
return frag; return frag;
@ -16242,22 +16284,28 @@
return $.on(replyLink, 'click', Navigate.navigate); return $.on(replyLink, 'click', Navigate.navigate);
}, },
post: function() { post: function() {
var boardID, hashlink, postID, postlink, threadID, _i, _len, _ref, _ref1; var linktype;
if (Conf['Quote Hash Navigation']) { if (!(g.VIEW === 'thread' && this.thread.ID === g.THREADID)) {
_ref = $$('.hashlink', this.nodes.comment); $.on($('a[title="Highlight this post"]', this.nodes.info), 'click', Navigate.navigate);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
hashlink = _ref[_i];
_ref1 = Get.postDataFromLink(hashlink), boardID = _ref1.boardID, threadID = _ref1.threadID, postID = _ref1.postID;
if (boardID !== g.BOARD.ID || (threadID !== g.THREADID)) {
$.on(hashlink, 'click', Navigate.navigate);
}
}
} }
if (g.VIEW === 'thread' && this.thread.ID === g.THREADID) { if (!(linktype = Conf['Quote Inlining'] && Conf['Quote Hash Navigation'] ? '.hashlink' : !Conf['Quote Inlining'] ? '.quotelink' : null)) {
return; return;
} }
postlink = $('a[title="Highlight this post"]', this.nodes.info); return Navigate.quoteLink($$(linktype, this.nodes.comment));
return $.on(postlink, 'click', Navigate.navigate); },
quoteLink: function(links) {
var link, _i, _len;
for (_i = 0, _len = links.length; _i < _len; _i++) {
link = links[_i];
Navigate.singleQuoteLink(link);
}
},
singleQuoteLink: function(link) {
var boardID, threadID, _ref;
_ref = Get.postDataFromLink(link), boardID = _ref.boardID, threadID = _ref.threadID;
if (g.VIEW === 'index' || boardID !== g.BOARD.ID || threadID !== g.THREADID) {
return $.on(link, 'click', Navigate.navigate);
}
}, },
clean: function() { clean: function() {
g.threads.forEach(function(thread) { g.threads.forEach(function(thread) {

View File

@ -8,7 +8,7 @@ Get =
excerpt = "#{excerpt[...67]}..." excerpt = "#{excerpt[...67]}..."
"/#{thread.board}/ - #{excerpt}" "/#{thread.board}/ - #{excerpt}"
threadFromRoot: (root) -> threadFromRoot: (root) ->
g.threads["#{g.BOARD}.#{root.id[1..]}"] g.threads[root.dataset.fullID]
threadFromNode: (node) -> threadFromNode: (node) ->
Get.threadFromRoot $.x 'ancestor::div[@class="thread"]', node Get.threadFromRoot $.x 'ancestor::div[@class="thread"]', node
postFromRoot: (root) -> postFromRoot: (root) ->
@ -17,8 +17,7 @@ Get =
postFromNode: (node) -> postFromNode: (node) ->
Get.postFromRoot $.x 'ancestor::div[contains(@class,"postContainer")][1]', node Get.postFromRoot $.x 'ancestor::div[contains(@class,"postContainer")][1]', node
contextFromNode: (node) -> contextFromNode: (node) ->
snapshot = $.X 'ancestor::div[contains(@class,"postContainer")]', node Get.postFromRoot $.x('ancestor::div[@class="thread"]', node).firstElementChild
Get.postFromRoot snapshot.snapshotItem(snapshot.length - 1)
postDataFromLink: (link) -> postDataFromLink: (link) ->
if link.hostname is 'boards.4chan.org' if link.hostname is 'boards.4chan.org'
path = link.pathname.split '/' path = link.pathname.split '/'

View File

@ -254,17 +254,21 @@ Index =
$.event 'change', null, Index.selectMode $.event 'change', null, Index.selectMode
cycleSortType: -> cycleSortType: ->
types = [Index.selectSort.options...].filter (option) -> !option.disabled types = []
i = 0
while option = Index.selectSort.options[i++]
types.push option if !option.disabled
for type, i in types for type, i in types
break if type.selected break if type.selected
types[(i + 1) % types.length].selected = true types[(i + 1) % types.length].selected = true
$.event 'change', null, Index.selectSort $.event 'change', null, Index.selectSort
catalogSwitch: -> catalogSwitch: ->
return if !Conf['JSON Navigation'] $.get 'JSON Navigation', true, (items) ->
$.set 'Index Mode', 'catalog' return if !items['JSON Navigation']
{hash} = window.location $.set 'Index Mode', 'catalog'
window.location = './' + hash {hash} = window.location
window.location = './' + hash
searchTest: -> searchTest: ->
return unless hash = window.location.hash return unless hash = window.location.hash
@ -333,13 +337,13 @@ Index =
Index.buildIndex() Index.buildIndex()
target: -> target: ->
for threadID, thread of g.BOARD.threads when thread.catalogView g.BOARD.threads.forEach (thread) ->
return if !thread.catalogView
{thumb} = thread.catalogView.nodes {thumb} = thread.catalogView.nodes
if Conf['Open threads in a new tab'] if Conf['Open threads in a new tab']
thumb.target = '_blank' thumb.target = '_blank'
else else
thumb.removeAttribute 'target' thumb.removeAttribute 'target'
return
replies: -> replies: ->
Index.buildThreads() Index.buildThreads()
@ -618,9 +622,9 @@ Index =
buildHRs: (threadRoots) -> buildHRs: (threadRoots) ->
nodes = [] nodes = []
for node in threadRoots i = 0
nodes.push node while node = threadRoots[i++]
nodes.push $.el 'hr' nodes.push node, $.el 'hr'
nodes nodes
buildReplies: (threads) -> buildReplies: (threads) ->
@ -653,7 +657,11 @@ Index =
for thread in Index.sortedThreads when !thread.catalogView for thread in Index.sortedThreads when !thread.catalogView
catalogThreads.push new CatalogThread Build.catalogThread(thread), thread catalogThreads.push new CatalogThread Build.catalogThread(thread), thread
Main.callbackNodes CatalogThread, catalogThreads Main.callbackNodes CatalogThread, catalogThreads
Index.sortedThreads.map (thread) -> thread.catalogView.nodes.root nodes = []
i = 0
while thread = Index.sortedThreads[i++]
nodes.push thread.catalogView.nodes.root
return nodes
sizeCatalogViews: (nodes) -> sizeCatalogViews: (nodes) ->
# XXX When browsers support CSS3 attr(), use it instead. # XXX When browsers support CSS3 attr(), use it instead.
@ -668,24 +676,46 @@ Index =
return return
sort: -> sort: ->
switch Conf['Index Sort'] sortedThreads = []
when 'bump' sortedThreadIDs = []
{
'bump': ->
sortedThreadIDs = Index.liveThreadIDs sortedThreadIDs = Index.liveThreadIDs
when 'lastreply' 'lastreply': ->
sortedThreadIDs = [Index.liveThreadData...].sort (a, b) -> liveData = [Index.liveThreadData...].sort (a, b) ->
[..., a] = a.last_replies if 'last_replies' of a [..., a] = a.last_replies if 'last_replies' of a
[..., b] = b.last_replies if 'last_replies' of b [..., b] = b.last_replies if 'last_replies' of b
b.no - a.no b.no - a.no
.map (data) -> data.no i = 0
when 'birth' while data = liveData[i++]
sortedThreadIDs.push data.no
return
'birth': ->
sortedThreadIDs = [Index.liveThreadIDs...].sort (a, b) -> b - a sortedThreadIDs = [Index.liveThreadIDs...].sort (a, b) -> b - a
when 'replycount' 'replycount': ->
sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no liveData = [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies)
when 'filecount' i = 0
sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no while data = liveData[i++]
Index.sortedThreads = sortedThreadIDs sortedThreadIDs.push data.no
.map (threadID) -> g.BOARD.threads[threadID] return
.filter (thread) -> thread.isHidden is Index.showHiddenThreads 'filecount': ->
liveData = [Index.liveThreadData...].sort((a, b) -> b.images - a.images)
i = 0
while data = liveData[i++]
sortedThreadIDs.push data.no
return
}[Conf['Index Sort']]()
i = 0
while threadID = sortedThreadIDs[i++]
sortedThreads.push g.BOARD.threads[threadID]
Index.sortedThreads = []
i = 0
while thread = sortedThreads[i++]
Index.sortedThreads.push thread if thread.isHidden is Index.showHiddenThreads
if Index.isSearching if Index.isSearching
Index.sortedThreads = Index.querySearch(Index.searchInput.value) or Index.sortedThreads Index.sortedThreads = Index.querySearch(Index.searchInput.value) or Index.sortedThreads
# Sticky threads # Sticky threads
@ -709,7 +739,8 @@ Index =
return return
threadsPerPage = Index.getThreadsNumPerPage() threadsPerPage = Index.getThreadsNumPerPage()
threads = Index.sortedThreads[threadsPerPage * pageNum ... threadsPerPage * (pageNum + 1)] threads = Index.sortedThreads[threadsPerPage * pageNum ... threadsPerPage * (pageNum + 1)]
nodes = threads.map (thread) -> thread.OP.nodes.root.parentNode nodes = []
nodes.push thread.OP.nodes.root.parentNode for thread in threads
Index.buildReplies threads Index.buildReplies threads
nodes = Index.buildHRs nodes nodes = Index.buildHRs nodes
Index.buildPagelist() Index.buildPagelist()
@ -718,7 +749,8 @@ Index =
nodes = Index.buildCatalogViews() nodes = Index.buildCatalogViews()
Index.sizeCatalogViews nodes Index.sizeCatalogViews nodes
else else
nodes = Index.sortedThreads.map (thread) -> thread.OP.nodes.root.parentNode nodes = []
nodes.push thread.OP.nodes.root.parentNode for thread in Index.sortedThreads
Index.buildReplies Index.sortedThreads Index.buildReplies Index.sortedThreads
nodes = Index.buildHRs nodes nodes = Index.buildHRs nodes
$.rmAll Index.root unless infinite $.rmAll Index.root unless infinite
@ -763,8 +795,13 @@ Index =
Index.search keywords Index.search keywords
search: (keywords) -> search: (keywords) ->
Index.sortedThreads.filter (thread) -> filtered = []
Index.searchMatch thread, keywords i = 0
{sortedThreads} = Index
while thread = sortedThreads[i++]
filtered.push thread if Index.searchMatch thread, keywords
Index.sortedThreads = filtered
searchMatch: (thread, keywords) -> searchMatch: (thread, keywords) ->
{info, file} = thread.OP {info, file} = thread.OP

View File

@ -10,7 +10,7 @@ Navigate =
$.add Index.navLinks, Navigate.el $.add Index.navLinks, Navigate.el
@title = -> return @title = -> return
@el = $.el 'div', @el = $.el 'div',
id: 'breadCrumb' id: 'breadCrumb'
@ -28,16 +28,29 @@ Navigate =
$.on replyLink, 'click', Navigate.navigate $.on replyLink, 'click', Navigate.navigate
post: -> # Allows us to navigate via JSON from thread to thread by hashes and quote highlights. post: -> # Allows us to navigate via JSON from thread to thread by hashes and quote highlights.
if Conf['Quote Hash Navigation']
for hashlink in $$ '.hashlink', @nodes.comment
{boardID, threadID, postID} = Get.postDataFromLink hashlink
if boardID isnt g.BOARD.ID or (threadID isnt g.THREADID)
$.on hashlink, 'click', Navigate.navigate
# We don't need to reload the thread inside the thread # We don't need to reload the thread inside the thread
return if g.VIEW is 'thread' and @thread.ID is g.THREADID unless g.VIEW is 'thread' and @thread.ID is g.THREADID
postlink = $ 'a[title="Highlight this post"]', @nodes.info $.on $('a[title="Highlight this post"]', @nodes.info), 'click', Navigate.navigate
$.on postlink, 'click', Navigate.navigate
return unless (linktype = if Conf['Quote Inlining'] and Conf['Quote Hash Navigation']
'.hashlink'
else if !Conf['Quote Inlining']
'.quotelink'
else
null
)
Navigate.quoteLink $$ linktype, @nodes.comment
quoteLink: (links) ->
for link in links
Navigate.singleQuoteLink link
return
singleQuoteLink: (link) ->
{boardID, threadID} = Get.postDataFromLink link
if g.VIEW is 'index' or boardID isnt g.BOARD.ID or threadID isnt g.THREADID
$.on link, 'click', Navigate.navigate
clean: -> clean: ->
# Garbage collection # Garbage collection

View File

@ -23,6 +23,7 @@ class Post
@thread.OP = @ @thread.OP = @
@thread.isSticky = !!$ '.stickyIcon', info @thread.isSticky = !!$ '.stickyIcon', info
@thread.isClosed = !!$ '.closedIcon', info @thread.isClosed = !!$ '.closedIcon', info
root.parentElement.dataset.fullID = @fullID
@info = {} @info = {}
if subject = $ '.subject', info if subject = $ '.subject', info

View File

@ -69,5 +69,10 @@ QuoteBacklink =
if Conf['Quote Inlining'] if Conf['Quote Inlining']
$.on a, 'click', QuoteInline.toggle $.on a, 'click', QuoteInline.toggle
if Conf['Quote Hash Navigation'] if Conf['Quote Hash Navigation']
QuoteInline.qiQuote a, quoter.isHidden hash = QuoteInline.qiQuote a, quoter.isHidden
if Conf['JSON Navigation']
if hash
Navigate.singleQuoteLink hash
else unless Conf['Quote Inlining']
Navigate.singleQuoteLink a
frag frag