diff --git a/builds/appchan-x.user.js b/builds/appchan-x.user.js
index 9cf4abd8a..1f66ee70a 100644
--- a/builds/appchan-x.user.js
+++ b/builds/appchan-x.user.js
@@ -8161,7 +8161,8 @@
QuotePreview = {
init: function() {
- if (!Conf['Quote Previewing']) {
+ var _ref;
+ if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && Conf['Quote Previewing'])) {
return;
}
if (Conf['Comment Expansion']) {
@@ -8244,7 +8245,8 @@
QuoteStrikeThrough = {
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 Post.callbacks.push({
@@ -8275,164 +8277,181 @@
QuoteThreading = {
init: function() {
- var input;
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
this.enabled = true;
this.controls = $.el('span', {
- innerHTML: ''
+ innerHTML: ""
+ });
+ this.threadNewLink = $.el('span', {
+ className: 'brackets-wrap threadnewlink',
+ hidden: true
+ });
+ $.extend(this.threadNewLink, {
+ innerHTML: "Thread New Posts"
+ });
+ $.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 = {
el: this.controls,
order: 98
});
- if (!Conf['Unread Count']) {
- $.on(d, '4chanXInitFinished', this.ready);
- }
+ Thread.callbacks.push({
+ name: 'Quote Threading',
+ cb: this.setThread
+ });
return Post.callbacks.push({
name: 'Quote Threading',
cb: this.node
});
},
- disconnect: function() {
- var input;
- if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
- return;
- }
- input = $('input', this.controls);
- $.off(input, 'change', this.toggle);
- Header.menu.rmEntry(this.entry);
- delete this.enabled;
- 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);
- }
+ parent: {},
+ children: {},
+ inserted: {},
+ setThread: function() {
+ QuoteThreading.thread = this;
+ return $.asap((function() {
+ return !Conf['Thread Updater'] || $('.navLinksBot > .updatelink');
+ }), function() {
+ return $.add($('.navLinksBot'), [$.tn(' '), QuoteThreading.threadNewLink]);
});
- if (Conf['Unread Count'] && Unread.thread.OP.nodes.root.parentElement.parentElement) {
- Unread.read();
- return Unread.update();
- }
},
node: function() {
- var keys, len, posts, quote, _i, _len, _ref;
- posts = g.posts;
- if (this.isClone || !QuoteThreading.enabled) {
+ var parent, parents, quote, thread;
+ if (this.isFetchedQuote || this.isClone || !this.isReply) {
return;
}
- if (Conf['Unread Count']) {
- Unread.posts.push(this);
+ thread = QuoteThreading.thread;
+ 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;
- }
- keys = [];
- len = g.BOARD.ID.length + 1;
- _ref = this.quotes;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- if ((quote.slice(len) < this.ID) && quote in posts) {
- keys.push(quote);
+ },
+ descendants: function(post) {
+ var child, children, posts, _i, _len;
+ posts = [post];
+ if (children = QuoteThreading.children[post.fullID]) {
+ for (_i = 0, _len = children.length; _i < _len; _i++) {
+ child = children[_i];
+ posts = posts.concat(QuoteThreading.descendants(child));
}
}
- if (keys.length !== 1) {
- return;
- }
- this.threaded = keys[0];
- return this.cb = QuoteThreading.nodeinsert;
+ return posts;
},
- nodeinsert: function(force) {
- var bottom, height, post, posts, root, threadContainer, top, _ref;
- post = g.posts[this.threaded];
- if (this.thread.OP === post) {
+ insert: function(post) {
+ var child, children, descendants, i, next, nodes, order, parent, prev, prev2, threadContainer, x, _base, _i, _j, _k, _len, _name;
+ if (!(QuoteThreading.enabled && (parent = QuoteThreading.parent[post.fullID]) && !QuoteThreading.inserted[post.fullID])) {
return false;
}
- posts = Unread.posts;
- root = post.nodes.root;
- if (!force) {
- height = doc.clientHeight;
- _ref = root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
- if (!((Conf['Unread Count'] && posts[post.ID]) || ((bottom < height) && (top > 0)))) {
- return false;
+ descendants = QuoteThreading.descendants(post);
+ if (!Unread.posts.has(parent.ID) && descendants.some(function(x) {
+ return Unread.posts.has(x.ID);
+ })) {
+ QuoteThreading.threadNewLink.hidden = 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')) {
- threadContainer = root.nextElementSibling;
- post = Get.postFromRoot($.x('descendant::div[contains(@class,"postContainer")][last()]', threadContainer));
- $.add(threadContainer, this.nodes.root);
+ if (i !== children.length) {
+ next = children[i];
+ for (_j = 0, _len = descendants.length; _j < _len; _j++) {
+ x = descendants[_j];
+ order.before(order[next.ID], order[x.ID]);
+ }
+ children.splice(i, 0, post);
+ $.before(next.nodes.root, nodes);
} else {
- threadContainer = $.el('div', {
- className: 'threadContainer'
- });
- $.add(threadContainer, this.nodes.root);
- $.after(root, threadContainer);
- $.addClass(root, 'threadOP');
+ prev = parent;
+ while ((prev2 = QuoteThreading.children[prev.fullID]) && prev2.length) {
+ prev = prev2[prev2.length - 1];
+ }
+ for (_k = descendants.length - 1; _k >= 0; _k += -1) {
+ x = descendants[_k];
+ order.after(order[prev.ID], order[x.ID]);
+ }
+ children.push(post);
+ $.add(threadContainer, nodes);
}
- if (!Conf['Unread Count']) {
- return true;
- }
- if (post = posts[post.ID]) {
- posts.after(post, posts[this.ID]);
- } else if (posts[this.ID]) {
- posts.prepend(posts[this.ID]);
+ QuoteThreading.inserted[post.fullID] = true;
+ if (!parent.nodes.threadContainer) {
+ parent.nodes.threadContainer = threadContainer;
+ $.addClass(parent.nodes.root, 'threadOP');
+ $.after(parent.nodes.root, threadContainer);
}
return true;
},
- toggle: function() {
- var container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref;
- if (QuoteThreading.enabled = this.checked) {
- QuoteThreading.force();
+ rethread: function(enabled) {
+ var nodes, posts, thread;
+ thread = QuoteThreading.thread;
+ posts = thread.posts;
+ if (QuoteThreading.enabled = enabled) {
+ posts.forEach(QuoteThreading.insert);
} else {
- thread = $('.thread');
- posts = [];
nodes = [];
- g.posts.forEach(function(post) {
- if (!(post === post.thread.OP || post.isClone)) {
- return posts.push(post);
+ Unread.order = new RandomAccessList;
+ QuoteThreading.inserted = {};
+ 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) {
- 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');
- }
+ $.add(thread.OP.nodes.root.parentNode, nodes);
}
- },
- kb: function() {
- var control;
- control = $.id('threadingControl');
- control.checked = !control.checked;
- return QuoteThreading.toggle.call(control);
+ Unread.position = Unread.order.first;
+ Unread.updatePosition();
+ Unread.setLine(true);
+ Unread.read();
+ return Unread.update();
}
};
Quotify = {
init: function() {
- if (!Conf['Resurrect Quotes']) {
+ var _ref;
+ if (((_ref = g.VIEW) !== 'index' && _ref !== 'thread') || !Conf['Resurrect Quotes'] && g.BOARD.ID !== 'pol') {
return;
}
if (Conf['Comment Expansion']) {
@@ -8458,7 +8477,7 @@
}
},
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')) {
Quotify.fixDeadlink(deadlink);
return;
@@ -8474,36 +8493,58 @@
boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
quoteID = "" + boardID + "." + postID;
if (post = g.posts[quoteID]) {
- a = $.el('a', {
- href: Build.path(boardID, post.thread.ID, postID),
- className: post.isDead ? 'quotelink deadlink' : 'quotelink',
- textContent: quote
- });
- $.extend(a.dataset, {
- boardID: boardID,
- threadID: post.thread.ID,
- postID: postID
- });
- } else if (redirect = Redirect.to('thread', {
- boardID: boardID,
- postID: postID
- })) {
- a = $.el('a', {
- href: redirect,
- className: 'deadlink',
- textContent: quote,
- target: '_blank'
- });
- if (Redirect.to('post', {
- boardID: boardID,
- postID: postID
- })) {
- $.addClass(a, 'quotelink');
+ if (!post.isDead) {
+ a = $.el('a', {
+ href: Build.postURL(boardID, post.thread.ID, postID),
+ className: 'quotelink',
+ textContent: quote
+ });
+ } else {
+ a = $.el('a', {
+ href: Build.postURL(boardID, post.thread.ID, postID),
+ className: 'quotelink deadlink',
+ target: '_blank',
+ textContent: "" + quote + "\u00A0(Dead)"
+ });
$.extend(a.dataset, {
boardID: boardID,
+ threadID: post.thread.ID,
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) {
this.quotes.push(quoteID);
@@ -10388,7 +10429,7 @@
return function(persona) {
_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.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) {
_this.flag = prev ? prev.flag : persona.flag;
}
diff --git a/builds/crx/script.js b/builds/crx/script.js
index 53dd87c7a..0149484cc 100644
--- a/builds/crx/script.js
+++ b/builds/crx/script.js
@@ -8206,7 +8206,8 @@
QuotePreview = {
init: function() {
- if (!Conf['Quote Previewing']) {
+ var _ref;
+ if (!(((_ref = g.VIEW) === 'index' || _ref === 'thread') && Conf['Quote Previewing'])) {
return;
}
if (Conf['Comment Expansion']) {
@@ -8289,7 +8290,8 @@
QuoteStrikeThrough = {
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 Post.callbacks.push({
@@ -8320,164 +8322,181 @@
QuoteThreading = {
init: function() {
- var input;
if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
return;
}
this.enabled = true;
this.controls = $.el('span', {
- innerHTML: ''
+ innerHTML: ""
+ });
+ this.threadNewLink = $.el('span', {
+ className: 'brackets-wrap threadnewlink',
+ hidden: true
+ });
+ $.extend(this.threadNewLink, {
+ innerHTML: "Thread New Posts"
+ });
+ $.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 = {
el: this.controls,
order: 98
});
- if (!Conf['Unread Count']) {
- $.on(d, '4chanXInitFinished', this.ready);
- }
+ Thread.callbacks.push({
+ name: 'Quote Threading',
+ cb: this.setThread
+ });
return Post.callbacks.push({
name: 'Quote Threading',
cb: this.node
});
},
- disconnect: function() {
- var input;
- if (!(Conf['Quote Threading'] && g.VIEW === 'thread')) {
- return;
- }
- input = $('input', this.controls);
- $.off(input, 'change', this.toggle);
- Header.menu.rmEntry(this.entry);
- delete this.enabled;
- 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);
- }
+ parent: {},
+ children: {},
+ inserted: {},
+ setThread: function() {
+ QuoteThreading.thread = this;
+ return $.asap((function() {
+ return !Conf['Thread Updater'] || $('.navLinksBot > .updatelink');
+ }), function() {
+ return $.add($('.navLinksBot'), [$.tn(' '), QuoteThreading.threadNewLink]);
});
- if (Conf['Unread Count'] && Unread.thread.OP.nodes.root.parentElement.parentElement) {
- Unread.read();
- return Unread.update();
- }
},
node: function() {
- var keys, len, posts, quote, _i, _len, _ref;
- posts = g.posts;
- if (this.isClone || !QuoteThreading.enabled) {
+ var parent, parents, quote, thread;
+ if (this.isFetchedQuote || this.isClone || !this.isReply) {
return;
}
- if (Conf['Unread Count']) {
- Unread.posts.push(this);
+ thread = QuoteThreading.thread;
+ 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;
- }
- keys = [];
- len = g.BOARD.ID.length + 1;
- _ref = this.quotes;
- for (_i = 0, _len = _ref.length; _i < _len; _i++) {
- quote = _ref[_i];
- if ((quote.slice(len) < this.ID) && quote in posts) {
- keys.push(quote);
+ },
+ descendants: function(post) {
+ var child, children, posts, _i, _len;
+ posts = [post];
+ if (children = QuoteThreading.children[post.fullID]) {
+ for (_i = 0, _len = children.length; _i < _len; _i++) {
+ child = children[_i];
+ posts = posts.concat(QuoteThreading.descendants(child));
}
}
- if (keys.length !== 1) {
- return;
- }
- this.threaded = keys[0];
- return this.cb = QuoteThreading.nodeinsert;
+ return posts;
},
- nodeinsert: function(force) {
- var bottom, height, post, posts, root, threadContainer, top, _ref;
- post = g.posts[this.threaded];
- if (this.thread.OP === post) {
+ insert: function(post) {
+ var child, children, descendants, i, next, nodes, order, parent, prev, prev2, threadContainer, x, _base, _i, _j, _k, _len, _name;
+ if (!(QuoteThreading.enabled && (parent = QuoteThreading.parent[post.fullID]) && !QuoteThreading.inserted[post.fullID])) {
return false;
}
- posts = Unread.posts;
- root = post.nodes.root;
- if (!force) {
- height = doc.clientHeight;
- _ref = root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
- if (!((Conf['Unread Count'] && posts[post.ID]) || ((bottom < height) && (top > 0)))) {
- return false;
+ descendants = QuoteThreading.descendants(post);
+ if (!Unread.posts.has(parent.ID) && descendants.some(function(x) {
+ return Unread.posts.has(x.ID);
+ })) {
+ QuoteThreading.threadNewLink.hidden = 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')) {
- threadContainer = root.nextElementSibling;
- post = Get.postFromRoot($.x('descendant::div[contains(@class,"postContainer")][last()]', threadContainer));
- $.add(threadContainer, this.nodes.root);
+ if (i !== children.length) {
+ next = children[i];
+ for (_j = 0, _len = descendants.length; _j < _len; _j++) {
+ x = descendants[_j];
+ order.before(order[next.ID], order[x.ID]);
+ }
+ children.splice(i, 0, post);
+ $.before(next.nodes.root, nodes);
} else {
- threadContainer = $.el('div', {
- className: 'threadContainer'
- });
- $.add(threadContainer, this.nodes.root);
- $.after(root, threadContainer);
- $.addClass(root, 'threadOP');
+ prev = parent;
+ while ((prev2 = QuoteThreading.children[prev.fullID]) && prev2.length) {
+ prev = prev2[prev2.length - 1];
+ }
+ for (_k = descendants.length - 1; _k >= 0; _k += -1) {
+ x = descendants[_k];
+ order.after(order[prev.ID], order[x.ID]);
+ }
+ children.push(post);
+ $.add(threadContainer, nodes);
}
- if (!Conf['Unread Count']) {
- return true;
- }
- if (post = posts[post.ID]) {
- posts.after(post, posts[this.ID]);
- } else if (posts[this.ID]) {
- posts.prepend(posts[this.ID]);
+ QuoteThreading.inserted[post.fullID] = true;
+ if (!parent.nodes.threadContainer) {
+ parent.nodes.threadContainer = threadContainer;
+ $.addClass(parent.nodes.root, 'threadOP');
+ $.after(parent.nodes.root, threadContainer);
}
return true;
},
- toggle: function() {
- var container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref;
- if (QuoteThreading.enabled = this.checked) {
- QuoteThreading.force();
+ rethread: function(enabled) {
+ var nodes, posts, thread;
+ thread = QuoteThreading.thread;
+ posts = thread.posts;
+ if (QuoteThreading.enabled = enabled) {
+ posts.forEach(QuoteThreading.insert);
} else {
- thread = $('.thread');
- posts = [];
nodes = [];
- g.posts.forEach(function(post) {
- if (!(post === post.thread.OP || post.isClone)) {
- return posts.push(post);
+ Unread.order = new RandomAccessList;
+ QuoteThreading.inserted = {};
+ 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) {
- 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');
- }
+ $.add(thread.OP.nodes.root.parentNode, nodes);
}
- },
- kb: function() {
- var control;
- control = $.id('threadingControl');
- control.checked = !control.checked;
- return QuoteThreading.toggle.call(control);
+ Unread.position = Unread.order.first;
+ Unread.updatePosition();
+ Unread.setLine(true);
+ Unread.read();
+ return Unread.update();
}
};
Quotify = {
init: function() {
- if (!Conf['Resurrect Quotes']) {
+ var _ref;
+ if (((_ref = g.VIEW) !== 'index' && _ref !== 'thread') || !Conf['Resurrect Quotes'] && g.BOARD.ID !== 'pol') {
return;
}
if (Conf['Comment Expansion']) {
@@ -8503,7 +8522,7 @@
}
},
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')) {
Quotify.fixDeadlink(deadlink);
return;
@@ -8519,36 +8538,58 @@
boardID = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
quoteID = "" + boardID + "." + postID;
if (post = g.posts[quoteID]) {
- a = $.el('a', {
- href: Build.path(boardID, post.thread.ID, postID),
- className: post.isDead ? 'quotelink deadlink' : 'quotelink',
- textContent: quote
- });
- $.extend(a.dataset, {
- boardID: boardID,
- threadID: post.thread.ID,
- postID: postID
- });
- } else if (redirect = Redirect.to('thread', {
- boardID: boardID,
- postID: postID
- })) {
- a = $.el('a', {
- href: redirect,
- className: 'deadlink',
- textContent: quote,
- target: '_blank'
- });
- if (Redirect.to('post', {
- boardID: boardID,
- postID: postID
- })) {
- $.addClass(a, 'quotelink');
+ if (!post.isDead) {
+ a = $.el('a', {
+ href: Build.postURL(boardID, post.thread.ID, postID),
+ className: 'quotelink',
+ textContent: quote
+ });
+ } else {
+ a = $.el('a', {
+ href: Build.postURL(boardID, post.thread.ID, postID),
+ className: 'quotelink deadlink',
+ target: '_blank',
+ textContent: "" + quote + "\u00A0(Dead)"
+ });
$.extend(a.dataset, {
boardID: boardID,
+ threadID: post.thread.ID,
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) {
this.quotes.push(quoteID);
@@ -10431,7 +10472,7 @@
return function(persona) {
_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.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) {
_this.flag = prev ? prev.flag : persona.flag;
}
diff --git a/src/Posting/QR.post.coffee b/src/Posting/QR.post.coffee
index 0cc1c547d..3ef816490 100644
--- a/src/Posting/QR.post.coffee
+++ b/src/Posting/QR.post.coffee
@@ -52,8 +52,6 @@ QR.post = class
@sub = if 'sub' of QR.persona.always
QR.persona.always.sub
- else if Conf['Remember Subject']
- if prev then prev.sub else persona.sub
else
''
diff --git a/src/Quotelinks/QuotePreview.coffee b/src/Quotelinks/QuotePreview.coffee
index fc6bf4d02..7d82087ff 100755
--- a/src/Quotelinks/QuotePreview.coffee
+++ b/src/Quotelinks/QuotePreview.coffee
@@ -1,6 +1,6 @@
QuotePreview =
init: ->
- return if !Conf['Quote Previewing']
+ return unless g.VIEW in ['index', 'thread'] and Conf['Quote Previewing']
if Conf['Comment Expansion']
ExpandComment.callbacks.push @node
diff --git a/src/Quotelinks/QuoteStrikeThrough.coffee b/src/Quotelinks/QuoteStrikeThrough.coffee
index 884c507a9..1eb9bf332 100755
--- a/src/Quotelinks/QuoteStrikeThrough.coffee
+++ b/src/Quotelinks/QuoteStrikeThrough.coffee
@@ -1,6 +1,7 @@
QuoteStrikeThrough =
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
name: 'Strike-through Quotes'
diff --git a/src/Quotelinks/QuoteThreading.coffee b/src/Quotelinks/QuoteThreading.coffee
index 25926b1e4..8c944dc52 100755
--- a/src/Quotelinks/QuoteThreading.coffee
+++ b/src/Quotelinks/QuoteThreading.coffee
@@ -8,123 +8,118 @@ QuoteThreading =
@enabled = true
@controls = $.el 'span',
- innerHTML: ''
+ <%= html('') %>
+ @threadNewLink = $.el 'span',
+ className: 'brackets-wrap threadnewlink'
+ hidden: true
+ $.extend @threadNewLink, <%= html('Thread New Posts') %>
- input = $ 'input', @controls
- $.on input, 'change', @toggle
+ $.on $('input', @controls), 'change', ->
+ QuoteThreading.rethread @checked
+ $.on @threadNewLink.firstElementChild, 'click', ->
+ QuoteThreading.threadNewLink.hidden = true
+ QuoteThreading.rethread true
Header.menu.addEntry @entry =
el: @controls
order: 98
- $.on d, '4chanXInitFinished', @ready unless Conf['Unread Count']
-
+ Thread.callbacks.push
+ name: 'Quote Threading'
+ cb: @setThread
Post.callbacks.push
name: 'Quote Threading'
cb: @node
- disconnect: ->
- return unless Conf['Quote Threading'] and g.VIEW is 'thread'
- input = $ 'input', @controls
- $.off input, 'change', @toggle
+ parent: {}
+ children: {}
+ inserted: {}
- Header.menu.rmEntry @entry
-
- delete @enabled
- delete @controls
- 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()
+ setThread: ->
+ QuoteThreading.thread = @
+ $.asap (-> !Conf['Thread Updater'] or $ '.navLinksBot > .updatelink'), ->
+ $.add $('.navLinksBot'), [$.tn(' '), QuoteThreading.threadNewLink]
node: ->
- {posts} = g
- return if @isClone or not QuoteThreading.enabled
+ return if @isFetchedQuote or @isClone or !@isReply
+ {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']
- return if @thread.OP is @ or @isHidden # Filtered
+ descendants: (post) ->
+ posts = [post]
+ if children = QuoteThreading.children[post.fullID]
+ for child in children
+ posts = posts.concat QuoteThreading.descendants child
+ posts
- keys = []
- len = g.BOARD.ID.length + 1
- keys.push quote for quote in @quotes when (quote[len..] < @ID) and quote of posts
+ insert: (post) ->
+ return false unless QuoteThreading.enabled and
+ (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]
- @cb = QuoteThreading.nodeinsert
-
- nodeinsert: (force) ->
- post = g.posts[@threaded]
-
- 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
+ {order} = Unread
+ children = (QuoteThreading.children[parent.fullID] or= [])
+ threadContainer = parent.nodes.threadContainer or $.el 'div', className: 'threadContainer'
+ nodes = [post.nodes.root]
+ nodes.push post.nodes.threadContainer if post.nodes.threadContainer
+ 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
- threadContainer = $.el 'div',
- className: 'threadContainer'
- $.add threadContainer, @nodes.root
- $.after root, threadContainer
- $.addClass root, 'threadOP'
+ prev = parent
+ while (prev2 = QuoteThreading.children[prev.fullID]) and prev2.length
+ prev = prev2[prev2.length-1]
+ order.after order[prev.ID], order[x.ID] for x in descendants by -1
+ children.push post
+ $.add threadContainer, nodes
- return true unless Conf['Unread Count']
+ QuoteThreading.inserted[post.fullID] = true
- if post = posts[post.ID]
- posts.after post, posts[@ID]
-
- else if posts[@ID]
- posts.prepend posts[@ID]
+ unless parent.nodes.threadContainer
+ parent.nodes.threadContainer = threadContainer
+ $.addClass parent.nodes.root, 'threadOP'
+ $.after parent.nodes.root, threadContainer
return true
- toggle: ->
- if QuoteThreading.enabled = @checked
- QuoteThreading.force()
+ rethread: (enabled) ->
+ {thread} = QuoteThreading
+ {posts} = thread
+ if QuoteThreading.enabled = enabled
+ posts.forEach QuoteThreading.insert
else
- thread = $('.thread')
- posts = []
nodes = []
-
- g.posts.forEach (post) ->
- posts.push post unless post is post.thread.OP or post.isClone
+ Unread.order = new RandomAccessList
+ QuoteThreading.inserted = {}
+ 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
-
- nodes.push post.nodes.root for post in posts
- $.add thread, nodes
-
- 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
+ Unread.position = Unread.order.first
+ Unread.updatePosition()
+ Unread.setLine true
+ Unread.read()
+ Unread.update()
diff --git a/src/Quotelinks/Quotify.coffee b/src/Quotelinks/Quotify.coffee
index 5186f024c..820e5abe3 100755
--- a/src/Quotelinks/Quotify.coffee
+++ b/src/Quotelinks/Quotify.coffee
@@ -1,6 +1,6 @@
Quotify =
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']
ExpandComment.callbacks.push @node
@@ -41,25 +41,45 @@ Quotify =
quoteID = "#{boardID}.#{postID}"
if post = g.posts[quoteID]
- # Don't add 'deadlink' when quotifying in an archived post,
- # and we don't know if the post died yet.
- a = $.el 'a',
- href: Build.path boardID, post.thread.ID, postID
- className: if post.isDead then 'quotelink deadlink' else 'quotelink'
- textContent: quote
- $.extend a.dataset, {boardID, threadID: post.thread.ID, postID}
+ unless post.isDead
+ # Don't (Dead) when quotifying in an archived post,
+ # and we know the post still exists.
+ a = $.el 'a',
+ href: Build.postURL boardID, post.thread.ID, postID
+ className: 'quotelink'
+ 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}
- # Replace the .deadlink span if we can redirect.
+ else if @board.ID is boardID is 'pol' and postID.length is 9 and postID[-2] is postID[-1]
+ # XXX Misquotes due to fake doubles on /pol/. Assume they are all intra-thread.
+ postID = postID[...-1]
+ quoteID = "#{boardID}.#{postID}"
a = $.el 'a',
- href: redirect
- className: 'deadlink'
+ href: Build.postURL boardID, @thread.ID, postID
+ className: 'quotelink'
textContent: quote
- target: '_blank'
- if Redirect.to 'post', {boardID, postID}
- # Make it function as a normal quote if we can fetch the post.
- $.addClass a, 'quotelink'
- $.extend a.dataset, {boardID, postID}
+
+ else if Conf['Resurrect Quotes']
+ redirect = Redirect.to 'thread', {boardID, threadID: 0, postID}
+ fetchable = Redirect.to 'post', {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