Finishing up merge, onto testing...

This commit is contained in:
Zixaphir 2015-01-09 23:51:32 -07:00
parent e4dde07c11
commit 409f1f9ecf
7 changed files with 497 additions and 401 deletions

View File

@ -8161,7 +8161,8 @@
QuotePreview = { QuotePreview = {
init: function() { init: function() {
if (!Conf['Quote Previewing']) { var _ref;
if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && Conf['Quote Previewing'])) {
return; return;
} }
if (Conf['Comment Expansion']) { if (Conf['Comment Expansion']) {
@ -8244,7 +8245,8 @@
QuoteStrikeThrough = { QuoteStrikeThrough = {
init: function() { init: function() {
if (!Conf['Post Hiding'] && !Conf['Post Hiding Link'] && !Conf['Filter']) { var _ref;
if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && (Conf['Post Hiding'] || Conf['Post Hiding Link'] || Conf['Filter']))) {
return; return;
} }
return Post.callbacks.push({ return Post.callbacks.push({
@ -8275,164 +8277,181 @@
QuoteThreading = { QuoteThreading = {
init: function() { init: function() {
var input;
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) { if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return; return;
} }
this.enabled = true; this.enabled = true;
this.controls = $.el('span', { this.controls = $.el('span', {
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>' innerHTML: "<label><input id=\"threadingControl\" type=\"checkbox\" checked> Threading</label>"
});
this.threadNewLink = $.el('span', {
className: 'brackets-wrap threadnewlink',
hidden: true
});
$.extend(this.threadNewLink, {
innerHTML: "<a href=\"javascript:;\">Thread New Posts</a>"
});
$.on($('input', this.controls), 'change', function() {
return QuoteThreading.rethread(this.checked);
});
$.on(this.threadNewLink.firstElementChild, 'click', function() {
QuoteThreading.threadNewLink.hidden = true;
return QuoteThreading.rethread(true);
}); });
input = $('input', this.controls);
$.on(input, 'change', this.toggle);
Header.menu.addEntry(this.entry = { Header.menu.addEntry(this.entry = {
el: this.controls, el: this.controls,
order: 98 order: 98
}); });
if (!Conf['Unread Count']) { Thread.callbacks.push({
$.on(d, '4chanXInitFinished', this.ready); name: 'Quote Threading',
} cb: this.setThread
});
return Post.callbacks.push({ return Post.callbacks.push({
name: 'Quote Threading', name: 'Quote Threading',
cb: this.node cb: this.node
}); });
}, },
disconnect: function() { parent: {},
var input; children: {},
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) { inserted: {},
return; setThread: function() {
} QuoteThreading.thread = this;
input = $('input', this.controls); return $.asap((function() {
$.off(input, 'change', this.toggle); return !Conf['Thread Updater'] || $('.navLinksBot > .updatelink');
Header.menu.rmEntry(this.entry); }), function() {
delete this.enabled; return $.add($('.navLinksBot'), [$.tn(' '), QuoteThreading.threadNewLink]);
delete this.controls;
delete this.entry;
return Post.callbacks.disconnect('Quote Threading');
},
ready: function() {
$.off(d, '4chanXInitFinished', QuoteThreading.ready);
return QuoteThreading.force();
},
force: function() {
g.posts.forEach(function(post) {
if (post.cb) {
return post.cb(true);
}
}); });
if (Conf['Unread Count'] && Unread.thread.OP.nodes.root.parentElement.parentElement) {
Unread.read();
return Unread.update();
}
}, },
node: function() { node: function() {
var keys, len, posts, quote, _i, _len, _ref; var parent, parents, quote, thread;
posts = g.posts; if (this.isFetchedQuote || this.isClone || !this.isReply) {
if (this.isClone || !QuoteThreading.enabled) {
return; return;
} }
if (Conf['Unread Count']) { thread = QuoteThreading.thread;
Unread.posts.push(this); parents = (function() {
var _i, _len, _ref, _results;
_ref = this.quotes;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quote = _ref[_i];
parent = g.posts[quote];
if (!parent || parent.isFetchedQuote || !parent.isReply || parent.ID >= this.ID) {
continue;
}
_results.push(parent);
}
return _results;
}).call(this);
if (parents.length === 1) {
return QuoteThreading.parent[this.fullID] = parents[0];
} }
if (this.thread.OP === this || this.isHidden) { },
return; descendants: function(post) {
} var child, children, posts, _i, _len;
keys = []; posts = [post];
len = g.BOARD.ID.length + 1; if (children = QuoteThreading.children[post.fullID]) {
_ref = this.quotes; for (_i = 0, _len = children.length; _i < _len; _i++) {
for (_i = 0, _len = _ref.length; _i < _len; _i++) { child = children[_i];
quote = _ref[_i]; posts = posts.concat(QuoteThreading.descendants(child));
if ((quote.slice(len) < this.ID) && quote in posts) {
keys.push(quote);
} }
} }
if (keys.length !== 1) { return posts;
return;
}
this.threaded = keys[0];
return this.cb = QuoteThreading.nodeinsert;
}, },
nodeinsert: function(force) { insert: function(post) {
var bottom, height, post, posts, root, threadContainer, top, _ref; var child, children, descendants, i, next, nodes, order, parent, prev, prev2, threadContainer, x, _base, _i, _j, _k, _len, _name;
post = g.posts[this.threaded]; if (!(QuoteThreading.enabled && (parent = QuoteThreading.parent[post.fullID]) && !QuoteThreading.inserted[post.fullID])) {
if (this.thread.OP === post) {
return false; return false;
} }
posts = Unread.posts; descendants = QuoteThreading.descendants(post);
root = post.nodes.root; if (!Unread.posts.has(parent.ID) && descendants.some(function(x) {
if (!force) { return Unread.posts.has(x.ID);
height = doc.clientHeight; })) {
_ref = root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top; QuoteThreading.threadNewLink.hidden = false;
if (!((Conf['Unread Count'] && posts[post.ID]) || ((bottom < height) && (top > 0)))) { return false;
return false; }
order = Unread.order;
children = ((_base = QuoteThreading.children)[_name = parent.fullID] || (_base[_name] = []));
threadContainer = parent.nodes.threadContainer || $.el('div', {
className: 'threadContainer'
});
nodes = [post.nodes.root];
if (post.nodes.threadContainer) {
nodes.push(post.nodes.threadContainer);
}
i = children.length;
for (_i = children.length - 1; _i >= 0; _i += -1) {
child = children[_i];
if (child.ID >= post.ID) {
i--;
} }
} }
if ($.hasClass(root, 'threadOP')) { if (i !== children.length) {
threadContainer = root.nextElementSibling; next = children[i];
post = Get.postFromRoot($.x('descendant::div[contains(@class,"postContainer")][last()]', threadContainer)); for (_j = 0, _len = descendants.length; _j < _len; _j++) {
$.add(threadContainer, this.nodes.root); x = descendants[_j];
order.before(order[next.ID], order[x.ID]);
}
children.splice(i, 0, post);
$.before(next.nodes.root, nodes);
} else { } else {
threadContainer = $.el('div', { prev = parent;
className: 'threadContainer' while ((prev2 = QuoteThreading.children[prev.fullID]) && prev2.length) {
}); prev = prev2[prev2.length - 1];
$.add(threadContainer, this.nodes.root); }
$.after(root, threadContainer); for (_k = descendants.length - 1; _k >= 0; _k += -1) {
$.addClass(root, 'threadOP'); x = descendants[_k];
order.after(order[prev.ID], order[x.ID]);
}
children.push(post);
$.add(threadContainer, nodes);
} }
if (!Conf['Unread Count']) { QuoteThreading.inserted[post.fullID] = true;
return true; if (!parent.nodes.threadContainer) {
} parent.nodes.threadContainer = threadContainer;
if (post = posts[post.ID]) { $.addClass(parent.nodes.root, 'threadOP');
posts.after(post, posts[this.ID]); $.after(parent.nodes.root, threadContainer);
} else if (posts[this.ID]) {
posts.prepend(posts[this.ID]);
} }
return true; return true;
}, },
toggle: function() { rethread: function(enabled) {
var container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref; var nodes, posts, thread;
if (QuoteThreading.enabled = this.checked) { thread = QuoteThreading.thread;
QuoteThreading.force(); posts = thread.posts;
if (QuoteThreading.enabled = enabled) {
posts.forEach(QuoteThreading.insert);
} else { } else {
thread = $('.thread');
posts = [];
nodes = []; nodes = [];
g.posts.forEach(function(post) { Unread.order = new RandomAccessList;
if (!(post === post.thread.OP || post.isClone)) { QuoteThreading.inserted = {};
return posts.push(post); posts.forEach(function(post) {
if (post.isFetchedQuote) {
return;
}
Unread.order.push(post);
if (post.isReply) {
nodes.push(post.nodes.root);
}
if (QuoteThreading.children[post.fullID]) {
delete QuoteThreading.children[post.fullID];
$.rmClass(post.nodes.root, 'threadOP');
$.rm(post.nodes.threadContainer);
return delete post.nodes.threadContainer;
} }
}); });
posts.sort(function(a, b) { $.add(thread.OP.nodes.root.parentNode, nodes);
return a.ID - b.ID;
});
for (_i = 0, _len = posts.length; _i < _len; _i++) {
post = posts[_i];
nodes.push(post.nodes.root);
}
$.add(thread, nodes);
containers = $$('.threadContainer', thread);
for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
container = containers[_j];
$.rm(container);
}
_ref = $$('.threadOP');
for (_k = 0, _len2 = _ref.length; _k < _len2; _k++) {
post = _ref[_k];
$.rmClass(post, 'threadOP');
}
} }
}, Unread.position = Unread.order.first;
kb: function() { Unread.updatePosition();
var control; Unread.setLine(true);
control = $.id('threadingControl'); Unread.read();
control.checked = !control.checked; return Unread.update();
return QuoteThreading.toggle.call(control);
} }
}; };
Quotify = { Quotify = {
init: function() { init: function() {
if (!Conf['Resurrect Quotes']) { var _ref;
if (((_ref = g.VIEW) !== 'index' && _ref !== 'thread') || !Conf['Resurrect Quotes'] && g.BOARD.ID !== 'pol') {
return; return;
} }
if (Conf['Comment Expansion']) { if (Conf['Comment Expansion']) {
@ -8458,7 +8477,7 @@
} }
}, },
parseDeadlink: function(deadlink) { parseDeadlink: function(deadlink) {
var a, boardID, m, post, postID, quote, quoteID, redirect, _ref; var a, boardID, fetchable, m, post, postID, quote, quoteID, redirect, _ref;
if ($.hasClass(deadlink.parentNode, 'prettyprint')) { if ($.hasClass(deadlink.parentNode, 'prettyprint')) {
Quotify.fixDeadlink(deadlink); Quotify.fixDeadlink(deadlink);
return; return;
@ -8474,36 +8493,58 @@
boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID; boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
quoteID = "" + boardID + "." + postID; quoteID = "" + boardID + "." + postID;
if (post = g.posts[quoteID]) { if (post = g.posts[quoteID]) {
a = $.el('a', { if (!post.isDead) {
href: Build.path(boardID, post.thread.ID, postID), a = $.el('a', {
className: post.isDead ? 'quotelink deadlink' : 'quotelink', href: Build.postURL(boardID, post.thread.ID, postID),
textContent: quote className: 'quotelink',
}); textContent: quote
$.extend(a.dataset, { });
boardID: boardID, } else {
threadID: post.thread.ID, a = $.el('a', {
postID: postID href: Build.postURL(boardID, post.thread.ID, postID),
}); className: 'quotelink deadlink',
} else if (redirect = Redirect.to('thread', { target: '_blank',
boardID: boardID, textContent: "" + quote + "\u00A0(Dead)"
postID: postID });
})) {
a = $.el('a', {
href: redirect,
className: 'deadlink',
textContent: quote,
target: '_blank'
});
if (Redirect.to('post', {
boardID: boardID,
postID: postID
})) {
$.addClass(a, 'quotelink');
$.extend(a.dataset, { $.extend(a.dataset, {
boardID: boardID, boardID: boardID,
threadID: post.thread.ID,
postID: postID postID: postID
}); });
} }
} else if ((this.board.ID === boardID && boardID === 'pol') && postID.length === 9 && postID[-2] === postID[-1]) {
postID = postID.slice(0, -1);
quoteID = "" + boardID + "." + postID;
a = $.el('a', {
href: Build.postURL(boardID, this.thread.ID, postID),
className: 'quotelink',
textContent: quote
});
} else if (Conf['Resurrect Quotes']) {
redirect = Redirect.to('thread', {
boardID: boardID,
threadID: 0,
postID: postID
});
fetchable = Redirect.to('post', {
boardID: boardID,
postID: postID
});
if (redirect || fetchable) {
a = $.el('a', {
href: redirect || 'javascript:;',
className: 'deadlink',
target: '_blank',
textContent: "" + quote + "\u00A0(Dead)"
});
if (fetchable) {
$.addClass(a, 'quotelink');
$.extend(a.dataset, {
boardID: boardID,
postID: postID
});
}
}
} }
if (__indexOf.call(this.quotes, quoteID) < 0) { if (__indexOf.call(this.quotes, quoteID) < 0) {
this.quotes.push(quoteID); this.quotes.push(quoteID);
@ -10388,7 +10429,7 @@
return function(persona) { return function(persona) {
_this.name = 'name' in QR.persona.always ? QR.persona.always.name : prev ? prev.name : persona.name; _this.name = 'name' in QR.persona.always ? QR.persona.always.name : prev ? prev.name : persona.name;
_this.email = 'email' in QR.persona.always ? QR.persona.always.email : prev && !/^sage$/.test(prev.email) ? prev.email : persona.email; _this.email = 'email' in QR.persona.always ? QR.persona.always.email : prev && !/^sage$/.test(prev.email) ? prev.email : persona.email;
_this.sub = 'sub' in QR.persona.always ? QR.persona.always.sub : Conf['Remember Subject'] ? prev ? prev.sub : persona.sub : ''; _this.sub = 'sub' in QR.persona.always ? QR.persona.always.sub : '';
if (QR.nodes.flag) { if (QR.nodes.flag) {
_this.flag = prev ? prev.flag : persona.flag; _this.flag = prev ? prev.flag : persona.flag;
} }

View File

@ -8206,7 +8206,8 @@
QuotePreview = { QuotePreview = {
init: function() { init: function() {
if (!Conf['Quote Previewing']) { var _ref;
if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && Conf['Quote Previewing'])) {
return; return;
} }
if (Conf['Comment Expansion']) { if (Conf['Comment Expansion']) {
@ -8289,7 +8290,8 @@
QuoteStrikeThrough = { QuoteStrikeThrough = {
init: function() { init: function() {
if (!Conf['Post Hiding'] && !Conf['Post Hiding Link'] && !Conf['Filter']) { var _ref;
if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && (Conf['Post Hiding'] || Conf['Post Hiding Link'] || Conf['Filter']))) {
return; return;
} }
return Post.callbacks.push({ return Post.callbacks.push({
@ -8320,164 +8322,181 @@
QuoteThreading = { QuoteThreading = {
init: function() { init: function() {
var input;
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) { if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return; return;
} }
this.enabled = true; this.enabled = true;
this.controls = $.el('span', { this.controls = $.el('span', {
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>' innerHTML: "<label><input id=\"threadingControl\" type=\"checkbox\" checked> Threading</label>"
});
this.threadNewLink = $.el('span', {
className: 'brackets-wrap threadnewlink',
hidden: true
});
$.extend(this.threadNewLink, {
innerHTML: "<a href=\"javascript:;\">Thread New Posts</a>"
});
$.on($('input', this.controls), 'change', function() {
return QuoteThreading.rethread(this.checked);
});
$.on(this.threadNewLink.firstElementChild, 'click', function() {
QuoteThreading.threadNewLink.hidden = true;
return QuoteThreading.rethread(true);
}); });
input = $('input', this.controls);
$.on(input, 'change', this.toggle);
Header.menu.addEntry(this.entry = { Header.menu.addEntry(this.entry = {
el: this.controls, el: this.controls,
order: 98 order: 98
}); });
if (!Conf['Unread Count']) { Thread.callbacks.push({
$.on(d, '4chanXInitFinished', this.ready); name: 'Quote Threading',
} cb: this.setThread
});
return Post.callbacks.push({ return Post.callbacks.push({
name: 'Quote Threading', name: 'Quote Threading',
cb: this.node cb: this.node
}); });
}, },
disconnect: function() { parent: {},
var input; children: {},
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) { inserted: {},
return; setThread: function() {
} QuoteThreading.thread = this;
input = $('input', this.controls); return $.asap((function() {
$.off(input, 'change', this.toggle); return !Conf['Thread Updater'] || $('.navLinksBot > .updatelink');
Header.menu.rmEntry(this.entry); }), function() {
delete this.enabled; return $.add($('.navLinksBot'), [$.tn(' '), QuoteThreading.threadNewLink]);
delete this.controls;
delete this.entry;
return Post.callbacks.disconnect('Quote Threading');
},
ready: function() {
$.off(d, '4chanXInitFinished', QuoteThreading.ready);
return QuoteThreading.force();
},
force: function() {
g.posts.forEach(function(post) {
if (post.cb) {
return post.cb(true);
}
}); });
if (Conf['Unread Count'] && Unread.thread.OP.nodes.root.parentElement.parentElement) {
Unread.read();
return Unread.update();
}
}, },
node: function() { node: function() {
var keys, len, posts, quote, _i, _len, _ref; var parent, parents, quote, thread;
posts = g.posts; if (this.isFetchedQuote || this.isClone || !this.isReply) {
if (this.isClone || !QuoteThreading.enabled) {
return; return;
} }
if (Conf['Unread Count']) { thread = QuoteThreading.thread;
Unread.posts.push(this); parents = (function() {
var _i, _len, _ref, _results;
_ref = this.quotes;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quote = _ref[_i];
parent = g.posts[quote];
if (!parent || parent.isFetchedQuote || !parent.isReply || parent.ID >= this.ID) {
continue;
}
_results.push(parent);
}
return _results;
}).call(this);
if (parents.length === 1) {
return QuoteThreading.parent[this.fullID] = parents[0];
} }
if (this.thread.OP === this || this.isHidden) { },
return; descendants: function(post) {
} var child, children, posts, _i, _len;
keys = []; posts = [post];
len = g.BOARD.ID.length + 1; if (children = QuoteThreading.children[post.fullID]) {
_ref = this.quotes; for (_i = 0, _len = children.length; _i < _len; _i++) {
for (_i = 0, _len = _ref.length; _i < _len; _i++) { child = children[_i];
quote = _ref[_i]; posts = posts.concat(QuoteThreading.descendants(child));
if ((quote.slice(len) < this.ID) && quote in posts) {
keys.push(quote);
} }
} }
if (keys.length !== 1) { return posts;
return;
}
this.threaded = keys[0];
return this.cb = QuoteThreading.nodeinsert;
}, },
nodeinsert: function(force) { insert: function(post) {
var bottom, height, post, posts, root, threadContainer, top, _ref; var child, children, descendants, i, next, nodes, order, parent, prev, prev2, threadContainer, x, _base, _i, _j, _k, _len, _name;
post = g.posts[this.threaded]; if (!(QuoteThreading.enabled && (parent = QuoteThreading.parent[post.fullID]) && !QuoteThreading.inserted[post.fullID])) {
if (this.thread.OP === post) {
return false; return false;
} }
posts = Unread.posts; descendants = QuoteThreading.descendants(post);
root = post.nodes.root; if (!Unread.posts.has(parent.ID) && descendants.some(function(x) {
if (!force) { return Unread.posts.has(x.ID);
height = doc.clientHeight; })) {
_ref = root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top; QuoteThreading.threadNewLink.hidden = false;
if (!((Conf['Unread Count'] && posts[post.ID]) || ((bottom < height) && (top > 0)))) { return false;
return false; }
order = Unread.order;
children = ((_base = QuoteThreading.children)[_name = parent.fullID] || (_base[_name] = []));
threadContainer = parent.nodes.threadContainer || $.el('div', {
className: 'threadContainer'
});
nodes = [post.nodes.root];
if (post.nodes.threadContainer) {
nodes.push(post.nodes.threadContainer);
}
i = children.length;
for (_i = children.length - 1; _i >= 0; _i += -1) {
child = children[_i];
if (child.ID >= post.ID) {
i--;
} }
} }
if ($.hasClass(root, 'threadOP')) { if (i !== children.length) {
threadContainer = root.nextElementSibling; next = children[i];
post = Get.postFromRoot($.x('descendant::div[contains(@class,"postContainer")][last()]', threadContainer)); for (_j = 0, _len = descendants.length; _j < _len; _j++) {
$.add(threadContainer, this.nodes.root); x = descendants[_j];
order.before(order[next.ID], order[x.ID]);
}
children.splice(i, 0, post);
$.before(next.nodes.root, nodes);
} else { } else {
threadContainer = $.el('div', { prev = parent;
className: 'threadContainer' while ((prev2 = QuoteThreading.children[prev.fullID]) && prev2.length) {
}); prev = prev2[prev2.length - 1];
$.add(threadContainer, this.nodes.root); }
$.after(root, threadContainer); for (_k = descendants.length - 1; _k >= 0; _k += -1) {
$.addClass(root, 'threadOP'); x = descendants[_k];
order.after(order[prev.ID], order[x.ID]);
}
children.push(post);
$.add(threadContainer, nodes);
} }
if (!Conf['Unread Count']) { QuoteThreading.inserted[post.fullID] = true;
return true; if (!parent.nodes.threadContainer) {
} parent.nodes.threadContainer = threadContainer;
if (post = posts[post.ID]) { $.addClass(parent.nodes.root, 'threadOP');
posts.after(post, posts[this.ID]); $.after(parent.nodes.root, threadContainer);
} else if (posts[this.ID]) {
posts.prepend(posts[this.ID]);
} }
return true; return true;
}, },
toggle: function() { rethread: function(enabled) {
var container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref; var nodes, posts, thread;
if (QuoteThreading.enabled = this.checked) { thread = QuoteThreading.thread;
QuoteThreading.force(); posts = thread.posts;
if (QuoteThreading.enabled = enabled) {
posts.forEach(QuoteThreading.insert);
} else { } else {
thread = $('.thread');
posts = [];
nodes = []; nodes = [];
g.posts.forEach(function(post) { Unread.order = new RandomAccessList;
if (!(post === post.thread.OP || post.isClone)) { QuoteThreading.inserted = {};
return posts.push(post); posts.forEach(function(post) {
if (post.isFetchedQuote) {
return;
}
Unread.order.push(post);
if (post.isReply) {
nodes.push(post.nodes.root);
}
if (QuoteThreading.children[post.fullID]) {
delete QuoteThreading.children[post.fullID];
$.rmClass(post.nodes.root, 'threadOP');
$.rm(post.nodes.threadContainer);
return delete post.nodes.threadContainer;
} }
}); });
posts.sort(function(a, b) { $.add(thread.OP.nodes.root.parentNode, nodes);
return a.ID - b.ID;
});
for (_i = 0, _len = posts.length; _i < _len; _i++) {
post = posts[_i];
nodes.push(post.nodes.root);
}
$.add(thread, nodes);
containers = $$('.threadContainer', thread);
for (_j = 0, _len1 = containers.length; _j < _len1; _j++) {
container = containers[_j];
$.rm(container);
}
_ref = $$('.threadOP');
for (_k = 0, _len2 = _ref.length; _k < _len2; _k++) {
post = _ref[_k];
$.rmClass(post, 'threadOP');
}
} }
}, Unread.position = Unread.order.first;
kb: function() { Unread.updatePosition();
var control; Unread.setLine(true);
control = $.id('threadingControl'); Unread.read();
control.checked = !control.checked; return Unread.update();
return QuoteThreading.toggle.call(control);
} }
}; };
Quotify = { Quotify = {
init: function() { init: function() {
if (!Conf['Resurrect Quotes']) { var _ref;
if (((_ref = g.VIEW) !== 'index' && _ref !== 'thread') || !Conf['Resurrect Quotes'] && g.BOARD.ID !== 'pol') {
return; return;
} }
if (Conf['Comment Expansion']) { if (Conf['Comment Expansion']) {
@ -8503,7 +8522,7 @@
} }
}, },
parseDeadlink: function(deadlink) { parseDeadlink: function(deadlink) {
var a, boardID, m, post, postID, quote, quoteID, redirect, _ref; var a, boardID, fetchable, m, post, postID, quote, quoteID, redirect, _ref;
if ($.hasClass(deadlink.parentNode, 'prettyprint')) { if ($.hasClass(deadlink.parentNode, 'prettyprint')) {
Quotify.fixDeadlink(deadlink); Quotify.fixDeadlink(deadlink);
return; return;
@ -8519,36 +8538,58 @@
boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID; boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
quoteID = "" + boardID + "." + postID; quoteID = "" + boardID + "." + postID;
if (post = g.posts[quoteID]) { if (post = g.posts[quoteID]) {
a = $.el('a', { if (!post.isDead) {
href: Build.path(boardID, post.thread.ID, postID), a = $.el('a', {
className: post.isDead ? 'quotelink deadlink' : 'quotelink', href: Build.postURL(boardID, post.thread.ID, postID),
textContent: quote className: 'quotelink',
}); textContent: quote
$.extend(a.dataset, { });
boardID: boardID, } else {
threadID: post.thread.ID, a = $.el('a', {
postID: postID href: Build.postURL(boardID, post.thread.ID, postID),
}); className: 'quotelink deadlink',
} else if (redirect = Redirect.to('thread', { target: '_blank',
boardID: boardID, textContent: "" + quote + "\u00A0(Dead)"
postID: postID });
})) {
a = $.el('a', {
href: redirect,
className: 'deadlink',
textContent: quote,
target: '_blank'
});
if (Redirect.to('post', {
boardID: boardID,
postID: postID
})) {
$.addClass(a, 'quotelink');
$.extend(a.dataset, { $.extend(a.dataset, {
boardID: boardID, boardID: boardID,
threadID: post.thread.ID,
postID: postID postID: postID
}); });
} }
} else if ((this.board.ID === boardID && boardID === 'pol') && postID.length === 9 && postID[-2] === postID[-1]) {
postID = postID.slice(0, -1);
quoteID = "" + boardID + "." + postID;
a = $.el('a', {
href: Build.postURL(boardID, this.thread.ID, postID),
className: 'quotelink',
textContent: quote
});
} else if (Conf['Resurrect Quotes']) {
redirect = Redirect.to('thread', {
boardID: boardID,
threadID: 0,
postID: postID
});
fetchable = Redirect.to('post', {
boardID: boardID,
postID: postID
});
if (redirect || fetchable) {
a = $.el('a', {
href: redirect || 'javascript:;',
className: 'deadlink',
target: '_blank',
textContent: "" + quote + "\u00A0(Dead)"
});
if (fetchable) {
$.addClass(a, 'quotelink');
$.extend(a.dataset, {
boardID: boardID,
postID: postID
});
}
}
} }
if (__indexOf.call(this.quotes, quoteID) < 0) { if (__indexOf.call(this.quotes, quoteID) < 0) {
this.quotes.push(quoteID); this.quotes.push(quoteID);
@ -10431,7 +10472,7 @@
return function(persona) { return function(persona) {
_this.name = 'name' in QR.persona.always ? QR.persona.always.name : prev ? prev.name : persona.name; _this.name = 'name' in QR.persona.always ? QR.persona.always.name : prev ? prev.name : persona.name;
_this.email = 'email' in QR.persona.always ? QR.persona.always.email : prev && !/^sage$/.test(prev.email) ? prev.email : persona.email; _this.email = 'email' in QR.persona.always ? QR.persona.always.email : prev && !/^sage$/.test(prev.email) ? prev.email : persona.email;
_this.sub = 'sub' in QR.persona.always ? QR.persona.always.sub : Conf['Remember Subject'] ? prev ? prev.sub : persona.sub : ''; _this.sub = 'sub' in QR.persona.always ? QR.persona.always.sub : '';
if (QR.nodes.flag) { if (QR.nodes.flag) {
_this.flag = prev ? prev.flag : persona.flag; _this.flag = prev ? prev.flag : persona.flag;
} }

View File

@ -52,8 +52,6 @@ QR.post = class
@sub = if 'sub' of QR.persona.always @sub = if 'sub' of QR.persona.always
QR.persona.always.sub QR.persona.always.sub
else if Conf['Remember Subject']
if prev then prev.sub else persona.sub
else else
'' ''

View File

@ -1,6 +1,6 @@
QuotePreview = QuotePreview =
init: -> init: ->
return if !Conf['Quote Previewing'] return unless g.VIEW in ['index', 'thread'] and Conf['Quote Previewing']
if Conf['Comment Expansion'] if Conf['Comment Expansion']
ExpandComment.callbacks.push @node ExpandComment.callbacks.push @node

View File

@ -1,6 +1,7 @@
QuoteStrikeThrough = QuoteStrikeThrough =
init: -> init: ->
return if !Conf['Post Hiding'] and !Conf['Post Hiding Link'] and !Conf['Filter'] return unless g.VIEW in ['index', 'thread'] and
(Conf['Post Hiding'] or Conf['Post Hiding Link'] or Conf['Filter'])
Post.callbacks.push Post.callbacks.push
name: 'Strike-through Quotes' name: 'Strike-through Quotes'

View File

@ -8,123 +8,118 @@ QuoteThreading =
@enabled = true @enabled = true
@controls = $.el 'span', @controls = $.el 'span',
innerHTML: '<label><input id=threadingControl type=checkbox checked> Threading</label>' <%= html('<label><input id="threadingControl" type="checkbox" checked> Threading</label>') %>
@threadNewLink = $.el 'span',
className: 'brackets-wrap threadnewlink'
hidden: true
$.extend @threadNewLink, <%= html('<a href="javascript:;">Thread New Posts</a>') %>
input = $ 'input', @controls $.on $('input', @controls), 'change', ->
$.on input, 'change', @toggle QuoteThreading.rethread @checked
$.on @threadNewLink.firstElementChild, 'click', ->
QuoteThreading.threadNewLink.hidden = true
QuoteThreading.rethread true
Header.menu.addEntry @entry = Header.menu.addEntry @entry =
el: @controls el: @controls
order: 98 order: 98
$.on d, '4chanXInitFinished', @ready unless Conf['Unread Count'] Thread.callbacks.push
name: 'Quote Threading'
cb: @setThread
Post.callbacks.push Post.callbacks.push
name: 'Quote Threading' name: 'Quote Threading'
cb: @node cb: @node
disconnect: -> parent: {}
return unless Conf['Quote Threading'] and g.VIEW is 'thread' children: {}
input = $ 'input', @controls inserted: {}
$.off input, 'change', @toggle
Header.menu.rmEntry @entry setThread: ->
QuoteThreading.thread = @
delete @enabled $.asap (-> !Conf['Thread Updater'] or $ '.navLinksBot > .updatelink'), ->
delete @controls $.add $('.navLinksBot'), [$.tn(' '), QuoteThreading.threadNewLink]
delete @entry
Post.callbacks.disconnect 'Quote Threading'
ready: ->
$.off d, '4chanXInitFinished', QuoteThreading.ready
QuoteThreading.force()
force: ->
g.posts.forEach (post) ->
post.cb true if post.cb
if Conf['Unread Count'] and Unread.thread.OP.nodes.root.parentElement.parentElement
Unread.read()
Unread.update()
node: -> node: ->
{posts} = g return if @isFetchedQuote or @isClone or !@isReply
return if @isClone or not QuoteThreading.enabled {thread} = QuoteThreading
parents = for quote in @quotes
parent = g.posts[quote]
continue if !parent or parent.isFetchedQuote or !parent.isReply or parent.ID >= @ID
parent
if parents.length is 1
QuoteThreading.parent[@fullID] = parents[0]
Unread.posts.push @ if Conf['Unread Count'] descendants: (post) ->
return if @thread.OP is @ or @isHidden # Filtered posts = [post]
if children = QuoteThreading.children[post.fullID]
for child in children
posts = posts.concat QuoteThreading.descendants child
posts
keys = [] insert: (post) ->
len = g.BOARD.ID.length + 1 return false unless QuoteThreading.enabled and
keys.push quote for quote in @quotes when (quote[len..] < @ID) and quote of posts (parent = QuoteThreading.parent[post.fullID]) and
!QuoteThreading.inserted[post.fullID]
return unless keys.length is 1 descendants = QuoteThreading.descendants post
if !Unread.posts.has(parent.ID) and descendants.some((x) -> Unread.posts.has(x.ID))
QuoteThreading.threadNewLink.hidden = false
return false
@threaded = keys[0] {order} = Unread
@cb = QuoteThreading.nodeinsert children = (QuoteThreading.children[parent.fullID] or= [])
threadContainer = parent.nodes.threadContainer or $.el 'div', className: 'threadContainer'
nodeinsert: (force) -> nodes = [post.nodes.root]
post = g.posts[@threaded] nodes.push post.nodes.threadContainer if post.nodes.threadContainer
return false if @thread.OP is post
{posts} = Unread
{root} = post.nodes
unless force
height = doc.clientHeight
{bottom, top} = root.getBoundingClientRect()
# Post is unread or is fully visible.
return false unless (Conf['Unread Count'] and posts[post.ID]) or ((bottom < height) and (top > 0))
if $.hasClass root, 'threadOP'
threadContainer = root.nextElementSibling
post = Get.postFromRoot $.x 'descendant::div[contains(@class,"postContainer")][last()]', threadContainer
$.add threadContainer, @nodes.root
i = children.length
i-- for child in children by -1 when child.ID >= post.ID
if i isnt children.length
next = children[i]
order.before order[next.ID], order[x.ID] for x in descendants
children.splice i, 0, post
$.before next.nodes.root, nodes
else else
threadContainer = $.el 'div', prev = parent
className: 'threadContainer' while (prev2 = QuoteThreading.children[prev.fullID]) and prev2.length
$.add threadContainer, @nodes.root prev = prev2[prev2.length-1]
$.after root, threadContainer order.after order[prev.ID], order[x.ID] for x in descendants by -1
$.addClass root, 'threadOP' children.push post
$.add threadContainer, nodes
return true unless Conf['Unread Count'] QuoteThreading.inserted[post.fullID] = true
if post = posts[post.ID] unless parent.nodes.threadContainer
posts.after post, posts[@ID] parent.nodes.threadContainer = threadContainer
$.addClass parent.nodes.root, 'threadOP'
else if posts[@ID] $.after parent.nodes.root, threadContainer
posts.prepend posts[@ID]
return true return true
toggle: -> rethread: (enabled) ->
if QuoteThreading.enabled = @checked {thread} = QuoteThreading
QuoteThreading.force() {posts} = thread
if QuoteThreading.enabled = enabled
posts.forEach QuoteThreading.insert
else else
thread = $('.thread')
posts = []
nodes = [] nodes = []
Unread.order = new RandomAccessList
g.posts.forEach (post) -> QuoteThreading.inserted = {}
posts.push post unless post is post.thread.OP or post.isClone posts.forEach (post) ->
return if post.isFetchedQuote
Unread.order.push post
nodes.push post.nodes.root if post.isReply
if QuoteThreading.children[post.fullID]
delete QuoteThreading.children[post.fullID]
$.rmClass post.nodes.root, 'threadOP'
$.rm post.nodes.threadContainer
delete post.nodes.threadContainer
$.add thread.OP.nodes.root.parentNode, nodes
posts.sort (a, b) -> a.ID - b.ID Unread.position = Unread.order.first
Unread.updatePosition()
nodes.push post.nodes.root for post in posts Unread.setLine true
$.add thread, nodes Unread.read()
Unread.update()
containers = $$ '.threadContainer', thread
$.rm container for container in containers
$.rmClass post, 'threadOP' for post in $$ '.threadOP'
return
kb: ->
control = $.id 'threadingControl'
control.checked = not control.checked
QuoteThreading.toggle.call control

View File

@ -1,6 +1,6 @@
Quotify = Quotify =
init: -> init: ->
return if !Conf['Resurrect Quotes'] return if g.VIEW not in ['index', 'thread'] or !Conf['Resurrect Quotes'] and g.BOARD.ID isnt 'pol'
if Conf['Comment Expansion'] if Conf['Comment Expansion']
ExpandComment.callbacks.push @node ExpandComment.callbacks.push @node
@ -41,25 +41,45 @@ Quotify =
quoteID = "#{boardID}.#{postID}" quoteID = "#{boardID}.#{postID}"
if post = g.posts[quoteID] if post = g.posts[quoteID]
# Don't add 'deadlink' when quotifying in an archived post, unless post.isDead
# and we don't know if the post died yet. # Don't (Dead) when quotifying in an archived post,
a = $.el 'a', # and we know the post still exists.
href: Build.path boardID, post.thread.ID, postID a = $.el 'a',
className: if post.isDead then 'quotelink deadlink' else 'quotelink' href: Build.postURL boardID, post.thread.ID, postID
textContent: quote className: 'quotelink'
$.extend a.dataset, {boardID, threadID: post.thread.ID, postID} textContent: quote
else
# Replace the .deadlink span if we can redirect.
a = $.el 'a',
href: Build.postURL boardID, post.thread.ID, postID
className: 'quotelink deadlink'
target: '_blank'
textContent: "#{quote}\u00A0(Dead)"
$.extend a.dataset, {boardID, threadID: post.thread.ID, postID}
else if redirect = Redirect.to 'thread', {boardID, postID} else if @board.ID is boardID is 'pol' and postID.length is 9 and postID[-2] is postID[-1]
# Replace the .deadlink span if we can redirect. # XXX Misquotes due to fake doubles on /pol/. Assume they are all intra-thread.
postID = postID[...-1]
quoteID = "#{boardID}.#{postID}"
a = $.el 'a', a = $.el 'a',
href: redirect href: Build.postURL boardID, @thread.ID, postID
className: 'deadlink' className: 'quotelink'
textContent: quote textContent: quote
target: '_blank'
if Redirect.to 'post', {boardID, postID} else if Conf['Resurrect Quotes']
# Make it function as a normal quote if we can fetch the post. redirect = Redirect.to 'thread', {boardID, threadID: 0, postID}
$.addClass a, 'quotelink' fetchable = Redirect.to 'post', {boardID, postID}
$.extend a.dataset, {boardID, postID} if redirect or fetchable
# Replace the .deadlink span if we can redirect or fetch the post.
a = $.el 'a',
href: redirect or 'javascript:;'
className: 'deadlink'
target: '_blank'
textContent: "#{quote}\u00A0(Dead)"
if fetchable
# Make it function as a normal quote if we can fetch the post.
$.addClass a, 'quotelink'
$.extend a.dataset, {boardID, postID}
@quotes.push quoteID unless quoteID in @quotes @quotes.push quoteID unless quoteID in @quotes