Merge branch 'v3' into Av2
Conflicts: builds/4chan-X.js builds/4chan-X.user.js builds/crx.crx builds/crx/script.js src/code/main.coffee src/code/misc/keybinds.coffee src/code/posting/qr.coffee src/css/style.css
This commit is contained in:
commit
ffec9f6881
@ -19,7 +19,7 @@
|
||||
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAElBMVEX///8EZgR8ulSk0oT///8EAgQ1A88mAAAAAXRSTlMAQObYZgAAAIpJREFUeF6t0sENwjAMhWF84N4H6gAYMUBkdQMYwfuvwmstEeD4kl892P0OaaWcpga2/K0SGII1HNBXARgu7veoY3ANd+esgMHZIz85u0EABrbms3pl/bkC1Tn5ihGOfQwqHeZ/FdYdirEMgCG2ZAQWDTL0m9FvjAhcvoGNAK2gZhGYYX9+ZgFm9gaiNmNkMENY4QAAAABJRU5ErkJggg==
|
||||
// ==/UserScript==
|
||||
|
||||
/* appchan x - Version 2.0.0 - 2013-04-16
|
||||
/* appchan x - Version 2.0.0 - 2013-04-19
|
||||
* http://zixaphir.github.com/appchan-x/
|
||||
*
|
||||
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
@ -42,7 +42,7 @@
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DataBoards, DeleteLink, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Get, GlobalMessage, Header, Icons, ImageExpand, ImageHover, ImageReplace, JSColor, Keybinds, Linkify, Main, MascotTools, Mascots, Menu, Nav, Notification, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DataBoards, DeleteLink, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Get, GlobalMessage, Header, Icons, ImageExpand, ImageHover, ImageReplace, JSColor, Keybinds, Linkify, Main, MascotTools, Mascots, Menu, Nav, Notification, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
__slice = [].slice,
|
||||
__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; };
|
||||
@ -133,7 +133,8 @@
|
||||
'Resurrect Quotes': [true, 'Link dead quotes to the archives.'],
|
||||
'Mark Quotes of You': [true, 'Add \'(You)\' to quotes linking to your posts.'],
|
||||
'Mark OP Quotes': [true, 'Add \'(OP)\' to OP quotes.'],
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.']
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.'],
|
||||
'Quote Threading': [false, 'Thread conversations']
|
||||
}
|
||||
},
|
||||
imageExpansion: {
|
||||
@ -2498,7 +2499,6 @@
|
||||
arg = args[_i];
|
||||
this.push.apply(this, arg);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
remove: function(object) {
|
||||
var index;
|
||||
@ -2565,6 +2565,7 @@
|
||||
}
|
||||
type = opts.type, cred = opts.cred, headers = opts.headers, upCallbacks = opts.upCallbacks, form = opts.form, sync = opts.sync;
|
||||
r = new XMLHttpRequest();
|
||||
r.overrideMimeType('text/html');
|
||||
type || (type = form && 'post' || 'get');
|
||||
r.open(type, url, !sync);
|
||||
for (key in headers) {
|
||||
@ -7066,7 +7067,7 @@
|
||||
hashScroll: function() {
|
||||
var post;
|
||||
|
||||
if (!(post = $.id(this.location.hash.slice(1)))) {
|
||||
if (!(post = this.location.hash.slice(1))) {
|
||||
return;
|
||||
}
|
||||
if ((Get.postFromRoot(post)).isHidden) {
|
||||
@ -7331,7 +7332,8 @@
|
||||
if (quote) {
|
||||
QR.quote.call($('input', $('.post.highlight', thread) || thread));
|
||||
}
|
||||
return QR.nodes.com.focus();
|
||||
QR.nodes.com.focus();
|
||||
return $.rmClass($('.qr-shortcut'), 'disabled');
|
||||
},
|
||||
tags: function(tag, ta) {
|
||||
var range, selEnd, selStart, value;
|
||||
@ -8329,7 +8331,7 @@
|
||||
return $.after(root, [$.tn(' '), icon]);
|
||||
},
|
||||
parse: function(postObjects) {
|
||||
var ID, OP, count, deletedFiles, deletedPosts, files, index, node, nodes, num, post, postObject, posts, scroll, _i, _len, _ref;
|
||||
var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
|
||||
|
||||
OP = postObjects[0];
|
||||
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
|
||||
@ -8337,7 +8339,6 @@
|
||||
ThreadUpdater.updateThreadStatus('Closed', OP);
|
||||
ThreadUpdater.thread.postLimit = !!OP.bumplimit;
|
||||
ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
|
||||
nodes = [];
|
||||
posts = [];
|
||||
index = [];
|
||||
files = [];
|
||||
@ -8354,7 +8355,6 @@
|
||||
}
|
||||
count++;
|
||||
node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
|
||||
nodes.push(node);
|
||||
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
|
||||
}
|
||||
deletedPosts = [];
|
||||
@ -8395,7 +8395,19 @@
|
||||
ThreadUpdater.lastPost = posts[count - 1].ID;
|
||||
Main.callbackNodes(Post, posts);
|
||||
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
|
||||
$.add(ThreadUpdater.root, nodes);
|
||||
for (key in posts) {
|
||||
post = posts[key];
|
||||
if (!posts.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
if (post.cb) {
|
||||
if (!post.cb.call(post)) {
|
||||
$.add(ThreadUpdater.root, post.nodes.root);
|
||||
}
|
||||
} else {
|
||||
$.add(ThreadUpdater.root, post.nodes.root);
|
||||
}
|
||||
}
|
||||
if (scroll) {
|
||||
if (Conf['Bottom Scroll']) {
|
||||
doc.scrollTop = d.body.clientHeight;
|
||||
@ -8715,26 +8727,27 @@
|
||||
return arr.splice(0, i);
|
||||
},
|
||||
read: function(e) {
|
||||
var bottom, height, i, post, _i, _len, _ref;
|
||||
var ID, bottom, height, i, post, posts, read, top, _ref;
|
||||
|
||||
if (d.hidden || !Unread.posts.length) {
|
||||
return;
|
||||
}
|
||||
height = doc.clientHeight;
|
||||
_ref = Unread.posts;
|
||||
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
||||
post = _ref[i];
|
||||
bottom = post.nodes.root.getBoundingClientRect().bottom;
|
||||
if (bottom > height) {
|
||||
break;
|
||||
posts = Unread.posts;
|
||||
read = [];
|
||||
i = posts.length;
|
||||
while (post = posts[--i]) {
|
||||
_ref = post.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
|
||||
if ((bottom < height) && (top > 0)) {
|
||||
ID = post.ID;
|
||||
posts.remove(post);
|
||||
}
|
||||
}
|
||||
if (!i) {
|
||||
if (!ID) {
|
||||
return;
|
||||
}
|
||||
Unread.lastReadPost = Unread.posts[i - 1].ID;
|
||||
Unread.lastReadPost = ID;
|
||||
Unread.saveLastReadPost();
|
||||
Unread.posts.splice(0, i);
|
||||
Unread.readArray(Unread.postsQuotingYou);
|
||||
if (e) {
|
||||
return Unread.update();
|
||||
@ -8886,6 +8899,7 @@
|
||||
QR.cleanNotifications();
|
||||
d.activeElement.blur();
|
||||
$.rmClass(QR.nodes.el, 'dump');
|
||||
$.toggleClass($('.qr-shortcut'), 'disabled');
|
||||
_ref = QR.posts;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
i = _ref[_i];
|
||||
@ -9141,7 +9155,8 @@
|
||||
com.setSelectionRange(range, range);
|
||||
com.focus();
|
||||
QR.selected.save(com);
|
||||
return QR.selected.save(thread);
|
||||
QR.selected.save(thread);
|
||||
return $.rmClass($('.qr-shortcut'), 'disabled');
|
||||
},
|
||||
characterCount: function() {
|
||||
var count, counter;
|
||||
@ -10438,6 +10453,151 @@
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
<3 aeosynth
|
||||
*/
|
||||
|
||||
|
||||
QuoteThreading = {
|
||||
init: function() {
|
||||
var input;
|
||||
|
||||
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
|
||||
return;
|
||||
}
|
||||
this.enabled = true;
|
||||
this.controls = $.el('span', {
|
||||
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>'
|
||||
});
|
||||
input = $('input', this.controls);
|
||||
$.on(input, 'change', QuoteThreading.toggle);
|
||||
$.event('AddMenuEntry', {
|
||||
type: 'header',
|
||||
el: this.controls,
|
||||
order: 115
|
||||
});
|
||||
$.on(d, '4chanXInitFinished', this.setup);
|
||||
return Post.prototype.callbacks.push({
|
||||
name: 'Quote Threading',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
setup: function() {
|
||||
var ID, post, posts;
|
||||
|
||||
$.off(d, '4chanXInitFinished', QuoteThreading.setup);
|
||||
posts = g.posts;
|
||||
for (ID in posts) {
|
||||
post = posts[ID];
|
||||
if (post.cb) {
|
||||
post.cb.call(post);
|
||||
}
|
||||
}
|
||||
return QuoteThreading.hasRun = true;
|
||||
},
|
||||
node: function() {
|
||||
var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
|
||||
|
||||
if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
|
||||
return;
|
||||
}
|
||||
quotes = this.quotes, ID = this.ID, fullID = this.fullID;
|
||||
posts = g.posts;
|
||||
if (!(post = posts[fullID]) || post.isHidden) {
|
||||
return;
|
||||
}
|
||||
uniq = {};
|
||||
len = ("" + g.BOARD).length + 1;
|
||||
for (_i = 0, _len = quotes.length; _i < _len; _i++) {
|
||||
quote = quotes[_i];
|
||||
qid = quote;
|
||||
if (!(qid.slice(len) < ID)) {
|
||||
continue;
|
||||
}
|
||||
if (qid in posts) {
|
||||
uniq[qid.slice(len)] = true;
|
||||
}
|
||||
}
|
||||
keys = Object.keys(uniq);
|
||||
if (keys.length !== 1) {
|
||||
return;
|
||||
}
|
||||
this.threaded = "" + g.BOARD + "." + keys[0];
|
||||
return this.cb = QuoteThreading.nodeinsert;
|
||||
},
|
||||
nodeinsert: function() {
|
||||
var posts, qpost, qroot, threadContainer;
|
||||
|
||||
posts = g.posts;
|
||||
qpost = posts[this.threaded];
|
||||
delete this.threaded;
|
||||
delete this.cb;
|
||||
if (this.thread.OP === qpost || (QuoteThreading.hasRun && !Unread.posts.contains(qpost))) {
|
||||
return false;
|
||||
}
|
||||
qroot = qpost.nodes.root;
|
||||
threadContainer = qroot.nextSibling;
|
||||
if ((threadContainer != null ? threadContainer.className : void 0) !== 'threadContainer') {
|
||||
threadContainer = $.el('div', {
|
||||
className: 'threadContainer'
|
||||
});
|
||||
$.after(qroot, threadContainer);
|
||||
}
|
||||
$.add(threadContainer, this.nodes.root);
|
||||
return true;
|
||||
},
|
||||
toggle: function() {
|
||||
var container, containers, node, nodes, replies, reply, thread, _i, _j, _k, _len, _len1, _len2, _results;
|
||||
|
||||
thread = $('.thread');
|
||||
replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
|
||||
QuoteThreading.enabled = this.checked;
|
||||
if (this.checked) {
|
||||
nodes = (function() {
|
||||
var _i, _len, _results;
|
||||
|
||||
_results = [];
|
||||
for (_i = 0, _len = replies.length; _i < _len; _i++) {
|
||||
reply = replies[_i];
|
||||
_results.push(Get.postFromNode(reply));
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
|
||||
node = nodes[_i];
|
||||
Unread.node.call(node);
|
||||
}
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = nodes.length; _j < _len1; _j++) {
|
||||
node = nodes[_j];
|
||||
_results.push(QuoteThreading.node(node));
|
||||
}
|
||||
return _results;
|
||||
} else {
|
||||
replies.sort(function(a, b) {
|
||||
var aID, bID;
|
||||
|
||||
aID = Number(a.id.slice(2));
|
||||
bID = Number(b.id.slice(2));
|
||||
return aID - bID;
|
||||
});
|
||||
$.add(thread, replies);
|
||||
containers = $$('.threadContainer', thread);
|
||||
for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
|
||||
container = containers[_k];
|
||||
$.rm(container);
|
||||
}
|
||||
return Unread.update(true);
|
||||
}
|
||||
},
|
||||
kb: function() {
|
||||
var control;
|
||||
|
||||
control = $.id('threadingControl');
|
||||
return control.click();
|
||||
}
|
||||
};
|
||||
|
||||
QuoteYou = {
|
||||
init: function() {
|
||||
if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
|
||||
@ -13434,6 +13594,7 @@
|
||||
'Thread Excerpt': ThreadExcerpt,
|
||||
'Favicon': Favicon,
|
||||
'Unread': Unread,
|
||||
'Quote Threading': QuoteThreading,
|
||||
'Thread Updater': ThreadUpdater,
|
||||
'Thread Stats': ThreadStats,
|
||||
'Thread Watcher': ThreadWatcher,
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAAElBMVEX///8EZgR8ulSk0oT///8EAgQ1A88mAAAAAXRSTlMAQObYZgAAAIpJREFUeF6t0sENwjAMhWF84N4H6gAYMUBkdQMYwfuvwmstEeD4kl892P0OaaWcpga2/K0SGII1HNBXARgu7veoY3ANd+esgMHZIz85u0EABrbms3pl/bkC1Tn5ihGOfQwqHeZ/FdYdirEMgCG2ZAQWDTL0m9FvjAhcvoGNAK2gZhGYYX9+ZgFm9gaiNmNkMENY4QAAAABJRU5ErkJggg==
|
||||
// ==/UserScript==
|
||||
|
||||
/* appchan x - Version 2.0.0 - 2013-04-16
|
||||
/* appchan x - Version 2.0.0 - 2013-04-19
|
||||
* http://zixaphir.github.com/appchan-x/
|
||||
*
|
||||
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
@ -42,7 +42,7 @@
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DataBoards, DeleteLink, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Get, GlobalMessage, Header, Icons, ImageExpand, ImageHover, ImageReplace, JSColor, Keybinds, Linkify, Main, MascotTools, Mascots, Menu, Nav, Notification, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DataBoards, DeleteLink, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Get, GlobalMessage, Header, Icons, ImageExpand, ImageHover, ImageReplace, JSColor, Keybinds, Linkify, Main, MascotTools, Mascots, Menu, Nav, Notification, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
__slice = [].slice,
|
||||
__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; };
|
||||
@ -134,7 +134,8 @@
|
||||
'Resurrect Quotes': [true, 'Link dead quotes to the archives.'],
|
||||
'Mark Quotes of You': [true, 'Add \'(You)\' to quotes linking to your posts.'],
|
||||
'Mark OP Quotes': [true, 'Add \'(OP)\' to OP quotes.'],
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.']
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.'],
|
||||
'Quote Threading': [false, 'Thread conversations']
|
||||
}
|
||||
},
|
||||
imageExpansion: {
|
||||
@ -2495,7 +2496,6 @@
|
||||
arg = args[_i];
|
||||
this.push.apply(this, arg);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
remove: function(object) {
|
||||
var index;
|
||||
@ -2562,6 +2562,7 @@
|
||||
}
|
||||
type = opts.type, cred = opts.cred, headers = opts.headers, upCallbacks = opts.upCallbacks, form = opts.form, sync = opts.sync;
|
||||
r = new XMLHttpRequest();
|
||||
r.overrideMimeType('text/html');
|
||||
type || (type = form && 'post' || 'get');
|
||||
r.open(type, url, !sync);
|
||||
for (key in headers) {
|
||||
@ -7058,7 +7059,7 @@
|
||||
hashScroll: function() {
|
||||
var post;
|
||||
|
||||
if (!(post = $.id(this.location.hash.slice(1)))) {
|
||||
if (!(post = this.location.hash.slice(1))) {
|
||||
return;
|
||||
}
|
||||
if ((Get.postFromRoot(post)).isHidden) {
|
||||
@ -7323,7 +7324,8 @@
|
||||
if (quote) {
|
||||
QR.quote.call($('input', $('.post.highlight', thread) || thread));
|
||||
}
|
||||
return QR.nodes.com.focus();
|
||||
QR.nodes.com.focus();
|
||||
return $.rmClass($('.qr-shortcut'), 'disabled');
|
||||
},
|
||||
tags: function(tag, ta) {
|
||||
var range, selEnd, selStart, value;
|
||||
@ -8321,7 +8323,7 @@
|
||||
return $.after(root, [$.tn(' '), icon]);
|
||||
},
|
||||
parse: function(postObjects) {
|
||||
var ID, OP, count, deletedFiles, deletedPosts, files, index, node, nodes, num, post, postObject, posts, scroll, _i, _len, _ref;
|
||||
var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
|
||||
|
||||
OP = postObjects[0];
|
||||
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
|
||||
@ -8329,7 +8331,6 @@
|
||||
ThreadUpdater.updateThreadStatus('Closed', OP);
|
||||
ThreadUpdater.thread.postLimit = !!OP.bumplimit;
|
||||
ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
|
||||
nodes = [];
|
||||
posts = [];
|
||||
index = [];
|
||||
files = [];
|
||||
@ -8346,7 +8347,6 @@
|
||||
}
|
||||
count++;
|
||||
node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
|
||||
nodes.push(node);
|
||||
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
|
||||
}
|
||||
deletedPosts = [];
|
||||
@ -8387,7 +8387,19 @@
|
||||
ThreadUpdater.lastPost = posts[count - 1].ID;
|
||||
Main.callbackNodes(Post, posts);
|
||||
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
|
||||
$.add(ThreadUpdater.root, nodes);
|
||||
for (key in posts) {
|
||||
post = posts[key];
|
||||
if (!posts.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
if (post.cb) {
|
||||
if (!post.cb.call(post)) {
|
||||
$.add(ThreadUpdater.root, post.nodes.root);
|
||||
}
|
||||
} else {
|
||||
$.add(ThreadUpdater.root, post.nodes.root);
|
||||
}
|
||||
}
|
||||
if (scroll) {
|
||||
if (Conf['Bottom Scroll']) {
|
||||
doc.scrollTop = d.body.clientHeight;
|
||||
@ -8707,26 +8719,27 @@
|
||||
return arr.splice(0, i);
|
||||
},
|
||||
read: function(e) {
|
||||
var bottom, height, i, post, _i, _len, _ref;
|
||||
var ID, bottom, height, i, post, posts, read, top, _ref;
|
||||
|
||||
if (d.hidden || !Unread.posts.length) {
|
||||
return;
|
||||
}
|
||||
height = doc.clientHeight;
|
||||
_ref = Unread.posts;
|
||||
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
||||
post = _ref[i];
|
||||
bottom = post.nodes.root.getBoundingClientRect().bottom;
|
||||
if (bottom > height) {
|
||||
break;
|
||||
posts = Unread.posts;
|
||||
read = [];
|
||||
i = posts.length;
|
||||
while (post = posts[--i]) {
|
||||
_ref = post.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
|
||||
if ((bottom < height) && (top > 0)) {
|
||||
ID = post.ID;
|
||||
posts.remove(post);
|
||||
}
|
||||
}
|
||||
if (!i) {
|
||||
if (!ID) {
|
||||
return;
|
||||
}
|
||||
Unread.lastReadPost = Unread.posts[i - 1].ID;
|
||||
Unread.lastReadPost = ID;
|
||||
Unread.saveLastReadPost();
|
||||
Unread.posts.splice(0, i);
|
||||
Unread.readArray(Unread.postsQuotingYou);
|
||||
if (e) {
|
||||
return Unread.update();
|
||||
@ -8878,6 +8891,7 @@
|
||||
QR.cleanNotifications();
|
||||
d.activeElement.blur();
|
||||
$.rmClass(QR.nodes.el, 'dump');
|
||||
$.toggleClass($('.qr-shortcut'), 'disabled');
|
||||
_ref = QR.posts;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
i = _ref[_i];
|
||||
@ -9133,7 +9147,8 @@
|
||||
com.setSelectionRange(range, range);
|
||||
com.focus();
|
||||
QR.selected.save(com);
|
||||
return QR.selected.save(thread);
|
||||
QR.selected.save(thread);
|
||||
return $.rmClass($('.qr-shortcut'), 'disabled');
|
||||
},
|
||||
characterCount: function() {
|
||||
var count, counter;
|
||||
@ -10455,6 +10470,151 @@
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
<3 aeosynth
|
||||
*/
|
||||
|
||||
|
||||
QuoteThreading = {
|
||||
init: function() {
|
||||
var input;
|
||||
|
||||
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
|
||||
return;
|
||||
}
|
||||
this.enabled = true;
|
||||
this.controls = $.el('span', {
|
||||
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>'
|
||||
});
|
||||
input = $('input', this.controls);
|
||||
$.on(input, 'change', QuoteThreading.toggle);
|
||||
$.event('AddMenuEntry', {
|
||||
type: 'header',
|
||||
el: this.controls,
|
||||
order: 115
|
||||
});
|
||||
$.on(d, '4chanXInitFinished', this.setup);
|
||||
return Post.prototype.callbacks.push({
|
||||
name: 'Quote Threading',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
setup: function() {
|
||||
var ID, post, posts;
|
||||
|
||||
$.off(d, '4chanXInitFinished', QuoteThreading.setup);
|
||||
posts = g.posts;
|
||||
for (ID in posts) {
|
||||
post = posts[ID];
|
||||
if (post.cb) {
|
||||
post.cb.call(post);
|
||||
}
|
||||
}
|
||||
return QuoteThreading.hasRun = true;
|
||||
},
|
||||
node: function() {
|
||||
var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
|
||||
|
||||
if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
|
||||
return;
|
||||
}
|
||||
quotes = this.quotes, ID = this.ID, fullID = this.fullID;
|
||||
posts = g.posts;
|
||||
if (!(post = posts[fullID]) || post.isHidden) {
|
||||
return;
|
||||
}
|
||||
uniq = {};
|
||||
len = ("" + g.BOARD).length + 1;
|
||||
for (_i = 0, _len = quotes.length; _i < _len; _i++) {
|
||||
quote = quotes[_i];
|
||||
qid = quote;
|
||||
if (!(qid.slice(len) < ID)) {
|
||||
continue;
|
||||
}
|
||||
if (qid in posts) {
|
||||
uniq[qid.slice(len)] = true;
|
||||
}
|
||||
}
|
||||
keys = Object.keys(uniq);
|
||||
if (keys.length !== 1) {
|
||||
return;
|
||||
}
|
||||
this.threaded = "" + g.BOARD + "." + keys[0];
|
||||
return this.cb = QuoteThreading.nodeinsert;
|
||||
},
|
||||
nodeinsert: function() {
|
||||
var posts, qpost, qroot, threadContainer;
|
||||
|
||||
posts = g.posts;
|
||||
qpost = posts[this.threaded];
|
||||
delete this.threaded;
|
||||
delete this.cb;
|
||||
if (this.thread.OP === qpost || (QuoteThreading.hasRun && !Unread.posts.contains(qpost))) {
|
||||
return false;
|
||||
}
|
||||
qroot = qpost.nodes.root;
|
||||
threadContainer = qroot.nextSibling;
|
||||
if ((threadContainer != null ? threadContainer.className : void 0) !== 'threadContainer') {
|
||||
threadContainer = $.el('div', {
|
||||
className: 'threadContainer'
|
||||
});
|
||||
$.after(qroot, threadContainer);
|
||||
}
|
||||
$.add(threadContainer, this.nodes.root);
|
||||
return true;
|
||||
},
|
||||
toggle: function() {
|
||||
var container, containers, node, nodes, replies, reply, thread, _i, _j, _k, _len, _len1, _len2, _results;
|
||||
|
||||
thread = $('.thread');
|
||||
replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
|
||||
QuoteThreading.enabled = this.checked;
|
||||
if (this.checked) {
|
||||
nodes = (function() {
|
||||
var _i, _len, _results;
|
||||
|
||||
_results = [];
|
||||
for (_i = 0, _len = replies.length; _i < _len; _i++) {
|
||||
reply = replies[_i];
|
||||
_results.push(Get.postFromNode(reply));
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
|
||||
node = nodes[_i];
|
||||
Unread.node.call(node);
|
||||
}
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = nodes.length; _j < _len1; _j++) {
|
||||
node = nodes[_j];
|
||||
_results.push(QuoteThreading.node(node));
|
||||
}
|
||||
return _results;
|
||||
} else {
|
||||
replies.sort(function(a, b) {
|
||||
var aID, bID;
|
||||
|
||||
aID = Number(a.id.slice(2));
|
||||
bID = Number(b.id.slice(2));
|
||||
return aID - bID;
|
||||
});
|
||||
$.add(thread, replies);
|
||||
containers = $$('.threadContainer', thread);
|
||||
for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
|
||||
container = containers[_k];
|
||||
$.rm(container);
|
||||
}
|
||||
return Unread.update(true);
|
||||
}
|
||||
},
|
||||
kb: function() {
|
||||
var control;
|
||||
|
||||
control = $.id('threadingControl');
|
||||
return control.click();
|
||||
}
|
||||
};
|
||||
|
||||
QuoteYou = {
|
||||
init: function() {
|
||||
if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
|
||||
@ -13453,6 +13613,7 @@
|
||||
'Thread Excerpt': ThreadExcerpt,
|
||||
'Favicon': Favicon,
|
||||
'Unread': Unread,
|
||||
'Quote Threading': QuoteThreading,
|
||||
'Thread Updater': ThreadUpdater,
|
||||
'Thread Stats': ThreadStats,
|
||||
'Thread Watcher': ThreadWatcher,
|
||||
|
||||
BIN
builds/crx.crx
BIN
builds/crx.crx
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
(function() {
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DataBoards, DeleteLink, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Get, GlobalMessage, Header, Icons, ImageExpand, ImageHover, ImageReplace, JSColor, Keybinds, Linkify, Main, MascotTools, Mascots, Menu, Nav, Notification, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
var $, $$, Anonymize, ArchiveLink, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DataBoards, DeleteLink, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Get, GlobalMessage, Header, Icons, ImageExpand, ImageHover, ImageReplace, JSColor, Keybinds, Linkify, Main, MascotTools, Mascots, Menu, Nav, Notification, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, Report, ReportLink, RevealSpoilers, Rice, Sauce, Settings, Style, ThemeTools, Themes, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, editMascot, editTheme, g, userNavigation,
|
||||
__slice = [].slice,
|
||||
__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; };
|
||||
@ -90,7 +90,8 @@
|
||||
'Resurrect Quotes': [true, 'Link dead quotes to the archives.'],
|
||||
'Mark Quotes of You': [true, 'Add \'(You)\' to quotes linking to your posts.'],
|
||||
'Mark OP Quotes': [true, 'Add \'(OP)\' to OP quotes.'],
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.']
|
||||
'Mark Cross-thread Quotes': [true, 'Add \'(Cross-thread)\' to cross-threads quotes.'],
|
||||
'Quote Threading': [false, 'Thread conversations']
|
||||
}
|
||||
},
|
||||
imageExpansion: {
|
||||
@ -2451,7 +2452,6 @@
|
||||
arg = args[_i];
|
||||
this.push.apply(this, arg);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
remove: function(object) {
|
||||
var index;
|
||||
@ -2518,6 +2518,7 @@
|
||||
}
|
||||
type = opts.type, cred = opts.cred, headers = opts.headers, upCallbacks = opts.upCallbacks, form = opts.form, sync = opts.sync;
|
||||
r = new XMLHttpRequest();
|
||||
r.overrideMimeType('text/html');
|
||||
type || (type = form && 'post' || 'get');
|
||||
r.open(type, url, !sync);
|
||||
for (key in headers) {
|
||||
@ -6980,7 +6981,7 @@
|
||||
hashScroll: function() {
|
||||
var post;
|
||||
|
||||
if (!(post = $.id(this.location.hash.slice(1)))) {
|
||||
if (!(post = this.location.hash.slice(1))) {
|
||||
return;
|
||||
}
|
||||
if ((Get.postFromRoot(post)).isHidden) {
|
||||
@ -7245,7 +7246,8 @@
|
||||
if (quote) {
|
||||
QR.quote.call($('input', $('.post.highlight', thread) || thread));
|
||||
}
|
||||
return QR.nodes.com.focus();
|
||||
QR.nodes.com.focus();
|
||||
return $.rmClass($('.qr-shortcut'), 'disabled');
|
||||
},
|
||||
tags: function(tag, ta) {
|
||||
var range, selEnd, selStart, value;
|
||||
@ -8243,7 +8245,7 @@
|
||||
return $.after(root, [$.tn(' '), icon]);
|
||||
},
|
||||
parse: function(postObjects) {
|
||||
var ID, OP, count, deletedFiles, deletedPosts, files, index, node, nodes, num, post, postObject, posts, scroll, _i, _len, _ref;
|
||||
var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, scroll, _i, _len, _ref;
|
||||
|
||||
OP = postObjects[0];
|
||||
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
|
||||
@ -8251,7 +8253,6 @@
|
||||
ThreadUpdater.updateThreadStatus('Closed', OP);
|
||||
ThreadUpdater.thread.postLimit = !!OP.bumplimit;
|
||||
ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
|
||||
nodes = [];
|
||||
posts = [];
|
||||
index = [];
|
||||
files = [];
|
||||
@ -8268,7 +8269,6 @@
|
||||
}
|
||||
count++;
|
||||
node = Build.postFromObject(postObject, ThreadUpdater.thread.board);
|
||||
nodes.push(node);
|
||||
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
|
||||
}
|
||||
deletedPosts = [];
|
||||
@ -8309,7 +8309,19 @@
|
||||
ThreadUpdater.lastPost = posts[count - 1].ID;
|
||||
Main.callbackNodes(Post, posts);
|
||||
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
|
||||
$.add(ThreadUpdater.root, nodes);
|
||||
for (key in posts) {
|
||||
post = posts[key];
|
||||
if (!posts.hasOwnProperty(key)) {
|
||||
continue;
|
||||
}
|
||||
if (post.cb) {
|
||||
if (!post.cb.call(post)) {
|
||||
$.add(ThreadUpdater.root, post.nodes.root);
|
||||
}
|
||||
} else {
|
||||
$.add(ThreadUpdater.root, post.nodes.root);
|
||||
}
|
||||
}
|
||||
if (scroll) {
|
||||
if (Conf['Bottom Scroll']) {
|
||||
d.body.scrollTop = d.body.clientHeight;
|
||||
@ -8629,26 +8641,27 @@
|
||||
return arr.splice(0, i);
|
||||
},
|
||||
read: function(e) {
|
||||
var bottom, height, i, post, _i, _len, _ref;
|
||||
var ID, bottom, height, i, post, posts, read, top, _ref;
|
||||
|
||||
if (d.hidden || !Unread.posts.length) {
|
||||
return;
|
||||
}
|
||||
height = doc.clientHeight;
|
||||
_ref = Unread.posts;
|
||||
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
||||
post = _ref[i];
|
||||
bottom = post.nodes.root.getBoundingClientRect().bottom;
|
||||
if (bottom > height) {
|
||||
break;
|
||||
posts = Unread.posts;
|
||||
read = [];
|
||||
i = posts.length;
|
||||
while (post = posts[--i]) {
|
||||
_ref = post.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
|
||||
if ((bottom < height) && (top > 0)) {
|
||||
ID = post.ID;
|
||||
posts.remove(post);
|
||||
}
|
||||
}
|
||||
if (!i) {
|
||||
if (!ID) {
|
||||
return;
|
||||
}
|
||||
Unread.lastReadPost = Unread.posts[i - 1].ID;
|
||||
Unread.lastReadPost = ID;
|
||||
Unread.saveLastReadPost();
|
||||
Unread.posts.splice(0, i);
|
||||
Unread.readArray(Unread.postsQuotingYou);
|
||||
if (e) {
|
||||
return Unread.update();
|
||||
@ -8806,6 +8819,7 @@
|
||||
QR.cleanNotifications();
|
||||
d.activeElement.blur();
|
||||
$.rmClass(QR.nodes.el, 'dump');
|
||||
$.toggleClass($('.qr-shortcut'), 'disabled');
|
||||
_ref = QR.posts;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
i = _ref[_i];
|
||||
@ -9061,7 +9075,8 @@
|
||||
com.setSelectionRange(range, range);
|
||||
com.focus();
|
||||
QR.selected.save(com);
|
||||
return QR.selected.save(thread);
|
||||
QR.selected.save(thread);
|
||||
return $.rmClass($('.qr-shortcut'), 'disabled');
|
||||
},
|
||||
characterCount: function() {
|
||||
var count, counter;
|
||||
@ -10358,6 +10373,151 @@
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
<3 aeosynth
|
||||
*/
|
||||
|
||||
|
||||
QuoteThreading = {
|
||||
init: function() {
|
||||
var input;
|
||||
|
||||
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
|
||||
return;
|
||||
}
|
||||
this.enabled = true;
|
||||
this.controls = $.el('span', {
|
||||
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>'
|
||||
});
|
||||
input = $('input', this.controls);
|
||||
$.on(input, 'change', QuoteThreading.toggle);
|
||||
$.event('AddMenuEntry', {
|
||||
type: 'header',
|
||||
el: this.controls,
|
||||
order: 115
|
||||
});
|
||||
$.on(d, '4chanXInitFinished', this.setup);
|
||||
return Post.prototype.callbacks.push({
|
||||
name: 'Quote Threading',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
setup: function() {
|
||||
var ID, post, posts;
|
||||
|
||||
$.off(d, '4chanXInitFinished', QuoteThreading.setup);
|
||||
posts = g.posts;
|
||||
for (ID in posts) {
|
||||
post = posts[ID];
|
||||
if (post.cb) {
|
||||
post.cb.call(post);
|
||||
}
|
||||
}
|
||||
return QuoteThreading.hasRun = true;
|
||||
},
|
||||
node: function() {
|
||||
var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len;
|
||||
|
||||
if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
|
||||
return;
|
||||
}
|
||||
quotes = this.quotes, ID = this.ID, fullID = this.fullID;
|
||||
posts = g.posts;
|
||||
if (!(post = posts[fullID]) || post.isHidden) {
|
||||
return;
|
||||
}
|
||||
uniq = {};
|
||||
len = ("" + g.BOARD).length + 1;
|
||||
for (_i = 0, _len = quotes.length; _i < _len; _i++) {
|
||||
quote = quotes[_i];
|
||||
qid = quote;
|
||||
if (!(qid.slice(len) < ID)) {
|
||||
continue;
|
||||
}
|
||||
if (qid in posts) {
|
||||
uniq[qid.slice(len)] = true;
|
||||
}
|
||||
}
|
||||
keys = Object.keys(uniq);
|
||||
if (keys.length !== 1) {
|
||||
return;
|
||||
}
|
||||
this.threaded = "" + g.BOARD + "." + keys[0];
|
||||
return this.cb = QuoteThreading.nodeinsert;
|
||||
},
|
||||
nodeinsert: function() {
|
||||
var posts, qpost, qroot, threadContainer;
|
||||
|
||||
posts = g.posts;
|
||||
qpost = posts[this.threaded];
|
||||
delete this.threaded;
|
||||
delete this.cb;
|
||||
if (this.thread.OP === qpost || (QuoteThreading.hasRun && !Unread.posts.contains(qpost))) {
|
||||
return false;
|
||||
}
|
||||
qroot = qpost.nodes.root;
|
||||
threadContainer = qroot.nextSibling;
|
||||
if ((threadContainer != null ? threadContainer.className : void 0) !== 'threadContainer') {
|
||||
threadContainer = $.el('div', {
|
||||
className: 'threadContainer'
|
||||
});
|
||||
$.after(qroot, threadContainer);
|
||||
}
|
||||
$.add(threadContainer, this.nodes.root);
|
||||
return true;
|
||||
},
|
||||
toggle: function() {
|
||||
var container, containers, node, nodes, replies, reply, thread, _i, _j, _k, _len, _len1, _len2, _results;
|
||||
|
||||
thread = $('.thread');
|
||||
replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
|
||||
QuoteThreading.enabled = this.checked;
|
||||
if (this.checked) {
|
||||
nodes = (function() {
|
||||
var _i, _len, _results;
|
||||
|
||||
_results = [];
|
||||
for (_i = 0, _len = replies.length; _i < _len; _i++) {
|
||||
reply = replies[_i];
|
||||
_results.push(Get.postFromNode(reply));
|
||||
}
|
||||
return _results;
|
||||
})();
|
||||
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
|
||||
node = nodes[_i];
|
||||
Unread.node.call(node);
|
||||
}
|
||||
_results = [];
|
||||
for (_j = 0, _len1 = nodes.length; _j < _len1; _j++) {
|
||||
node = nodes[_j];
|
||||
_results.push(QuoteThreading.node(node));
|
||||
}
|
||||
return _results;
|
||||
} else {
|
||||
replies.sort(function(a, b) {
|
||||
var aID, bID;
|
||||
|
||||
aID = Number(a.id.slice(2));
|
||||
bID = Number(b.id.slice(2));
|
||||
return aID - bID;
|
||||
});
|
||||
$.add(thread, replies);
|
||||
containers = $$('.threadContainer', thread);
|
||||
for (_k = 0, _len2 = containers.length; _k < _len2; _k++) {
|
||||
container = containers[_k];
|
||||
$.rm(container);
|
||||
}
|
||||
return Unread.update(true);
|
||||
}
|
||||
},
|
||||
kb: function() {
|
||||
var control;
|
||||
|
||||
control = $.id('threadingControl');
|
||||
return control.click();
|
||||
}
|
||||
};
|
||||
|
||||
QuoteYou = {
|
||||
init: function() {
|
||||
if (g.VIEW === 'catalog' || !Conf['Mark Quotes of You'] || !Conf['Quick Reply']) {
|
||||
@ -13356,6 +13516,7 @@
|
||||
'Thread Excerpt': ThreadExcerpt,
|
||||
'Favicon': Favicon,
|
||||
'Unread': Unread,
|
||||
'Quote Threading': QuoteThreading,
|
||||
'Thread Updater': ThreadUpdater,
|
||||
'Thread Stats': ThreadStats,
|
||||
'Thread Watcher': ThreadWatcher,
|
||||
|
||||
@ -301,6 +301,10 @@ Config =
|
||||
true
|
||||
'Add \'(Cross-thread)\' to cross-threads quotes.'
|
||||
]
|
||||
'Quote Threading': [
|
||||
false
|
||||
'Thread conversations'
|
||||
]
|
||||
|
||||
imageExpansion:
|
||||
'Fit width': [
|
||||
|
||||
@ -137,6 +137,7 @@ Main =
|
||||
'Thread Excerpt': ThreadExcerpt
|
||||
'Favicon': Favicon
|
||||
'Unread': Unread
|
||||
'Quote Threading': QuoteThreading
|
||||
'Thread Updater': ThreadUpdater
|
||||
'Thread Stats': ThreadStats
|
||||
'Thread Watcher': ThreadWatcher
|
||||
|
||||
@ -177,7 +177,7 @@ Header =
|
||||
(if hide then $.addClass else $.rmClass) Header.nav, 'autohide'
|
||||
|
||||
hashScroll: ->
|
||||
return unless post = $.id @location.hash[1..]
|
||||
return unless post = @location.hash[1..]
|
||||
return if (Get.postFromRoot post).isHidden
|
||||
Header.scrollToPost post
|
||||
|
||||
|
||||
@ -134,6 +134,7 @@ Keybinds =
|
||||
if quote
|
||||
QR.quote.call $ 'input', $('.post.highlight', thread) or thread
|
||||
do QR.nodes.com.focus
|
||||
$.rmClass $('.qr-shortcut'), 'disabled'
|
||||
|
||||
tags: (tag, ta) ->
|
||||
value = ta.value
|
||||
|
||||
@ -219,7 +219,6 @@ ThreadUpdater =
|
||||
ThreadUpdater.thread.postLimit = !!OP.bumplimit
|
||||
ThreadUpdater.thread.fileLimit = !!OP.imagelimit
|
||||
|
||||
nodes = [] # post container elements
|
||||
posts = [] # post objects
|
||||
index = [] # existing posts
|
||||
files = [] # existing files
|
||||
@ -233,7 +232,6 @@ ThreadUpdater =
|
||||
# Insert new posts, not older ones.
|
||||
count++
|
||||
node = Build.postFromObject postObject, ThreadUpdater.thread.board
|
||||
nodes.push node
|
||||
posts.push new Post node, ThreadUpdater.thread, ThreadUpdater.thread.board
|
||||
|
||||
deletedPosts = []
|
||||
@ -259,6 +257,7 @@ ThreadUpdater =
|
||||
unless count
|
||||
ThreadUpdater.set 'status', null, null
|
||||
ThreadUpdater.outdateCount++
|
||||
|
||||
else
|
||||
ThreadUpdater.set 'status', "+#{count}", 'new'
|
||||
ThreadUpdater.outdateCount = 0
|
||||
@ -272,7 +271,15 @@ ThreadUpdater =
|
||||
|
||||
scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and
|
||||
ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25
|
||||
$.add ThreadUpdater.root, nodes
|
||||
|
||||
for key, post of posts
|
||||
continue unless posts.hasOwnProperty key
|
||||
if post.cb
|
||||
unless post.cb.call post
|
||||
$.add ThreadUpdater.root, post.nodes.root
|
||||
else
|
||||
$.add ThreadUpdater.root, post.nodes.root
|
||||
|
||||
if scroll
|
||||
if Conf['Bottom Scroll']
|
||||
<% if (type === 'crx') { %>d.body<% } else { %>doc<% } %>.scrollTop = d.body.clientHeight
|
||||
|
||||
@ -100,15 +100,20 @@ Unread =
|
||||
|
||||
read: (e) ->
|
||||
return if d.hidden or !Unread.posts.length
|
||||
height = doc.clientHeight
|
||||
for post, i in Unread.posts
|
||||
{bottom} = post.nodes.root.getBoundingClientRect()
|
||||
break if bottom > height # post is not completely read
|
||||
return unless i
|
||||
height = doc.clientHeight
|
||||
{posts} = Unread
|
||||
read = []
|
||||
i = posts.length
|
||||
|
||||
Unread.lastReadPost = Unread.posts[i - 1].ID
|
||||
while post = posts[--i]
|
||||
{bottom, top} = post.nodes.root.getBoundingClientRect()
|
||||
if (bottom < height) and (top > 0) # post is completely read
|
||||
ID = post.ID
|
||||
posts.remove post
|
||||
return unless ID
|
||||
|
||||
Unread.lastReadPost = ID
|
||||
Unread.saveLastReadPost()
|
||||
Unread.posts.splice 0, i
|
||||
Unread.readArray Unread.postsQuotingYou
|
||||
Unread.update() if e
|
||||
|
||||
|
||||
@ -81,6 +81,7 @@ QR =
|
||||
QR.cleanNotifications()
|
||||
d.activeElement.blur()
|
||||
$.rmClass QR.nodes.el, 'dump'
|
||||
$.toggleClass $('.qr-shortcut'), 'disabled'
|
||||
for i in QR.posts
|
||||
QR.posts[0].rm()
|
||||
QR.cooldown.auto = false
|
||||
@ -302,6 +303,8 @@ QR =
|
||||
QR.selected.save com
|
||||
QR.selected.save thread
|
||||
|
||||
$.rmClass $('.qr-shortcut'), 'disabled'
|
||||
|
||||
characterCount: ->
|
||||
counter = QR.nodes.charCount
|
||||
count = QR.nodes.com.textLength
|
||||
|
||||
97
src/code/quoting/quotethreading.coffee
Normal file
97
src/code/quoting/quotethreading.coffee
Normal file
@ -0,0 +1,97 @@
|
||||
###
|
||||
<3 aeosynth
|
||||
###
|
||||
|
||||
QuoteThreading =
|
||||
init: ->
|
||||
return unless Conf['Quote Threading'] and g.VIEW is 'thread'
|
||||
|
||||
@enabled = true
|
||||
@controls = $.el 'span',
|
||||
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>'
|
||||
|
||||
input = $ 'input', @controls
|
||||
$.on input, 'change', QuoteThreading.toggle
|
||||
|
||||
$.event 'AddMenuEntry',
|
||||
type: 'header'
|
||||
el: @controls
|
||||
order: 115
|
||||
|
||||
$.on d, '4chanXInitFinished', @setup
|
||||
|
||||
Post::callbacks.push
|
||||
name: 'Quote Threading'
|
||||
cb: @node
|
||||
|
||||
setup: ->
|
||||
$.off d, '4chanXInitFinished', QuoteThreading.setup
|
||||
{posts} = g
|
||||
|
||||
for ID, post of posts
|
||||
if post.cb
|
||||
post.cb.call post
|
||||
|
||||
QuoteThreading.hasRun = true
|
||||
|
||||
node: ->
|
||||
return if @isClone or not QuoteThreading.enabled or @thread.OP is @
|
||||
|
||||
{quotes, ID, fullID} = @
|
||||
{posts} = g
|
||||
return if !(post = posts[fullID]) or post.isHidden # Filtered
|
||||
|
||||
uniq = {}
|
||||
len = "#{g.BOARD}".length + 1
|
||||
for quote in quotes
|
||||
qid = quote
|
||||
continue unless qid[len..] < ID
|
||||
if qid of posts
|
||||
uniq[qid[len..]] = true
|
||||
|
||||
keys = Object.keys uniq
|
||||
return unless keys.length is 1
|
||||
|
||||
@threaded = "#{g.BOARD}.#{keys[0]}"
|
||||
@cb = QuoteThreading.nodeinsert
|
||||
|
||||
nodeinsert: ->
|
||||
{posts} = g
|
||||
qpost = posts[@threaded]
|
||||
|
||||
delete @threaded
|
||||
delete @cb
|
||||
|
||||
return false if @thread.OP is qpost or (QuoteThreading.hasRun and !Unread.posts.contains qpost)
|
||||
|
||||
qroot = qpost.nodes.root
|
||||
threadContainer = qroot.nextSibling
|
||||
if threadContainer?.className isnt 'threadContainer'
|
||||
threadContainer = $.el 'div',
|
||||
className: 'threadContainer'
|
||||
$.after qroot, threadContainer
|
||||
|
||||
$.add threadContainer, @nodes.root
|
||||
return true
|
||||
|
||||
toggle: ->
|
||||
thread = $ '.thread'
|
||||
replies = $$ '.thread > .replyContainer, .threadContainer > .replyContainer', thread
|
||||
QuoteThreading.enabled = @checked
|
||||
if @checked
|
||||
nodes = (Get.postFromNode reply for reply in replies)
|
||||
Unread.node.call node for node in nodes
|
||||
QuoteThreading.node node for node in nodes
|
||||
else
|
||||
replies.sort (a, b) ->
|
||||
aID = Number a.id[2..]
|
||||
bID = Number b.id[2..]
|
||||
aID - bID
|
||||
$.add thread, replies
|
||||
containers = $$ '.threadContainer', thread
|
||||
$.rm container for container in containers
|
||||
Unread.update true
|
||||
|
||||
kb: ->
|
||||
control = $.id 'threadingControl'
|
||||
control.click()
|
||||
@ -36,7 +36,7 @@ $.extend Array::,
|
||||
args = arguments
|
||||
for arg in args
|
||||
@push.apply @, arg
|
||||
return @
|
||||
return
|
||||
|
||||
remove: (object) ->
|
||||
if (index = @indexOf object) > -1
|
||||
@ -78,6 +78,7 @@ $.extend $,
|
||||
ajax: (url, callbacks, opts={}) ->
|
||||
{type, cred, headers, upCallbacks, form, sync} = opts
|
||||
r = new XMLHttpRequest()
|
||||
r.overrideMimeType 'text/html'
|
||||
type or= form and 'post' or 'get'
|
||||
r.open type, url, !sync
|
||||
for key, val of headers
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user