Start working on putting in aeosynth's RandomAccessList

For performance, obviously.
This commit is contained in:
Zixaphir 2014-01-04 13:38:09 -07:00
parent 43751a00b8
commit 6574746e90
7 changed files with 311 additions and 78 deletions

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.2.44 - 2013-12-27 * 4chan X - Version 1.2.44 - 2014-01-04
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
@ -8,11 +8,11 @@
* http://zixaphir.github.io/appchan-x/ * http://zixaphir.github.io/appchan-x/
* 4chan x Copyright © 2009-2011 James Campos <james.r.campos@gmail.com> * 4chan x Copyright © 2009-2011 James Campos <james.r.campos@gmail.com>
* https://github.com/aeosynth/4chan-x * https://github.com/aeosynth/4chan-x
* 4chan x Copyright © 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com> * 4chan x Copyright © 2012-2014 Nicolas Stepien <stepien.nicolas@gmail.com>
* https://4chan-x.just-believe.in/ * https://4chan-x.just-believe.in/
* 4chan x Copyright © 2013-2013 Jordan Bates <saudrapsmann@gmail.com> * 4chan x Copyright © 2013-2014 Jordan Bates <saudrapsmann@gmail.com>
* http://seaweedchan.github.io/4chan-x/ * http://seaweedchan.github.io/4chan-x/
* 4chan x Copyright © 2012-2013 ihavenoface * 4chan x Copyright © 2012-2014 ihavenoface
* http://ihavenoface.github.io/4chan-x/ * http://ihavenoface.github.io/4chan-x/
* 4chan SS Copyright © 2011-2013 Ahodesuka * 4chan SS Copyright © 2011-2013 Ahodesuka
* https://github.com/ahodesuka/4chan-Style-Script/ * https://github.com/ahodesuka/4chan-Style-Script/

View File

@ -22,7 +22,7 @@
// ==/UserScript== // ==/UserScript==
/* /*
* 4chan X - Version 1.2.44 - 2013-12-27 * 4chan X - Version 1.2.44 - 2014-01-04
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
@ -31,11 +31,11 @@
* http://zixaphir.github.io/appchan-x/ * http://zixaphir.github.io/appchan-x/
* 4chan x Copyright © 2009-2011 James Campos <james.r.campos@gmail.com> * 4chan x Copyright © 2009-2011 James Campos <james.r.campos@gmail.com>
* https://github.com/aeosynth/4chan-x * https://github.com/aeosynth/4chan-x
* 4chan x Copyright © 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com> * 4chan x Copyright © 2012-2014 Nicolas Stepien <stepien.nicolas@gmail.com>
* https://4chan-x.just-believe.in/ * https://4chan-x.just-believe.in/
* 4chan x Copyright © 2013-2013 Jordan Bates <saudrapsmann@gmail.com> * 4chan x Copyright © 2013-2014 Jordan Bates <saudrapsmann@gmail.com>
* http://seaweedchan.github.io/4chan-x/ * http://seaweedchan.github.io/4chan-x/
* 4chan x Copyright © 2012-2013 ihavenoface * 4chan x Copyright © 2012-2014 ihavenoface
* http://ihavenoface.github.io/4chan-x/ * http://ihavenoface.github.io/4chan-x/
* 4chan SS Copyright © 2011-2013 Ahodesuka * 4chan SS Copyright © 2011-2013 Ahodesuka
* https://github.com/ahodesuka/4chan-Style-Script/ * https://github.com/ahodesuka/4chan-Style-Script/
@ -104,7 +104,7 @@
'use strict'; 'use strict';
(function() { (function() {
var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Gallery, Get, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, InfiniScroll, Keybinds, Linkify, Main, Menu, Nav, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g, var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Gallery, Get, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, InfiniScroll, Keybinds, Linkify, Main, Menu, Nav, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__slice = [].slice, __slice = [].slice,
__hasProp = {}.hasOwnProperty, __hasProp = {}.hasOwnProperty,
@ -1458,6 +1458,87 @@
})(); })();
RandomAccessList = (function() {
function RandomAccessList() {
this.first = null;
this.last = null;
this.length = 0;
}
RandomAccessList.prototype.push = function(item) {
var ID, last;
ID = item.ID;
last = this.last;
$.extend(item, {
prev: last,
next: null
});
this[ID] = item;
this.last = last ? last.next = item : this.first = item;
return this.length++;
};
RandomAccessList.prototype.after = function(root, item) {
var next;
if (item.prev === root) {
return;
}
this.rmi(item);
next = root.next;
next.prev = root.next = item;
item.prev = root;
return item.next = next;
};
RandomAccessList.prototype.shift = function() {
return this.rm(this.first.ID);
};
RandomAccessList.prototype.splice = function(start, end) {
var cur, next;
if (!this[end]) {
return;
}
cur = start === 0 ? this.first : this[start];
while (cur !== this[end]) {
if (!(next = cur.next, cur)) {
return;
}
this.rm(cur);
cur = next;
}
};
RandomAccessList.prototype.rm = function(ID) {
var item;
item = this[ID];
if (!item) {
return;
}
delete this[ID];
this.length--;
return this.rmi(item);
};
RandomAccessList.prototype.rmi = function(item) {
var next, prev;
prev = item.prev, next = item.next;
if (prev) {
prev.next = next;
} else {
this.first = next;
}
if (next) {
return next.prev = prev;
} else {
return this.last = prev;
}
};
return RandomAccessList;
})();
Polyfill = { Polyfill = {
init: function() {}, init: function() {},
notificationPermission: function() { notificationPermission: function() {
@ -4868,10 +4949,11 @@
return QuoteThreading.hasRun = true; return QuoteThreading.hasRun = true;
}, },
node: function() { node: function() {
var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len; var ID, fullID, keys, len, post, posts, qid, quote, quotes, replies, uniq, _i, _len;
if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) { if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
return; return;
} }
replies = Unread.replies;
quotes = this.quotes, ID = this.ID, fullID = this.fullID; quotes = this.quotes, ID = this.ID, fullID = this.fullID;
posts = g.posts; posts = g.posts;
if (!(post = posts[fullID]) || post.isHidden) { if (!(post = posts[fullID]) || post.isHidden) {
@ -4907,7 +4989,7 @@
if (QuoteThreading.hasRun) { if (QuoteThreading.hasRun) {
height = doc.clientHeight; height = doc.clientHeight;
_ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top; _ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
if (!(__indexOf.call(Unread.posts, qpost) >= 0 || ((bottom < height) && (top > 0)))) { if (!(Unread.posts[qpost.ID] || ((bottom < height) && (top > 0)))) {
return false; return false;
} }
} }
@ -4926,6 +5008,7 @@
}, },
toggle: function() { toggle: function() {
var container, containers, node, post, replies, reply, thread, _i, _j, _k, _len, _len1, _len2, _ref; var container, containers, node, post, replies, reply, thread, _i, _j, _k, _len, _len1, _len2, _ref;
Unread.replies = new RandomAccessList;
thread = $('.thread'); thread = $('.thread');
replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread); replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
QuoteThreading.enabled = this.checked; QuoteThreading.enabled = this.checked;
@ -9393,7 +9476,7 @@
this.hr = $.el('hr', { this.hr = $.el('hr', {
id: 'unread-line' id: 'unread-line'
}); });
this.posts = []; this.posts = new RandomAccessList;
this.postsQuotingYou = []; this.postsQuotingYou = [];
return Thread.callbacks.push({ return Thread.callbacks.push({
name: 'Unread', name: 'Unread',
@ -9437,7 +9520,7 @@
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
return; return;
} }
if (post = Unread.posts[0]) { if (post = Unread.posts.first) {
while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root)) { while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root)) {
if (!(post = Get.postFromRoot(root)).isHidden) { if (!(post = Get.postFromRoot(root)).isHidden) {
break; break;
@ -9458,7 +9541,7 @@
}); });
}, },
sync: function() { sync: function() {
var lastReadPost; var lastReadPost, post;
lastReadPost = Unread.db.get({ lastReadPost = Unread.db.get({
boardID: Unread.thread.board.ID, boardID: Unread.thread.board.ID,
threadID: Unread.thread.ID, threadID: Unread.thread.ID,
@ -9469,6 +9552,14 @@
} }
Unread.lastReadPost = lastReadPost; Unread.lastReadPost = lastReadPost;
Unread.readArray(Unread.posts); Unread.readArray(Unread.posts);
post = Unread.posts.first;
while (post) {
if (post.ID > Unread.lastReadPost) {
break;
}
post = post.next;
}
Unread.posts.splice(0, i);
Unread.readArray(Unread.postsQuotingYou); Unread.readArray(Unread.postsQuotingYou);
if (Conf['Unread Line']) { if (Conf['Unread Line']) {
Unread.setLine(); Unread.setLine();
@ -9546,12 +9637,13 @@
} }
}, },
readSinglePost: function(post) { readSinglePost: function(post) {
var i; var ID, i;
if ((i = Unread.posts.indexOf(post)) === -1) { ID = post.ID;
if (!Unread.posts[ID]) {
return; return;
} }
Unread.posts.splice(i, 1); Unread.posts.splice(ID(post.next.ID));
if (i === 0) { if (post === Unread.posts.first) {
Unread.lastReadPost = post.ID; Unread.lastReadPost = post.ID;
Unread.saveLastReadPost(); Unread.saveLastReadPost();
} }
@ -9571,14 +9663,14 @@
return arr.splice(0, i); return arr.splice(0, i);
}, },
read: $.debounce(50, function(e) { read: $.debounce(50, function(e) {
var ID, height, i, post, posts; var ID, height, post, posts;
if (d.hidden || !Unread.posts.length) { if (d.hidden || !Unread.posts.length) {
return; return;
} }
height = doc.clientHeight; height = doc.clientHeight;
posts = Unread.posts; posts = Unread.posts;
i = 0; post = posts.first;
while (post = posts[i]) { while (post) {
if (Header.getBottomOf(post.nodes.root) > -1) { if (Header.getBottomOf(post.nodes.root) > -1) {
ID = post.ID; ID = post.ID;
if (Conf['Mark Quotes of You']) { if (Conf['Mark Quotes of You']) {
@ -9586,23 +9678,15 @@
QuoteYou.lastRead = post.nodes.root; QuoteYou.lastRead = post.nodes.root;
} }
} }
if (Conf['Quote Threading']) { post = post.next;
posts.splice(i, 1);
continue;
}
} else { } else {
if (!Conf['Quote Threading']) { break;
break;
}
} }
i++;
}
if (i && !Conf['Quote Threading']) {
posts.splice(0, i);
} }
if (!ID) { if (!ID) {
return; return;
} }
posts.splice(0, ID);
if (Unread.lastReadPost < ID || !Unread.lastReadPost) { if (Unread.lastReadPost < ID || !Unread.lastReadPost) {
Unread.lastReadPost = ID; Unread.lastReadPost = ID;
} }

View File

@ -1,6 +1,6 @@
// Generated by CoffeeScript // Generated by CoffeeScript
/* /*
* 4chan X - Version 1.2.44 - 2013-12-27 * 4chan X - Version 1.2.44 - 2014-01-04
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE
@ -9,11 +9,11 @@
* http://zixaphir.github.io/appchan-x/ * http://zixaphir.github.io/appchan-x/
* 4chan x Copyright © 2009-2011 James Campos <james.r.campos@gmail.com> * 4chan x Copyright © 2009-2011 James Campos <james.r.campos@gmail.com>
* https://github.com/aeosynth/4chan-x * https://github.com/aeosynth/4chan-x
* 4chan x Copyright © 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com> * 4chan x Copyright © 2012-2014 Nicolas Stepien <stepien.nicolas@gmail.com>
* https://4chan-x.just-believe.in/ * https://4chan-x.just-believe.in/
* 4chan x Copyright © 2013-2013 Jordan Bates <saudrapsmann@gmail.com> * 4chan x Copyright © 2013-2014 Jordan Bates <saudrapsmann@gmail.com>
* http://seaweedchan.github.io/4chan-x/ * http://seaweedchan.github.io/4chan-x/
* 4chan x Copyright © 2012-2013 ihavenoface * 4chan x Copyright © 2012-2014 ihavenoface
* http://ihavenoface.github.io/4chan-x/ * http://ihavenoface.github.io/4chan-x/
* 4chan SS Copyright © 2011-2013 Ahodesuka * 4chan SS Copyright © 2011-2013 Ahodesuka
* https://github.com/ahodesuka/4chan-Style-Script/ * https://github.com/ahodesuka/4chan-Style-Script/
@ -82,7 +82,7 @@
'use strict'; 'use strict';
(function() { (function() {
var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Gallery, Get, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, InfiniScroll, Keybinds, Linkify, Main, Menu, Nav, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g, var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, CatalogLinks, Clone, Conf, Config, CustomCSS, DataBoard, DeleteLink, Dice, DownloadLink, Emoji, ExpandComment, ExpandThread, FappeTyme, Favicon, FileInfo, Filter, Fourchan, Gallery, Get, Header, IDColor, ImageExpand, ImageHover, ImageLoader, Index, InfiniScroll, Keybinds, Linkify, Main, Menu, Nav, Notice, PSAHiding, Polyfill, Post, PostHiding, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, Report, ReportLink, RevealSpoilers, Sauce, Settings, Thread, ThreadExcerpt, ThreadHiding, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, c, d, doc, g,
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; },
__slice = [].slice, __slice = [].slice,
__hasProp = {}.hasOwnProperty, __hasProp = {}.hasOwnProperty,
@ -1479,6 +1479,87 @@
})(); })();
RandomAccessList = (function() {
function RandomAccessList() {
this.first = null;
this.last = null;
this.length = 0;
}
RandomAccessList.prototype.push = function(item) {
var ID, last;
ID = item.ID;
last = this.last;
$.extend(item, {
prev: last,
next: null
});
this[ID] = item;
this.last = last ? last.next = item : this.first = item;
return this.length++;
};
RandomAccessList.prototype.after = function(root, item) {
var next;
if (item.prev === root) {
return;
}
this.rmi(item);
next = root.next;
next.prev = root.next = item;
item.prev = root;
return item.next = next;
};
RandomAccessList.prototype.shift = function() {
return this.rm(this.first.ID);
};
RandomAccessList.prototype.splice = function(start, end) {
var cur, next;
if (!this[end]) {
return;
}
cur = start === 0 ? this.first : this[start];
while (cur !== this[end]) {
if (!(next = cur.next, cur)) {
return;
}
this.rm(cur);
cur = next;
}
};
RandomAccessList.prototype.rm = function(ID) {
var item;
item = this[ID];
if (!item) {
return;
}
delete this[ID];
this.length--;
return this.rmi(item);
};
RandomAccessList.prototype.rmi = function(item) {
var next, prev;
prev = item.prev, next = item.next;
if (prev) {
prev.next = next;
} else {
this.first = next;
}
if (next) {
return next.prev = prev;
} else {
return this.last = prev;
}
};
return RandomAccessList;
})();
Polyfill = { Polyfill = {
init: function() { init: function() {
this.notificationPermission(); this.notificationPermission();
@ -4886,10 +4967,11 @@
return QuoteThreading.hasRun = true; return QuoteThreading.hasRun = true;
}, },
node: function() { node: function() {
var ID, fullID, keys, len, post, posts, qid, quote, quotes, uniq, _i, _len; var ID, fullID, keys, len, post, posts, qid, quote, quotes, replies, uniq, _i, _len;
if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) { if (this.isClone || !QuoteThreading.enabled || this.thread.OP === this) {
return; return;
} }
replies = Unread.replies;
quotes = this.quotes, ID = this.ID, fullID = this.fullID; quotes = this.quotes, ID = this.ID, fullID = this.fullID;
posts = g.posts; posts = g.posts;
if (!(post = posts[fullID]) || post.isHidden) { if (!(post = posts[fullID]) || post.isHidden) {
@ -4925,7 +5007,7 @@
if (QuoteThreading.hasRun) { if (QuoteThreading.hasRun) {
height = doc.clientHeight; height = doc.clientHeight;
_ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top; _ref = qpost.nodes.root.getBoundingClientRect(), bottom = _ref.bottom, top = _ref.top;
if (!(__indexOf.call(Unread.posts, qpost) >= 0 || ((bottom < height) && (top > 0)))) { if (!(Unread.posts[qpost.ID] || ((bottom < height) && (top > 0)))) {
return false; return false;
} }
} }
@ -4944,6 +5026,7 @@
}, },
toggle: function() { toggle: function() {
var container, containers, node, post, replies, reply, thread, _i, _j, _k, _len, _len1, _len2, _ref; var container, containers, node, post, replies, reply, thread, _i, _j, _k, _len, _len1, _len2, _ref;
Unread.replies = new RandomAccessList;
thread = $('.thread'); thread = $('.thread');
replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread); replies = $$('.thread > .replyContainer, .threadContainer > .replyContainer', thread);
QuoteThreading.enabled = this.checked; QuoteThreading.enabled = this.checked;
@ -9391,7 +9474,7 @@
this.hr = $.el('hr', { this.hr = $.el('hr', {
id: 'unread-line' id: 'unread-line'
}); });
this.posts = []; this.posts = new RandomAccessList;
this.postsQuotingYou = []; this.postsQuotingYou = [];
return Thread.callbacks.push({ return Thread.callbacks.push({
name: 'Unread', name: 'Unread',
@ -9435,7 +9518,7 @@
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
return; return;
} }
if (post = Unread.posts[0]) { if (post = Unread.posts.first) {
while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root)) { while (root = $.x('preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root)) {
if (!(post = Get.postFromRoot(root)).isHidden) { if (!(post = Get.postFromRoot(root)).isHidden) {
break; break;
@ -9456,7 +9539,7 @@
}); });
}, },
sync: function() { sync: function() {
var lastReadPost; var lastReadPost, post;
lastReadPost = Unread.db.get({ lastReadPost = Unread.db.get({
boardID: Unread.thread.board.ID, boardID: Unread.thread.board.ID,
threadID: Unread.thread.ID, threadID: Unread.thread.ID,
@ -9467,6 +9550,14 @@
} }
Unread.lastReadPost = lastReadPost; Unread.lastReadPost = lastReadPost;
Unread.readArray(Unread.posts); Unread.readArray(Unread.posts);
post = Unread.posts.first;
while (post) {
if (post.ID > Unread.lastReadPost) {
break;
}
post = post.next;
}
Unread.posts.splice(0, i);
Unread.readArray(Unread.postsQuotingYou); Unread.readArray(Unread.postsQuotingYou);
if (Conf['Unread Line']) { if (Conf['Unread Line']) {
Unread.setLine(); Unread.setLine();
@ -9544,12 +9635,13 @@
} }
}, },
readSinglePost: function(post) { readSinglePost: function(post) {
var i; var ID, i;
if ((i = Unread.posts.indexOf(post)) === -1) { ID = post.ID;
if (!Unread.posts[ID]) {
return; return;
} }
Unread.posts.splice(i, 1); Unread.posts.splice(ID(post.next.ID));
if (i === 0) { if (post === Unread.posts.first) {
Unread.lastReadPost = post.ID; Unread.lastReadPost = post.ID;
Unread.saveLastReadPost(); Unread.saveLastReadPost();
} }
@ -9569,14 +9661,14 @@
return arr.splice(0, i); return arr.splice(0, i);
}, },
read: $.debounce(50, function(e) { read: $.debounce(50, function(e) {
var ID, height, i, post, posts; var ID, height, post, posts;
if (d.hidden || !Unread.posts.length) { if (d.hidden || !Unread.posts.length) {
return; return;
} }
height = doc.clientHeight; height = doc.clientHeight;
posts = Unread.posts; posts = Unread.posts;
i = 0; post = posts.first;
while (post = posts[i]) { while (post) {
if (Header.getBottomOf(post.nodes.root) > -1) { if (Header.getBottomOf(post.nodes.root) > -1) {
ID = post.ID; ID = post.ID;
if (Conf['Mark Quotes of You']) { if (Conf['Mark Quotes of You']) {
@ -9584,23 +9676,15 @@
QuoteYou.lastRead = post.nodes.root; QuoteYou.lastRead = post.nodes.root;
} }
} }
if (Conf['Quote Threading']) { post = post.next;
posts.splice(i, 1);
continue;
}
} else { } else {
if (!Conf['Quote Threading']) { break;
break;
}
} }
i++;
}
if (i && !Conf['Quote Threading']) {
posts.splice(0, i);
} }
if (!ID) { if (!ID) {
return; return;
} }
posts.splice(0, ID);
if (Unread.lastReadPost < ID || !Unread.lastReadPost) { if (Unread.lastReadPost < ID || !Unread.lastReadPost) {
Unread.lastReadPost = ID; Unread.lastReadPost = ID;
} }

View File

@ -3,4 +3,5 @@
<%= grunt.file.read('src/General/lib/post.class') %> <%= grunt.file.read('src/General/lib/post.class') %>
<%= grunt.file.read('src/General/lib/clone.class') %> <%= grunt.file.read('src/General/lib/clone.class') %>
<%= grunt.file.read('src/General/lib/databoard.class') %> <%= grunt.file.read('src/General/lib/databoard.class') %>
<%= grunt.file.read('src/General/lib/notice.class') %> <%= grunt.file.read('src/General/lib/notice.class') %>
<%= grunt.file.read('src/General/lib/randomaccesslist.class') %>

View File

@ -0,0 +1,58 @@
class RandomAccessList
constructor: ->
@first = null
@last = null
@length = 0
push: (item) ->
{ID} = item
{last} = @
$.extend item,
prev: last
next: null
@[ID] = item
@last = if last
last.next = item
else
@first = item
@length++
after: (root, item) ->
return if item.prev is root
@rmi item
{next} = root
next.prev = root.next = item
item.prev = root
item.next = next
shift: ->
@rm @first.ID
splice: (start, end) ->
return unless @[end]
cur = if start is 0 then @first else @[start]
while cur isnt @[end]
return unless {next} = cur
@rm cur
cur = next
rm: (ID) ->
item = @[ID]
return unless item
delete @[ID]
@length--
@rmi item
rmi: (item) ->
{prev, next} = item
if prev
prev.next = next
else
@first = next
if next
next.prev = prev
else
@last = prev

View File

@ -5,7 +5,7 @@ Unread =
@db = new DataBoard 'lastReadPosts', @sync @db = new DataBoard 'lastReadPosts', @sync
@hr = $.el 'hr', @hr = $.el 'hr',
id: 'unread-line' id: 'unread-line'
@posts = [] @posts = new RandomAccessList
@postsQuotingYou = [] @postsQuotingYou = []
Thread.callbacks.push Thread.callbacks.push
@ -36,7 +36,7 @@ Unread =
return unless Conf['Scroll to Last Read Post'] return unless Conf['Scroll to Last Read Post']
# Let the header's onload callback handle it. # Let the header's onload callback handle it.
return if (hash = location.hash.match /\d+/) and hash[0] of Unread.thread.posts return if (hash = location.hash.match /\d+/) and hash[0] of Unread.thread.posts
if post = Unread.posts[0] if post = Unread.posts.first
# Scroll to a non-hidden, non-OP post that's before the first unread post. # Scroll to a non-hidden, non-OP post that's before the first unread post.
while root = $.x 'preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root while root = $.x 'preceding-sibling::div[contains(@class,"replyContainer")][1]', post.nodes.root
break unless (post = Get.postFromRoot root).isHidden break unless (post = Get.postFromRoot root).isHidden
@ -60,6 +60,13 @@ Unread =
return unless Unread.lastReadPost < lastReadPost return unless Unread.lastReadPost < lastReadPost
Unread.lastReadPost = lastReadPost Unread.lastReadPost = lastReadPost
Unread.readArray Unread.posts Unread.readArray Unread.posts
post = Unread.posts.first
while post
break if post.ID > Unread.lastReadPost
post = post.next
Unread.posts.splice 0, i
Unread.readArray Unread.postsQuotingYou Unread.readArray Unread.postsQuotingYou
Unread.setLine() if Conf['Unread Line'] Unread.setLine() if Conf['Unread Line']
Unread.update() Unread.update()
@ -114,9 +121,10 @@ Unread =
Unread.addPosts e.detail.newPosts Unread.addPosts e.detail.newPosts
readSinglePost: (post) -> readSinglePost: (post) ->
return if (i = Unread.posts.indexOf post) is -1 {ID} = post
Unread.posts.splice i, 1 return unless Unread.posts[ID]
if i is 0 Unread.posts.splice ID post.next.ID
if post is Unread.posts.first
Unread.lastReadPost = post.ID Unread.lastReadPost = post.ID
Unread.saveLastReadPost() Unread.saveLastReadPost()
if (i = Unread.postsQuotingYou.indexOf post) isnt -1 if (i = Unread.postsQuotingYou.indexOf post) isnt -1
@ -132,27 +140,22 @@ Unread =
return if d.hidden or !Unread.posts.length return if d.hidden or !Unread.posts.length
height = doc.clientHeight height = doc.clientHeight
{posts} = Unread {posts} = Unread
i = 0
while post = posts[i] post = posts.first
while post
if Header.getBottomOf(post.nodes.root) > -1 # post is not completely read if Header.getBottomOf(post.nodes.root) > -1 # post is not completely read
{ID} = post {ID} = post
if Conf['Mark Quotes of You'] if Conf['Mark Quotes of You']
if post.info.yours if post.info.yours
QuoteYou.lastRead = post.nodes.root QuoteYou.lastRead = post.nodes.root
if Conf['Quote Threading'] post = post.next
posts.splice i, 1
continue
else else
unless Conf['Quote Threading'] break
break
i++
if i and !Conf['Quote Threading']
posts.splice 0, i
return unless ID return unless ID
posts.splice 0, ID
Unread.lastReadPost = ID if Unread.lastReadPost < ID or !Unread.lastReadPost Unread.lastReadPost = ID if Unread.lastReadPost < ID or !Unread.lastReadPost
Unread.saveLastReadPost() Unread.saveLastReadPost()
Unread.readArray Unread.postsQuotingYou Unread.readArray Unread.postsQuotingYou

View File

@ -36,6 +36,8 @@ QuoteThreading =
node: -> node: ->
return if @isClone or not QuoteThreading.enabled or @thread.OP is @ return if @isClone or not QuoteThreading.enabled or @thread.OP is @
{replies} = Unread
{quotes, ID, fullID} = @ {quotes, ID, fullID} = @
{posts} = g {posts} = g
@ -68,7 +70,7 @@ QuoteThreading =
{bottom, top} = qpost.nodes.root.getBoundingClientRect() {bottom, top} = qpost.nodes.root.getBoundingClientRect()
# Post is unread or is fully visible. # Post is unread or is fully visible.
return false unless qpost in Unread.posts or ((bottom < height) and (top > 0)) return false unless Unread.posts[qpost.ID] or ((bottom < height) and (top > 0))
qroot = qpost.nodes.root qroot = qpost.nodes.root
unless $.hasClass qroot, 'threadOP' unless $.hasClass qroot, 'threadOP'
@ -83,6 +85,7 @@ QuoteThreading =
return true return true
toggle: -> toggle: ->
Unread.replies = new RandomAccessList
thread = $ '.thread' thread = $ '.thread'
replies = $$ '.thread > .replyContainer, .threadContainer > .replyContainer', thread replies = $$ '.thread > .replyContainer, .threadContainer > .replyContainer', thread
QuoteThreading.enabled = @checked QuoteThreading.enabled = @checked