From 481ca6af725b89321be25478326748697c0c2a87 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Tue, 14 Jan 2014 17:18:30 -0700 Subject: [PATCH 01/19] Fix and use thread.collect for GC Also merge appchan's JSON option fixes --- LICENSE | 2 +- builds/4chan-X.user.js | 80 +++++++++++++++++++----------------- builds/crx/script.js | 80 +++++++++++++++++++----------------- src/General/Main.coffee | 39 ++++++++++-------- src/General/Navigate.coffee | 5 +-- src/General/lib/thread.class | 3 +- 6 files changed, 109 insertions(+), 100 deletions(-) diff --git a/LICENSE b/LICENSE index 5b61dddf7..c3a9eca17 100755 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.3.2 - 2014-01-13 +* 4chan X - Version 1.3.2 - 2014-01-14 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 433af2b54..59ba54363 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -22,7 +22,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.3.2 - 2014-01-13 +* 4chan X - Version 1.3.2 - 2014-01-14 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -949,10 +949,10 @@ }; Thread.prototype.collect = function() { - var post, postID, _i, _len, _ref; + var post, postID, _ref; _ref = this.posts; - for (post = _i = 0, _len = _ref.length; _i < _len; post = ++_i) { - postID = _ref[post]; + for (postID in _ref) { + post = _ref[postID]; post.collect(); } delete g.threads[this.fullID]; @@ -11924,12 +11924,13 @@ } }, clean: function() { - var posts, threads; + var id, posts, thread, threads, _ref; posts = g.posts, threads = g.threads; - g.posts = {}; - g.threads = {}; - g.BOARD.posts = {}; - g.BOARD.threads = {}; + _ref = g.threads; + for (id in _ref) { + thread = _ref[id]; + thread.collect(); + } QuoteBacklink.containers = {}; return $.rmAll($('.board')); }, @@ -13033,7 +13034,7 @@ }); $.before(styleSelector.previousSibling, [$.tn('['), passLink, $.tn(']\u00A0\u00A0')]); } - if (g.VIEW === 'thread') { + if (!(Conf['JSON Navigation'] && g.VIEW === 'index')) { Main.initThread(); } else { $.event('4chanXInitFinished'); @@ -13056,37 +13057,40 @@ } }, initThread: function() { - var err, errors, postRoot, posts, thread, threadRoot, _i, _len, _ref; - if (!(threadRoot = $('.thread'))) { - return; - } - thread = new Thread(+threadRoot.id.slice(1), g.BOARD); - posts = []; - _ref = $$('.thread > .postContainer', threadRoot); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - postRoot = _ref[_i]; - try { - posts.push(new Post(postRoot, thread, g.BOARD, { - isOriginalMarkup: true - })); - } catch (_error) { - err = _error; - if (!errors) { - errors = []; + var board, err, errors, postRoot, posts, thread, threadRoot, threads, _i, _j, _len, _len1, _ref, _ref1; + if (board = $('.board')) { + threads = []; + posts = []; + _ref = $$('.board > .thread', board); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + threadRoot = _ref[_i]; + thread = new Thread(+threadRoot.id.slice(1), g.BOARD); + threads.push(thread); + _ref1 = $$('.thread > .postContainer', threadRoot); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + postRoot = _ref1[_j]; + try { + posts.push(new Post(postRoot, thread, g.BOARD)); + } catch (_error) { + err = _error; + if (!errors) { + errors = []; + } + errors.push({ + message: "Parsing of Post No." + (postRoot.id.match(/\d+/)) + " failed. Post will be skipped.", + error: err + }); + } } - errors.push({ - message: "Parsing of Post No." + (postRoot.id.match(/\d+/)) + " failed. Post will be skipped.", - error: err - }); } + if (errors) { + Main.handleErrors(errors); + } + Main.callbackNodes(Thread, threads); + return Main.callbackNodesDB(Post, posts, function() { + return $.event('4chanXInitFinished'); + }); } - if (errors) { - Main.handleErrors(errors); - } - Main.callbackNodes(Thread, [thread]); - return Main.callbackNodesDB(Post, posts, function() { - return $.event('4chanXInitFinished'); - }); }, callbackNodes: function(klass, nodes) { var cb, i, node; diff --git a/builds/crx/script.js b/builds/crx/script.js index eb9650742..ed2fe23e3 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.3.2 - 2014-01-13 +* 4chan X - Version 1.3.2 - 2014-01-14 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -954,10 +954,10 @@ }; Thread.prototype.collect = function() { - var post, postID, _i, _len, _ref; + var post, postID, _ref; _ref = this.posts; - for (post = _i = 0, _len = _ref.length; _i < _len; post = ++_i) { - postID = _ref[post]; + for (postID in _ref) { + post = _ref[postID]; post.collect(); } delete g.threads[this.fullID]; @@ -11913,12 +11913,13 @@ } }, clean: function() { - var posts, threads; + var id, posts, thread, threads, _ref; posts = g.posts, threads = g.threads; - g.posts = {}; - g.threads = {}; - g.BOARD.posts = {}; - g.BOARD.threads = {}; + _ref = g.threads; + for (id in _ref) { + thread = _ref[id]; + thread.collect(); + } QuoteBacklink.containers = {}; return $.rmAll($('.board')); }, @@ -13020,7 +13021,7 @@ }); $.before(styleSelector.previousSibling, [$.tn('['), passLink, $.tn(']\u00A0\u00A0')]); } - if (g.VIEW === 'thread') { + if (!(Conf['JSON Navigation'] && g.VIEW === 'index')) { Main.initThread(); } else { $.event('4chanXInitFinished'); @@ -13033,37 +13034,40 @@ } }, initThread: function() { - var err, errors, postRoot, posts, thread, threadRoot, _i, _len, _ref; - if (!(threadRoot = $('.thread'))) { - return; - } - thread = new Thread(+threadRoot.id.slice(1), g.BOARD); - posts = []; - _ref = $$('.thread > .postContainer', threadRoot); - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - postRoot = _ref[_i]; - try { - posts.push(new Post(postRoot, thread, g.BOARD, { - isOriginalMarkup: true - })); - } catch (_error) { - err = _error; - if (!errors) { - errors = []; + var board, err, errors, postRoot, posts, thread, threadRoot, threads, _i, _j, _len, _len1, _ref, _ref1; + if (board = $('.board')) { + threads = []; + posts = []; + _ref = $$('.board > .thread', board); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + threadRoot = _ref[_i]; + thread = new Thread(+threadRoot.id.slice(1), g.BOARD); + threads.push(thread); + _ref1 = $$('.thread > .postContainer', threadRoot); + for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) { + postRoot = _ref1[_j]; + try { + posts.push(new Post(postRoot, thread, g.BOARD)); + } catch (_error) { + err = _error; + if (!errors) { + errors = []; + } + errors.push({ + message: "Parsing of Post No." + (postRoot.id.match(/\d+/)) + " failed. Post will be skipped.", + error: err + }); + } } - errors.push({ - message: "Parsing of Post No." + (postRoot.id.match(/\d+/)) + " failed. Post will be skipped.", - error: err - }); } + if (errors) { + Main.handleErrors(errors); + } + Main.callbackNodes(Thread, threads); + return Main.callbackNodesDB(Post, posts, function() { + return $.event('4chanXInitFinished'); + }); } - if (errors) { - Main.handleErrors(errors); - } - Main.callbackNodes(Thread, [thread]); - return Main.callbackNodesDB(Post, posts, function() { - return $.event('4chanXInitFinished'); - }); }, callbackNodes: function(klass, nodes) { var cb, i, node; diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 5eda4422d..7ccb225ac 100755 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -131,7 +131,7 @@ Main = 'left=0,top=0,width=500,height=255,toolbar=0,resizable=0' $.before styleSelector.previousSibling, [$.tn '['; passLink, $.tn ']\u00A0\u00A0'] - if g.VIEW is 'thread' + unless Conf['JSON Navigation'] and g.VIEW is 'index' Main.initThread() else $.event '4chanXInitFinished' @@ -150,23 +150,28 @@ Main = new Notice 'warning', 'Cookies need to be enabled on 4chan for <%= meta.name %> to operate properly.', 30 initThread: -> - return unless threadRoot = $ '.thread' - thread = new Thread +threadRoot.id[1..], g.BOARD - posts = [] - for postRoot in $$ '.thread > .postContainer', threadRoot - try - posts.push new Post postRoot, thread, g.BOARD, {isOriginalMarkup: true} - catch err - # Skip posts that we failed to parse. - errors = [] unless errors - errors.push - message: "Parsing of Post No.#{postRoot.id.match /\d+/} failed. Post will be skipped." - error: err - Main.handleErrors errors if errors + if board = $ '.board' + threads = [] + posts = [] - Main.callbackNodes Thread, [thread] - Main.callbackNodesDB Post, posts, -> - $.event '4chanXInitFinished' + for threadRoot in $$ '.board > .thread', board + thread = new Thread +threadRoot.id[1..], g.BOARD + threads.push thread + for postRoot in $$ '.thread > .postContainer', threadRoot + try + posts.push new Post postRoot, thread, g.BOARD + catch err + # Skip posts that we failed to parse. + unless errors + errors = [] + errors.push + message: "Parsing of Post No.#{postRoot.id.match(/\d+/)} failed. Post will be skipped." + error: err + Main.handleErrors errors if errors + + Main.callbackNodes Thread, threads + Main.callbackNodesDB Post, posts, -> + $.event '4chanXInitFinished' callbackNodes: (klass, nodes) -> i = 0 diff --git a/src/General/Navigate.coffee b/src/General/Navigate.coffee index 63806eb3a..43659ebc9 100644 --- a/src/General/Navigate.coffee +++ b/src/General/Navigate.coffee @@ -34,10 +34,7 @@ Navigate = {posts, threads} = g # Garbage collection - g.posts = {} - g.threads = {} - g.BOARD.posts = {} - g.BOARD.threads = {} + thread.collect() for id, thread of g.threads QuoteBacklink.containers = {} diff --git a/src/General/lib/thread.class b/src/General/lib/thread.class index 395e06eb6..da1bfbb03 100755 --- a/src/General/lib/thread.class +++ b/src/General/lib/thread.class @@ -44,7 +44,6 @@ class Thread @timeOfDeath = Date.now() collect: -> - for postID, post in @posts - post.collect() + post.collect() for postID, post of @posts delete g.threads[@fullID] delete @board.threads[@] From dc5daeba0688b54c5d2677737f432257ab21415f Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Tue, 14 Jan 2014 20:16:59 -0700 Subject: [PATCH 02/19] I really don't like iterating through objects. --- builds/4chan-X.user.js | 324 +++++++++++++++----------- builds/crx/script.js | 324 +++++++++++++++----------- src/Filtering/Recursive.coffee | 3 +- src/General/Get.coffee | 16 +- src/General/Globals.coffee | 4 +- src/General/Index.coffee | 28 +-- src/General/Main.coffee | 3 + src/General/Navigate.coffee | 2 +- src/General/lib/$.coffee | 6 + src/General/lib/board.class | 4 +- src/General/lib/classes.coffee | 3 +- src/General/lib/post.class | 8 +- src/General/lib/simpledict.class | 14 ++ src/General/lib/thread.class | 10 +- src/Images/ImageExpand.coffee | 22 +- src/Images/ImageLoader.coffee | 9 +- src/Miscellaneous/ExpandThread.coffee | 3 +- src/Monitoring/ThreadStats.coffee | 2 +- src/Monitoring/ThreadUpdater.coffee | 4 +- src/Monitoring/ThreadWatcher.coffee | 6 +- src/Monitoring/Unread.coffee | 7 +- src/Posting/QR.coffee | 2 +- src/Quotelinks/QuoteThreading.coffee | 8 +- 23 files changed, 467 insertions(+), 345 deletions(-) create mode 100644 src/General/lib/simpledict.class diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 59ba54363..bc001cc5c 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -104,7 +104,7 @@ 'use strict'; (function() { - var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, Callbacks, 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, Navigate, 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, + var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, Callbacks, 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, Navigate, 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, SimpleDict, 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; }, __slice = [].slice, __hasProp = {}.hasOwnProperty, @@ -363,9 +363,7 @@ g = { VERSION: '1.3.2', NAMESPACE: '4chan X.', - boards: {}, - threads: {}, - posts: {} + boards: {} }; $ = function(selector, root) { @@ -807,6 +805,16 @@ }; })(); + $.remove = function(arr, value) { + var i; + i = arr.indexOf(value); + if (i === -1) { + return false; + } + arr.splice(i, 1); + return true; + }; + $$ = function(selector, root) { if (root == null) { root = d.body; @@ -880,8 +888,8 @@ function Board(ID) { this.ID = ID; - this.threads = {}; - this.posts = {}; + this.threads = new SimpleDict; + this.posts = new SimpleDict; g.boards[this] = this; } @@ -900,12 +908,12 @@ this.ID = ID; this.board = board; this.fullID = "" + this.board + "." + this.ID; - this.posts = {}; + this.posts = new SimpleDict; this.isSticky = false; this.isClosed = false; this.postLimit = false; this.fileLimit = false; - g.threads[this.fullID] = board.threads[this] = this; + g.threads.push(this.fullID, board.threads.push(this, this)); } Thread.prototype.setPage = function(pageNum) { @@ -949,14 +957,11 @@ }; Thread.prototype.collect = function() { - var post, postID, _ref; - _ref = this.posts; - for (postID in _ref) { - post = _ref[postID]; - post.collect(); - } - delete g.threads[this.fullID]; - return delete this.board.threads[this]; + this.posts.forEach(function(post) { + return post.collect(); + }); + g.threads.rm(this.fullID); + return this.board.threads.rm(this); }; return Thread; @@ -1035,7 +1040,7 @@ this.parseQuotes(); this.parseFile(that); this.clones = []; - g.posts[this.fullID] = thread.posts[this] = board.posts[this] = this; + g.posts.push(this.fullID, thread.posts.push(this, board.posts.push(this, this))); if (that.isArchived) { this.kill(); } @@ -1205,9 +1210,9 @@ Post.prototype.collect = function() { this.kill(); - delete g.posts[this.fullID]; - delete this.thread.posts[this]; - return delete this.board.posts[this]; + g.posts.rm(this.fullID); + this.thread.posts.rm(this); + return this.board.posts.rm(this); }; Post.prototype.addClone = function(context) { @@ -1605,6 +1610,41 @@ })(); + SimpleDict = (function() { + function SimpleDict() { + this.keys = []; + } + + SimpleDict.prototype.push = function(key, data) { + key = "" + key; + if (!this[key]) { + this.keys.push(key); + } + return this[key] = data; + }; + + SimpleDict.prototype.rm = function(key) { + key = "" + key; + if ($.remove(this.keys, key)) { + return delete this[key]; + } + }; + + SimpleDict.prototype.forEach = function(fn) { + var key, _i, _len, _ref, _results; + _ref = __slice.call(this.keys); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push(fn(this[key])); + } + return _results; + }; + + return SimpleDict; + + })(); + Polyfill = { init: function() {}, notificationPermission: function() { @@ -2559,7 +2599,7 @@ } } catch (_error) { err = _error; - c.error('Index failure:', err); + c.error("Index failure: " + err.message, err.stack); if (notice) { notice.setType('error'); notice.el.lastElementChild.textContent = 'Index refresh failed.'; @@ -2587,7 +2627,6 @@ return Index.setPage(); }, parseThreadList: function(pages) { - var thread, threadID, _ref, _ref1; Index.pagesNum = pages.length; Index.threadsNumPerPage = pages[0].threads.length; Index.liveThreadData = pages.reduce((function(arr, next) { @@ -2596,13 +2635,12 @@ Index.liveThreadIDs = Index.liveThreadData.map(function(data) { return data.no; }); - _ref = g.BOARD.threads; - for (threadID in _ref) { - thread = _ref[threadID]; - if (_ref1 = thread.ID, __indexOf.call(Index.liveThreadIDs, _ref1) < 0) { - thread.collect(); + g.BOARD.threads.forEach(function(thread) { + var _ref; + if (_ref = thread.ID, __indexOf.call(Index.liveThreadIDs, _ref) < 0) { + return thread.collect(); } - } + }); }, buildThreads: function() { var err, errors, i, posts, thread, threadData, threadRoot, threads, _i, _len, _ref; @@ -2612,20 +2650,20 @@ _ref = Index.liveThreadData; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { threadData = _ref[i]; - threadRoot = Build.thread(g.BOARD, threadData); - Index.nodes.push(threadRoot, $.el('hr')); - if (thread = g.BOARD.threads[threadData.no]) { - thread.setPage(Math.floor(i / Index.threadsNumPerPage)); - thread.setStatus('Sticky', !!threadData.sticky); - thread.setStatus('Closed', !!threadData.closed); - } else { - thread = new Thread(threadData.no, g.BOARD); - threads.push(thread); - } - if (thread.ID in thread.posts) { - continue; - } try { + threadRoot = Build.thread(g.BOARD, threadData); + if (thread = g.BOARD.threads[threadData.no]) { + thread.setPage(Math.floor(i / Index.threadsNumPerPage)); + thread.setStatus('Sticky', !!threadData.sticky); + thread.setStatus('Closed', !!threadData.closed); + } else { + thread = new Thread(threadData.no, g.BOARD); + threads.push(thread); + } + Index.nodes.push(threadRoot, $.el('hr')); + if (thread.ID in thread.posts) { + continue; + } posts.push(new Post($('.opContainer', threadRoot), thread, g.BOARD)); } catch (_error) { err = _error; @@ -2633,7 +2671,7 @@ errors = []; } errors.push({ - message: "Parsing of Post No." + thread + " failed. Post will be skipped.", + message: "Parsing of Thread No." + thread + " failed. Thread will be skipped.", error: err }); } @@ -3105,36 +3143,38 @@ }; }, allQuotelinksLinkingTo: function(post) { - var ID, handleQuotes, quote, quotedPost, quotelinks, quoterPost, _i, _len, _ref, _ref1, _ref2; + var fullID, handleQuotes, posts, qPost, quote, quotelinks, _i, _len, _ref; quotelinks = []; - handleQuotes = function(post, type) { + posts = g.posts; + fullID = { + post: post + }; + handleQuotes = function(qPost, type) { var clone, _i, _len, _ref; - quotelinks.push.apply(quotelinks, post.nodes[type]); - _ref = post.clones; + quotelinks.push.apply(quotelinks, qPost.nodes[type]); + _ref = qPost.clones; for (_i = 0, _len = _ref.length; _i < _len; _i++) { clone = _ref[_i]; quotelinks.push.apply(quotelinks, clone.nodes[type]); } }; - _ref = g.posts; - for (ID in _ref) { - quoterPost = _ref[ID]; - if (_ref1 = post.fullID, __indexOf.call(quoterPost.quotes, _ref1) >= 0) { - handleQuotes(quoterPost, 'quotelinks'); + posts.forEach(function(qPost) { + if (__indexOf.call(qPost.quotes, fullID) >= 0) { + return handleQuotes(qPost, 'quotelinks'); } - } + }); if (Conf['Quote Backlinks']) { - _ref2 = post.quotes; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - quote = _ref2[_i]; - if (quotedPost = g.posts[quote]) { - handleQuotes(quotedPost, 'backlinks'); + _ref = post.quotes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + quote = _ref[_i]; + if (qPost = posts[quote]) { + handleQuotes(qPost, 'backlinks'); } } } return quotelinks.filter(function(quotelink) { - var boardID, postID, _ref3; - _ref3 = Get.postDataFromLink(quotelink), boardID = _ref3.boardID, postID = _ref3.postID; + var boardID, postID, _ref1; + _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID; return boardID === post.board.ID && postID === post.ID; }); }, @@ -4400,16 +4440,14 @@ } }, apply: function() { - var ID, args, fullID, post, recursive, _ref; + var args, fullID, post, recursive; recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; fullID = post.fullID; - _ref = g.posts; - for (ID in _ref) { - post = _ref[ID]; + return g.posts.forEach(function(post) { if (__indexOf.call(post.quotes, fullID) >= 0) { - recursive.apply(null, [post].concat(__slice.call(args))); + return recursive.apply(null, [post].concat(__slice.call(args))); } - } + }); } }; @@ -5125,14 +5163,11 @@ return QuoteThreading.force(); }, force: function() { - var ID, post, _ref; - _ref = g.posts; - for (ID in _ref) { - post = _ref[ID]; + return g.posts.forEach(function(post) { if (post.cb) { - post.cb(true); + return post.cb(true); } - } + }); }, node: function() { var keys, len, post, posts, quote, _i, _len, _ref; @@ -5199,20 +5234,18 @@ return true; }, toggle: function() { - var ID, container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + var container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref; if (QuoteThreading.enabled = this.checked) { QuoteThreading.force(); } else { thread = $('.thread'); posts = []; nodes = []; - _ref = g.posts; - for (ID in _ref) { - post = _ref[ID]; + g.posts.forEach(function(post) { if (!(post === post.thread.OP || post.isClone)) { - posts.push(post); + return posts.push(post); } - } + }); posts.sort(function(a, b) { return a.ID - b.ID; }); @@ -5226,9 +5259,9 @@ container = containers[_j]; $.rm(container); } - _ref1 = $$('.threadOP'); - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - post = _ref1[_k]; + _ref = $$('.threadOP'); + for (_k = 0, _len2 = _ref.length; _k < _len2; _k++) { + post = _ref[_k]; $.rmClass(post, 'threadOP'); } } @@ -5836,13 +5869,15 @@ return QR.nodes.fileInput.click(); }, generatePostableThreadsList: function() { - var list, options, thread, val; + var list, options, thread, val, _i, _len, _ref; if (!QR.nodes) { return; } list = QR.nodes.thread; options = [list.firstChild]; - for (thread in g.BOARD.threads) { + _ref = g.BOARD.threads.keys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + thread = _ref[_i]; options.push($.el('option', { value: thread, textContent: "Thread No." + thread @@ -7371,8 +7406,19 @@ return ImageExpand.toggle(Get.postFromNode(this)); }, toggleAll: function() { - var ID, file, func, post, _i, _len, _ref, _ref1; + var func; $.event('CloseMenu'); + func = function(post) { + var file; + file = post.file; + if (!(file && file.isImage && doc.contains(post.nodes.root))) { + return; + } + if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && Header.getTopOf(file.thumb) < 0)) { + return; + } + return $.queueTask(func, post); + }; if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) { ImageExpand.EAI.className = 'contract-all-shortcut fa fa-compress'; ImageExpand.EAI.title = 'Contract All Images'; @@ -7382,22 +7428,15 @@ ImageExpand.EAI.title = 'Expand All Images'; func = ImageExpand.contract; } - _ref = g.posts; - for (ID in _ref) { - post = _ref[ID]; - _ref1 = [post].concat(post.clones); - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - post = _ref1[_i]; - file = post.file; - if (!(file && file.isImage && doc.contains(post.nodes.root))) { - continue; - } - if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && Header.getTopOf(file.thumb) < 0)) { - continue; - } - $.queueTask(func, post); + return g.posts.forEach(function(post) { + var _i, _len, _ref; + func(post); + _ref = post.clones; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + post = _ref[_i]; + func(post); } - } + }); }, setFitness: function() { return (this.checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-')); @@ -7681,6 +7720,10 @@ name: 'Image Replace', cb: this.node }); + Thread.callbacks.push({ + name: 'Image Replace', + cb: this.thread + }); if (!(Conf['Image Prefetching'] && g.VIEW === 'thread')) { return; } @@ -7695,6 +7738,9 @@ order: 104 }); }, + thread: function() { + return ImageLoader.thread = this; + }, node: function() { var URL, img, string, style, thumb, type, _ref, _ref1; if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) { @@ -7717,14 +7763,10 @@ return img.src = URL; }, toggle: function() { - var enabled, id, post, _ref; + var enabled; enabled = Conf['prefetch'] = this.checked; if (enabled) { - _ref = g.threads["" + g.BOARD.ID + "." + g.THREADID].posts; - for (id in _ref) { - post = _ref[id]; - ImageLoader.node.call(post); - } + ImageLoader.thread.posts.forEach(ImageLoader.node.call); } } }; @@ -8721,17 +8763,15 @@ }); }, node: function() { - var ID, fileCount, post, postCount, _ref; + var fileCount, postCount; postCount = 0; fileCount = 0; - _ref = this.posts; - for (ID in _ref) { - post = _ref[ID]; + this.posts.forEach(function(post) { postCount++; if (post.file) { - fileCount++; + return fileCount++; } - } + }); ThreadStats.thread = this; ThreadStats.fetchPage(); ThreadStats.update(postCount, fileCount); @@ -9112,7 +9152,7 @@ return new Notice('info', "The thread is " + change + ".", 30); }, parse: function(postObjects) { - var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _len, _ref; + var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1, _ref; OP = postObjects[0]; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); @@ -9139,9 +9179,11 @@ } deletedPosts = []; deletedFiles = []; - _ref = ThreadUpdater.thread.posts; - for (ID in _ref) { - post = _ref[ID]; + posts = ThreadUpdater.thread.posts; + _ref = posts.keys; + for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { + ID = _ref[_j]; + post = posts[ID]; ID = +ID; if (__indexOf.call(index, ID) < 0) { post.kill(); @@ -9360,7 +9402,7 @@ _ref = db.data.boards[boardID]; for (threadID in _ref) { data = _ref[threadID]; - if (!data.isDead && !(threadID in g.BOARD.threads)) { + if (!data.isDead && __indexOf.call(g.BOARD.threads.keys, threadID) < 0) { if (Conf['Auto Prune']) { ThreadWatcher.db["delete"]({ boardID: boardID, @@ -9498,7 +9540,7 @@ return div; }, refresh: function() { - var boardID, data, helper, list, nodes, refresher, thread, threadID, toggler, watched, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3; + var boardID, data, helper, list, nodes, refresher, thread, threadID, threads, toggler, watched, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; nodes = []; _ref = ThreadWatcher.getAll(); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -9508,9 +9550,11 @@ list = ThreadWatcher.list; $.rmAll(list); $.add(list, nodes); - _ref2 = g.BOARD.threads; - for (threadID in _ref2) { - thread = _ref2[threadID]; + threads = g.BOARD.threads; + _ref2 = threads.keys; + for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { + threadID = _ref2[_j]; + thread = threads[threadID]; toggler = $('.watch-thread-link', thread.OP.nodes.post); watched = ThreadWatcher.db.get({ boardID: thread.board.ID, @@ -9521,8 +9565,8 @@ toggler.title = "" + helper[1] + " Thread"; } _ref3 = ThreadWatcher.menu.refreshers; - for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { - refresher = _ref3[_j]; + for (_k = 0, _len2 = _ref3.length; _k < _len2; _k++) { + refresher = _ref3[_k]; refresher(); } }, @@ -9763,16 +9807,14 @@ } }, ready: function() { - var ID, post, posts, _ref; + var posts; $.off(d, '4chanXInitFinished', Unread.ready); posts = []; - _ref = Unread.thread.posts; - for (ID in _ref) { - post = _ref[ID]; + Unread.thread.posts.forEach(function(post) { if (post.isReply) { - posts.push(post); + return posts.push(post); } - } + }); if (!Conf['Quote Threading']) { Unread.addPosts(posts); } @@ -9784,7 +9826,7 @@ } }, scroll: function() { - var down, hash, post, posts, root; + var down, hash, keys, post, posts, root; if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { return; } @@ -9799,8 +9841,9 @@ } down = true; } else { - posts = Object.keys(Unread.thread.posts); - root = Unread.thread.posts[posts[posts.length - 1]].nodes.root; + posts = Unread.thread.posts; + keys = posts.keys; + root = posts[keys[keys.length - 1]].nodes.root; } if (Header.getBottomOf(root) < 0) { return Header.scrollTo(root, down); @@ -10700,13 +10743,10 @@ } }, onIndexRefresh: function() { - var thread, threadID, _ref; ExpandThread.disconnect(true); - _ref = g.BOARD.threads; - for (threadID in _ref) { - thread = _ref[threadID]; - ExpandThread.setButton(thread); - } + return g.BOARD.threads.forEach(function(thread) { + return ExpandThread.setButton(thread); + }); }, text: function(status, posts, files) { return ("" + status + " " + posts + " post" + (posts > 1 ? 's' : '')) + (+files ? " and " + files + " image repl" + (files > 1 ? 'ies' : 'y') : "") + (" " + (status === '-' ? 'shown' : 'omitted') + "."); @@ -11924,13 +11964,11 @@ } }, clean: function() { - var id, posts, thread, threads, _ref; + var posts, threads; posts = g.posts, threads = g.threads; - _ref = g.threads; - for (id in _ref) { - thread = _ref[id]; - thread.collect(); - } + g.threads.forEach(function(thread) { + return thread.collect(); + }); QuoteBacklink.containers = {}; return $.rmAll($('.board')); }, @@ -12876,6 +12914,8 @@ Main = { init: function() { var db, flatten, pathname, _i, _len, _ref, _ref1; + g.threads = new SimpleDict; + g.posts = new SimpleDict; pathname = location.pathname.split('/'); g.BOARD = new Board(pathname[1]); if ((_ref = g.BOARD.ID) === 'z' || _ref === 'fk') { diff --git a/builds/crx/script.js b/builds/crx/script.js index ed2fe23e3..7f1b2cea6 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -82,7 +82,7 @@ 'use strict'; (function() { - var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, Callbacks, 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, Navigate, 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, + var $, $$, Anonymize, ArchiveLink, AutoGIF, Banner, Board, Build, Callbacks, 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, Navigate, 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, SimpleDict, 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; }, __slice = [].slice, __hasProp = {}.hasOwnProperty, @@ -341,9 +341,7 @@ g = { VERSION: '1.3.2', NAMESPACE: '4chan X.', - boards: {}, - threads: {}, - posts: {} + boards: {} }; $ = function(selector, root) { @@ -812,6 +810,16 @@ }; })(); + $.remove = function(arr, value) { + var i; + i = arr.indexOf(value); + if (i === -1) { + return false; + } + arr.splice(i, 1); + return true; + }; + $$ = function(selector, root) { if (root == null) { root = d.body; @@ -885,8 +893,8 @@ function Board(ID) { this.ID = ID; - this.threads = {}; - this.posts = {}; + this.threads = new SimpleDict; + this.posts = new SimpleDict; g.boards[this] = this; } @@ -905,12 +913,12 @@ this.ID = ID; this.board = board; this.fullID = "" + this.board + "." + this.ID; - this.posts = {}; + this.posts = new SimpleDict; this.isSticky = false; this.isClosed = false; this.postLimit = false; this.fileLimit = false; - g.threads[this.fullID] = board.threads[this] = this; + g.threads.push(this.fullID, board.threads.push(this, this)); } Thread.prototype.setPage = function(pageNum) { @@ -954,14 +962,11 @@ }; Thread.prototype.collect = function() { - var post, postID, _ref; - _ref = this.posts; - for (postID in _ref) { - post = _ref[postID]; - post.collect(); - } - delete g.threads[this.fullID]; - return delete this.board.threads[this]; + this.posts.forEach(function(post) { + return post.collect(); + }); + g.threads.rm(this.fullID); + return this.board.threads.rm(this); }; return Thread; @@ -1040,7 +1045,7 @@ this.parseQuotes(); this.parseFile(that); this.clones = []; - g.posts[this.fullID] = thread.posts[this] = board.posts[this] = this; + g.posts.push(this.fullID, thread.posts.push(this, board.posts.push(this, this))); if (that.isArchived) { this.kill(); } @@ -1211,9 +1216,9 @@ Post.prototype.collect = function() { this.kill(); - delete g.posts[this.fullID]; - delete this.thread.posts[this]; - return delete this.board.posts[this]; + g.posts.rm(this.fullID); + this.thread.posts.rm(this); + return this.board.posts.rm(this); }; Post.prototype.addClone = function(context) { @@ -1611,6 +1616,41 @@ })(); + SimpleDict = (function() { + function SimpleDict() { + this.keys = []; + } + + SimpleDict.prototype.push = function(key, data) { + key = "" + key; + if (!this[key]) { + this.keys.push(key); + } + return this[key] = data; + }; + + SimpleDict.prototype.rm = function(key) { + key = "" + key; + if ($.remove(this.keys, key)) { + return delete this[key]; + } + }; + + SimpleDict.prototype.forEach = function(fn) { + var key, _i, _len, _ref, _results; + _ref = __slice.call(this.keys); + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + key = _ref[_i]; + _results.push(fn(this[key])); + } + return _results; + }; + + return SimpleDict; + + })(); + Polyfill = { init: function() { this.notificationPermission(); @@ -2569,7 +2609,7 @@ } } catch (_error) { err = _error; - c.error('Index failure:', err); + c.error("Index failure: " + err.message, err.stack); if (notice) { notice.setType('error'); notice.el.lastElementChild.textContent = 'Index refresh failed.'; @@ -2597,7 +2637,6 @@ return Index.setPage(); }, parseThreadList: function(pages) { - var thread, threadID, _ref, _ref1; Index.pagesNum = pages.length; Index.threadsNumPerPage = pages[0].threads.length; Index.liveThreadData = pages.reduce((function(arr, next) { @@ -2606,13 +2645,12 @@ Index.liveThreadIDs = Index.liveThreadData.map(function(data) { return data.no; }); - _ref = g.BOARD.threads; - for (threadID in _ref) { - thread = _ref[threadID]; - if (_ref1 = thread.ID, __indexOf.call(Index.liveThreadIDs, _ref1) < 0) { - thread.collect(); + g.BOARD.threads.forEach(function(thread) { + var _ref; + if (_ref = thread.ID, __indexOf.call(Index.liveThreadIDs, _ref) < 0) { + return thread.collect(); } - } + }); }, buildThreads: function() { var err, errors, i, posts, thread, threadData, threadRoot, threads, _i, _len, _ref; @@ -2622,20 +2660,20 @@ _ref = Index.liveThreadData; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { threadData = _ref[i]; - threadRoot = Build.thread(g.BOARD, threadData); - Index.nodes.push(threadRoot, $.el('hr')); - if (thread = g.BOARD.threads[threadData.no]) { - thread.setPage(Math.floor(i / Index.threadsNumPerPage)); - thread.setStatus('Sticky', !!threadData.sticky); - thread.setStatus('Closed', !!threadData.closed); - } else { - thread = new Thread(threadData.no, g.BOARD); - threads.push(thread); - } - if (thread.ID in thread.posts) { - continue; - } try { + threadRoot = Build.thread(g.BOARD, threadData); + if (thread = g.BOARD.threads[threadData.no]) { + thread.setPage(Math.floor(i / Index.threadsNumPerPage)); + thread.setStatus('Sticky', !!threadData.sticky); + thread.setStatus('Closed', !!threadData.closed); + } else { + thread = new Thread(threadData.no, g.BOARD); + threads.push(thread); + } + Index.nodes.push(threadRoot, $.el('hr')); + if (thread.ID in thread.posts) { + continue; + } posts.push(new Post($('.opContainer', threadRoot), thread, g.BOARD)); } catch (_error) { err = _error; @@ -2643,7 +2681,7 @@ errors = []; } errors.push({ - message: "Parsing of Post No." + thread + " failed. Post will be skipped.", + message: "Parsing of Thread No." + thread + " failed. Thread will be skipped.", error: err }); } @@ -3115,36 +3153,38 @@ }; }, allQuotelinksLinkingTo: function(post) { - var ID, handleQuotes, quote, quotedPost, quotelinks, quoterPost, _i, _len, _ref, _ref1, _ref2; + var fullID, handleQuotes, posts, qPost, quote, quotelinks, _i, _len, _ref; quotelinks = []; - handleQuotes = function(post, type) { + posts = g.posts; + fullID = { + post: post + }; + handleQuotes = function(qPost, type) { var clone, _i, _len, _ref; - quotelinks.push.apply(quotelinks, post.nodes[type]); - _ref = post.clones; + quotelinks.push.apply(quotelinks, qPost.nodes[type]); + _ref = qPost.clones; for (_i = 0, _len = _ref.length; _i < _len; _i++) { clone = _ref[_i]; quotelinks.push.apply(quotelinks, clone.nodes[type]); } }; - _ref = g.posts; - for (ID in _ref) { - quoterPost = _ref[ID]; - if (_ref1 = post.fullID, __indexOf.call(quoterPost.quotes, _ref1) >= 0) { - handleQuotes(quoterPost, 'quotelinks'); + posts.forEach(function(qPost) { + if (__indexOf.call(qPost.quotes, fullID) >= 0) { + return handleQuotes(qPost, 'quotelinks'); } - } + }); if (Conf['Quote Backlinks']) { - _ref2 = post.quotes; - for (_i = 0, _len = _ref2.length; _i < _len; _i++) { - quote = _ref2[_i]; - if (quotedPost = g.posts[quote]) { - handleQuotes(quotedPost, 'backlinks'); + _ref = post.quotes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + quote = _ref[_i]; + if (qPost = posts[quote]) { + handleQuotes(qPost, 'backlinks'); } } } return quotelinks.filter(function(quotelink) { - var boardID, postID, _ref3; - _ref3 = Get.postDataFromLink(quotelink), boardID = _ref3.boardID, postID = _ref3.postID; + var boardID, postID, _ref1; + _ref1 = Get.postDataFromLink(quotelink), boardID = _ref1.boardID, postID = _ref1.postID; return boardID === post.board.ID && postID === post.ID; }); }, @@ -4403,16 +4443,14 @@ } }, apply: function() { - var ID, args, fullID, post, recursive, _ref; + var args, fullID, post, recursive; recursive = arguments[0], post = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : []; fullID = post.fullID; - _ref = g.posts; - for (ID in _ref) { - post = _ref[ID]; + return g.posts.forEach(function(post) { if (__indexOf.call(post.quotes, fullID) >= 0) { - recursive.apply(null, [post].concat(__slice.call(args))); + return recursive.apply(null, [post].concat(__slice.call(args))); } - } + }); } }; @@ -5128,14 +5166,11 @@ return QuoteThreading.force(); }, force: function() { - var ID, post, _ref; - _ref = g.posts; - for (ID in _ref) { - post = _ref[ID]; + return g.posts.forEach(function(post) { if (post.cb) { - post.cb(true); + return post.cb(true); } - } + }); }, node: function() { var keys, len, post, posts, quote, _i, _len, _ref; @@ -5202,20 +5237,18 @@ return true; }, toggle: function() { - var ID, container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref, _ref1; + var container, containers, nodes, post, posts, thread, _i, _j, _k, _len, _len1, _len2, _ref; if (QuoteThreading.enabled = this.checked) { QuoteThreading.force(); } else { thread = $('.thread'); posts = []; nodes = []; - _ref = g.posts; - for (ID in _ref) { - post = _ref[ID]; + g.posts.forEach(function(post) { if (!(post === post.thread.OP || post.isClone)) { - posts.push(post); + return posts.push(post); } - } + }); posts.sort(function(a, b) { return a.ID - b.ID; }); @@ -5229,9 +5262,9 @@ container = containers[_j]; $.rm(container); } - _ref1 = $$('.threadOP'); - for (_k = 0, _len2 = _ref1.length; _k < _len2; _k++) { - post = _ref1[_k]; + _ref = $$('.threadOP'); + for (_k = 0, _len2 = _ref.length; _k < _len2; _k++) { + post = _ref[_k]; $.rmClass(post, 'threadOP'); } } @@ -5844,13 +5877,15 @@ return QR.nodes.fileInput.click(); }, generatePostableThreadsList: function() { - var list, options, thread, val; + var list, options, thread, val, _i, _len, _ref; if (!QR.nodes) { return; } list = QR.nodes.thread; options = [list.firstChild]; - for (thread in g.BOARD.threads) { + _ref = g.BOARD.threads.keys; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + thread = _ref[_i]; options.push($.el('option', { value: thread, textContent: "Thread No." + thread @@ -7354,8 +7389,19 @@ return ImageExpand.toggle(Get.postFromNode(this)); }, toggleAll: function() { - var ID, file, func, post, _i, _len, _ref, _ref1; + var func; $.event('CloseMenu'); + func = function(post) { + var file; + file = post.file; + if (!(file && file.isImage && doc.contains(post.nodes.root))) { + return; + } + if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && Header.getTopOf(file.thumb) < 0)) { + return; + } + return $.queueTask(func, post); + }; if (ImageExpand.on = $.hasClass(ImageExpand.EAI, 'expand-all-shortcut')) { ImageExpand.EAI.className = 'contract-all-shortcut fa fa-compress'; ImageExpand.EAI.title = 'Contract All Images'; @@ -7365,22 +7411,15 @@ ImageExpand.EAI.title = 'Expand All Images'; func = ImageExpand.contract; } - _ref = g.posts; - for (ID in _ref) { - post = _ref[ID]; - _ref1 = [post].concat(post.clones); - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - post = _ref1[_i]; - file = post.file; - if (!(file && file.isImage && doc.contains(post.nodes.root))) { - continue; - } - if (ImageExpand.on && (!Conf['Expand spoilers'] && file.isSpoiler || Conf['Expand from here'] && Header.getTopOf(file.thumb) < 0)) { - continue; - } - $.queueTask(func, post); + return g.posts.forEach(function(post) { + var _i, _len, _ref; + func(post); + _ref = post.clones; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + post = _ref[_i]; + func(post); } - } + }); }, setFitness: function() { return (this.checked ? $.addClass : $.rmClass)(doc, this.name.toLowerCase().replace(/\s+/g, '-')); @@ -7664,6 +7703,10 @@ name: 'Image Replace', cb: this.node }); + Thread.callbacks.push({ + name: 'Image Replace', + cb: this.thread + }); if (!(Conf['Image Prefetching'] && g.VIEW === 'thread')) { return; } @@ -7678,6 +7721,9 @@ order: 104 }); }, + thread: function() { + return ImageLoader.thread = this; + }, node: function() { var URL, img, string, style, thumb, type, _ref, _ref1; if (this.isClone || this.isHidden || this.thread.isHidden || !((_ref = this.file) != null ? _ref.isImage : void 0)) { @@ -7700,14 +7746,10 @@ return img.src = URL; }, toggle: function() { - var enabled, id, post, _ref; + var enabled; enabled = Conf['prefetch'] = this.checked; if (enabled) { - _ref = g.threads["" + g.BOARD.ID + "." + g.THREADID].posts; - for (id in _ref) { - post = _ref[id]; - ImageLoader.node.call(post); - } + ImageLoader.thread.posts.forEach(ImageLoader.node.call); } } }; @@ -8704,17 +8746,15 @@ }); }, node: function() { - var ID, fileCount, post, postCount, _ref; + var fileCount, postCount; postCount = 0; fileCount = 0; - _ref = this.posts; - for (ID in _ref) { - post = _ref[ID]; + this.posts.forEach(function(post) { postCount++; if (post.file) { - fileCount++; + return fileCount++; } - } + }); ThreadStats.thread = this; ThreadStats.fetchPage(); ThreadStats.update(postCount, fileCount); @@ -9095,7 +9135,7 @@ return new Notice('info', "The thread is " + change + ".", 30); }, parse: function(postObjects) { - var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _len, _ref; + var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1, _ref; OP = postObjects[0]; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); @@ -9122,9 +9162,11 @@ } deletedPosts = []; deletedFiles = []; - _ref = ThreadUpdater.thread.posts; - for (ID in _ref) { - post = _ref[ID]; + posts = ThreadUpdater.thread.posts; + _ref = posts.keys; + for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { + ID = _ref[_j]; + post = posts[ID]; ID = +ID; if (__indexOf.call(index, ID) < 0) { post.kill(); @@ -9343,7 +9385,7 @@ _ref = db.data.boards[boardID]; for (threadID in _ref) { data = _ref[threadID]; - if (!data.isDead && !(threadID in g.BOARD.threads)) { + if (!data.isDead && __indexOf.call(g.BOARD.threads.keys, threadID) < 0) { if (Conf['Auto Prune']) { ThreadWatcher.db["delete"]({ boardID: boardID, @@ -9481,7 +9523,7 @@ return div; }, refresh: function() { - var boardID, data, helper, list, nodes, refresher, thread, threadID, toggler, watched, _i, _j, _len, _len1, _ref, _ref1, _ref2, _ref3; + var boardID, data, helper, list, nodes, refresher, thread, threadID, threads, toggler, watched, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2, _ref3; nodes = []; _ref = ThreadWatcher.getAll(); for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -9491,9 +9533,11 @@ list = ThreadWatcher.list; $.rmAll(list); $.add(list, nodes); - _ref2 = g.BOARD.threads; - for (threadID in _ref2) { - thread = _ref2[threadID]; + threads = g.BOARD.threads; + _ref2 = threads.keys; + for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) { + threadID = _ref2[_j]; + thread = threads[threadID]; toggler = $('.watch-thread-link', thread.OP.nodes.post); watched = ThreadWatcher.db.get({ boardID: thread.board.ID, @@ -9504,8 +9548,8 @@ toggler.title = "" + helper[1] + " Thread"; } _ref3 = ThreadWatcher.menu.refreshers; - for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) { - refresher = _ref3[_j]; + for (_k = 0, _len2 = _ref3.length; _k < _len2; _k++) { + refresher = _ref3[_k]; refresher(); } }, @@ -9746,16 +9790,14 @@ } }, ready: function() { - var ID, post, posts, _ref; + var posts; $.off(d, '4chanXInitFinished', Unread.ready); posts = []; - _ref = Unread.thread.posts; - for (ID in _ref) { - post = _ref[ID]; + Unread.thread.posts.forEach(function(post) { if (post.isReply) { - posts.push(post); + return posts.push(post); } - } + }); if (!Conf['Quote Threading']) { Unread.addPosts(posts); } @@ -9767,7 +9809,7 @@ } }, scroll: function() { - var down, hash, post, posts, root; + var down, hash, keys, post, posts, root; if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { return; } @@ -9782,8 +9824,9 @@ } down = true; } else { - posts = Object.keys(Unread.thread.posts); - root = Unread.thread.posts[posts[posts.length - 1]].nodes.root; + posts = Unread.thread.posts; + keys = posts.keys; + root = posts[keys[keys.length - 1]].nodes.root; } if (Header.getBottomOf(root) < 0) { return Header.scrollTo(root, down); @@ -10689,13 +10732,10 @@ } }, onIndexRefresh: function() { - var thread, threadID, _ref; ExpandThread.disconnect(true); - _ref = g.BOARD.threads; - for (threadID in _ref) { - thread = _ref[threadID]; - ExpandThread.setButton(thread); - } + return g.BOARD.threads.forEach(function(thread) { + return ExpandThread.setButton(thread); + }); }, text: function(status, posts, files) { return ("" + status + " " + posts + " post" + (posts > 1 ? 's' : '')) + (+files ? " and " + files + " image repl" + (files > 1 ? 'ies' : 'y') : "") + (" " + (status === '-' ? 'shown' : 'omitted') + "."); @@ -11913,13 +11953,11 @@ } }, clean: function() { - var id, posts, thread, threads, _ref; + var posts, threads; posts = g.posts, threads = g.threads; - _ref = g.threads; - for (id in _ref) { - thread = _ref[id]; - thread.collect(); - } + g.threads.forEach(function(thread) { + return thread.collect(); + }); QuoteBacklink.containers = {}; return $.rmAll($('.board')); }, @@ -12863,6 +12901,8 @@ Main = { init: function() { var db, flatten, pathname, _i, _len, _ref, _ref1; + g.threads = new SimpleDict; + g.posts = new SimpleDict; pathname = location.pathname.split('/'); g.BOARD = new Board(pathname[1]); if ((_ref = g.BOARD.ID) === 'z' || _ref === 'fk') { diff --git a/src/Filtering/Recursive.coffee b/src/Filtering/Recursive.coffee index da5496ceb..6d84dd78b 100755 --- a/src/Filtering/Recursive.coffee +++ b/src/Filtering/Recursive.coffee @@ -32,7 +32,6 @@ Recursive = apply: (recursive, post, args...) -> {fullID} = post - for ID, post of g.posts + g.posts.forEach (post) -> if fullID in post.quotes recursive post, args... - return diff --git a/src/General/Get.coffee b/src/General/Get.coffee index 605a0f651..0f41b7f9e 100755 --- a/src/General/Get.coffee +++ b/src/General/Get.coffee @@ -40,22 +40,28 @@ Get = allQuotelinksLinkingTo: (post) -> # Get quotelinks & backlinks linking to the given post. quotelinks = [] - handleQuotes = (post, type) -> - quotelinks.push post.nodes[type]... - quotelinks.push clone.nodes[type]... for clone in post.clones + {posts} = g + fullID = {post} + handleQuotes = (qPost, type) -> + quotelinks.push qPost.nodes[type]... + quotelinks.push clone.nodes[type]... for clone in qPost.clones return # First: # In every posts, # if it did quote this post, # get all their backlinks. - handleQuotes quoterPost, 'quotelinks' for ID, quoterPost of g.posts when post.fullID in quoterPost.quotes + posts.forEach (qPost) -> + if fullID in qPost.quotes + handleQuotes qPost, 'quotelinks' + # Second: # If we have quote backlinks: # in all posts this post quoted # and their clones, # get all of their backlinks. if Conf['Quote Backlinks'] - handleQuotes quotedPost, 'backlinks' for quote in post.quotes when quotedPost = g.posts[quote] + handleQuotes qPost, 'backlinks' for quote in post.quotes when qPost = posts[quote] + # Third: # Filter out irrelevant quotelinks. quotelinks.filter (quotelink) -> diff --git a/src/General/Globals.coffee b/src/General/Globals.coffee index d5d09eaa6..e301f775a 100755 --- a/src/General/Globals.coffee +++ b/src/General/Globals.coffee @@ -5,6 +5,4 @@ doc = d.documentElement g = VERSION: '<%= version %>' NAMESPACE: '<%= meta.name %>.' - boards: {} - threads: {} - posts: {} + boards: {} \ No newline at end of file diff --git a/src/General/Index.coffee b/src/General/Index.coffee index b293af5de..5438d1bdc 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -277,7 +277,7 @@ Index = else if req.status is 304 and pageNum? Index.pageNav pageNum catch err - c.error 'Index failure:', err + c.error "Index failure: #{err.message}", err.stack # network error or non-JSON content for example. if notice notice.setType 'error' @@ -308,8 +308,8 @@ Index = Index.threadsNumPerPage = pages[0].threads.length Index.liveThreadData = pages.reduce ((arr, next) -> arr.concat next.threads), [] Index.liveThreadIDs = Index.liveThreadData.map (data) -> data.no - for threadID, thread of g.BOARD.threads when thread.ID not in Index.liveThreadIDs - thread.collect() + g.BOARD.threads.forEach (thread) -> + thread.collect() unless thread.ID in Index.liveThreadIDs return buildThreads: -> @@ -317,23 +317,23 @@ Index = threads = [] posts = [] for threadData, i in Index.liveThreadData - threadRoot = Build.thread g.BOARD, threadData - Index.nodes.push threadRoot, $.el 'hr' - if thread = g.BOARD.threads[threadData.no] - thread.setPage Math.floor i / Index.threadsNumPerPage - thread.setStatus 'Sticky', !!threadData.sticky - thread.setStatus 'Closed', !!threadData.closed - else - thread = new Thread threadData.no, g.BOARD - threads.push thread - continue if thread.ID of thread.posts try + threadRoot = Build.thread g.BOARD, threadData + if thread = g.BOARD.threads[threadData.no] + thread.setPage Math.floor i / Index.threadsNumPerPage + thread.setStatus 'Sticky', !!threadData.sticky + thread.setStatus 'Closed', !!threadData.closed + else + thread = new Thread threadData.no, g.BOARD + threads.push thread + Index.nodes.push threadRoot, $.el 'hr' + continue if thread.ID of thread.posts posts.push new Post $('.opContainer', threadRoot), thread, g.BOARD catch err # Skip posts that we failed to parse. errors = [] unless errors errors.push - message: "Parsing of Post No.#{thread} failed. Post will be skipped." + message: "Parsing of Thread No.#{thread} failed. Thread will be skipped." error: err Main.handleErrors errors if errors diff --git a/src/General/Main.coffee b/src/General/Main.coffee index 7ccb225ac..5603518a0 100755 --- a/src/General/Main.coffee +++ b/src/General/Main.coffee @@ -1,5 +1,8 @@ Main = init: -> + g.threads = new SimpleDict + g.posts = new SimpleDict + pathname = location.pathname.split '/' g.BOARD = new Board pathname[1] return if g.BOARD.ID in ['z', 'fk'] diff --git a/src/General/Navigate.coffee b/src/General/Navigate.coffee index 43659ebc9..95a0d9d2d 100644 --- a/src/General/Navigate.coffee +++ b/src/General/Navigate.coffee @@ -34,7 +34,7 @@ Navigate = {posts, threads} = g # Garbage collection - thread.collect() for id, thread of g.threads + g.threads.forEach (thread) -> thread.collect() QuoteBacklink.containers = {} diff --git a/src/General/lib/$.coffee b/src/General/lib/$.coffee index 87807ac9c..3e45ed12a 100755 --- a/src/General/lib/$.coffee +++ b/src/General/lib/$.coffee @@ -404,5 +404,11 @@ $.set = do -> return <% } %> +$.remove = (arr, value) -> + i = arr.indexOf value + return false if i is -1 + arr.splice i, 1 + true + $$ = (selector, root=d.body) -> [root.querySelectorAll(selector)...] diff --git a/src/General/lib/board.class b/src/General/lib/board.class index 23d9211b5..4b4fdd720 100755 --- a/src/General/lib/board.class +++ b/src/General/lib/board.class @@ -2,7 +2,7 @@ class Board toString: -> @ID constructor: (@ID) -> - @threads = {} - @posts = {} + @threads = new SimpleDict + @posts = new SimpleDict g.boards[@] = @ \ No newline at end of file diff --git a/src/General/lib/classes.coffee b/src/General/lib/classes.coffee index 5654ff914..eba1788af 100755 --- a/src/General/lib/classes.coffee +++ b/src/General/lib/classes.coffee @@ -5,4 +5,5 @@ <%= grunt.file.read('src/General/lib/clone.class') %> <%= grunt.file.read('src/General/lib/databoard.class') %> <%= grunt.file.read('src/General/lib/notice.class') %> -<%= grunt.file.read('src/General/lib/randomaccesslist.class') %> \ No newline at end of file +<%= grunt.file.read('src/General/lib/randomaccesslist.class') %> +<%= grunt.file.read('src/General/lib/simpledict.class') %> \ No newline at end of file diff --git a/src/General/lib/post.class b/src/General/lib/post.class index b1a3f4beb..a5e6ebc6f 100755 --- a/src/General/lib/post.class +++ b/src/General/lib/post.class @@ -54,7 +54,7 @@ class Post @parseFile that @clones = [] - g.posts[@fullID] = thread.posts[@] = board.posts[@] = @ + g.posts.push @fullID, thread.posts.push @, board.posts.push @, @ @kill() if that.isArchived parseComment: -> @@ -208,9 +208,9 @@ class Post collect: -> @kill() - delete g.posts[@fullID] - delete @thread.posts[@] - delete @board.posts[@] + g.posts.rm @fullID + @thread.posts.rm @ + @board.posts.rm @ addClone: (context) -> new Clone @, context diff --git a/src/General/lib/simpledict.class b/src/General/lib/simpledict.class new file mode 100644 index 000000000..7dddffc69 --- /dev/null +++ b/src/General/lib/simpledict.class @@ -0,0 +1,14 @@ +class SimpleDict + constructor: -> + @keys = [] + + push: (key, data) -> + key = "#{key}" + @keys.push key unless @[key] + @[key] = data + + rm: (key) -> + key = "#{key}" + delete @[key] if $.remove @keys, key + + forEach: (fn) -> fn @[key] for key in [@keys...] diff --git a/src/General/lib/thread.class b/src/General/lib/thread.class index da1bfbb03..48153a54d 100755 --- a/src/General/lib/thread.class +++ b/src/General/lib/thread.class @@ -4,13 +4,13 @@ class Thread constructor: (@ID, @board) -> @fullID = "#{@board}.#{@ID}" - @posts = {} + @posts = new SimpleDict @isSticky = false @isClosed = false @postLimit = false @fileLimit = false - g.threads[@fullID] = board.threads[@] = @ + g.threads.push @fullID, board.threads.push @, @ setPage: (pageNum) -> icon = $ '.page-num', @OP.nodes.post @@ -44,6 +44,6 @@ class Thread @timeOfDeath = Date.now() collect: -> - post.collect() for postID, post of @posts - delete g.threads[@fullID] - delete @board.threads[@] + @posts.forEach (post) -> post.collect() + g.threads.rm @fullID + @board.threads.rm @ diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index 135a50481..b4e1f1ed5 100755 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -32,6 +32,14 @@ ImageExpand = ImageExpand.toggle Get.postFromNode @ toggleAll: -> $.event 'CloseMenu' + func = (post) -> + {file} = post + return unless file and file.isImage and doc.contains post.nodes.root + if ImageExpand.on and + (!Conf['Expand spoilers'] and file.isSpoiler or + Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0) + return + $.queueTask func, post if ImageExpand.on = $.hasClass ImageExpand.EAI, 'expand-all-shortcut' ImageExpand.EAI.className = 'contract-all-shortcut fa fa-compress' ImageExpand.EAI.title = 'Contract All Images' @@ -40,16 +48,10 @@ ImageExpand = ImageExpand.EAI.className = 'expand-all-shortcut fa fa-expand' ImageExpand.EAI.title = 'Expand All Images' func = ImageExpand.contract - for ID, post of g.posts - for post in [post].concat post.clones - {file} = post - continue unless file and file.isImage and doc.contains post.nodes.root - if ImageExpand.on and - (!Conf['Expand spoilers'] and file.isSpoiler or - Conf['Expand from here'] and Header.getTopOf(file.thumb) < 0) - continue - $.queueTask func, post - return + g.posts.forEach (post) -> + func post + func post for post in post.clones + return setFitness: -> (if @checked then $.addClass else $.rmClass) doc, @name.toLowerCase().replace /\s+/g, '-' diff --git a/src/Images/ImageLoader.coffee b/src/Images/ImageLoader.coffee index 66220873e..dd9d8af99 100755 --- a/src/Images/ImageLoader.coffee +++ b/src/Images/ImageLoader.coffee @@ -7,6 +7,10 @@ ImageLoader = name: 'Image Replace' cb: @node + Thread.callbacks.push + name: 'Image Replace' + cb: @thread + return unless Conf['Image Prefetching'] and g.VIEW is 'thread' prefetch = $.el 'label', @@ -19,6 +23,9 @@ ImageLoader = type: 'header' el: prefetch order: 104 + + thread: -> + ImageLoader.thread = @ node: -> return if @isClone or @isHidden or @thread.isHidden or !@file?.isImage @@ -38,5 +45,5 @@ ImageLoader = toggle: -> enabled = Conf['prefetch'] = @checked if enabled - ImageLoader.node.call post for id, post of g.threads["#{g.BOARD.ID}.#{g.THREADID}"].posts + ImageLoader.thread.posts.forEach ImageLoader.node.call return \ No newline at end of file diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index bed91a082..69accf4af 100755 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -19,9 +19,8 @@ ExpandThread = onIndexRefresh: -> ExpandThread.disconnect true - for threadID, thread of g.BOARD.threads + g.BOARD.threads.forEach (thread) -> ExpandThread.setButton thread - return text: (status, posts, files) -> "#{status} #{posts} post#{if posts > 1 then 's' else ''}" + diff --git a/src/Monitoring/ThreadStats.coffee b/src/Monitoring/ThreadStats.coffee index 6d9e46fd4..6212f6021 100755 --- a/src/Monitoring/ThreadStats.coffee +++ b/src/Monitoring/ThreadStats.coffee @@ -26,7 +26,7 @@ ThreadStats = node: -> postCount = 0 fileCount = 0 - for ID, post of @posts + @posts.forEach (post) -> postCount++ fileCount++ if post.file ThreadStats.thread = @ diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index 59ae4d6c3..43b61e8da 100755 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -290,7 +290,9 @@ ThreadUpdater = deletedFiles = [] # Check for deleted posts/files. - for ID, post of ThreadUpdater.thread.posts + {posts} = ThreadUpdater.thread + for ID in posts.keys + post = posts[ID] # XXX tmp fix for 4chan's racing condition # giving us false-positive dead posts. # continue if post.isDead diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index ca6d15873..80197bcf3 100755 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -96,7 +96,7 @@ ThreadWatcher = onIndexRefresh: -> {db} = ThreadWatcher boardID = g.BOARD.ID - for threadID, data of db.data.boards[boardID] when not data.isDead and threadID not of g.BOARD.threads + for threadID, data of db.data.boards[boardID] when not data.isDead and threadID not in g.BOARD.threads.keys if Conf['Auto Prune'] ThreadWatcher.db.delete {boardID, threadID} else @@ -180,7 +180,9 @@ ThreadWatcher = $.rmAll list $.add list, nodes - for threadID, thread of g.BOARD.threads + {threads} = g.BOARD + for threadID in threads.keys + thread = threads[threadID] toggler = $ '.watch-thread-link', thread.OP.nodes.post watched = ThreadWatcher.db.get {boardID: thread.board.ID, threadID} helper = if watched then ['addClass', 'Unwatch'] else ['rmClass', 'Watch'] diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index 3c23e6de3..ba9cb5fca 100755 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -42,7 +42,7 @@ Unread = ready: -> $.off d, '4chanXInitFinished', Unread.ready posts = [] - posts.push post for ID, post of Unread.thread.posts when post.isReply + Unread.thread.posts.forEach (post) -> posts.push post if post.isReply Unread.addPosts posts unless Conf['Quote Threading'] QuoteThreading.force() if Conf['Quote Threading'] Unread.scroll() if Conf['Scroll to Last Read Post'] @@ -58,8 +58,9 @@ Unread = down = true else # Scroll to the last read post. - posts = Object.keys Unread.thread.posts - {root} = Unread.thread.posts[posts[posts.length - 1]].nodes + {posts} = Unread.thread + {keys} = posts + {root} = posts[keys[keys.length - 1]].nodes # Scroll to the target unless we scrolled past it. Header.scrollTo root, down if Header.getBottomOf(root) < 0 diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 6f158edd9..122fb6927 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -326,7 +326,7 @@ QR = return unless QR.nodes list = QR.nodes.thread options = [list.firstChild] - for thread of g.BOARD.threads + for thread in g.BOARD.threads.keys options.push $.el 'option', value: thread textContent: "Thread No.#{thread}" diff --git a/src/Quotelinks/QuoteThreading.coffee b/src/Quotelinks/QuoteThreading.coffee index 85a15cfd2..077dde1e7 100755 --- a/src/Quotelinks/QuoteThreading.coffee +++ b/src/Quotelinks/QuoteThreading.coffee @@ -42,8 +42,8 @@ QuoteThreading = QuoteThreading.force() force: -> - post.cb true for ID, post of g.posts when post.cb - return + g.posts.forEach (post) -> + post.cb true if post.cb node: -> {posts} = g @@ -106,8 +106,10 @@ QuoteThreading = thread = $('.thread') posts = [] nodes = [] + + g.posts.forEach (post) -> + posts.push post unless post is post.thread.OP or post.isClone - posts.push post for ID, post of g.posts when not (post is post.thread.OP or post.isClone) posts.sort (a, b) -> a.ID - b.ID nodes.push post.nodes.root for post in posts From 56397d7ba2f0b54d1e545dd0b9e918398c6e93f0 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Tue, 14 Jan 2014 20:25:18 -0700 Subject: [PATCH 03/19] Oops. --- builds/4chan-X.user.js | 2 +- builds/crx/script.js | 2 +- src/Monitoring/ThreadWatcher.coffee | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index bc001cc5c..c37561c14 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -9402,7 +9402,7 @@ _ref = db.data.boards[boardID]; for (threadID in _ref) { data = _ref[threadID]; - if (!data.isDead && __indexOf.call(g.BOARD.threads.keys, threadID) < 0) { + if (!data.isDead && !(threadID in g.BOARD.threads)) { if (Conf['Auto Prune']) { ThreadWatcher.db["delete"]({ boardID: boardID, diff --git a/builds/crx/script.js b/builds/crx/script.js index 7f1b2cea6..c87dcff8b 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -9385,7 +9385,7 @@ _ref = db.data.boards[boardID]; for (threadID in _ref) { data = _ref[threadID]; - if (!data.isDead && __indexOf.call(g.BOARD.threads.keys, threadID) < 0) { + if (!data.isDead && !(threadID in g.BOARD.threads)) { if (Conf['Auto Prune']) { ThreadWatcher.db["delete"]({ boardID: boardID, diff --git a/src/Monitoring/ThreadWatcher.coffee b/src/Monitoring/ThreadWatcher.coffee index 80197bcf3..44db2c33a 100755 --- a/src/Monitoring/ThreadWatcher.coffee +++ b/src/Monitoring/ThreadWatcher.coffee @@ -96,7 +96,7 @@ ThreadWatcher = onIndexRefresh: -> {db} = ThreadWatcher boardID = g.BOARD.ID - for threadID, data of db.data.boards[boardID] when not data.isDead and threadID not in g.BOARD.threads.keys + for threadID, data of db.data.boards[boardID] when not data.isDead and threadID not of g.BOARD.threads if Conf['Auto Prune'] ThreadWatcher.db.delete {boardID, threadID} else From 9e6e9686e65596ddb7d4dba29fd4ce0867b82f5d Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Wed, 15 Jan 2014 15:25:57 -0700 Subject: [PATCH 04/19] We don't need an entire method for a set of code we only use once --- LICENSE | 2 +- builds/4chan-X.user.js | 20 +++++++------------- builds/crx/script.js | 20 +++++++------------- src/General/lib/$.coffee | 6 ------ src/General/lib/simpledict.class | 4 +++- 5 files changed, 18 insertions(+), 34 deletions(-) diff --git a/LICENSE b/LICENSE index c3a9eca17..8466855be 100755 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.3.2 - 2014-01-14 +* 4chan X - Version 1.3.2 - 2014-01-15 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index c37561c14..e37735474 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -22,7 +22,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.3.2 - 2014-01-14 +* 4chan X - Version 1.3.2 - 2014-01-15 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -805,16 +805,6 @@ }; })(); - $.remove = function(arr, value) { - var i; - i = arr.indexOf(value); - if (i === -1) { - return false; - } - arr.splice(i, 1); - return true; - }; - $$ = function(selector, root) { if (root == null) { root = d.body; @@ -1624,9 +1614,13 @@ }; SimpleDict.prototype.rm = function(key) { + var i; key = "" + key; - if ($.remove(this.keys, key)) { - return delete this[key]; + if ((i = this.keys.indexOf(key)) !== -1) { + this.keys.splice(i, 1); + if ($.remove(this.keys, key)) { + return delete this[key]; + } } }; diff --git a/builds/crx/script.js b/builds/crx/script.js index c87dcff8b..5fd0faabd 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.3.2 - 2014-01-14 +* 4chan X - Version 1.3.2 - 2014-01-15 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -810,16 +810,6 @@ }; })(); - $.remove = function(arr, value) { - var i; - i = arr.indexOf(value); - if (i === -1) { - return false; - } - arr.splice(i, 1); - return true; - }; - $$ = function(selector, root) { if (root == null) { root = d.body; @@ -1630,9 +1620,13 @@ }; SimpleDict.prototype.rm = function(key) { + var i; key = "" + key; - if ($.remove(this.keys, key)) { - return delete this[key]; + if ((i = this.keys.indexOf(key)) !== -1) { + this.keys.splice(i, 1); + if ($.remove(this.keys, key)) { + return delete this[key]; + } } }; diff --git a/src/General/lib/$.coffee b/src/General/lib/$.coffee index 3e45ed12a..87807ac9c 100755 --- a/src/General/lib/$.coffee +++ b/src/General/lib/$.coffee @@ -404,11 +404,5 @@ $.set = do -> return <% } %> -$.remove = (arr, value) -> - i = arr.indexOf value - return false if i is -1 - arr.splice i, 1 - true - $$ = (selector, root=d.body) -> [root.querySelectorAll(selector)...] diff --git a/src/General/lib/simpledict.class b/src/General/lib/simpledict.class index 7dddffc69..34ce15cf4 100644 --- a/src/General/lib/simpledict.class +++ b/src/General/lib/simpledict.class @@ -9,6 +9,8 @@ class SimpleDict rm: (key) -> key = "#{key}" - delete @[key] if $.remove @keys, key + if (i = @keys.indexOf key) isnt -1 + @keys.splice i, 1 + delete @[key] if $.remove @keys, key forEach: (fn) -> fn @[key] for key in [@keys...] From 30f4d0922bb589f5065caa4b4f779cab6e1a4a44 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Wed, 15 Jan 2014 17:09:25 -0700 Subject: [PATCH 05/19] Don't change titles until we've successfully navigated. --- builds/4chan-X.user.js | 169 ++++++++++++++++--------------- builds/crx/script.js | 169 ++++++++++++++++--------------- src/General/Index.coffee | 2 + src/General/Navigate.coffee | 99 ++++++++++-------- src/General/lib/simpledict.class | 2 +- src/Monitoring/Favicon.coffee | 103 ++++++++++--------- 6 files changed, 289 insertions(+), 255 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index e37735474..a4c60ab83 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1618,9 +1618,7 @@ key = "" + key; if ((i = this.keys.indexOf(key)) !== -1) { this.keys.splice(i, 1); - if ($.remove(this.keys, key)) { - return delete this[key]; - } + return delete this[key]; } }; @@ -2585,6 +2583,7 @@ } return; } + Navigate.title(); try { if (req.status === 200) { Index.parse(JSON.parse(req.response), pageNum); @@ -8676,29 +8675,30 @@ return Favicon["switch"](); }, "switch": function() { - var f, funreadDeadY, t, _ref; - t = 'data:image/png;base64,'; + var f, funreadDeadY, i, items, t; + items = { + ferongr: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///9zBQC/AADpDAP/gID/q6voCwJJTwpOAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxUlEQVR42q1TOwrCQBB9s0FRtJI0WoqFtSLYegoP4gVSeJsUHsHSI3iFeIqRXXgwrhlXwYHHhLwPTB7B36abBCV+0pA4DUBQUNZYQptGtW3jtoKyxgoe0yrBCoyZfL/5ioQ3URZOXW9I341l3oo+NXEZiW4CEuIzvPECopED4OaZ3RNmeAm4u+a8Jr5f17VyVoL8fr8qcltzwlyyj2iqcgPOQ9ExkHAITgD75bYBe0A5S4H/P9htuWMF3QXoQpwaKeT+lnsC6JE5I6aq6fEAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8AcH4AtswA2PJ55fKi6fIA1/FtpPADAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxElEQVQ4y2NgoBq4/vE/HJOsBiRQUIfA2AzBqQYqUfn00/9FLz+BaQxDCKqBmX7jExijKEDSDJPHrnnbGQhGV4RmOFwdVkNwhQMheYwQxhaIi7b9Z9A3gWAQm2BUoQOgRhgA8o7j1ozLC4LCyAZcx6kZI5qg4kLKqggDFFWxJySsUQVzlb4pwgAJaTRvokcVNgOqOv8zcHBCsL07DgNg8YsczzA5MxtUL+DMD8g0slxI/H8GQ/P/DJKyeKIRpglXZsIiBwBhP5O+VbI/JgAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8oeQBJ3ABV/wHM/7Lu/+ZU/gAqUP3dAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAx0lEQVQ4y2NgoBYI+cfwH4ZJVgMS0KhEYGyG4FQDkzjzf9P/d/+fgWl0QwiqgSkI/c8IxsgKkDXD5LFq9rwDweiK0A2HqcNqCK5wICSPEcLYAtH+AMN/IXMIBrEJRie6OEgjDAC5x3FqxuUFNiEUA67j1IweTTBxBQ1puAG86jgSEraogskJWSBcwCGF5k30qMJmgMFEhv/MXBAs5oLDAFj8IsczTE7UEeECbhU8+QGZRpaTi2b4L2zF8J9TGk80wjThykzY5AAW/2O1C2mIbgAAAABJRU5ErkJggg=='], + 'xat-': ['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'], + Mayhem: ['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'], + '4chanJS': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AABnZ2f///8nFk05AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AAD///9nZ2f77Y6hAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8NnZ2f////82iC9AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8P///9nZ2cgIeMlAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDNlyjJnZ2f///+6o7dfAAAAAXRSTlMAQObYZgAAAERJREFUeF6NjkEKADEIA51o///lJZfQxUsHITogWi8AvwZJuxmYa25xDooBLEwOWFTYAsYVhdorLZt9Ng9xCUTCUCQ2H3F4ANrZ2WNiAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDP///9lyjJnZ2cIHys9AAAAAXRSTlMAQObYZgAAAENJREFUeF6NjUEKwEAMAjNm9/9fLkEslFwqgjoEUn8EfAqSdrkwzj6ieyyTkQEVGWRvANfO1iEX620AjgBEwqR4Y+sBeGAA6d+vQ4IAAAAASUVORK5CYII='], + Original: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX/////AAD///8AAABBZmS3AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhElEQVR42q1RwQnAMAjMu5M4guAKXa4j5dUROo5tipSDcrFChUONd0di2m/hEGVOHDyIPufgwAFASDkpoSzmBrkJ2UMyR9LsJ3rvrqo3Rt1YMIMhhNnOxLMnoMFBxHyJAr2IOBFzA8U+6pLBdmEJTA0aMVjpDd6Loks0s5HZNwYx8tfZCZ0kll7ORffZAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///8ul8P///8AAACaqgkzAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eILZO5/XI0UAgm7H9tOsu0yGWAQSOoFijHOxOANGqm/LczpOaXs4gISrPZ+gc2+hO5w2xdwgOjBFUIF+sEJrhUl9JFr+badFwR+BfqlmGUJAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///9mzDP///8AAACT0n1lAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eIDhbn/cTVSCCTsfmw7ybbLZIBBIKkXKKU0E4M3aKT+tjCn5xiziwuIsNr7BTb7ErrDZV/AAaIHdwgV6AcnuFaU0Eeu5dt2XiUyBjCQ2bIrAAAAAElFTkSuQmCC'] + }[Conf['favicon']]; f = Favicon; - _ref = (function() { - switch (Conf['favicon']) { - case 'ferongr': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///9zBQC/AADpDAP/gID/q6voCwJJTwpOAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxUlEQVR42q1TOwrCQBB9s0FRtJI0WoqFtSLYegoP4gVSeJsUHsHSI3iFeIqRXXgwrhlXwYHHhLwPTB7B36abBCV+0pA4DUBQUNZYQptGtW3jtoKyxgoe0yrBCoyZfL/5ioQ3URZOXW9I341l3oo+NXEZiW4CEuIzvPECopED4OaZ3RNmeAm4u+a8Jr5f17VyVoL8fr8qcltzwlyyj2iqcgPOQ9ExkHAITgD75bYBe0A5S4H/P9htuWMF3QXoQpwaKeT+lnsC6JE5I6aq6fEAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8AcH4AtswA2PJ55fKi6fIA1/FtpPADAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxElEQVQ4y2NgoBq4/vE/HJOsBiRQUIfA2AzBqQYqUfn00/9FLz+BaQxDCKqBmX7jExijKEDSDJPHrnnbGQhGV4RmOFwdVkNwhQMheYwQxhaIi7b9Z9A3gWAQm2BUoQOgRhgA8o7j1ozLC4LCyAZcx6kZI5qg4kLKqggDFFWxJySsUQVzlb4pwgAJaTRvokcVNgOqOv8zcHBCsL07DgNg8YsczzA5MxtUL+DMD8g0slxI/H8GQ/P/DJKyeKIRpglXZsIiBwBhP5O+VbI/JgAAAABJRU5ErkJggg==', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8oeQBJ3ABV/wHM/7Lu/+ZU/gAqUP3dAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAx0lEQVQ4y2NgoBYI+cfwH4ZJVgMS0KhEYGyG4FQDkzjzf9P/d/+fgWl0QwiqgSkI/c8IxsgKkDXD5LFq9rwDweiK0A2HqcNqCK5wICSPEcLYAtH+AMN/IXMIBrEJRie6OEgjDAC5x3FqxuUFNiEUA67j1IweTTBxBQ1puAG86jgSEraogskJWSBcwCGF5k30qMJmgMFEhv/MXBAs5oLDAFj8IsczTE7UEeECbhU8+QGZRpaTi2b4L2zF8J9TGk80wjThykzY5AAW/2O1C2mIbgAAAABJRU5ErkJggg==']; - case 'xat-': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAPFBMVEX9AAD8AAD/AAD+AADAExKKXl2CfHqLkZFub2yfaF3bZ2PzZGL/zs//iYr/AAASAAAGAAAAAAAAAAAAAADpOCseAAAADHRSTlP9MAcAATVYeprJ5O/MbzqoAAAAXklEQVQY03VPQQ7AIAgz8QAG4dL//3VVcVk2Vw4tDVQp9YVyMACIEkIxDEQEGjHFnBjCbPU5EXBfnBns6WRG1Wbuvbtb0z9jr6Qh2KGQenp2/+xpsFQnrePAuulz7QUTuwm5NnwmIAAAAABJRU5ErkJggg==', t + 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAMAAACuAq9NAAAAY1BMVEUBAAACAQELCQkPDQwgFBMzKilOSEdva2iEgoCReHOadXClamDIaWbxcG7+hIX+mpv+m5z+oqP+tLX+zc7//f3+9PT97Oz23t750NDbra3zwL87LCwAAAAGAABHAADPAAD/AABkWeLDAAAAHHRSTlO5/fTv8Na2n42lsMvi8v3+/v749OaITDsDAQABSG2w8gAAAGdJREFUCNdNjtEKgDAIRYVGCmsyqCe7q/3/V2azQfpwPehVyQCIMIt4YYTeO7LHKMiGlDIkuh2qofR6obUqhtc4F637XreU1h+m41gcJX/DHyJWXYHzkCMm+hd3a4GezLNr8PQA4bQHEXEQFRJP5NAAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAPFBMVEUAAAAAAAAAAAAAAABFRUdsa2yRjop4dXVpZ2tdcI9dfKdBirUzlMBHpdxSquRisfOs2/99xv8umMMAAABljCUFAAAAEHRSTlN7FwUAQVt6kZ2/zej59vTv0aAplgAAAGNJREFUGNNtj1EOwCAIQ5eYIPCD0vvfdYi6LJvy0fICNVzl864DAECVuVKYAeDuEFVJkxPDmM1+TTh6n7oy0FvrWBmF1aIPYspnUGWvSE1A2KGgcvp2AtU3iGJOmcch6pHftTekXQrRd6slMAAAAABJRU5ErkJggg==', t + 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAMAAACuAq9NAAAAY1BMVEUAAAAAAAAAAAAAAAAREBAWFRY1NDROTE1iYGFzdXp4eoCAgYVlc4mHjZiYoa6zvcqy1/Pg8v+e1f+b1P6X0f2DyP5jsu49msgymcctkLomc5QbPU0SIiwNFxwumMMAAAAAAADALpU1AAAAHnRSTlPNLgcBAAABBxhdc4WznarD8P7+/v3+8/z9/vz2+PUOYDHSAAAAZElEQVQI102OsQ6AMAhEMWGDpTbUQUvu/79ShDYRhuMFDiAGIKIqEgUT3B0akQVxyhgp1XWYldLnhfXTkF5WHdZb69cz9YdPazNQdA0vRK2ahftQDGNjfHHXZjgSV5cRGQHCwS8j7A9loVSnzwAAAABJRU5ErkJggg==', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAPFBMVEUAAAAAAAAAAAAAAAAfJSBLUU1ydHR8fn6Ri5Frbm9dn19jvEFt30tv5VB082KR/33Z/9Gq/5tmzDMAAADw+5ntAAAAEHRSTlP++ywHAAE2Wnuayez19O/+EzXeOQAAAF9JREFUGNN1TzESwCAIc3AABxDy/78WFXu91oYhIYcRSn2hHAwAxAEKMQy4O1pgijkxhMjqc8KhujgzoGaKzKjcRK13U2n8Z+wnaRB2KKievt2bPY0o5knrOETd9Ln2AuDLCz1j8HTeAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAMAAACuAq9NAAAAY1BMVEUPGgsCBAIBAQEBAQAAAQAAAAABAQEFBQQQEw85SDdVa1GhzJm967TZ+NLP+sbM+8S6/a3k/9+s/pyr/puX/oSd15KIuoGBj39tfm1qj2RepFlu2VRkwzZlyTNatC5myzMAAAAOPREWAAAAHnRSTlP4/fz331IPBQIBAAECOly37/7+/v7XwpWktNDy+f7X56yoAAAAZElEQVQI102NwQ7AIAhDMdku3JwkIiaz//+VQ9FkcCgvpUAMoKpX9YEJYww0s7YG4iW9Lwl3QCSUZhZSHsHKslqXknPpRPpDypkmtr0cWBGntnseOeKgGd6UAr1Vj8vw9sKFmz+fERAp5vutHwAAAABJRU5ErkJggg==']; - case 'Mayhem': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABFklEQVR4AZ2R4WqEMBCEFy1yiJQQ14gcIhIuFBFR+qPQ93+v66QMksrlTwMfkZ2ZZbMKTgVqYIDl3YAbeCM31lJP/Zul4MAEPJjBQGNDLGsz8PQ6aqLAP5PTdd1WlmU09mSKtdTDRgrkzspJPKq6RxMahfj9yhOzQEZwZAwfzrk1ox3MXibIN8hO4MAjeV72CemJGWblnRsOYOdoGw0jebB20BPAwKzUQPlrFhrXFw1Wagu9yuzZwINzVAZCURRL+gRr7Wd8Vtqg4Th/lsUmewyk9WQ/A7NiwJz5VV/GmO+MNjMrFvh/NPDMigHTaeJN09a27ZHRJmalBg54CgfvAGYSLpoHjlmpuAwFdzDy7oGS/qIpM9UPFGg1b1kUlssAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABR0lEQVR4AYWSQWq0QBCFCw0SRIK0PQ4hiIhEZBhEySLyewUPEMgqR/JIXiDhzz7kKKYePIZajEzDRxfV9dWU3SO6IiVWUsVxT5R75Y4gTmwNnUh4kCulUiuV8sjChDjmKtaUcHgmHsnNrMPh0IVhiMIjKZGzNXDoyhMzF7C89z2KtFGD+FoNXEUKZdgpaPM8P++cDXTtBDca7EyQK8+bXTufYBccuvLAG26UnqN1LCgI4g/lm7zTgSux4vk0J8rnKw3+m1//pBPbBrVyGZVNmiAITviEtm3t+D+2QcJx7GUxlN4594K4ZY75Xzh0JVWqnad6TdP0H+LRNBjHcYNDV5xS32qwaC4my7Lwn6guu5QoomgbdFmWDYhnM8E8zxscuhLzPWtKA/dGqUizrityX9M0YX+DQ1ciXobnP6vgfmTOM7Znnk70B58pPaEvx+epAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA/ElEQVR4AZ3RUWqEMBSF4ftQZAhSREQJIiIXpQwi+tSldkFdWPsLhyEE0ocKH2Fyzg1mNJ4KAQ1arTUeeJMH6qwTUJmCHjMcC6KKtbSIylzdXpl18J/k4fdTpUFmPLOOa9bGe+P4+n5RYYfLXuiMsAlXofBxK2QXpvwN/jqg+AY91vR+pStk+apZe0fEhhMXDhUmWXEoO9WNmrWAzvRPq7jnB2jvUGfWTEgPcJzZFTbZk/0Tnh5QI+af6lVGvq/Do2atwVL4VJ+3QrZo1lr4Pw5wzVqDWaV7SUvHrZDNmrWAHq7g0rphkS3LXDMBVqFGhxGT1gGdDFnWaab6BRmXRvbxDmYiAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABQElEQVR4AY2SQUrEQBBFS9CMNFEkhAQdYmiCIUgcZlYGc4VsBcGVF/AuWXme4F7RtXiVWF9+Y9MYtOHRTdX/NZWaEj2RYpQTJeEdK4fKPuA7DjSGXiQkU0qlUqxySmFMEsYsNSU8zEmK4OwdEbmkKCclYoGmolfWCGyenh1O0EJE2gXNWpFC2S0IGrCQ29EbdPCPAmEHmXIxByf8hDAPD71yzAnXypatbSgoAN8Pyju5h4deMUrqJk1z+0uBN+/XX+gxfoFK2QafUJO2aRq//Q+/QIx2wr+Kwq0rusrP/QKf9MTCtbQLf9U1wNvYnz3qug45S68kSvVXgbPbx3nvYPXNOI7cRPWySukK+DcGCvA+urqZ3RmGAbmSXjFK5rpwW8nhWVJP04TYa9/3uO/goVciDiPlZhW8c8ZAHuRSeqIv32FK/GYGL8YAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA/ElEQVR4AZ3RUWqEMBSF4ftQZAihDCKKiAQJShERQx+6o662e2p/4TCEQF468BEm95yLovFr4PBEq9PjgTd5wBcZp6559AiIWDAq6KXV3aJMUMfDOsTf7Mf/XaFBAvYiE9W16b74/vl8UeBAlKOSmWAzUiXwcavMkrrFE9QXVJ+gx5q9XvUVivmqrr1jxIYLCacCs6y6S8psGNU1hw4Bu4JHuUB3pzJBHZcviLiKV9jkyO4vxHyBx1h+qlcY5b2Wj+raE0vlU33dKrNFXWsR/7EgqmtPBIXuIw+dt8osqGsOPaIGSeeGRbZiFtVxsAYeHSbMOgd0MhSzTp3mD4RaQX4aW3NMAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABP0lEQVR4AYWS0UqFQBCGhziImNRBRImDmUgiIaF0kWSP4AMEXXXTE/QiPpL3UdR19Crb/PAvLEtyFj5mmfn/cdxd0RUokbJXEsZYCZUd4D72NBG8wkKmlEqtVMoFhTFJmKuoKelBTVIkjbNE5IainJTIeZqaXjkg8fp+Z7GCjiLQbWgOihTKsCFowUZtoNef4HgDf4JMuTbe8n/Br8NDr5zxhBul52i3FBQE+xflmzzTA69ESmpPmubunwZfztc/6IncBrXSe7/QkK5tW3f8H7dBjHH8q6Kwt033V6Hb4JeeWPgsq42rugfYZ92psWscRwMPvZIo9bEGD2+F2YUnBizLwpeoXnYpbQM34kAB9peP58aueZ4NPPRKxPusaRoYG6UizbquyH1O04T4RA+8EvAwUr6sgjFnDuReLaUn+ANygUa7+9SCWgAAAABJRU5ErkJggg==']; - case '4chanJS': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AABnZ2f///8nFk05AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AAD///9nZ2f77Y6hAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8NnZ2f////82iC9AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8P///9nZ2cgIeMlAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDNlyjJnZ2f///+6o7dfAAAAAXRSTlMAQObYZgAAAERJREFUeF6NjkEKADEIA51o///lJZfQxUsHITogWi8AvwZJuxmYa25xDooBLEwOWFTYAsYVhdorLZt9Ng9xCUTCUCQ2H3F4ANrZ2WNiAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDP///9lyjJnZ2cIHys9AAAAAXRSTlMAQObYZgAAAENJREFUeF6NjUEKwEAMAjNm9/9fLkEslFwqgjoEUn8EfAqSdrkwzj6ieyyTkQEVGWRvANfO1iEX620AjgBEwqR4Y+sBeGAA6d+vQ4IAAAAASUVORK5CYII=']; - case 'Original': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX/////AAD///8AAABBZmS3AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhElEQVR42q1RwQnAMAjMu5M4guAKXa4j5dUROo5tipSDcrFChUONd0di2m/hEGVOHDyIPufgwAFASDkpoSzmBrkJ2UMyR9LsJ3rvrqo3Rt1YMIMhhNnOxLMnoMFBxHyJAr2IOBFzA8U+6pLBdmEJTA0aMVjpDd6Loks0s5HZNwYx8tfZCZ0kll7ORffZAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///8ul8P///8AAACaqgkzAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eILZO5/XI0UAgm7H9tOsu0yGWAQSOoFijHOxOANGqm/LczpOaXs4gISrPZ+gc2+hO5w2xdwgOjBFUIF+sEJrhUl9JFr+badFwR+BfqlmGUJAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///9mzDP///8AAACT0n1lAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eIDhbn/cTVSCCTsfmw7ybbLZIBBIKkXKKU0E4M3aKT+tjCn5xiziwuIsNr7BTb7ErrDZV/AAaIHdwgV6AcnuFaU0Eeu5dt2XiUyBjCQ2bIrAAAAAElFTkSuQmCC']; - } - })(), f.unreadDead = _ref[0], funreadDeadY = _ref[1], f.unreadSFW = _ref[2], f.unreadSFWY = _ref[3], f.unreadNSFW = _ref[4], f.unreadNSFWY = _ref[5]; - if (Favicon.SFW) { - Favicon.unread = Favicon.unreadSFW; - return Favicon.unreadY = Favicon.unreadSFWY; + t = 'data:image/png;base64,'; + i = 0; + while (items[i]) { + items[i] = t + items[i++]; + } + f.unreadDead = items[0], funreadDeadY = items[1], f.unreadSFW = items[2], f.unreadSFWY = items[3], f.unreadNSFW = items[4], f.unreadNSFWY = items[5]; + return f.update(); + }, + update: function() { + if (this.SFW) { + this.unread = this.unreadSFW; + return this.unreadY = this.unreadSFWY; } else { - Favicon.unread = Favicon.unreadNSFW; - return Favicon.unreadY = Favicon.unreadNSFWY; + this.unread = this.unreadNSFW; + return this.unreadY = this.unreadNSFWY; } }, dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==', @@ -11924,6 +11924,7 @@ $.ready(function() { return $.on(window, 'popstate', Navigate.popstate); }); + this.title = function() {}; Thread.callbacks.push({ name: 'Navigate', cb: this.thread @@ -12050,10 +12051,13 @@ }, updateBoard: function(boardID) { var fullBoardList, onload, req; - g.BOARD = new Board(boardID); req = null; + fullBoardList = $('#full-board-list', Header.boardList); + $.rmClass($('.current', fullBoardList), 'current'); + $.addClass($("a[href*='/" + boardID + "/']", fullBoardList), 'current'); + Header.generateBoardList(Conf['boardnav'].replace(/(\r\n|\n|\r)/g, ' ')); onload = function(e) { - var board, findStyle, mainStyleSheet, newStyleSheet, sfw, style; + var aboard, board, err, _i, _len, _ref; if (e.type === 'abort') { req.onloadend = null; return; @@ -12061,70 +12065,68 @@ if (req.status !== 200) { return; } - board = (function() { - var err, _i, _len, _ref; - try { - _ref = JSON.parse(req.response).boards; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - board = _ref[_i]; - if (board.board === boardID) { - return board; - } + try { + _ref = JSON.parse(req.response).boards; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + aboard = _ref[_i]; + if (!(aboard.board === boardID)) { + continue; } - } catch (_error) { - err = _error; - Main.handleErrors([ - { - message: "Navigation failed to update board name.", - error: err - } - ]); - return false; + board = aboard; + break; } - })(); + } catch (_error) { + err = _error; + Main.handleErrors([ + { + message: "Navigation failed to update board name.", + error: err + } + ]); + return false; + } if (!board) { return; } Navigate.updateTitle(board); - if (Favicon.SFW === (sfw = !!board.ws_board)) { - return; - } - findStyle = function(_arg) { - var base, style, type; - type = _arg[0], base = _arg[1]; - style = d.cookie.match(new RegExp("" + type + "\_style\=([^;]+)")); - return [(style ? style[1] : base), "" + type + "_style"]; - }; - style = findStyle(sfw ? ['ws', 'Yotsuba B New'] : ['nws', 'Yotsuba New']); - $.globalEval("var style_group = '" + style[1] + "'"); - mainStyleSheet = $('link[title=switch]', d.head); - newStyleSheet = $("link[title='" + style[0] + "']", d.head); - Favicon.SFW = sfw; - Favicon.el.href = "//s.4cdn.org/image/favicon" + (sfw ? '-ws' : '') + ".ico"; - $.add(d.head, Favicon.el); - Favicon["switch"](); - mainStyleSheet.href = newStyleSheet.href; - return Main.setClass(); + return Navigate.updateFavicon(!!board.ws_board); }; - fullBoardList = $('#full-board-list', Header.boardList); - $.rmClass($('.current', fullBoardList), 'current'); - $.addClass($("a[href*='/" + boardID + "/']", fullBoardList), 'current'); - Header.generateBoardList(Conf['boardnav'].replace(/(\r\n|\n|\r)/g, ' ')); return req = $.ajax('//a.4cdn.org/boards.json', { onabort: onload, onloadend: onload }); }, + updateFavicon: function(sfw) { + var findStyle, mainStyleSheet, newStyleSheet, style; + Favicon.el.href = "//s.4cdn.org/image/favicon" + (sfw ? '-ws' : '') + ".ico"; + $.add(d.head, Favicon.el); + if (Favicon.SFW === sfw) { + return; + } + Favicon.SFW = sfw; + Favicon.update(); + findStyle = function(type, base) { + var style; + style = d.cookie.match(new RegExp("" + type + "\_style\=([^;]+)")); + return ["" + type + "_style", (style ? style[1] : base)]; + }; + style = findStyle.apply(null, sfw ? ['ws', 'Yotsuba B New'] : ['nws', 'Yotsuba New']); + $.globalEval("var style_group = '" + style[0] + "'"); + mainStyleSheet = $('link[title=switch]', d.head); + newStyleSheet = $("link[title='" + style[1] + "']", d.head); + mainStyleSheet.href = newStyleSheet.href; + return Main.setClass(); + }, updateTitle: function(_arg) { var board, subtitle, title; board = _arg.board, title = _arg.title; if (subtitle = $('.boardSubtitle')) { $.rm(subtitle); } - return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title; + return $('.boardTitle').textContent = d.title = "" + board + " = " + title; }, navigate: function(e) { - var boardID, onload, pageNum, path, threadID, view; + var boardID, load, pageNum, path, threadID, view; if (this.hostname !== 'boards.4chan.org' || window.location.hostname === 'rs.4chan.org' || (e && (e.shiftKey || (e.type === 'click' && e.button !== 0)))) { return; } @@ -12140,6 +12142,7 @@ if (e) { e.preventDefault(); } + Navigate.title = function() {}; delete Index.pageNum; path = this.pathname; if (this.hash) { @@ -12163,18 +12166,22 @@ } if (view === 'index') { if (boardID === g.BOARD.ID) { - d.title = $('.boardTitle').textContent; + Navigate.title = function() { + return d.title = $('.boardTitle').textContent; + }; } else { - Navigate.updateBoard(boardID); + g.BOARD = new Board(boardID); + Navigate.title = function() { + return Navigate.updateBoard(boardID); + }; } return Index.update(pageNum); } else { - onload = function(e) { - return Navigate.load(e); - }; + Navigate.updateFavicon(Favicon.SFW); + load = Navigate.load; Navigate.req = $.ajax("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", { - onabort: onload, - onloadend: onload + onabort: load, + onloadend: load }); return setTimeout((function() { if (Navigate.req && !Navigate.notice) { @@ -12192,14 +12199,14 @@ } delete Navigate.req; delete Navigate.notice; - if (e.type === 'abort') { + if (e.type === 'abort' || req.status !== 200) { req.onloadend = null; + new Notice('warning', "Failed to load thread." + (req.status ? " " + req.status : '')); return; } + Navigate.title(); try { - if (req.status === 200) { - return Navigate.parse(JSON.parse(req.response).posts); - } + return Navigate.parse(JSON.parse(req.response).posts); } catch (_error) { err = _error; console.error('Navigate failure:'); diff --git a/builds/crx/script.js b/builds/crx/script.js index 5fd0faabd..f3684733a 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1624,9 +1624,7 @@ key = "" + key; if ((i = this.keys.indexOf(key)) !== -1) { this.keys.splice(i, 1); - if ($.remove(this.keys, key)) { - return delete this[key]; - } + return delete this[key]; } }; @@ -2595,6 +2593,7 @@ } return; } + Navigate.title(); try { if (req.status === 200) { Index.parse(JSON.parse(req.response), pageNum); @@ -8659,29 +8658,30 @@ return Favicon["switch"](); }, "switch": function() { - var f, funreadDeadY, t, _ref; - t = 'data:image/png;base64,'; + var f, funreadDeadY, i, items, t; + items = { + ferongr: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///9zBQC/AADpDAP/gID/q6voCwJJTwpOAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxUlEQVR42q1TOwrCQBB9s0FRtJI0WoqFtSLYegoP4gVSeJsUHsHSI3iFeIqRXXgwrhlXwYHHhLwPTB7B36abBCV+0pA4DUBQUNZYQptGtW3jtoKyxgoe0yrBCoyZfL/5ioQ3URZOXW9I341l3oo+NXEZiW4CEuIzvPECopED4OaZ3RNmeAm4u+a8Jr5f17VyVoL8fr8qcltzwlyyj2iqcgPOQ9ExkHAITgD75bYBe0A5S4H/P9htuWMF3QXoQpwaKeT+lnsC6JE5I6aq6fEAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8AcH4AtswA2PJ55fKi6fIA1/FtpPADAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxElEQVQ4y2NgoBq4/vE/HJOsBiRQUIfA2AzBqQYqUfn00/9FLz+BaQxDCKqBmX7jExijKEDSDJPHrnnbGQhGV4RmOFwdVkNwhQMheYwQxhaIi7b9Z9A3gWAQm2BUoQOgRhgA8o7j1ozLC4LCyAZcx6kZI5qg4kLKqggDFFWxJySsUQVzlb4pwgAJaTRvokcVNgOqOv8zcHBCsL07DgNg8YsczzA5MxtUL+DMD8g0slxI/H8GQ/P/DJKyeKIRpglXZsIiBwBhP5O+VbI/JgAAAABJRU5ErkJggg==', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8oeQBJ3ABV/wHM/7Lu/+ZU/gAqUP3dAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAx0lEQVQ4y2NgoBYI+cfwH4ZJVgMS0KhEYGyG4FQDkzjzf9P/d/+fgWl0QwiqgSkI/c8IxsgKkDXD5LFq9rwDweiK0A2HqcNqCK5wICSPEcLYAtH+AMN/IXMIBrEJRie6OEgjDAC5x3FqxuUFNiEUA67j1IweTTBxBQ1puAG86jgSEraogskJWSBcwCGF5k30qMJmgMFEhv/MXBAs5oLDAFj8IsczTE7UEeECbhU8+QGZRpaTi2b4L2zF8J9TGk80wjThykzY5AAW/2O1C2mIbgAAAABJRU5ErkJggg=='], + 'xat-': ['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'], + Mayhem: ['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'], + '4chanJS': ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AABnZ2f///8nFk05AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AAD///9nZ2f77Y6hAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8NnZ2f////82iC9AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8P///9nZ2cgIeMlAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDNlyjJnZ2f///+6o7dfAAAAAXRSTlMAQObYZgAAAERJREFUeF6NjkEKADEIA51o///lJZfQxUsHITogWi8AvwZJuxmYa25xDooBLEwOWFTYAsYVhdorLZt9Ng9xCUTCUCQ2H3F4ANrZ2WNiAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDP///9lyjJnZ2cIHys9AAAAAXRSTlMAQObYZgAAAENJREFUeF6NjUEKwEAMAjNm9/9fLkEslFwqgjoEUn8EfAqSdrkwzj6ieyyTkQEVGWRvANfO1iEX620AjgBEwqR4Y+sBeGAA6d+vQ4IAAAAASUVORK5CYII='], + Original: ['iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX/////AAD///8AAABBZmS3AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhElEQVR42q1RwQnAMAjMu5M4guAKXa4j5dUROo5tipSDcrFChUONd0di2m/hEGVOHDyIPufgwAFASDkpoSzmBrkJ2UMyR9LsJ3rvrqo3Rt1YMIMhhNnOxLMnoMFBxHyJAr2IOBFzA8U+6pLBdmEJTA0aMVjpDd6Loks0s5HZNwYx8tfZCZ0kll7ORffZAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///8ul8P///8AAACaqgkzAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eILZO5/XI0UAgm7H9tOsu0yGWAQSOoFijHOxOANGqm/LczpOaXs4gISrPZ+gc2+hO5w2xdwgOjBFUIF+sEJrhUl9JFr+badFwR+BfqlmGUJAAAAAElFTkSuQmCC', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///9mzDP///8AAACT0n1lAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eIDhbn/cTVSCCTsfmw7ybbLZIBBIKkXKKU0E4M3aKT+tjCn5xiziwuIsNr7BTb7ErrDZV/AAaIHdwgV6AcnuFaU0Eeu5dt2XiUyBjCQ2bIrAAAAAElFTkSuQmCC'] + }[Conf['favicon']]; f = Favicon; - _ref = (function() { - switch (Conf['favicon']) { - case 'ferongr': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///9zBQC/AADpDAP/gID/q6voCwJJTwpOAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxUlEQVR42q1TOwrCQBB9s0FRtJI0WoqFtSLYegoP4gVSeJsUHsHSI3iFeIqRXXgwrhlXwYHHhLwPTB7B36abBCV+0pA4DUBQUNZYQptGtW3jtoKyxgoe0yrBCoyZfL/5ioQ3URZOXW9I341l3oo+NXEZiW4CEuIzvPECopED4OaZ3RNmeAm4u+a8Jr5f17VyVoL8fr8qcltzwlyyj2iqcgPOQ9ExkHAITgD75bYBe0A5S4H/P9htuWMF3QXoQpwaKeT+lnsC6JE5I6aq6fEAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8AcH4AtswA2PJ55fKi6fIA1/FtpPADAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAxElEQVQ4y2NgoBq4/vE/HJOsBiRQUIfA2AzBqQYqUfn00/9FLz+BaQxDCKqBmX7jExijKEDSDJPHrnnbGQhGV4RmOFwdVkNwhQMheYwQxhaIi7b9Z9A3gWAQm2BUoQOgRhgA8o7j1ozLC4LCyAZcx6kZI5qg4kLKqggDFFWxJySsUQVzlb4pwgAJaTRvokcVNgOqOv8zcHBCsL07DgNg8YsczzA5MxtUL+DMD8g0slxI/H8GQ/P/DJKyeKIRpglXZsIiBwBhP5O+VbI/JgAAAABJRU5ErkJggg==', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAFVBMVEX///8oeQBJ3ABV/wHM/7Lu/+ZU/gAqUP3dAAAAAXRSTlMAQObYZgAAAGJJREFUeF5Fi7ENg0AQBCfa/AFdDh2gdwPIogMK2E2+/xLslwOvdqRJhv+GQQPUCtJM7svankLrq/I+TY5e6Ueh1jyBMX7AFJi9vwfyVO4CbbO6jNYpp9GyVPbdkFhVgAQ2H0NOE5jk9DT8AAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAx0lEQVQ4y2NgoBYI+cfwH4ZJVgMS0KhEYGyG4FQDkzjzf9P/d/+fgWl0QwiqgSkI/c8IxsgKkDXD5LFq9rwDweiK0A2HqcNqCK5wICSPEcLYAtH+AMN/IXMIBrEJRie6OEgjDAC5x3FqxuUFNiEUA67j1IweTTBxBQ1puAG86jgSEraogskJWSBcwCGF5k30qMJmgMFEhv/MXBAs5oLDAFj8IsczTE7UEeECbhU8+QGZRpaTi2b4L2zF8J9TGk80wjThykzY5AAW/2O1C2mIbgAAAABJRU5ErkJggg==']; - case 'xat-': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAPFBMVEX9AAD8AAD/AAD+AADAExKKXl2CfHqLkZFub2yfaF3bZ2PzZGL/zs//iYr/AAASAAAGAAAAAAAAAAAAAADpOCseAAAADHRSTlP9MAcAATVYeprJ5O/MbzqoAAAAXklEQVQY03VPQQ7AIAgz8QAG4dL//3VVcVk2Vw4tDVQp9YVyMACIEkIxDEQEGjHFnBjCbPU5EXBfnBns6WRG1Wbuvbtb0z9jr6Qh2KGQenp2/+xpsFQnrePAuulz7QUTuwm5NnwmIAAAAABJRU5ErkJggg==', t + 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAMAAACuAq9NAAAAY1BMVEUBAAACAQELCQkPDQwgFBMzKilOSEdva2iEgoCReHOadXClamDIaWbxcG7+hIX+mpv+m5z+oqP+tLX+zc7//f3+9PT97Oz23t750NDbra3zwL87LCwAAAAGAABHAADPAAD/AABkWeLDAAAAHHRSTlO5/fTv8Na2n42lsMvi8v3+/v749OaITDsDAQABSG2w8gAAAGdJREFUCNdNjtEKgDAIRYVGCmsyqCe7q/3/V2azQfpwPehVyQCIMIt4YYTeO7LHKMiGlDIkuh2qofR6obUqhtc4F637XreU1h+m41gcJX/DHyJWXYHzkCMm+hd3a4GezLNr8PQA4bQHEXEQFRJP5NAAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAPFBMVEUAAAAAAAAAAAAAAABFRUdsa2yRjop4dXVpZ2tdcI9dfKdBirUzlMBHpdxSquRisfOs2/99xv8umMMAAABljCUFAAAAEHRSTlN7FwUAQVt6kZ2/zej59vTv0aAplgAAAGNJREFUGNNtj1EOwCAIQ5eYIPCD0vvfdYi6LJvy0fICNVzl864DAECVuVKYAeDuEFVJkxPDmM1+TTh6n7oy0FvrWBmF1aIPYspnUGWvSE1A2KGgcvp2AtU3iGJOmcch6pHftTekXQrRd6slMAAAAABJRU5ErkJggg==', t + 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAMAAACuAq9NAAAAY1BMVEUAAAAAAAAAAAAAAAAREBAWFRY1NDROTE1iYGFzdXp4eoCAgYVlc4mHjZiYoa6zvcqy1/Pg8v+e1f+b1P6X0f2DyP5jsu49msgymcctkLomc5QbPU0SIiwNFxwumMMAAAAAAADALpU1AAAAHnRSTlPNLgcBAAABBxhdc4WznarD8P7+/v3+8/z9/vz2+PUOYDHSAAAAZElEQVQI102OsQ6AMAhEMWGDpTbUQUvu/79ShDYRhuMFDiAGIKIqEgUT3B0akQVxyhgp1XWYldLnhfXTkF5WHdZb69cz9YdPazNQdA0vRK2ahftQDGNjfHHXZjgSV5cRGQHCwS8j7A9loVSnzwAAAABJRU5ErkJggg==', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAPFBMVEUAAAAAAAAAAAAAAAAfJSBLUU1ydHR8fn6Ri5Frbm9dn19jvEFt30tv5VB082KR/33Z/9Gq/5tmzDMAAADw+5ntAAAAEHRSTlP++ywHAAE2Wnuayez19O/+EzXeOQAAAF9JREFUGNN1TzESwCAIc3AABxDy/78WFXu91oYhIYcRSn2hHAwAxAEKMQy4O1pgijkxhMjqc8KhujgzoGaKzKjcRK13U2n8Z+wnaRB2KKievt2bPY0o5knrOETd9Ln2AuDLCz1j8HTeAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAAA4AAAANCAMAAACuAq9NAAAAY1BMVEUPGgsCBAIBAQEBAQAAAQAAAAABAQEFBQQQEw85SDdVa1GhzJm967TZ+NLP+sbM+8S6/a3k/9+s/pyr/puX/oSd15KIuoGBj39tfm1qj2RepFlu2VRkwzZlyTNatC5myzMAAAAOPREWAAAAHnRSTlP4/fz331IPBQIBAAECOly37/7+/v7XwpWktNDy+f7X56yoAAAAZElEQVQI102NwQ7AIAhDMdku3JwkIiaz//+VQ9FkcCgvpUAMoKpX9YEJYww0s7YG4iW9Lwl3QCSUZhZSHsHKslqXknPpRPpDypkmtr0cWBGntnseOeKgGd6UAr1Vj8vw9sKFmz+fERAp5vutHwAAAABJRU5ErkJggg==']; - case 'Mayhem': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABFklEQVR4AZ2R4WqEMBCEFy1yiJQQ14gcIhIuFBFR+qPQ93+v66QMksrlTwMfkZ2ZZbMKTgVqYIDl3YAbeCM31lJP/Zul4MAEPJjBQGNDLGsz8PQ6aqLAP5PTdd1WlmU09mSKtdTDRgrkzspJPKq6RxMahfj9yhOzQEZwZAwfzrk1ox3MXibIN8hO4MAjeV72CemJGWblnRsOYOdoGw0jebB20BPAwKzUQPlrFhrXFw1Wagu9yuzZwINzVAZCURRL+gRr7Wd8Vtqg4Th/lsUmewyk9WQ/A7NiwJz5VV/GmO+MNjMrFvh/NPDMigHTaeJN09a27ZHRJmalBg54CgfvAGYSLpoHjlmpuAwFdzDy7oGS/qIpM9UPFGg1b1kUlssAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABR0lEQVR4AYWSQWq0QBCFCw0SRIK0PQ4hiIhEZBhEySLyewUPEMgqR/JIXiDhzz7kKKYePIZajEzDRxfV9dWU3SO6IiVWUsVxT5R75Y4gTmwNnUh4kCulUiuV8sjChDjmKtaUcHgmHsnNrMPh0IVhiMIjKZGzNXDoyhMzF7C89z2KtFGD+FoNXEUKZdgpaPM8P++cDXTtBDca7EyQK8+bXTufYBccuvLAG26UnqN1LCgI4g/lm7zTgSux4vk0J8rnKw3+m1//pBPbBrVyGZVNmiAITviEtm3t+D+2QcJx7GUxlN4594K4ZY75Xzh0JVWqnad6TdP0H+LRNBjHcYNDV5xS32qwaC4my7Lwn6guu5QoomgbdFmWDYhnM8E8zxscuhLzPWtKA/dGqUizrityX9M0YX+DQ1ciXobnP6vgfmTOM7Znnk70B58pPaEvx+epAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA/ElEQVR4AZ3RUWqEMBSF4ftQZAhSREQJIiIXpQwi+tSldkFdWPsLhyEE0ocKH2Fyzg1mNJ4KAQ1arTUeeJMH6qwTUJmCHjMcC6KKtbSIylzdXpl18J/k4fdTpUFmPLOOa9bGe+P4+n5RYYfLXuiMsAlXofBxK2QXpvwN/jqg+AY91vR+pStk+apZe0fEhhMXDhUmWXEoO9WNmrWAzvRPq7jnB2jvUGfWTEgPcJzZFTbZk/0Tnh5QI+af6lVGvq/Do2atwVL4VJ+3QrZo1lr4Pw5wzVqDWaV7SUvHrZDNmrWAHq7g0rphkS3LXDMBVqFGhxGT1gGdDFnWaab6BRmXRvbxDmYiAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABQElEQVR4AY2SQUrEQBBFS9CMNFEkhAQdYmiCIUgcZlYGc4VsBcGVF/AuWXme4F7RtXiVWF9+Y9MYtOHRTdX/NZWaEj2RYpQTJeEdK4fKPuA7DjSGXiQkU0qlUqxySmFMEsYsNSU8zEmK4OwdEbmkKCclYoGmolfWCGyenh1O0EJE2gXNWpFC2S0IGrCQ29EbdPCPAmEHmXIxByf8hDAPD71yzAnXypatbSgoAN8Pyju5h4deMUrqJk1z+0uBN+/XX+gxfoFK2QafUJO2aRq//Q+/QIx2wr+Kwq0rusrP/QKf9MTCtbQLf9U1wNvYnz3qug45S68kSvVXgbPbx3nvYPXNOI7cRPWySukK+DcGCvA+urqZ3RmGAbmSXjFK5rpwW8nhWVJP04TYa9/3uO/goVciDiPlZhW8c8ZAHuRSeqIv32FK/GYGL8YAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAA/ElEQVR4AZ3RUWqEMBSF4ftQZAihDCKKiAQJShERQx+6o662e2p/4TCEQF468BEm95yLovFr4PBEq9PjgTd5wBcZp6559AiIWDAq6KXV3aJMUMfDOsTf7Mf/XaFBAvYiE9W16b74/vl8UeBAlKOSmWAzUiXwcavMkrrFE9QXVJ+gx5q9XvUVivmqrr1jxIYLCacCs6y6S8psGNU1hw4Bu4JHuUB3pzJBHZcviLiKV9jkyO4vxHyBx1h+qlcY5b2Wj+raE0vlU33dKrNFXWsR/7EgqmtPBIXuIw+dt8osqGsOPaIGSeeGRbZiFtVxsAYeHSbMOgd0MhSzTp3mD4RaQX4aW3NMAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABP0lEQVR4AYWS0UqFQBCGhziImNRBRImDmUgiIaF0kWSP4AMEXXXTE/QiPpL3UdR19Crb/PAvLEtyFj5mmfn/cdxd0RUokbJXEsZYCZUd4D72NBG8wkKmlEqtVMoFhTFJmKuoKelBTVIkjbNE5IainJTIeZqaXjkg8fp+Z7GCjiLQbWgOihTKsCFowUZtoNef4HgDf4JMuTbe8n/Br8NDr5zxhBul52i3FBQE+xflmzzTA69ESmpPmubunwZfztc/6IncBrXSe7/QkK5tW3f8H7dBjHH8q6Kwt033V6Hb4JeeWPgsq42rugfYZ92psWscRwMPvZIo9bEGD2+F2YUnBizLwpeoXnYpbQM34kAB9peP58aueZ4NPPRKxPusaRoYG6UizbquyH1O04T4RA+8EvAwUr6sgjFnDuReLaUn+ANygUa7+9SCWgAAAABJRU5ErkJggg==']; - case '4chanJS': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AABnZ2f///8nFk05AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAD/AAD///9nZ2f77Y6hAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8NnZ2f////82iC9AAAAAXRSTlMAQObYZgAAAEFJREFUeNqNjgEKACAMAjvX/98cAkkxgmSgO8Bt/Ai4ApJ6KKhzF3OiEMDASrGB/QWgPEHsUpN+Ng9xAETMYhDrWmeHAMcmvycWAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAD1BMVEUBAAAAAAAul8P///9nZ2cgIeMlAAAAAXRSTlMAQObYZgAAAEBJREFUeF6NjQEKACAMAnfW/98cAxFiBIngOsTqR8B1IGkeG9p5i7XabgAGZNigXgA8aoCUxvzWAIcBItGiSEwdccYA3BuRAWkAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDNlyjJnZ2f///+6o7dfAAAAAXRSTlMAQObYZgAAAERJREFUeF6NjkEKADEIA51o///lJZfQxUsHITogWi8AvwZJuxmYa25xDooBLEwOWFTYAsYVhdorLZt9Ng9xCUTCUCQ2H3F4ANrZ2WNiAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAElBMVEUBAAAAAABmzDP///9lyjJnZ2cIHys9AAAAAXRSTlMAQObYZgAAAENJREFUeF6NjUEKwEAMAjNm9/9fLkEslFwqgjoEUn8EfAqSdrkwzj6ieyyTkQEVGWRvANfO1iEX620AjgBEwqR4Y+sBeGAA6d+vQ4IAAAAASUVORK5CYII=']; - case 'Original': - return [t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX/////AAD///8AAABBZmS3AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAhElEQVR42q1RwQnAMAjMu5M4guAKXa4j5dUROo5tipSDcrFChUONd0di2m/hEGVOHDyIPufgwAFASDkpoSzmBrkJ2UMyR9LsJ3rvrqo3Rt1YMIMhhNnOxLMnoMFBxHyJAr2IOBFzA8U+6pLBdmEJTA0aMVjpDd6Loks0s5HZNwYx8tfZCZ0kll7ORffZAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///8ul8P///8AAACaqgkzAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAABBQcHFx4KISoNLToaVW4oKCgul8M4ODg7OzvBwcH///8uS/CdAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eILZO5/XI0UAgm7H9tOsu0yGWAQSOoFijHOxOANGqm/LczpOaXs4gISrPZ+gc2+hO5w2xdwgOjBFUIF+sEJrhUl9JFr+badFwR+BfqlmGUJAAAAAElFTkSuQmCC', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEX///9mzDP///8AAACT0n1lAAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=', t + 'iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAALVBMVEUAAAAAAAAAAAAAAAAECAIQIAgWLAsePA8oKCg4ODg6dB07OztmzDPBwcH///+rsf3XAAAAA3RSTlMAx9dmesIgAAAAV0lEQVR42m2NWw6AIBAD1eIDhbn/cTVSCCTsfmw7ybbLZIBBIKkXKKU0E4M3aKT+tjCn5xiziwuIsNr7BTb7ErrDZV/AAaIHdwgV6AcnuFaU0Eeu5dt2XiUyBjCQ2bIrAAAAAElFTkSuQmCC']; - } - })(), f.unreadDead = _ref[0], funreadDeadY = _ref[1], f.unreadSFW = _ref[2], f.unreadSFWY = _ref[3], f.unreadNSFW = _ref[4], f.unreadNSFWY = _ref[5]; - if (Favicon.SFW) { - Favicon.unread = Favicon.unreadSFW; - return Favicon.unreadY = Favicon.unreadSFWY; + t = 'data:image/png;base64,'; + i = 0; + while (items[i]) { + items[i] = t + items[i++]; + } + f.unreadDead = items[0], funreadDeadY = items[1], f.unreadSFW = items[2], f.unreadSFWY = items[3], f.unreadNSFW = items[4], f.unreadNSFWY = items[5]; + return f.update(); + }, + update: function() { + if (this.SFW) { + this.unread = this.unreadSFW; + return this.unreadY = this.unreadSFWY; } else { - Favicon.unread = Favicon.unreadNSFW; - return Favicon.unreadY = Favicon.unreadNSFWY; + this.unread = this.unreadNSFW; + return this.unreadY = this.unreadNSFWY; } }, dead: 'data:image/gif;base64,R0lGODlhEAAQAKECAAAAAP8AAP///////yH5BAEKAAIALAAAAAAQABAAAAIvlI+pq+D9DAgUoFkPDlbs7lFZKIJOJJ3MyraoB14jFpOcVMpzrnF3OKlZYsMWowAAOw==', @@ -11913,6 +11913,7 @@ $.ready(function() { return $.on(window, 'popstate', Navigate.popstate); }); + this.title = function() {}; Thread.callbacks.push({ name: 'Navigate', cb: this.thread @@ -12039,10 +12040,13 @@ }, updateBoard: function(boardID) { var fullBoardList, onload, req; - g.BOARD = new Board(boardID); req = null; + fullBoardList = $('#full-board-list', Header.boardList); + $.rmClass($('.current', fullBoardList), 'current'); + $.addClass($("a[href*='/" + boardID + "/']", fullBoardList), 'current'); + Header.generateBoardList(Conf['boardnav'].replace(/(\r\n|\n|\r)/g, ' ')); onload = function(e) { - var board, findStyle, mainStyleSheet, newStyleSheet, sfw, style; + var aboard, board, err, _i, _len, _ref; if (e.type === 'abort') { req.onloadend = null; return; @@ -12050,70 +12054,68 @@ if (req.status !== 200) { return; } - board = (function() { - var err, _i, _len, _ref; - try { - _ref = JSON.parse(req.response).boards; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - board = _ref[_i]; - if (board.board === boardID) { - return board; - } + try { + _ref = JSON.parse(req.response).boards; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + aboard = _ref[_i]; + if (!(aboard.board === boardID)) { + continue; } - } catch (_error) { - err = _error; - Main.handleErrors([ - { - message: "Navigation failed to update board name.", - error: err - } - ]); - return false; + board = aboard; + break; } - })(); + } catch (_error) { + err = _error; + Main.handleErrors([ + { + message: "Navigation failed to update board name.", + error: err + } + ]); + return false; + } if (!board) { return; } Navigate.updateTitle(board); - if (Favicon.SFW === (sfw = !!board.ws_board)) { - return; - } - findStyle = function(_arg) { - var base, style, type; - type = _arg[0], base = _arg[1]; - style = d.cookie.match(new RegExp("" + type + "\_style\=([^;]+)")); - return [(style ? style[1] : base), "" + type + "_style"]; - }; - style = findStyle(sfw ? ['ws', 'Yotsuba B New'] : ['nws', 'Yotsuba New']); - $.globalEval("var style_group = '" + style[1] + "'"); - mainStyleSheet = $('link[title=switch]', d.head); - newStyleSheet = $("link[title='" + style[0] + "']", d.head); - Favicon.SFW = sfw; - Favicon.el.href = "//s.4cdn.org/image/favicon" + (sfw ? '-ws' : '') + ".ico"; - $.add(d.head, Favicon.el); - Favicon["switch"](); - mainStyleSheet.href = newStyleSheet.href; - return Main.setClass(); + return Navigate.updateFavicon(!!board.ws_board); }; - fullBoardList = $('#full-board-list', Header.boardList); - $.rmClass($('.current', fullBoardList), 'current'); - $.addClass($("a[href*='/" + boardID + "/']", fullBoardList), 'current'); - Header.generateBoardList(Conf['boardnav'].replace(/(\r\n|\n|\r)/g, ' ')); return req = $.ajax('//a.4cdn.org/boards.json', { onabort: onload, onloadend: onload }); }, + updateFavicon: function(sfw) { + var findStyle, mainStyleSheet, newStyleSheet, style; + Favicon.el.href = "//s.4cdn.org/image/favicon" + (sfw ? '-ws' : '') + ".ico"; + $.add(d.head, Favicon.el); + if (Favicon.SFW === sfw) { + return; + } + Favicon.SFW = sfw; + Favicon.update(); + findStyle = function(type, base) { + var style; + style = d.cookie.match(new RegExp("" + type + "\_style\=([^;]+)")); + return ["" + type + "_style", (style ? style[1] : base)]; + }; + style = findStyle.apply(null, sfw ? ['ws', 'Yotsuba B New'] : ['nws', 'Yotsuba New']); + $.globalEval("var style_group = '" + style[0] + "'"); + mainStyleSheet = $('link[title=switch]', d.head); + newStyleSheet = $("link[title='" + style[1] + "']", d.head); + mainStyleSheet.href = newStyleSheet.href; + return Main.setClass(); + }, updateTitle: function(_arg) { var board, subtitle, title; board = _arg.board, title = _arg.title; if (subtitle = $('.boardSubtitle')) { $.rm(subtitle); } - return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title; + return $('.boardTitle').textContent = d.title = "" + board + " = " + title; }, navigate: function(e) { - var boardID, onload, pageNum, path, threadID, view; + var boardID, load, pageNum, path, threadID, view; if (this.hostname !== 'boards.4chan.org' || window.location.hostname === 'rs.4chan.org' || (e && (e.shiftKey || (e.type === 'click' && e.button !== 0)))) { return; } @@ -12129,6 +12131,7 @@ if (e) { e.preventDefault(); } + Navigate.title = function() {}; delete Index.pageNum; path = this.pathname; if (this.hash) { @@ -12152,18 +12155,22 @@ } if (view === 'index') { if (boardID === g.BOARD.ID) { - d.title = $('.boardTitle').textContent; + Navigate.title = function() { + return d.title = $('.boardTitle').textContent; + }; } else { - Navigate.updateBoard(boardID); + g.BOARD = new Board(boardID); + Navigate.title = function() { + return Navigate.updateBoard(boardID); + }; } return Index.update(pageNum); } else { - onload = function(e) { - return Navigate.load(e); - }; + Navigate.updateFavicon(Favicon.SFW); + load = Navigate.load; Navigate.req = $.ajax("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", { - onabort: onload, - onloadend: onload + onabort: load, + onloadend: load }); return setTimeout((function() { if (Navigate.req && !Navigate.notice) { @@ -12181,14 +12188,14 @@ } delete Navigate.req; delete Navigate.notice; - if (e.type === 'abort') { + if (e.type === 'abort' || req.status !== 200) { req.onloadend = null; + new Notice('warning', "Failed to load thread." + (req.status ? " " + req.status : '')); return; } + Navigate.title(); try { - if (req.status === 200) { - return Navigate.parse(JSON.parse(req.response).posts); - } + return Navigate.parse(JSON.parse(req.response).posts); } catch (_error) { err = _error; console.error('Navigate failure:'); diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 5438d1bdc..b011fc9ea 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -271,6 +271,8 @@ Index = new Notice 'warning', err, 1 return + Navigate.title() + try if req.status is 200 Index.parse JSON.parse(req.response), pageNum diff --git a/src/General/Navigate.coffee b/src/General/Navigate.coffee index 95a0d9d2d..bea89a0f5 100644 --- a/src/General/Navigate.coffee +++ b/src/General/Navigate.coffee @@ -1,11 +1,13 @@ Navigate = - path: window.location.pathname + path: window.location.pathname init: -> return if g.VIEW is 'catalog' or g.BOARD.ID is 'f' or !Conf['JSON Navigation'] # blink/webkit throw a popstate on page load. Not what we want. $.ready -> $.on window, 'popstate', Navigate.popstate + @title = -> return + Thread.callbacks.push name: 'Navigate' cb: @thread @@ -105,10 +107,13 @@ Navigate = $.off d, 'IndexRefresh', QR.generatePostableThreadsList updateBoard: (boardID) -> - g.BOARD = new Board boardID - req = null + fullBoardList = $ '#full-board-list', Header.boardList + $.rmClass $('.current', fullBoardList), 'current' + $.addClass $("a[href*='/#{boardID}/']", fullBoardList), 'current' + Header.generateBoardList Conf['boardnav'].replace /(\r\n|\n|\r)/g, ' ' + onload = (e) -> if e.type is 'abort' req.onloadend = null @@ -116,9 +121,10 @@ Navigate = return unless req.status is 200 - board = do -> try - for board in JSON.parse(req.response).boards - return board if board.board is boardID + try + for aboard in JSON.parse(req.response).boards when aboard.board is boardID + board = aboard + break catch err Main.handleErrors [ @@ -129,44 +135,42 @@ Navigate = return unless board Navigate.updateTitle board - - return if Favicon.SFW is sfw = !!board.ws_board # Board SFW status hasn't changed - - findStyle = ([type, base]) -> - style = d.cookie.match new RegExp "#{type}\_style\=([^;]+)" - return [(if style then style[1] else base), "#{type}_style"] - - style = findStyle if sfw - ['ws', 'Yotsuba B New'] - else - ['nws', 'Yotsuba New'] - - $.globalEval "var style_group = '#{style[1]}'" - - mainStyleSheet = $ 'link[title=switch]', d.head - newStyleSheet = $ "link[title='#{style[0]}']", d.head - - Favicon.SFW = sfw - Favicon.el.href = "//s.4cdn.org/image/favicon#{if sfw then '-ws' else ''}.ico" - $.add d.head, Favicon.el # Changing the href alone doesn't update the icon on Firefox - Favicon.switch() - - mainStyleSheet.href = newStyleSheet.href - - Main.setClass() - - fullBoardList = $ '#full-board-list', Header.boardList - $.rmClass $('.current', fullBoardList), 'current' - $.addClass $("a[href*='/#{boardID}/']", fullBoardList), 'current' - Header.generateBoardList Conf['boardnav'].replace /(\r\n|\n|\r)/g, ' ' + Navigate.updateFavicon !!board.ws_board req = $.ajax '//a.4cdn.org/boards.json', onabort: onload onloadend: onload + updateFavicon: (sfw) -> + # TODO: think of a better name for this. Changes style, too. + Favicon.el.href = "//s.4cdn.org/image/favicon#{if sfw then '-ws' else ''}.ico" + $.add d.head, Favicon.el # Changing the href alone doesn't update the icon on Firefox + + return if Favicon.SFW is sfw # Board SFW status hasn't changed + + Favicon.SFW = sfw + Favicon.update() + findStyle = (type, base) -> + style = d.cookie.match new RegExp "#{type}\_style\=([^;]+)" + return ["#{type}_style", (if style then style[1] else base)] + + style = findStyle.apply null, if sfw + ['ws', 'Yotsuba B New'] + else + ['nws', 'Yotsuba New'] + + $.globalEval "var style_group = '#{style[0]}'" + + mainStyleSheet = $ 'link[title=switch]', d.head + newStyleSheet = $ "link[title='#{style[1]}']", d.head + + mainStyleSheet.href = newStyleSheet.href + + Main.setClass() + updateTitle: ({board, title}) -> $.rm subtitle if subtitle = $ '.boardSubtitle' - $('.boardTitle').textContent = d.title = "/#{board}/ - #{title}" + $('.boardTitle').textContent = d.title = "#{board} = #{title}" navigate: (e) -> return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org' or @@ -180,6 +184,7 @@ Navigate = return if view is 'catalog' or 'f' in [boardID, g.BOARD.ID] e.preventDefault() if e + Navigate.title = -> return delete Index.pageNum @@ -203,18 +208,20 @@ Navigate = if view is 'index' if boardID is g.BOARD.ID - d.title = $('.boardTitle').textContent + Navigate.title = -> d.title = $('.boardTitle').textContent else - Navigate.updateBoard boardID + g.BOARD = new Board boardID + Navigate.title = -> Navigate.updateBoard boardID Index.update pageNum # Moving from index to thread or thread to thread else - onload = (e) -> Navigate.load e + Navigate.updateFavicon Favicon.SFW + {load} = Navigate Navigate.req = $.ajax "//a.4cdn.org/#{boardID}/res/#{threadID}.json", - onabort: onload - onloadend: onload + onabort: load + onloadend: load setTimeout (-> if Navigate.req and !Navigate.notice @@ -228,13 +235,15 @@ Navigate = delete Navigate.req delete Navigate.notice - if e.type is 'abort' + if e.type is 'abort' or req.status isnt 200 req.onloadend = null + new Notice 'warning', "Failed to load thread.#{if req.status then " #{req.status}" else ''}" return + Navigate.title() + try - if req.status is 200 - Navigate.parse JSON.parse(req.response).posts + Navigate.parse JSON.parse(req.response).posts catch err console.error 'Navigate failure:' console.log err diff --git a/src/General/lib/simpledict.class b/src/General/lib/simpledict.class index 34ce15cf4..48baac2af 100644 --- a/src/General/lib/simpledict.class +++ b/src/General/lib/simpledict.class @@ -11,6 +11,6 @@ class SimpleDict key = "#{key}" if (i = @keys.indexOf key) isnt -1 @keys.splice i, 1 - delete @[key] if $.remove @keys, key + delete @[key] forEach: (fn) -> fn @[key] for key in [@keys...] diff --git a/src/Monitoring/Favicon.coffee b/src/Monitoring/Favicon.coffee index 98384ac50..7eb292692 100755 --- a/src/Monitoring/Favicon.coffee +++ b/src/Monitoring/Favicon.coffee @@ -10,55 +10,64 @@ Favicon = Favicon.switch() switch: -> - t = 'data:image/png;base64,' + items = { + ferongr: [ + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadDead.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadDeadY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadSFWY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadNSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadNSFWY.png", {encoding: "base64"}) %>' + ] + 'xat-': [ + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadDead.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadDeadY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadSFWY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadNSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadNSFWY.png", {encoding: "base64"}) %>' + ] + Mayhem: [ + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadDead.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadDeadY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadSFWY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadNSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadNSFWY.png", {encoding: "base64"}) %>' + ] + '4chanJS': [ + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadDead.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadDeadY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadSFWY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadNSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadNSFWY.png", {encoding: "base64"}) %>' + ] + Original: [ + '<%= grunt.file.read("src/General/img/favicons/Original/unreadDead.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Original/unreadDeadY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Original/unreadSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Original/unreadSFWY.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Original/unreadNSFW.png", {encoding: "base64"}) %>' + '<%= grunt.file.read("src/General/img/favicons/Original/unreadNSFWY.png", {encoding: "base64"}) %>' + ] + }[Conf['favicon']] + f = Favicon - [f.unreadDead, funreadDeadY, f.unreadSFW, f.unreadSFWY, f.unreadNSFW, f.unreadNSFWY] = switch Conf['favicon'] - when 'ferongr' then [ - t + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadDead.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadDeadY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadSFWY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadNSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/ferongr/unreadNSFWY.png", {encoding: "base64"}) %>' - ] - when 'xat-' then [ - t + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadDead.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadDeadY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadSFWY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadNSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/xat-/unreadNSFWY.png", {encoding: "base64"}) %>' - ] - when 'Mayhem' then [ - t + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadDead.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadDeadY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadSFWY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadNSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Mayhem/unreadNSFWY.png", {encoding: "base64"}) %>' - ] - when '4chanJS' then [ - t + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadDead.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadDeadY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadSFWY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadNSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/4chanJS/unreadNSFWY.png", {encoding: "base64"}) %>' - ] - when 'Original' then [ - t + '<%= grunt.file.read("src/General/img/favicons/Original/unreadDead.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Original/unreadDeadY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Original/unreadSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Original/unreadSFWY.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Original/unreadNSFW.png", {encoding: "base64"}) %>' - t + '<%= grunt.file.read("src/General/img/favicons/Original/unreadNSFWY.png", {encoding: "base64"}) %>' - ] - if Favicon.SFW - Favicon.unread = Favicon.unreadSFW - Favicon.unreadY = Favicon.unreadSFWY + t = 'data:image/png;base64,' + i = 0 + while items[i] + items[i] = t + items[i++] + [f.unreadDead, funreadDeadY, f.unreadSFW, f.unreadSFWY, f.unreadNSFW, f.unreadNSFWY] = items + f.update() + + update: -> + if @SFW + @unread = @unreadSFW + @unreadY = @unreadSFWY else - Favicon.unread = Favicon.unreadNSFW - Favicon.unreadY = Favicon.unreadNSFWY + @unread = @unreadNSFW + @unreadY = @unreadNSFWY dead: 'data:image/gif;base64,<%= grunt.file.read("src/General/img/favicons/dead.gif", {encoding: "base64"}) %>' logo: 'data:image/png;base64,<%= grunt.file.read("src/General/img/icon128.png", {encoding: "base64"}) %>' From 19c8ffe4d6b12c29f65092fff06bcf9b7fe6621a Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Wed, 15 Jan 2014 17:10:46 -0700 Subject: [PATCH 06/19] Cruft --- builds/4chan-X.user.js | 3 +-- builds/crx/script.js | 3 +-- src/General/Navigate.coffee | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index a4c60ab83..41e174d6f 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -12123,7 +12123,7 @@ if (subtitle = $('.boardSubtitle')) { $.rm(subtitle); } - return $('.boardTitle').textContent = d.title = "" + board + " = " + title; + return $('.boardTitle').textContent = d.title = "" + board + " - " + title; }, navigate: function(e) { var boardID, load, pageNum, path, threadID, view; @@ -12204,7 +12204,6 @@ new Notice('warning', "Failed to load thread." + (req.status ? " " + req.status : '')); return; } - Navigate.title(); try { return Navigate.parse(JSON.parse(req.response).posts); } catch (_error) { diff --git a/builds/crx/script.js b/builds/crx/script.js index f3684733a..982ed9780 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -12112,7 +12112,7 @@ if (subtitle = $('.boardSubtitle')) { $.rm(subtitle); } - return $('.boardTitle').textContent = d.title = "" + board + " = " + title; + return $('.boardTitle').textContent = d.title = "" + board + " - " + title; }, navigate: function(e) { var boardID, load, pageNum, path, threadID, view; @@ -12193,7 +12193,6 @@ new Notice('warning', "Failed to load thread." + (req.status ? " " + req.status : '')); return; } - Navigate.title(); try { return Navigate.parse(JSON.parse(req.response).posts); } catch (_error) { diff --git a/src/General/Navigate.coffee b/src/General/Navigate.coffee index bea89a0f5..6728b50ed 100644 --- a/src/General/Navigate.coffee +++ b/src/General/Navigate.coffee @@ -170,7 +170,7 @@ Navigate = updateTitle: ({board, title}) -> $.rm subtitle if subtitle = $ '.boardSubtitle' - $('.boardTitle').textContent = d.title = "#{board} = #{title}" + $('.boardTitle').textContent = d.title = "#{board} - #{title}" navigate: (e) -> return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org' or @@ -240,8 +240,6 @@ Navigate = new Notice 'warning', "Failed to load thread.#{if req.status then " #{req.status}" else ''}" return - Navigate.title() - try Navigate.parse JSON.parse(req.response).posts catch err From 879206219b92b8ec78b5b2545549fbcea9026e03 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 00:51:47 -0700 Subject: [PATCH 07/19] Oops --- LICENSE | 2 +- builds/4chan-X.user.js | 4 ++-- builds/crx/script.js | 4 ++-- src/General/Navigate.coffee | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/LICENSE b/LICENSE index 8466855be..6bb57545a 100755 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.3.2 - 2014-01-15 +* 4chan X - Version 1.3.2 - 2014-01-16 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 41e174d6f..99c90f1b1 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -22,7 +22,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.3.2 - 2014-01-15 +* 4chan X - Version 1.3.2 - 2014-01-16 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -12123,7 +12123,7 @@ if (subtitle = $('.boardSubtitle')) { $.rm(subtitle); } - return $('.boardTitle').textContent = d.title = "" + board + " - " + title; + return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title; }, navigate: function(e) { var boardID, load, pageNum, path, threadID, view; diff --git a/builds/crx/script.js b/builds/crx/script.js index 982ed9780..8b9d645f9 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.3.2 - 2014-01-15 +* 4chan X - Version 1.3.2 - 2014-01-16 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -12112,7 +12112,7 @@ if (subtitle = $('.boardSubtitle')) { $.rm(subtitle); } - return $('.boardTitle').textContent = d.title = "" + board + " - " + title; + return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title; }, navigate: function(e) { var boardID, load, pageNum, path, threadID, view; diff --git a/src/General/Navigate.coffee b/src/General/Navigate.coffee index 6728b50ed..56b17a4f3 100644 --- a/src/General/Navigate.coffee +++ b/src/General/Navigate.coffee @@ -170,7 +170,7 @@ Navigate = updateTitle: ({board, title}) -> $.rm subtitle if subtitle = $ '.boardSubtitle' - $('.boardTitle').textContent = d.title = "#{board} - #{title}" + $('.boardTitle').textContent = d.title = "/#{board}/ - #{title}" navigate: (e) -> return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org' or From 3b7aa9f398e30a3b41d960dfbb853a5dac525863 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 04:27:33 -0700 Subject: [PATCH 08/19] Deal with 304 status with board navigation --- builds/4chan-X.user.js | 4 +++- builds/crx/script.js | 4 +++- src/General/Index.coffee | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 99c90f1b1..3ea1d8519 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -2192,6 +2192,7 @@ if (g.BOARD.ID === 'f' || g.VIEW === 'catalog' || !Conf['JSON Navigation']) { return; } + this.board = "" + g.BOARD; this.button = $.el('a', { className: 'index-refresh-shortcut fa fa-refresh', title: 'Refresh', @@ -2585,7 +2586,8 @@ } Navigate.title(); try { - if (req.status === 200) { + if (req.status === 200 || Index.board !== ("" + g.BOARD)) { + Index.board = "" + g.BOARD; Index.parse(JSON.parse(req.response), pageNum); } else if (req.status === 304 && (pageNum != null)) { Index.pageNav(pageNum); diff --git a/builds/crx/script.js b/builds/crx/script.js index 8b9d645f9..ac9efb420 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -2202,6 +2202,7 @@ if (g.BOARD.ID === 'f' || g.VIEW === 'catalog' || !Conf['JSON Navigation']) { return; } + this.board = "" + g.BOARD; this.button = $.el('a', { className: 'index-refresh-shortcut fa fa-refresh', title: 'Refresh', @@ -2595,7 +2596,8 @@ } Navigate.title(); try { - if (req.status === 200) { + if (req.status === 200 || Index.board !== ("" + g.BOARD)) { + Index.board = "" + g.BOARD; Index.parse(JSON.parse(req.response), pageNum); } else if (req.status === 304 && (pageNum != null)) { Index.pageNav(pageNum); diff --git a/src/General/Index.coffee b/src/General/Index.coffee index b011fc9ea..1959cdb1f 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -2,6 +2,8 @@ Index = init: -> return if g.BOARD.ID is 'f' or g.VIEW is 'catalog' or !Conf['JSON Navigation'] + @board = "#{g.BOARD}" + @button = $.el 'a', className: 'index-refresh-shortcut fa fa-refresh' title: 'Refresh' @@ -274,7 +276,8 @@ Index = Navigate.title() try - if req.status is 200 + if req.status is 200 or Index.board isnt "#{g.BOARD}" + Index.board = "#{g.BOARD}" Index.parse JSON.parse(req.response), pageNum else if req.status is 304 and pageNum? Index.pageNav pageNum From d34284a8d0cddde3e475e6ee4b37c232e6b45ba2 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 04:31:27 -0700 Subject: [PATCH 09/19] I misunderstood: we're not caching the result with lastmodified. --- builds/4chan-X.user.js | 6 +++--- builds/crx/script.js | 6 +++--- src/General/Index.coffee | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 3ea1d8519..ba25d1e63 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -2554,7 +2554,7 @@ onabort: onload, onloadend: onload }, { - whenModified: true + whenModified: Index.board === ("" + g.BOARD) }); return $.addClass(Index.button, 'fa-spin'); }, @@ -2585,9 +2585,9 @@ return; } Navigate.title(); + Index.board = "" + g.BOARD; try { - if (req.status === 200 || Index.board !== ("" + g.BOARD)) { - Index.board = "" + g.BOARD; + if (req.status === 200) { Index.parse(JSON.parse(req.response), pageNum); } else if (req.status === 304 && (pageNum != null)) { Index.pageNav(pageNum); diff --git a/builds/crx/script.js b/builds/crx/script.js index ac9efb420..c68e169e8 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -2564,7 +2564,7 @@ onabort: onload, onloadend: onload }, { - whenModified: true + whenModified: Index.board === ("" + g.BOARD) }); return $.addClass(Index.button, 'fa-spin'); }, @@ -2595,9 +2595,9 @@ return; } Navigate.title(); + Index.board = "" + g.BOARD; try { - if (req.status === 200 || Index.board !== ("" + g.BOARD)) { - Index.board = "" + g.BOARD; + if (req.status === 200) { Index.parse(JSON.parse(req.response), pageNum); } else if (req.status === 304 && (pageNum != null)) { Index.pageNav(pageNum); diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 1959cdb1f..f01dc7dc2 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -247,7 +247,7 @@ Index = onabort: onload onloadend: onload , - whenModified: true + whenModified: Index.board is "#{g.BOARD}" $.addClass Index.button, 'fa-spin' load: (e, pageNum) -> @@ -274,10 +274,10 @@ Index = return Navigate.title() + Index.board = "#{g.BOARD}" try - if req.status is 200 or Index.board isnt "#{g.BOARD}" - Index.board = "#{g.BOARD}" + if req.status is 200 Index.parse JSON.parse(req.response), pageNum else if req.status is 304 and pageNum? Index.pageNav pageNum From ef99677f142c6b2dadb0e3f70745f0c4b14cf7d4 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 08:28:40 -0700 Subject: [PATCH 10/19] Consolidate things a little --- builds/4chan-X.user.js | 102 ++++++++++++++++++++------------------- builds/crx/script.js | 102 ++++++++++++++++++++------------------- src/General/Index.coffee | 40 +++++++++------ 3 files changed, 130 insertions(+), 114 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index ba25d1e63..535756d8d 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -2718,43 +2718,34 @@ return Main.callbackNodes(Post, posts); }, sort: function() { - var i, sortedThreadIDs, threadID, _i, _len; - switch (Conf['Index Sort']) { - case 'bump': - sortedThreadIDs = Index.liveThreadIDs; - break; - case 'lastreply': - sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { - if ('last_replies' in a) { - a = a.last_replies[a.last_replies.length - 1]; - } - if ('last_replies' in b) { - b = b.last_replies[b.last_replies.length - 1]; - } - return b.no - a.no; - }).map(function(data) { - return data.no; - }); - break; - case 'birth': - sortedThreadIDs = __slice.call(Index.liveThreadIDs).sort(function(a, b) { - return b - a; - }); - break; - case 'replycount': - sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { - return b.replies - a.replies; - }).map(function(data) { - return data.no; - }); - break; - case 'filecount': - sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { - return b.images - a.images; - }).map(function(data) { - return data.no; - }); - } + var cnd, fn, i, item, items, sortOnTop, sortedThreadIDs, threadID, _i, _len; + sortedThreadIDs = { + lastreply: __slice.call(Index.liveThreadData).sort(function(a, b) { + if ('last_replies' in a) { + a = a.last_replies[a.last_replies.length - 1]; + } + if ('last_replies' in b) { + b = b.last_replies[b.last_replies.length - 1]; + } + return b.no - a.no; + }).map(function(data) { + return data.no; + }), + bump: Index.liveThreadIDs, + birth: __slice.call(Index.liveThreadIDs).sort(function(a, b) { + return b - a; + }), + replycount: __slice.call(Index.liveThreadData).sort(function(a, b) { + return b.replies - a.replies; + }).map(function(data) { + return data.no; + }), + filecount: __slice.call(Index.liveThreadData).sort(function(a, b) { + return b.images - a.images; + }).map(function(data) { + return data.no; + }) + }[Conf['Index Sort']]; Index.sortedNodes = []; for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { threadID = sortedThreadIDs[_i]; @@ -2764,18 +2755,31 @@ if (Index.isSearching) { Index.sortedNodes = Index.querySearch(Index.searchInput.value) || Index.sortedNodes; } - Index.sortOnTop(function(thread) { - return thread.isSticky; - }); - if (Conf['Filter']) { - Index.sortOnTop(function(thread) { - return thread.isOnTop; - }); - } - if (Conf['Anchor Hidden Threads']) { - return Index.sortOnTop(function(thread) { - return !thread.isHidden; - }); + sortOnTop = Index.sortOnTop; + items = [ + { + fn: function(thread) { + return thread.isSticky; + }, + cnd: true + }, { + fn: function(thread) { + return thread.isOnTop; + }, + cnd: Conf['Filter'] + }, { + fn: function(thread) { + return !thread.isHidden; + }, + cnd: Conf['Anchor Hidden Threads'] + } + ]; + i = 0; + while (item = items[i++]) { + fn = item.fn, cnd = item.cnd; + if (fn) { + sortOnTop(fn); + } } }, sortOnTop: function(match) { diff --git a/builds/crx/script.js b/builds/crx/script.js index c68e169e8..819f7145e 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -2728,43 +2728,34 @@ return Main.callbackNodes(Post, posts); }, sort: function() { - var i, sortedThreadIDs, threadID, _i, _len; - switch (Conf['Index Sort']) { - case 'bump': - sortedThreadIDs = Index.liveThreadIDs; - break; - case 'lastreply': - sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { - if ('last_replies' in a) { - a = a.last_replies[a.last_replies.length - 1]; - } - if ('last_replies' in b) { - b = b.last_replies[b.last_replies.length - 1]; - } - return b.no - a.no; - }).map(function(data) { - return data.no; - }); - break; - case 'birth': - sortedThreadIDs = __slice.call(Index.liveThreadIDs).sort(function(a, b) { - return b - a; - }); - break; - case 'replycount': - sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { - return b.replies - a.replies; - }).map(function(data) { - return data.no; - }); - break; - case 'filecount': - sortedThreadIDs = __slice.call(Index.liveThreadData).sort(function(a, b) { - return b.images - a.images; - }).map(function(data) { - return data.no; - }); - } + var cnd, fn, i, item, items, sortOnTop, sortedThreadIDs, threadID, _i, _len; + sortedThreadIDs = { + lastreply: __slice.call(Index.liveThreadData).sort(function(a, b) { + if ('last_replies' in a) { + a = a.last_replies[a.last_replies.length - 1]; + } + if ('last_replies' in b) { + b = b.last_replies[b.last_replies.length - 1]; + } + return b.no - a.no; + }).map(function(data) { + return data.no; + }), + bump: Index.liveThreadIDs, + birth: __slice.call(Index.liveThreadIDs).sort(function(a, b) { + return b - a; + }), + replycount: __slice.call(Index.liveThreadData).sort(function(a, b) { + return b.replies - a.replies; + }).map(function(data) { + return data.no; + }), + filecount: __slice.call(Index.liveThreadData).sort(function(a, b) { + return b.images - a.images; + }).map(function(data) { + return data.no; + }) + }[Conf['Index Sort']]; Index.sortedNodes = []; for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { threadID = sortedThreadIDs[_i]; @@ -2774,18 +2765,31 @@ if (Index.isSearching) { Index.sortedNodes = Index.querySearch(Index.searchInput.value) || Index.sortedNodes; } - Index.sortOnTop(function(thread) { - return thread.isSticky; - }); - if (Conf['Filter']) { - Index.sortOnTop(function(thread) { - return thread.isOnTop; - }); - } - if (Conf['Anchor Hidden Threads']) { - return Index.sortOnTop(function(thread) { - return !thread.isHidden; - }); + sortOnTop = Index.sortOnTop; + items = [ + { + fn: function(thread) { + return thread.isSticky; + }, + cnd: true + }, { + fn: function(thread) { + return thread.isOnTop; + }, + cnd: Conf['Filter'] + }, { + fn: function(thread) { + return !thread.isHidden; + }, + cnd: Conf['Anchor Hidden Threads'] + } + ]; + i = 0; + while (item = items[i++]) { + fn = item.fn, cnd = item.cnd; + if (fn) { + sortOnTop(fn); + } } }, sortOnTop: function(match) { diff --git a/src/General/Index.coffee b/src/General/Index.coffee index f01dc7dc2..3e2cb30c6 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -374,21 +374,18 @@ Index = Main.callbackNodes Post, posts sort: -> - switch Conf['Index Sort'] - when 'bump' - sortedThreadIDs = Index.liveThreadIDs - when 'lastreply' - sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> + sortedThreadIDs = { + lastreply: + [Index.liveThreadData...].sort((a, b) -> a = a.last_replies[a.last_replies.length - 1] if 'last_replies' of a b = b.last_replies[b.last_replies.length - 1] if 'last_replies' of b b.no - a.no ).map (data) -> data.no - when 'birth' - sortedThreadIDs = [Index.liveThreadIDs...].sort (a, b) -> b - a - when 'replycount' - sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no - when 'filecount' - sortedThreadIDs = [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no + bump: Index.liveThreadIDs + birth: [Index.liveThreadIDs...].sort (a, b) -> b - a + replycount: [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no + filecount: [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no + }[Conf['Index Sort']] Index.sortedNodes = [] for threadID in sortedThreadIDs i = Index.liveThreadIDs.indexOf(threadID) * 2 @@ -396,11 +393,22 @@ Index = if Index.isSearching Index.sortedNodes = Index.querySearch(Index.searchInput.value) or Index.sortedNodes # Sticky threads - Index.sortOnTop (thread) -> thread.isSticky - # Highlighted threads - Index.sortOnTop((thread) -> thread.isOnTop) if Conf['Filter'] - # Non-hidden threads - Index.sortOnTop((thread) -> !thread.isHidden) if Conf['Anchor Hidden Threads'] + {sortOnTop} = Index + items = [ + fn: (thread) -> thread.isSticky + cnd: true + , # Highlighted threads + fn: (thread) -> thread.isOnTop + cnd: Conf['Filter'] + , # Non-hidden threads + fn: (thread) -> !thread.isHidden + cnd: Conf['Anchor Hidden Threads'] + ] + i = 0 + while item = items[i++] + {fn, cnd} = item + sortOnTop fn if fn + return sortOnTop: (match) -> offset = 0 From 69288c7ebe96cf4b7f4e7e3671cf8cf49a84b095 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 09:56:20 -0700 Subject: [PATCH 11/19] More or less just trying to optimize this. --- builds/4chan-X.user.js | 72 ++++++++++++++++++++++++---------------- builds/crx/script.js | 72 ++++++++++++++++++++++++---------------- src/General/Index.coffee | 60 ++++++++++++++++++--------------- 3 files changed, 122 insertions(+), 82 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 535756d8d..2c3c0c488 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -2360,7 +2360,7 @@ }); }, scroll: $.debounce(100, function() { - var nodes, nodesPerPage, pageNum; + var nodes, nodesPerPage, offset, pageNum; if (Index.req || Conf['Index Mode'] !== 'infinite' || (doc.scrollTop <= doc.scrollHeight - (300 + window.innerHeight)) || g.VIEW === 'thread') { return; } @@ -2371,12 +2371,13 @@ if (pageNum >= Index.pagesNum) { return Index.endNotice(); } - nodesPerPage = Index.threadsNumPerPage * 2; - nodes = Index.sortedNodes.slice(nodesPerPage * pageNum, nodesPerPage * (pageNum + 1)); + nodesPerPage = Index.threadsNumPerPage; + offset = nodesPerPage * pageNum; + nodes = Index.sortedNodes.slice(offset, offset + nodesPerPage); if (Conf['Show Replies']) { Index.buildReplies(nodes); } - $.add(Index.root, nodes); + Index.buildStructure(nodes); return Index.setPage(pageNum); }), endNotice: (function() { @@ -2655,7 +2656,7 @@ thread = new Thread(threadData.no, g.BOARD); threads.push(thread); } - Index.nodes.push(threadRoot, $.el('hr')); + Index.nodes.push(threadRoot); if (thread.ID in thread.posts) { continue; } @@ -2682,7 +2683,7 @@ buildReplies: function(threadRoots) { var data, err, errors, i, lastReplies, node, nodes, post, posts, thread, threadRoot, _i, _j, _len, _len1; posts = []; - for (_i = 0, _len = threadRoots.length; _i < _len; _i += 2) { + for (_i = 0, _len = threadRoots.length; _i < _len; _i++) { threadRoot = threadRoots[_i]; thread = Get.threadFromRoot(threadRoot); i = Index.liveThreadIDs.indexOf(thread.ID); @@ -2718,7 +2719,7 @@ return Main.callbackNodes(Post, posts); }, sort: function() { - var cnd, fn, i, item, items, sortOnTop, sortedThreadIDs, threadID, _i, _len; + var cnd, fn, i, item, items, nodes, sortedThreadIDs, threadID, _i, _len; sortedThreadIDs = { lastreply: __slice.call(Index.liveThreadData).sort(function(a, b) { if ('last_replies' in a) { @@ -2747,15 +2748,14 @@ }) }[Conf['Index Sort']]; Index.sortedNodes = []; + nodes = Index.nodes; for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { threadID = sortedThreadIDs[_i]; - i = Index.liveThreadIDs.indexOf(threadID) * 2; - Index.sortedNodes.push(Index.nodes[i], Index.nodes[i + 1]); + Index.sortedNodes.push(nodes[Index.liveThreadIDs.indexOf(threadID)]); } - if (Index.isSearching) { - Index.sortedNodes = Index.querySearch(Index.searchInput.value) || Index.sortedNodes; + if (Index.isSearching && (nodes = Index.querySearch(Index.searchInput.value))) { + Index.sortedNodes = nodes; } - sortOnTop = Index.sortOnTop; items = [ { fn: function(thread) { @@ -2777,28 +2777,30 @@ i = 0; while (item = items[i++]) { fn = item.fn, cnd = item.cnd; - if (fn) { - sortOnTop(fn); + if (cnd) { + Index.sortOnTop(fn); } } }, sortOnTop: function(match) { - var i, offset, threadRoot, _i, _len, _ref, _ref1; + var i, offset, threadRoot, _i, _len, _ref; offset = 0; + i = 0; _ref = Index.sortedNodes; - for (i = _i = 0, _len = _ref.length; _i < _len; i = _i += 2) { + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { threadRoot = _ref[i]; if (match(Get.threadFromRoot(threadRoot))) { - (_ref1 = Index.sortedNodes).splice.apply(_ref1, [offset++ * 2, 0].concat(__slice.call(Index.sortedNodes.splice(i, 2)))); + Index.sortedNodes.splice(offset++, 0, Index.sortedNodes.splice(i, 1)[0]); } } }, buildIndex: function() { - var nodes, nodesPerPage, pageNum; + var nodes, nodesPerPage, offset, pageNum; if (Conf['Index Mode'] !== 'all pages') { pageNum = Index.getCurrentPage(); - nodesPerPage = Index.threadsNumPerPage * 2; - nodes = Index.sortedNodes.slice(nodesPerPage * pageNum, nodesPerPage * (pageNum + 1)); + nodesPerPage = Index.threadsNumPerPage; + offset = nodesPerPage * pageNum; + nodes = Index.sortedNodes.slice(offset, offset + nodesPerPage); } else { nodes = Index.sortedNodes; } @@ -2807,8 +2809,22 @@ if (Conf['Show Replies']) { Index.buildReplies(nodes); } - $.add(Index.root, nodes); - return $.event('IndexBuild', nodes); + return Index.buildStructure(nodes); + }, + buildStructure: function(nodes) { + var hr, i, node, result, _i, _len, _ref; + result = $.frag(); + i = 0; + while (node = nodes[i++]) { + $.add(result, [node, $.el('hr')]); + } + $.add(Index.root, result); + _ref = $$('hr + hr', Index.root); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + hr = _ref[_i]; + $.rm(hr); + } + return $.event('IndexBuild', result); }, isSearching: false, clearSearch: function() { @@ -2851,16 +2867,16 @@ return Index.search(keywords); }, search: function(keywords) { - var found, i, threadRoot, _i, _len, _ref; - found = []; + var threadRoot, _i, _len, _ref, _results; _ref = Index.sortedNodes; - for (i = _i = 0, _len = _ref.length; _i < _len; i = _i += 2) { - threadRoot = _ref[i]; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + threadRoot = _ref[_i]; if (Index.searchMatch(Get.threadFromRoot(threadRoot), keywords)) { - found.push(Index.sortedNodes[i], Index.sortedNodes[i + 1]); + _results.push(threadRoot); } } - return found; + return _results; }, searchMatch: function(thread, keywords) { var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1; diff --git a/builds/crx/script.js b/builds/crx/script.js index 819f7145e..fab976f9c 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -2370,7 +2370,7 @@ }); }, scroll: $.debounce(100, function() { - var nodes, nodesPerPage, pageNum; + var nodes, nodesPerPage, offset, pageNum; if (Index.req || Conf['Index Mode'] !== 'infinite' || (doc.scrollTop <= doc.scrollHeight - (300 + window.innerHeight)) || g.VIEW === 'thread') { return; } @@ -2381,12 +2381,13 @@ if (pageNum >= Index.pagesNum) { return Index.endNotice(); } - nodesPerPage = Index.threadsNumPerPage * 2; - nodes = Index.sortedNodes.slice(nodesPerPage * pageNum, nodesPerPage * (pageNum + 1)); + nodesPerPage = Index.threadsNumPerPage; + offset = nodesPerPage * pageNum; + nodes = Index.sortedNodes.slice(offset, offset + nodesPerPage); if (Conf['Show Replies']) { Index.buildReplies(nodes); } - $.add(Index.root, nodes); + Index.buildStructure(nodes); return Index.setPage(pageNum); }), endNotice: (function() { @@ -2665,7 +2666,7 @@ thread = new Thread(threadData.no, g.BOARD); threads.push(thread); } - Index.nodes.push(threadRoot, $.el('hr')); + Index.nodes.push(threadRoot); if (thread.ID in thread.posts) { continue; } @@ -2692,7 +2693,7 @@ buildReplies: function(threadRoots) { var data, err, errors, i, lastReplies, node, nodes, post, posts, thread, threadRoot, _i, _j, _len, _len1; posts = []; - for (_i = 0, _len = threadRoots.length; _i < _len; _i += 2) { + for (_i = 0, _len = threadRoots.length; _i < _len; _i++) { threadRoot = threadRoots[_i]; thread = Get.threadFromRoot(threadRoot); i = Index.liveThreadIDs.indexOf(thread.ID); @@ -2728,7 +2729,7 @@ return Main.callbackNodes(Post, posts); }, sort: function() { - var cnd, fn, i, item, items, sortOnTop, sortedThreadIDs, threadID, _i, _len; + var cnd, fn, i, item, items, nodes, sortedThreadIDs, threadID, _i, _len; sortedThreadIDs = { lastreply: __slice.call(Index.liveThreadData).sort(function(a, b) { if ('last_replies' in a) { @@ -2757,15 +2758,14 @@ }) }[Conf['Index Sort']]; Index.sortedNodes = []; + nodes = Index.nodes; for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { threadID = sortedThreadIDs[_i]; - i = Index.liveThreadIDs.indexOf(threadID) * 2; - Index.sortedNodes.push(Index.nodes[i], Index.nodes[i + 1]); + Index.sortedNodes.push(nodes[Index.liveThreadIDs.indexOf(threadID)]); } - if (Index.isSearching) { - Index.sortedNodes = Index.querySearch(Index.searchInput.value) || Index.sortedNodes; + if (Index.isSearching && (nodes = Index.querySearch(Index.searchInput.value))) { + Index.sortedNodes = nodes; } - sortOnTop = Index.sortOnTop; items = [ { fn: function(thread) { @@ -2787,28 +2787,30 @@ i = 0; while (item = items[i++]) { fn = item.fn, cnd = item.cnd; - if (fn) { - sortOnTop(fn); + if (cnd) { + Index.sortOnTop(fn); } } }, sortOnTop: function(match) { - var i, offset, threadRoot, _i, _len, _ref, _ref1; + var i, offset, threadRoot, _i, _len, _ref; offset = 0; + i = 0; _ref = Index.sortedNodes; - for (i = _i = 0, _len = _ref.length; _i < _len; i = _i += 2) { + for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { threadRoot = _ref[i]; if (match(Get.threadFromRoot(threadRoot))) { - (_ref1 = Index.sortedNodes).splice.apply(_ref1, [offset++ * 2, 0].concat(__slice.call(Index.sortedNodes.splice(i, 2)))); + Index.sortedNodes.splice(offset++, 0, Index.sortedNodes.splice(i, 1)[0]); } } }, buildIndex: function() { - var nodes, nodesPerPage, pageNum; + var nodes, nodesPerPage, offset, pageNum; if (Conf['Index Mode'] !== 'all pages') { pageNum = Index.getCurrentPage(); - nodesPerPage = Index.threadsNumPerPage * 2; - nodes = Index.sortedNodes.slice(nodesPerPage * pageNum, nodesPerPage * (pageNum + 1)); + nodesPerPage = Index.threadsNumPerPage; + offset = nodesPerPage * pageNum; + nodes = Index.sortedNodes.slice(offset, offset + nodesPerPage); } else { nodes = Index.sortedNodes; } @@ -2817,8 +2819,22 @@ if (Conf['Show Replies']) { Index.buildReplies(nodes); } - $.add(Index.root, nodes); - return $.event('IndexBuild', nodes); + return Index.buildStructure(nodes); + }, + buildStructure: function(nodes) { + var hr, i, node, result, _i, _len, _ref; + result = $.frag(); + i = 0; + while (node = nodes[i++]) { + $.add(result, [node, $.el('hr')]); + } + $.add(Index.root, result); + _ref = $$('hr + hr', Index.root); + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + hr = _ref[_i]; + $.rm(hr); + } + return $.event('IndexBuild', result); }, isSearching: false, clearSearch: function() { @@ -2861,16 +2877,16 @@ return Index.search(keywords); }, search: function(keywords) { - var found, i, threadRoot, _i, _len, _ref; - found = []; + var threadRoot, _i, _len, _ref, _results; _ref = Index.sortedNodes; - for (i = _i = 0, _len = _ref.length; _i < _len; i = _i += 2) { - threadRoot = _ref[i]; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + threadRoot = _ref[_i]; if (Index.searchMatch(Get.threadFromRoot(threadRoot), keywords)) { - found.push(Index.sortedNodes[i], Index.sortedNodes[i + 1]); + _results.push(threadRoot); } } - return found; + return _results; }, searchMatch: function(thread, keywords) { var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1; diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 3e2cb30c6..4efda8098 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -115,12 +115,16 @@ Index = scroll: $.debounce 100, -> return if Index.req or Conf['Index Mode'] isnt 'infinite' or (doc.scrollTop <= doc.scrollHeight - (300 + window.innerHeight)) or g.VIEW is 'thread' Index.pageNum = Index.getCurrentPage() unless Index.pageNum? # Avoid having to pushState to keep track of the current page + pageNum = Index.pageNum++ return Index.endNotice() if pageNum >= Index.pagesNum - nodesPerPage = Index.threadsNumPerPage * 2 - nodes = Index.sortedNodes[nodesPerPage * pageNum ... nodesPerPage * (pageNum + 1)] + + nodesPerPage = Index.threadsNumPerPage + offset = nodesPerPage * pageNum + nodes = Index.sortedNodes[offset ... offset + nodesPerPage] + Index.buildReplies nodes if Conf['Show Replies'] - $.add Index.root, nodes + Index.buildStructure nodes Index.setPage pageNum endNotice: do -> @@ -331,7 +335,7 @@ Index = else thread = new Thread threadData.no, g.BOARD threads.push thread - Index.nodes.push threadRoot, $.el 'hr' + Index.nodes.push threadRoot continue if thread.ID of thread.posts posts.push new Post $('.opContainer', threadRoot), thread, g.BOARD catch err @@ -350,7 +354,7 @@ Index = buildReplies: (threadRoots) -> posts = [] - for threadRoot in threadRoots by 2 + for threadRoot in threadRoots thread = Get.threadFromRoot threadRoot i = Index.liveThreadIDs.indexOf thread.ID continue unless lastReplies = Index.liveThreadData[i].last_replies @@ -382,19 +386,18 @@ Index = b.no - a.no ).map (data) -> data.no bump: Index.liveThreadIDs - birth: [Index.liveThreadIDs...].sort (a, b) -> b - a + birth: [Index.liveThreadIDs... ].sort (a, b) -> b - a replycount: [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no - filecount: [Index.liveThreadData...].sort((a, b) -> b.images - a.images).map (data) -> data.no + filecount: [Index.liveThreadData...].sort((a, b) -> b.images - a.images ).map (data) -> data.no }[Conf['Index Sort']] Index.sortedNodes = [] + {nodes} = Index for threadID in sortedThreadIDs - i = Index.liveThreadIDs.indexOf(threadID) * 2 - Index.sortedNodes.push Index.nodes[i], Index.nodes[i + 1] - if Index.isSearching - Index.sortedNodes = Index.querySearch(Index.searchInput.value) or Index.sortedNodes - # Sticky threads - {sortOnTop} = Index + Index.sortedNodes.push nodes[Index.liveThreadIDs.indexOf(threadID)] + if Index.isSearching and nodes = Index.querySearch(Index.searchInput.value) + Index.sortedNodes = nodes items = [ + # Sticky threads fn: (thread) -> thread.isSticky cnd: true , # Highlighted threads @@ -407,27 +410,37 @@ Index = i = 0 while item = items[i++] {fn, cnd} = item - sortOnTop fn if fn + Index.sortOnTop fn if cnd return sortOnTop: (match) -> offset = 0 - for threadRoot, i in Index.sortedNodes by 2 when match Get.threadFromRoot threadRoot - Index.sortedNodes.splice offset++ * 2, 0, Index.sortedNodes.splice(i, 2)... + i = 0 + for threadRoot, i in Index.sortedNodes + if match Get.threadFromRoot threadRoot + Index.sortedNodes.splice offset++, 0, Index.sortedNodes.splice(i, 1)[0] return buildIndex: -> if Conf['Index Mode'] isnt 'all pages' pageNum = Index.getCurrentPage() - nodesPerPage = Index.threadsNumPerPage * 2 - nodes = Index.sortedNodes[nodesPerPage * pageNum ... nodesPerPage * (pageNum + 1)] + nodesPerPage = Index.threadsNumPerPage + offset = nodesPerPage * pageNum + nodes = Index.sortedNodes[offset ... offset + nodesPerPage] else nodes = Index.sortedNodes $.rmAll Index.root $.rmAll Header.hover Index.buildReplies nodes if Conf['Show Replies'] - $.add Index.root, nodes - $.event 'IndexBuild', nodes + Index.buildStructure nodes + + buildStructure: (nodes) -> + result = $.frag() + i = 0 + $.add result, [node, $.el 'hr'] while node = nodes[i++] + $.add Index.root, result + $.rm hr for hr in $$ 'hr + hr', Index.root # Temp fix until I figure out where I fucked up + $.event 'IndexBuild', result isSearching: false @@ -467,12 +480,7 @@ Index = return unless keywords = query.toLowerCase().match /\S+/g Index.search keywords - search: (keywords) -> - found = [] - for threadRoot, i in Index.sortedNodes by 2 - if Index.searchMatch Get.threadFromRoot(threadRoot), keywords - found.push Index.sortedNodes[i], Index.sortedNodes[i + 1] - found + search: (keywords) -> threadRoot for threadRoot in Index.sortedNodes when Index.searchMatch Get.threadFromRoot(threadRoot), keywords searchMatch: (thread, keywords) -> {info, file} = thread.OP From c32390c437b4a09987c35dac33a8a37338866804 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 10:02:08 -0700 Subject: [PATCH 12/19] Small oversights --- builds/4chan-X.user.js | 1 - builds/crx/script.js | 1 - src/General/Index.coffee | 6 ++---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 2c3c0c488..efdaf8e69 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -2785,7 +2785,6 @@ sortOnTop: function(match) { var i, offset, threadRoot, _i, _len, _ref; offset = 0; - i = 0; _ref = Index.sortedNodes; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { threadRoot = _ref[i]; diff --git a/builds/crx/script.js b/builds/crx/script.js index fab976f9c..9fb7260a1 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -2795,7 +2795,6 @@ sortOnTop: function(match) { var i, offset, threadRoot, _i, _len, _ref; offset = 0; - i = 0; _ref = Index.sortedNodes; for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { threadRoot = _ref[i]; diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 4efda8098..e9ca91a98 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -415,10 +415,8 @@ Index = sortOnTop: (match) -> offset = 0 - i = 0 - for threadRoot, i in Index.sortedNodes - if match Get.threadFromRoot threadRoot - Index.sortedNodes.splice offset++, 0, Index.sortedNodes.splice(i, 1)[0] + for threadRoot, i in Index.sortedNodes when match Get.threadFromRoot threadRoot + Index.sortedNodes.splice offset++, 0, Index.sortedNodes.splice(i, 1)[0] return buildIndex: -> From 6095a979216ba3ba15b79c630b8f758903e0e471 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 11:07:19 -0700 Subject: [PATCH 13/19] More of a proof of concept than anything. May revert? --- builds/4chan-X.user.js | 121 ++++++++++++++++++------- builds/crx/script.js | 121 ++++++++++++++++++------- src/General/Index.coffee | 60 +++++++++--- src/General/lib/randomaccesslist.class | 24 ++++- src/Monitoring/Unread.coffee | 8 +- 5 files changed, 241 insertions(+), 93 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index efdaf8e69..05e4a11be 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1523,19 +1523,40 @@ this.length = 0; } - RandomAccessList.prototype.push = function(item) { - var ID, last; - ID = item.ID; + RandomAccessList.prototype.push = function(data) { + var ID, item, last; + ID = data.ID; + ID || (ID = data.id); if (this[ID]) { return; } last = this.last; + this[ID] = item = { + prev: last, + next: null, + data: data, + ID: ID + }; item.prev = last; - this[ID] = item; this.last = last ? last.next = item : this.first = item; return this.length++; }; + RandomAccessList.prototype.before = function(root, item) { + var prev; + if (item.next === root) { + return; + } + this.rmi(item); + prev = root.prev; + root.prev = item; + item.next = root; + item.prev = prev; + if (prev) { + return prev.next = item; + } + }; + RandomAccessList.prototype.after = function(root, item) { var next; if (item.prev === root) { @@ -2360,7 +2381,7 @@ }); }, scroll: $.debounce(100, function() { - var nodes, nodesPerPage, offset, pageNum; + var nodes, pageNum; if (Index.req || Conf['Index Mode'] !== 'infinite' || (doc.scrollTop <= doc.scrollHeight - (300 + window.innerHeight)) || g.VIEW === 'thread') { return; } @@ -2371,9 +2392,7 @@ if (pageNum >= Index.pagesNum) { return Index.endNotice(); } - nodesPerPage = Index.threadsNumPerPage; - offset = nodesPerPage * pageNum; - nodes = Index.sortedNodes.slice(offset, offset + nodesPerPage); + nodes = Index.buildSinglePage(pageNum); if (Conf['Show Replies']) { Index.buildReplies(nodes); } @@ -2719,7 +2738,7 @@ return Main.callbackNodes(Post, posts); }, sort: function() { - var cnd, fn, i, item, items, nodes, sortedThreadIDs, threadID, _i, _len; + var cnd, fn, i, item, items, node, nodes, sortedThreadIDs, threadID, _i, _j, _len, _len1; sortedThreadIDs = { lastreply: __slice.call(Index.liveThreadData).sort(function(a, b) { if ('last_replies' in a) { @@ -2747,14 +2766,18 @@ return data.no; }) }[Conf['Index Sort']]; - Index.sortedNodes = []; + Index.sortedNodes = new RandomAccessList; nodes = Index.nodes; for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { threadID = sortedThreadIDs[_i]; Index.sortedNodes.push(nodes[Index.liveThreadIDs.indexOf(threadID)]); } if (Index.isSearching && (nodes = Index.querySearch(Index.searchInput.value))) { - Index.sortedNodes = nodes; + Index.sortedNodes = new RandomAccessList; + for (_j = 0, _len1 = nodes.length; _j < _len1; _j++) { + node = nodes[_j]; + Index.sortedNodes.push(node); + } } items = [ { @@ -2783,25 +2806,36 @@ } }, sortOnTop: function(match) { - var i, offset, threadRoot, _i, _len, _ref; + var j, offset, sortedNodes, target, threadRoot; offset = 0; - _ref = Index.sortedNodes; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - threadRoot = _ref[i]; - if (match(Get.threadFromRoot(threadRoot))) { - Index.sortedNodes.splice(offset++, 0, Index.sortedNodes.splice(i, 1)[0]); + sortedNodes = Index.sortedNodes; + threadRoot = Index.sortedNodes.first; + while (threadRoot) { + if (match(Get.threadFromRoot(threadRoot.data))) { + target = Index.sortedNodes.first; + j = 0; + while (j++ < offset) { + target = target.next; + } + if (threadRoot !== target) { + offset++; + sortedNodes.before(target, threadRoot); + } } + threadRoot = threadRoot.next; } }, buildIndex: function() { - var nodes, nodesPerPage, offset, pageNum; + var nodes, target; if (Conf['Index Mode'] !== 'all pages') { - pageNum = Index.getCurrentPage(); - nodesPerPage = Index.threadsNumPerPage; - offset = nodesPerPage * pageNum; - nodes = Index.sortedNodes.slice(offset, offset + nodesPerPage); + nodes = Index.buildSinglePage(Index.getCurrentPage()); } else { - nodes = Index.sortedNodes; + nodes = []; + target = Index.sortedNodes.first; + while (target) { + nodes.push(target.data); + target = target.next; + } } $.rmAll(Index.root); $.rmAll(Header.hover); @@ -2810,6 +2844,22 @@ } return Index.buildStructure(nodes); }, + buildSinglePage: function(pageNum) { + var end, i, nodes, nodesPerPage, offset, target; + nodes = []; + nodesPerPage = Index.threadsNumPerPage; + offset = nodesPerPage * pageNum; + end = offset + nodesPerPage; + target = Index.sortedNodes.first; + i = 0; + while (i <= end) { + if (offset <= i++) { + nodes.push(target.data); + } + target = target.next; + } + return nodes; + }, buildStructure: function(nodes) { var hr, i, node, result, _i, _len, _ref; result = $.frag(); @@ -2866,16 +2916,17 @@ return Index.search(keywords); }, search: function(keywords) { - var threadRoot, _i, _len, _ref, _results; - _ref = Index.sortedNodes; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - threadRoot = _ref[_i]; - if (Index.searchMatch(Get.threadFromRoot(threadRoot), keywords)) { - _results.push(threadRoot); + var data, found, target; + found = []; + target = Index.sortedNodes.first; + while (target) { + data = target.data; + if (Index.searchMatch(Get.threadFromRoot(data), keywords)) { + found.push(data); } + target = target.next; } - return _results; + return found; }, searchMatch: function(thread, keywords) { var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1; @@ -9904,10 +9955,10 @@ if (!(post.prev || post.next)) { Unread.posts.push(post); } - Unread.addPostQuotingYou(post); + Unread.addPostQuotingYou(post.data); } if (Conf['Unread Line']) { - Unread.setLine((_ref = Unread.posts.first, __indexOf.call(posts, _ref) >= 0)); + Unread.setLine((_ref = Unread.posts.first.data, __indexOf.call(posts, _ref) >= 0)); } Unread.read(); return Unread.update(); @@ -9989,13 +10040,13 @@ height = doc.clientHeight; posts = Unread.posts; while (post = posts.first) { - if (!(Header.getBottomOf(post.nodes.root) > -1)) { + if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { break; } ID = post.ID; posts.rm(ID); if (Conf['Mark Quotes of You'] && post.info.yours) { - QuoteYou.lastRead = post.nodes.root; + QuoteYou.lastRead = post.data.nodes.root; } } if (!ID) { diff --git a/builds/crx/script.js b/builds/crx/script.js index 9fb7260a1..c223d0013 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1529,19 +1529,40 @@ this.length = 0; } - RandomAccessList.prototype.push = function(item) { - var ID, last; - ID = item.ID; + RandomAccessList.prototype.push = function(data) { + var ID, item, last; + ID = data.ID; + ID || (ID = data.id); if (this[ID]) { return; } last = this.last; + this[ID] = item = { + prev: last, + next: null, + data: data, + ID: ID + }; item.prev = last; - this[ID] = item; this.last = last ? last.next = item : this.first = item; return this.length++; }; + RandomAccessList.prototype.before = function(root, item) { + var prev; + if (item.next === root) { + return; + } + this.rmi(item); + prev = root.prev; + root.prev = item; + item.next = root; + item.prev = prev; + if (prev) { + return prev.next = item; + } + }; + RandomAccessList.prototype.after = function(root, item) { var next; if (item.prev === root) { @@ -2370,7 +2391,7 @@ }); }, scroll: $.debounce(100, function() { - var nodes, nodesPerPage, offset, pageNum; + var nodes, pageNum; if (Index.req || Conf['Index Mode'] !== 'infinite' || (doc.scrollTop <= doc.scrollHeight - (300 + window.innerHeight)) || g.VIEW === 'thread') { return; } @@ -2381,9 +2402,7 @@ if (pageNum >= Index.pagesNum) { return Index.endNotice(); } - nodesPerPage = Index.threadsNumPerPage; - offset = nodesPerPage * pageNum; - nodes = Index.sortedNodes.slice(offset, offset + nodesPerPage); + nodes = Index.buildSinglePage(pageNum); if (Conf['Show Replies']) { Index.buildReplies(nodes); } @@ -2729,7 +2748,7 @@ return Main.callbackNodes(Post, posts); }, sort: function() { - var cnd, fn, i, item, items, nodes, sortedThreadIDs, threadID, _i, _len; + var cnd, fn, i, item, items, node, nodes, sortedThreadIDs, threadID, _i, _j, _len, _len1; sortedThreadIDs = { lastreply: __slice.call(Index.liveThreadData).sort(function(a, b) { if ('last_replies' in a) { @@ -2757,14 +2776,18 @@ return data.no; }) }[Conf['Index Sort']]; - Index.sortedNodes = []; + Index.sortedNodes = new RandomAccessList; nodes = Index.nodes; for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { threadID = sortedThreadIDs[_i]; Index.sortedNodes.push(nodes[Index.liveThreadIDs.indexOf(threadID)]); } if (Index.isSearching && (nodes = Index.querySearch(Index.searchInput.value))) { - Index.sortedNodes = nodes; + Index.sortedNodes = new RandomAccessList; + for (_j = 0, _len1 = nodes.length; _j < _len1; _j++) { + node = nodes[_j]; + Index.sortedNodes.push(node); + } } items = [ { @@ -2793,25 +2816,36 @@ } }, sortOnTop: function(match) { - var i, offset, threadRoot, _i, _len, _ref; + var j, offset, sortedNodes, target, threadRoot; offset = 0; - _ref = Index.sortedNodes; - for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) { - threadRoot = _ref[i]; - if (match(Get.threadFromRoot(threadRoot))) { - Index.sortedNodes.splice(offset++, 0, Index.sortedNodes.splice(i, 1)[0]); + sortedNodes = Index.sortedNodes; + threadRoot = Index.sortedNodes.first; + while (threadRoot) { + if (match(Get.threadFromRoot(threadRoot.data))) { + target = Index.sortedNodes.first; + j = 0; + while (j++ < offset) { + target = target.next; + } + if (threadRoot !== target) { + offset++; + sortedNodes.before(target, threadRoot); + } } + threadRoot = threadRoot.next; } }, buildIndex: function() { - var nodes, nodesPerPage, offset, pageNum; + var nodes, target; if (Conf['Index Mode'] !== 'all pages') { - pageNum = Index.getCurrentPage(); - nodesPerPage = Index.threadsNumPerPage; - offset = nodesPerPage * pageNum; - nodes = Index.sortedNodes.slice(offset, offset + nodesPerPage); + nodes = Index.buildSinglePage(Index.getCurrentPage()); } else { - nodes = Index.sortedNodes; + nodes = []; + target = Index.sortedNodes.first; + while (target) { + nodes.push(target.data); + target = target.next; + } } $.rmAll(Index.root); $.rmAll(Header.hover); @@ -2820,6 +2854,22 @@ } return Index.buildStructure(nodes); }, + buildSinglePage: function(pageNum) { + var end, i, nodes, nodesPerPage, offset, target; + nodes = []; + nodesPerPage = Index.threadsNumPerPage; + offset = nodesPerPage * pageNum; + end = offset + nodesPerPage; + target = Index.sortedNodes.first; + i = 0; + while (i <= end) { + if (offset <= i++) { + nodes.push(target.data); + } + target = target.next; + } + return nodes; + }, buildStructure: function(nodes) { var hr, i, node, result, _i, _len, _ref; result = $.frag(); @@ -2876,16 +2926,17 @@ return Index.search(keywords); }, search: function(keywords) { - var threadRoot, _i, _len, _ref, _results; - _ref = Index.sortedNodes; - _results = []; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - threadRoot = _ref[_i]; - if (Index.searchMatch(Get.threadFromRoot(threadRoot), keywords)) { - _results.push(threadRoot); + var data, found, target; + found = []; + target = Index.sortedNodes.first; + while (target) { + data = target.data; + if (Index.searchMatch(Get.threadFromRoot(data), keywords)) { + found.push(data); } + target = target.next; } - return _results; + return found; }, searchMatch: function(thread, keywords) { var file, info, key, keyword, text, _i, _j, _len, _len1, _ref, _ref1; @@ -9887,10 +9938,10 @@ if (!(post.prev || post.next)) { Unread.posts.push(post); } - Unread.addPostQuotingYou(post); + Unread.addPostQuotingYou(post.data); } if (Conf['Unread Line']) { - Unread.setLine((_ref = Unread.posts.first, __indexOf.call(posts, _ref) >= 0)); + Unread.setLine((_ref = Unread.posts.first.data, __indexOf.call(posts, _ref) >= 0)); } Unread.read(); return Unread.update(); @@ -9972,13 +10023,13 @@ height = doc.clientHeight; posts = Unread.posts; while (post = posts.first) { - if (!(Header.getBottomOf(post.nodes.root) > -1)) { + if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { break; } ID = post.ID; posts.rm(ID); if (Conf['Mark Quotes of You'] && post.info.yours) { - QuoteYou.lastRead = post.nodes.root; + QuoteYou.lastRead = post.data.nodes.root; } } if (!ID) { diff --git a/src/General/Index.coffee b/src/General/Index.coffee index e9ca91a98..8e577e1c1 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -119,11 +119,8 @@ Index = pageNum = Index.pageNum++ return Index.endNotice() if pageNum >= Index.pagesNum - nodesPerPage = Index.threadsNumPerPage - offset = nodesPerPage * pageNum - nodes = Index.sortedNodes[offset ... offset + nodesPerPage] - - Index.buildReplies nodes if Conf['Show Replies'] + nodes = Index.buildSinglePage pageNum + Index.buildReplies nodes if Conf['Show Replies'] Index.buildStructure nodes Index.setPage pageNum @@ -390,12 +387,13 @@ Index = replycount: [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no filecount: [Index.liveThreadData...].sort((a, b) -> b.images - a.images ).map (data) -> data.no }[Conf['Index Sort']] - Index.sortedNodes = [] + Index.sortedNodes = new RandomAccessList {nodes} = Index for threadID in sortedThreadIDs Index.sortedNodes.push nodes[Index.liveThreadIDs.indexOf(threadID)] if Index.isSearching and nodes = Index.querySearch(Index.searchInput.value) - Index.sortedNodes = nodes + Index.sortedNodes = new RandomAccessList + Index.sortedNodes.push node for node in nodes items = [ # Sticky threads fn: (thread) -> thread.isSticky @@ -415,23 +413,47 @@ Index = sortOnTop: (match) -> offset = 0 - for threadRoot, i in Index.sortedNodes when match Get.threadFromRoot threadRoot - Index.sortedNodes.splice offset++, 0, Index.sortedNodes.splice(i, 1)[0] + {sortedNodes} = Index + threadRoot = Index.sortedNodes.first + while threadRoot + if match Get.threadFromRoot threadRoot.data + target = Index.sortedNodes.first + j = 0 + while j++ < offset + target = target.next + unless threadRoot is target + offset++ + sortedNodes.before target, threadRoot + threadRoot = threadRoot.next return buildIndex: -> if Conf['Index Mode'] isnt 'all pages' - pageNum = Index.getCurrentPage() - nodesPerPage = Index.threadsNumPerPage - offset = nodesPerPage * pageNum - nodes = Index.sortedNodes[offset ... offset + nodesPerPage] + nodes = Index.buildSinglePage Index.getCurrentPage() else - nodes = Index.sortedNodes + nodes = [] + target = Index.sortedNodes.first + while target + nodes.push target.data + target = target.next $.rmAll Index.root $.rmAll Header.hover Index.buildReplies nodes if Conf['Show Replies'] Index.buildStructure nodes + buildSinglePage: (pageNum) -> + nodes = [] + nodesPerPage = Index.threadsNumPerPage + offset = nodesPerPage * pageNum + end = offset + nodesPerPage + target = Index.sortedNodes.first + i = 0 + while i <= end + if offset <= i++ + nodes.push target.data + target = target.next + nodes + buildStructure: (nodes) -> result = $.frag() i = 0 @@ -478,7 +500,15 @@ Index = return unless keywords = query.toLowerCase().match /\S+/g Index.search keywords - search: (keywords) -> threadRoot for threadRoot in Index.sortedNodes when Index.searchMatch Get.threadFromRoot(threadRoot), keywords + search: (keywords) -> + found = [] + target = Index.sortedNodes.first + while target + {data} = target + if Index.searchMatch Get.threadFromRoot(data), keywords + found.push data + target = target.next + found searchMatch: (thread, keywords) -> {info, file} = thread.OP diff --git a/src/General/lib/randomaccesslist.class b/src/General/lib/randomaccesslist.class index e16e57204..9ccbfeb43 100644 --- a/src/General/lib/randomaccesslist.class +++ b/src/General/lib/randomaccesslist.class @@ -2,18 +2,34 @@ class RandomAccessList constructor: -> @length = 0 - push: (item) -> - {ID} = item + push: (data) -> + {ID} = data + ID or= data.id return if @[ID] {last} = @ + @[ID] = item = + prev: last + next: null + data: data + ID: ID item.prev = last - @[ID] = item @last = if last last.next = item else @first = item @length++ + before: (root, item) -> + return if item.next is root + + @rmi item + + {prev} = root + root.prev = item + item.next = root + item.prev = prev + prev.next = item if prev + after: (root, item) -> return if item.prev is root @@ -24,7 +40,7 @@ class RandomAccessList item.prev = root item.next = next next.prev = item if next - + prepend: (item) -> {first} = @ return if item is first or not @[item.ID] diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index ba9cb5fca..ab5729e3b 100755 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -92,10 +92,10 @@ Unread = postID: ID } Unread.posts.push post unless post.prev or post.next - Unread.addPostQuotingYou post + Unread.addPostQuotingYou post.data if Conf['Unread Line'] # Force line on visible threads if there were no unread posts previously. - Unread.setLine Unread.posts.first in posts + Unread.setLine Unread.posts.first.data in posts Unread.read() Unread.update() @@ -151,12 +151,12 @@ Unread = {posts} = Unread while post = posts.first - break unless Header.getBottomOf(post.nodes.root) > -1 # post is not completely read + break unless Header.getBottomOf(post.data.nodes.root) > -1 # post is not completely read {ID} = post posts.rm ID if Conf['Mark Quotes of You'] and post.info.yours - QuoteYou.lastRead = post.nodes.root + QuoteYou.lastRead = post.data.nodes.root return unless ID From 8135493359f922aef5b774c2033041fb38e077f9 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 11:19:37 -0700 Subject: [PATCH 14/19] Fix unread count for your posts, among other things --- builds/4chan-X.user.js | 16 ++++++++++------ builds/crx/script.js | 16 ++++++++++------ src/Monitoring/Unread.coffee | 14 +++++++++----- 3 files changed, 29 insertions(+), 17 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 05e4a11be..1a8757cb3 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -9955,7 +9955,7 @@ if (!(post.prev || post.next)) { Unread.posts.push(post); } - Unread.addPostQuotingYou(post.data); + Unread.addPostQuotingYou(post); } if (Conf['Unread Line']) { Unread.setLine((_ref = Unread.posts.first.data, __indexOf.call(posts, _ref) >= 0)); @@ -10033,20 +10033,24 @@ return arr.splice(0, i); }, read: $.debounce(100, function(e) { - var ID, height, post, posts; + var ID, data, height, post, posts; if (d.hidden || !Unread.posts.length) { return; } height = doc.clientHeight; posts = Unread.posts; while (post = posts.first) { - if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { + ID = post.ID, data = post.data; + if (!(Header.getBottomOf(data.nodes.root) > -1)) { break; } - ID = post.ID; posts.rm(ID); - if (Conf['Mark Quotes of You'] && post.info.yours) { - QuoteYou.lastRead = post.data.nodes.root; + if (Conf['Mark Quotes of You'] && QR.db.get({ + boardID: data.board.ID, + threadID: data.thread.ID, + postID: ID + })) { + QuoteYou.lastRead = data.nodes.root; } } if (!ID) { diff --git a/builds/crx/script.js b/builds/crx/script.js index c223d0013..d959177b8 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -9938,7 +9938,7 @@ if (!(post.prev || post.next)) { Unread.posts.push(post); } - Unread.addPostQuotingYou(post.data); + Unread.addPostQuotingYou(post); } if (Conf['Unread Line']) { Unread.setLine((_ref = Unread.posts.first.data, __indexOf.call(posts, _ref) >= 0)); @@ -10016,20 +10016,24 @@ return arr.splice(0, i); }, read: $.debounce(100, function(e) { - var ID, height, post, posts; + var ID, data, height, post, posts; if (d.hidden || !Unread.posts.length) { return; } height = doc.clientHeight; posts = Unread.posts; while (post = posts.first) { - if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { + ID = post.ID, data = post.data; + if (!(Header.getBottomOf(data.nodes.root) > -1)) { break; } - ID = post.ID; posts.rm(ID); - if (Conf['Mark Quotes of You'] && post.info.yours) { - QuoteYou.lastRead = post.data.nodes.root; + if (Conf['Mark Quotes of You'] && QR.db.get({ + boardID: data.board.ID, + threadID: data.thread.ID, + postID: ID + })) { + QuoteYou.lastRead = data.nodes.root; } } if (!ID) { diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index ab5729e3b..56a610731 100755 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -92,7 +92,7 @@ Unread = postID: ID } Unread.posts.push post unless post.prev or post.next - Unread.addPostQuotingYou post.data + Unread.addPostQuotingYou post if Conf['Unread Line'] # Force line on visible threads if there were no unread posts previously. Unread.setLine Unread.posts.first.data in posts @@ -151,12 +151,16 @@ Unread = {posts} = Unread while post = posts.first - break unless Header.getBottomOf(post.data.nodes.root) > -1 # post is not completely read - {ID} = post + {ID, data} = post + break unless Header.getBottomOf(data.nodes.root) > -1 # post is not completely read posts.rm ID - if Conf['Mark Quotes of You'] and post.info.yours - QuoteYou.lastRead = post.data.nodes.root + if Conf['Mark Quotes of You'] and QR.db.get { + boardID: data.board.ID + threadID: data.thread.ID + postID: ID + } + QuoteYou.lastRead = data.nodes.root return unless ID From fc90fd45d991b257328b82bb23b9e6ee448fd6eb Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 11:56:21 -0700 Subject: [PATCH 15/19] Fix thread updater --- builds/4chan-X.user.js | 22 ++++++++-------------- builds/crx/script.js | 22 ++++++++-------------- src/Monitoring/ThreadUpdater.coffee | 10 ++++------ 3 files changed, 20 insertions(+), 34 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 1a8757cb3..df16a79dc 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -9218,7 +9218,7 @@ return new Notice('info', "The thread is " + change + ".", 30); }, parse: function(postObjects) { - var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1, _ref; + var OP, count, deletedFiles, deletedPosts, files, index, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1; OP = postObjects[0]; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); @@ -9245,12 +9245,9 @@ } deletedPosts = []; deletedFiles = []; - posts = ThreadUpdater.thread.posts; - _ref = posts.keys; - for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { - ID = _ref[_j]; - post = posts[ID]; - ID = +ID; + ThreadUpdater.thread.posts.forEach(function(post) { + var ID; + ID = +post.ID; if (__indexOf.call(index, ID) < 0) { post.kill(); deletedPosts.push(post); @@ -9261,9 +9258,9 @@ deletedFiles.push(post); } if (ThreadUpdater.postID && ThreadUpdater.postID === ID) { - ThreadUpdater.foundPost = true; + return ThreadUpdater.foundPost = true; } - } + }); if (!count) { ThreadUpdater.set('status', null, null); ThreadUpdater.outdateCount++; @@ -9281,11 +9278,8 @@ ThreadUpdater.lastPost = posts[count - 1].ID; Main.callbackNodes(Post, posts); scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25; - for (key in posts) { - post = posts[key]; - if (!posts.hasOwnProperty(key)) { - continue; - } + for (_j = 0, _len1 = posts.length; _j < _len1; _j++) { + post = posts[_j]; root = post.nodes.root; if (post.cb) { if (!post.cb()) { diff --git a/builds/crx/script.js b/builds/crx/script.js index d959177b8..3613fc935 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -9201,7 +9201,7 @@ return new Notice('info', "The thread is " + change + ".", 30); }, parse: function(postObjects) { - var ID, OP, count, deletedFiles, deletedPosts, files, index, key, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1, _ref; + var OP, count, deletedFiles, deletedPosts, files, index, node, num, post, postObject, posts, root, scroll, _i, _j, _len, _len1; OP = postObjects[0]; Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); @@ -9228,12 +9228,9 @@ } deletedPosts = []; deletedFiles = []; - posts = ThreadUpdater.thread.posts; - _ref = posts.keys; - for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) { - ID = _ref[_j]; - post = posts[ID]; - ID = +ID; + ThreadUpdater.thread.posts.forEach(function(post) { + var ID; + ID = +post.ID; if (__indexOf.call(index, ID) < 0) { post.kill(); deletedPosts.push(post); @@ -9244,9 +9241,9 @@ deletedFiles.push(post); } if (ThreadUpdater.postID && ThreadUpdater.postID === ID) { - ThreadUpdater.foundPost = true; + return ThreadUpdater.foundPost = true; } - } + }); if (!count) { ThreadUpdater.set('status', null, null); ThreadUpdater.outdateCount++; @@ -9264,11 +9261,8 @@ ThreadUpdater.lastPost = posts[count - 1].ID; Main.callbackNodes(Post, posts); scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25; - for (key in posts) { - post = posts[key]; - if (!posts.hasOwnProperty(key)) { - continue; - } + for (_j = 0, _len1 = posts.length; _j < _len1; _j++) { + post = posts[_j]; root = post.nodes.root; if (post.cb) { if (!post.cb()) { diff --git a/src/Monitoring/ThreadUpdater.coffee b/src/Monitoring/ThreadUpdater.coffee index 43b61e8da..a55877426 100755 --- a/src/Monitoring/ThreadUpdater.coffee +++ b/src/Monitoring/ThreadUpdater.coffee @@ -290,13 +290,11 @@ ThreadUpdater = deletedFiles = [] # Check for deleted posts/files. - {posts} = ThreadUpdater.thread - for ID in posts.keys - post = posts[ID] + ThreadUpdater.thread.posts.forEach (post) -> # XXX tmp fix for 4chan's racing condition # giving us false-positive dead posts. # continue if post.isDead - ID = +ID + ID = +post.ID unless ID in index post.kill() @@ -307,6 +305,7 @@ ThreadUpdater = post.kill true deletedFiles.push post + # Fetching your own posts after posting if ThreadUpdater.postID and ThreadUpdater.postID is ID ThreadUpdater.foundPost = true @@ -327,8 +326,7 @@ ThreadUpdater = scroll = Conf['Auto Scroll'] and ThreadUpdater.scrollBG() and ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25 - for key, post of posts - continue unless posts.hasOwnProperty key + for post in posts root = post.nodes.root if post.cb unless post.cb() From 7eb2d0aa3411488960055487f3c25ea86320603f Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 16:44:18 -0700 Subject: [PATCH 16/19] Mostly fix everything broken. Mostly. --- builds/4chan-X.user.js | 129 ++++++++++++++----------- builds/crx/script.js | 129 ++++++++++++++----------- src/General/Index.coffee | 45 ++++----- src/General/Navigate.coffee | 6 +- src/General/lib/randomaccesslist.class | 8 +- src/Monitoring/Unread.coffee | 17 ++-- src/Quotelinks/QuoteThreading.coffee | 14 ++- 7 files changed, 193 insertions(+), 155 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index df16a79dc..db4c49811 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -1519,8 +1519,15 @@ })(); RandomAccessList = (function() { - function RandomAccessList() { + function RandomAccessList(items) { + var item, _i, _len; this.length = 0; + if (items) { + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + this.push(item); + } + } } RandomAccessList.prototype.push = function(data) { @@ -1589,6 +1596,15 @@ return this.rm(this.first.ID); }; + RandomAccessList.prototype.order = function() { + var item, order; + order = [item = this.first]; + while (item = item.next) { + order.push(item); + } + return order; + }; + RandomAccessList.prototype.rm = function(ID) { var item; item = this[ID]; @@ -2738,46 +2754,44 @@ return Main.callbackNodes(Post, posts); }, sort: function() { - var cnd, fn, i, item, items, node, nodes, sortedThreadIDs, threadID, _i, _j, _len, _len1; + var cnd, fn, i, item, items, liveThreadData, liveThreadIDs, nodes, sortedNodes, sortedThreadIDs, threadID, _i, _len; + liveThreadIDs = Index.liveThreadIDs, liveThreadData = Index.liveThreadData; sortedThreadIDs = { - lastreply: __slice.call(Index.liveThreadData).sort(function(a, b) { - if ('last_replies' in a) { - a = a.last_replies[a.last_replies.length - 1]; + lastreply: __slice.call(liveThreadData).sort(function(a, b) { + var num; + if ((num = a.last_replies)) { + a = num[num.length - 1]; } - if ('last_replies' in b) { - b = b.last_replies[b.last_replies.length - 1]; + if ((num = b.last_replies)) { + b = num[num.length - 1]; } return b.no - a.no; - }).map(function(data) { - return data.no; + }).map(function(post) { + return post.no; }), - bump: Index.liveThreadIDs, - birth: __slice.call(Index.liveThreadIDs).sort(function(a, b) { + bump: liveThreadIDs, + birth: __slice.call(liveThreadIDs).sort(function(a, b) { return b - a; }), - replycount: __slice.call(Index.liveThreadData).sort(function(a, b) { + replycount: __slice.call(liveThreadData).sort(function(a, b) { return b.replies - a.replies; - }).map(function(data) { - return data.no; + }).map(function(post) { + return post.no; }), - filecount: __slice.call(Index.liveThreadData).sort(function(a, b) { + filecount: __slice.call(liveThreadData).sort(function(a, b) { return b.images - a.images; - }).map(function(data) { - return data.no; + }).map(function(post) { + return post.no; }) }[Conf['Index Sort']]; - Index.sortedNodes = new RandomAccessList; + Index.sortedNodes = sortedNodes = new RandomAccessList; nodes = Index.nodes; for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { threadID = sortedThreadIDs[_i]; - Index.sortedNodes.push(nodes[Index.liveThreadIDs.indexOf(threadID)]); + sortedNodes.push(nodes[Index.liveThreadIDs.indexOf(threadID)]); } if (Index.isSearching && (nodes = Index.querySearch(Index.searchInput.value))) { - Index.sortedNodes = new RandomAccessList; - for (_j = 0, _len1 = nodes.length; _j < _len1; _j++) { - node = nodes[_j]; - Index.sortedNodes.push(node); - } + Index.sortedNodes = new RandomAccessList(nodes); } items = [ { @@ -2809,10 +2823,10 @@ var j, offset, sortedNodes, target, threadRoot; offset = 0; sortedNodes = Index.sortedNodes; - threadRoot = Index.sortedNodes.first; + threadRoot = sortedNodes.first; while (threadRoot) { if (match(Get.threadFromRoot(threadRoot.data))) { - target = Index.sortedNodes.first; + target = sortedNodes.first; j = 0; while (j++ < offset) { target = target.next; @@ -2830,11 +2844,9 @@ if (Conf['Index Mode'] !== 'all pages') { nodes = Index.buildSinglePage(Index.getCurrentPage()); } else { - nodes = []; - target = Index.sortedNodes.first; - while (target) { + nodes = [(target = Index.sortedNodes.first).data]; + while (target = target.next) { nodes.push(target.data); - target = target.next; } } $.rmAll(Index.root); @@ -2845,17 +2857,15 @@ return Index.buildStructure(nodes); }, buildSinglePage: function(pageNum) { - var end, i, nodes, nodesPerPage, offset, target; + var end, nodes, nodesPerPage, offset, target; nodes = []; nodesPerPage = Index.threadsNumPerPage; offset = nodesPerPage * pageNum; end = offset + nodesPerPage; - target = Index.sortedNodes.first; - i = 0; - while (i <= end) { - if (offset <= i++) { - nodes.push(target.data); - } + target = Index.sortedNodes.order()[offset]; + Index.sortedNodes; + while ((offset++ <= end) && target) { + nodes.push(target.data); target = target.next; } return nodes; @@ -5228,14 +5238,18 @@ return QuoteThreading.force(); }, force: function() { - return g.posts.forEach(function(post) { + 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() { - var keys, len, post, posts, quote, _i, _len, _ref; + var keys, len, posts, quote, _i, _len, _ref; posts = g.posts; if (this.isClone || !QuoteThreading.enabled) { return; @@ -5243,7 +5257,7 @@ if (Conf['Unread Count']) { Unread.posts.push(this); } - if (this.thread.OP === this || !(post = posts[this.fullID]) || post.isHidden) { + if (this.thread.OP === this || this.isHidden) { return; } keys = []; @@ -5291,10 +5305,10 @@ if (!Conf['Unread Count']) { return true; } - if (posts[post.ID]) { - posts.after(post, this); + if (post = posts[post.ID]) { + posts.after(post, posts[this.ID]); } else { - posts.prepend(this); + posts.prepend(posts[this.ID]); } return true; }, @@ -9891,7 +9905,7 @@ return; } 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.data.nodes.root)) { if (!(post = Get.postFromRoot(root)).isHidden) { break; } @@ -9935,7 +9949,7 @@ return Unread.update(); }, addPosts: function(posts) { - var ID, post, _i, _len, _ref; + var ID, post, _i, _len, _ref, _ref1; for (_i = 0, _len = posts.length; _i < _len; _i++) { post = posts[_i]; ID = post.ID; @@ -9952,7 +9966,7 @@ Unread.addPostQuotingYou(post); } if (Conf['Unread Line']) { - Unread.setLine((_ref = Unread.posts.first.data, __indexOf.call(posts, _ref) >= 0)); + Unread.setLine((_ref = (_ref1 = Unread.posts.first) != null ? _ref1.data : void 0, __indexOf.call(posts, _ref) >= 0)); } Unread.read(); return Unread.update(); @@ -10001,16 +10015,17 @@ } }, readSinglePost: function(post) { - var ID, i; + var ID, i, posts; ID = post.ID; - if (!Unread.posts[ID]) { + posts = Unread.posts; + if (!posts[ID]) { return; } - if (post === Unread.posts.first) { + if (post === posts.first) { Unread.lastReadPost = ID; Unread.saveLastReadPost(); } - Unread.posts.rm(ID); + posts.rm(ID); if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) { Unread.postsQuotingYou.splice(i, 1); } @@ -10034,10 +10049,10 @@ height = doc.clientHeight; posts = Unread.posts; while (post = posts.first) { - ID = post.ID, data = post.data; - if (!(Header.getBottomOf(data.nodes.root) > -1)) { + if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { break; } + ID = post.ID, data = post.data; posts.rm(ID); if (Conf['Mark Quotes of You'] && QR.db.get({ boardID: data.board.ID, @@ -10077,8 +10092,8 @@ if (!(post = Unread.posts.first)) { return $.rm(Unread.hr); } - if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.nodes.root)) { - return $.before(post.nodes.root, Unread.hr); + if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.data.nodes.root)) { + return $.before(post.data.nodes.root, Unread.hr); } }, update: function() { @@ -12092,7 +12107,7 @@ err = _error; error = [ { - message: "Quote Threading Failed.", + message: "" + name + " Failed.", error: err } ]; @@ -12323,7 +12338,8 @@ } Main.callbackNodes(Thread, [thread]); Main.callbackNodes(Post, posts); - Navigate.ready('Quote Threading', QuoteThreading.force, Conf['Quote Threading']); + Navigate.ready('Quote Threading', QuoteThreading.force, Conf['Quote Threading'] && !Conf['Unread Count']); + Navigate.ready('Unread Count', Unread.ready, Conf['Unread Count']); Navigate.buildThread(); return Header.hashScroll.call(window); }, @@ -12333,7 +12349,6 @@ $.rmAll(board); $.add(board, [Navigate.threadRoot, $.el('hr')]); if (Conf['Unread Count']) { - Navigate.ready('Unread Count', Unread.ready, !Conf['Quote Threading']); Unread.read(); return Unread.update(); } diff --git a/builds/crx/script.js b/builds/crx/script.js index 3613fc935..d7c282fa4 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1525,8 +1525,15 @@ })(); RandomAccessList = (function() { - function RandomAccessList() { + function RandomAccessList(items) { + var item, _i, _len; this.length = 0; + if (items) { + for (_i = 0, _len = items.length; _i < _len; _i++) { + item = items[_i]; + this.push(item); + } + } } RandomAccessList.prototype.push = function(data) { @@ -1595,6 +1602,15 @@ return this.rm(this.first.ID); }; + RandomAccessList.prototype.order = function() { + var item, order; + order = [item = this.first]; + while (item = item.next) { + order.push(item); + } + return order; + }; + RandomAccessList.prototype.rm = function(ID) { var item; item = this[ID]; @@ -2748,46 +2764,44 @@ return Main.callbackNodes(Post, posts); }, sort: function() { - var cnd, fn, i, item, items, node, nodes, sortedThreadIDs, threadID, _i, _j, _len, _len1; + var cnd, fn, i, item, items, liveThreadData, liveThreadIDs, nodes, sortedNodes, sortedThreadIDs, threadID, _i, _len; + liveThreadIDs = Index.liveThreadIDs, liveThreadData = Index.liveThreadData; sortedThreadIDs = { - lastreply: __slice.call(Index.liveThreadData).sort(function(a, b) { - if ('last_replies' in a) { - a = a.last_replies[a.last_replies.length - 1]; + lastreply: __slice.call(liveThreadData).sort(function(a, b) { + var num; + if ((num = a.last_replies)) { + a = num[num.length - 1]; } - if ('last_replies' in b) { - b = b.last_replies[b.last_replies.length - 1]; + if ((num = b.last_replies)) { + b = num[num.length - 1]; } return b.no - a.no; - }).map(function(data) { - return data.no; + }).map(function(post) { + return post.no; }), - bump: Index.liveThreadIDs, - birth: __slice.call(Index.liveThreadIDs).sort(function(a, b) { + bump: liveThreadIDs, + birth: __slice.call(liveThreadIDs).sort(function(a, b) { return b - a; }), - replycount: __slice.call(Index.liveThreadData).sort(function(a, b) { + replycount: __slice.call(liveThreadData).sort(function(a, b) { return b.replies - a.replies; - }).map(function(data) { - return data.no; + }).map(function(post) { + return post.no; }), - filecount: __slice.call(Index.liveThreadData).sort(function(a, b) { + filecount: __slice.call(liveThreadData).sort(function(a, b) { return b.images - a.images; - }).map(function(data) { - return data.no; + }).map(function(post) { + return post.no; }) }[Conf['Index Sort']]; - Index.sortedNodes = new RandomAccessList; + Index.sortedNodes = sortedNodes = new RandomAccessList; nodes = Index.nodes; for (_i = 0, _len = sortedThreadIDs.length; _i < _len; _i++) { threadID = sortedThreadIDs[_i]; - Index.sortedNodes.push(nodes[Index.liveThreadIDs.indexOf(threadID)]); + sortedNodes.push(nodes[Index.liveThreadIDs.indexOf(threadID)]); } if (Index.isSearching && (nodes = Index.querySearch(Index.searchInput.value))) { - Index.sortedNodes = new RandomAccessList; - for (_j = 0, _len1 = nodes.length; _j < _len1; _j++) { - node = nodes[_j]; - Index.sortedNodes.push(node); - } + Index.sortedNodes = new RandomAccessList(nodes); } items = [ { @@ -2819,10 +2833,10 @@ var j, offset, sortedNodes, target, threadRoot; offset = 0; sortedNodes = Index.sortedNodes; - threadRoot = Index.sortedNodes.first; + threadRoot = sortedNodes.first; while (threadRoot) { if (match(Get.threadFromRoot(threadRoot.data))) { - target = Index.sortedNodes.first; + target = sortedNodes.first; j = 0; while (j++ < offset) { target = target.next; @@ -2840,11 +2854,9 @@ if (Conf['Index Mode'] !== 'all pages') { nodes = Index.buildSinglePage(Index.getCurrentPage()); } else { - nodes = []; - target = Index.sortedNodes.first; - while (target) { + nodes = [(target = Index.sortedNodes.first).data]; + while (target = target.next) { nodes.push(target.data); - target = target.next; } } $.rmAll(Index.root); @@ -2855,17 +2867,15 @@ return Index.buildStructure(nodes); }, buildSinglePage: function(pageNum) { - var end, i, nodes, nodesPerPage, offset, target; + var end, nodes, nodesPerPage, offset, target; nodes = []; nodesPerPage = Index.threadsNumPerPage; offset = nodesPerPage * pageNum; end = offset + nodesPerPage; - target = Index.sortedNodes.first; - i = 0; - while (i <= end) { - if (offset <= i++) { - nodes.push(target.data); - } + target = Index.sortedNodes.order()[offset]; + Index.sortedNodes; + while ((offset++ <= end) && target) { + nodes.push(target.data); target = target.next; } return nodes; @@ -5231,14 +5241,18 @@ return QuoteThreading.force(); }, force: function() { - return g.posts.forEach(function(post) { + 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() { - var keys, len, post, posts, quote, _i, _len, _ref; + var keys, len, posts, quote, _i, _len, _ref; posts = g.posts; if (this.isClone || !QuoteThreading.enabled) { return; @@ -5246,7 +5260,7 @@ if (Conf['Unread Count']) { Unread.posts.push(this); } - if (this.thread.OP === this || !(post = posts[this.fullID]) || post.isHidden) { + if (this.thread.OP === this || this.isHidden) { return; } keys = []; @@ -5294,10 +5308,10 @@ if (!Conf['Unread Count']) { return true; } - if (posts[post.ID]) { - posts.after(post, this); + if (post = posts[post.ID]) { + posts.after(post, posts[this.ID]); } else { - posts.prepend(this); + posts.prepend(posts[this.ID]); } return true; }, @@ -9874,7 +9888,7 @@ return; } 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.data.nodes.root)) { if (!(post = Get.postFromRoot(root)).isHidden) { break; } @@ -9918,7 +9932,7 @@ return Unread.update(); }, addPosts: function(posts) { - var ID, post, _i, _len, _ref; + var ID, post, _i, _len, _ref, _ref1; for (_i = 0, _len = posts.length; _i < _len; _i++) { post = posts[_i]; ID = post.ID; @@ -9935,7 +9949,7 @@ Unread.addPostQuotingYou(post); } if (Conf['Unread Line']) { - Unread.setLine((_ref = Unread.posts.first.data, __indexOf.call(posts, _ref) >= 0)); + Unread.setLine((_ref = (_ref1 = Unread.posts.first) != null ? _ref1.data : void 0, __indexOf.call(posts, _ref) >= 0)); } Unread.read(); return Unread.update(); @@ -9984,16 +9998,17 @@ } }, readSinglePost: function(post) { - var ID, i; + var ID, i, posts; ID = post.ID; - if (!Unread.posts[ID]) { + posts = Unread.posts; + if (!posts[ID]) { return; } - if (post === Unread.posts.first) { + if (post === posts.first) { Unread.lastReadPost = ID; Unread.saveLastReadPost(); } - Unread.posts.rm(ID); + posts.rm(ID); if ((i = Unread.postsQuotingYou.indexOf(post)) !== -1) { Unread.postsQuotingYou.splice(i, 1); } @@ -10017,10 +10032,10 @@ height = doc.clientHeight; posts = Unread.posts; while (post = posts.first) { - ID = post.ID, data = post.data; - if (!(Header.getBottomOf(data.nodes.root) > -1)) { + if (!(Header.getBottomOf(post.data.nodes.root) > -1)) { break; } + ID = post.ID, data = post.data; posts.rm(ID); if (Conf['Mark Quotes of You'] && QR.db.get({ boardID: data.board.ID, @@ -10060,8 +10075,8 @@ if (!(post = Unread.posts.first)) { return $.rm(Unread.hr); } - if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.nodes.root)) { - return $.before(post.nodes.root, Unread.hr); + if ($.x('preceding-sibling::div[contains(@class,"replyContainer")]', post.data.nodes.root)) { + return $.before(post.data.nodes.root, Unread.hr); } }, update: function(dontrepeat) { @@ -12081,7 +12096,7 @@ err = _error; error = [ { - message: "Quote Threading Failed.", + message: "" + name + " Failed.", error: err } ]; @@ -12312,7 +12327,8 @@ } Main.callbackNodes(Thread, [thread]); Main.callbackNodes(Post, posts); - Navigate.ready('Quote Threading', QuoteThreading.force, Conf['Quote Threading']); + Navigate.ready('Quote Threading', QuoteThreading.force, Conf['Quote Threading'] && !Conf['Unread Count']); + Navigate.ready('Unread Count', Unread.ready, Conf['Unread Count']); Navigate.buildThread(); return Header.hashScroll.call(window); }, @@ -12322,7 +12338,6 @@ $.rmAll(board); $.add(board, [Navigate.threadRoot, $.el('hr')]); if (Conf['Unread Count']) { - Navigate.ready('Unread Count', Unread.ready, !Conf['Quote Threading']); Unread.read(); return Unread.update(); } diff --git a/src/General/Index.coffee b/src/General/Index.coffee index 8e577e1c1..5b72b1882 100644 --- a/src/General/Index.coffee +++ b/src/General/Index.coffee @@ -375,25 +375,25 @@ Index = Main.callbackNodes Post, posts sort: -> + {liveThreadIDs, liveThreadData} = Index sortedThreadIDs = { lastreply: - [Index.liveThreadData...].sort((a, b) -> - a = a.last_replies[a.last_replies.length - 1] if 'last_replies' of a - b = b.last_replies[b.last_replies.length - 1] if 'last_replies' of b + [liveThreadData...].sort((a, b) -> + a = num[num.length - 1] if (num = a.last_replies) + b = num[num.length - 1] if (num = b.last_replies) b.no - a.no - ).map (data) -> data.no - bump: Index.liveThreadIDs - birth: [Index.liveThreadIDs... ].sort (a, b) -> b - a - replycount: [Index.liveThreadData...].sort((a, b) -> b.replies - a.replies).map (data) -> data.no - filecount: [Index.liveThreadData...].sort((a, b) -> b.images - a.images ).map (data) -> data.no + ).map (post) -> post.no + bump: liveThreadIDs + birth: [liveThreadIDs... ].sort (a, b) -> b - a + replycount: [liveThreadData...].sort((a, b) -> b.replies - a.replies).map (post) -> post.no + filecount: [liveThreadData...].sort((a, b) -> b.images - a.images ).map (post) -> post.no }[Conf['Index Sort']] - Index.sortedNodes = new RandomAccessList + Index.sortedNodes = sortedNodes = new RandomAccessList {nodes} = Index for threadID in sortedThreadIDs - Index.sortedNodes.push nodes[Index.liveThreadIDs.indexOf(threadID)] + sortedNodes.push nodes[Index.liveThreadIDs.indexOf(threadID)] if Index.isSearching and nodes = Index.querySearch(Index.searchInput.value) - Index.sortedNodes = new RandomAccessList - Index.sortedNodes.push node for node in nodes + Index.sortedNodes = new RandomAccessList nodes items = [ # Sticky threads fn: (thread) -> thread.isSticky @@ -414,10 +414,10 @@ Index = sortOnTop: (match) -> offset = 0 {sortedNodes} = Index - threadRoot = Index.sortedNodes.first + threadRoot = sortedNodes.first while threadRoot if match Get.threadFromRoot threadRoot.data - target = Index.sortedNodes.first + target = sortedNodes.first j = 0 while j++ < offset target = target.next @@ -431,11 +431,9 @@ Index = if Conf['Index Mode'] isnt 'all pages' nodes = Index.buildSinglePage Index.getCurrentPage() else - nodes = [] - target = Index.sortedNodes.first - while target + nodes = [(target = Index.sortedNodes.first).data] + while target = target.next nodes.push target.data - target = target.next $.rmAll Index.root $.rmAll Header.hover Index.buildReplies nodes if Conf['Show Replies'] @@ -446,11 +444,10 @@ Index = nodesPerPage = Index.threadsNumPerPage offset = nodesPerPage * pageNum end = offset + nodesPerPage - target = Index.sortedNodes.first - i = 0 - while i <= end - if offset <= i++ - nodes.push target.data + target = Index.sortedNodes.order()[offset] + Index.sortedNodes + while (offset++ <= end) and target + nodes.push target.data target = target.next nodes @@ -501,7 +498,7 @@ Index = Index.search keywords search: (keywords) -> - found = [] + found = [] target = Index.sortedNodes.first while target {data} = target diff --git a/src/General/Navigate.coffee b/src/General/Navigate.coffee index 56b17a4f3..8843d9a0c 100644 --- a/src/General/Navigate.coffee +++ b/src/General/Navigate.coffee @@ -83,7 +83,7 @@ Navigate = feature() if condition catch err error = [ - message: "Quote Threading Failed." + message: "#{name} Failed." error: err ] Main.handleErrors error if error @@ -284,7 +284,8 @@ Navigate = Main.callbackNodes Thread, [thread] Main.callbackNodes Post, posts - Navigate.ready 'Quote Threading', QuoteThreading.force, Conf['Quote Threading'] + Navigate.ready 'Quote Threading', QuoteThreading.force, Conf['Quote Threading'] and not Conf['Unread Count'] + Navigate.ready 'Unread Count', Unread.ready, Conf['Unread Count'] Navigate.buildThread() Header.hashScroll.call window @@ -295,7 +296,6 @@ Navigate = $.add board, [Navigate.threadRoot, $.el 'hr'] if Conf['Unread Count'] - Navigate.ready 'Unread Count', Unread.ready, not Conf['Quote Threading'] Unread.read() Unread.update() diff --git a/src/General/lib/randomaccesslist.class b/src/General/lib/randomaccesslist.class index 9ccbfeb43..b161177b4 100644 --- a/src/General/lib/randomaccesslist.class +++ b/src/General/lib/randomaccesslist.class @@ -1,6 +1,7 @@ class RandomAccessList - constructor: -> + constructor: (items) -> @length = 0 + @push item for item in items if items push: (data) -> {ID} = data @@ -52,6 +53,11 @@ class RandomAccessList shift: -> @rm @first.ID + + order: -> + order = [item = @first] + order.push item while item = item.next + order rm: (ID) -> item = @[ID] diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index 56a610731..6b5989a68 100755 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -52,7 +52,7 @@ Unread = return if (hash = location.hash.match /\d+/) and hash[0] of Unread.thread.posts if post = Unread.posts.first # 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.data.nodes.root break unless (post = Get.postFromRoot root).isHidden return unless root down = true @@ -95,7 +95,7 @@ Unread = Unread.addPostQuotingYou post if Conf['Unread Line'] # Force line on visible threads if there were no unread posts previously. - Unread.setLine Unread.posts.first.data in posts + Unread.setLine Unread.posts.first?.data in posts Unread.read() Unread.update() @@ -131,11 +131,12 @@ Unread = readSinglePost: (post) -> {ID} = post - return unless Unread.posts[ID] - if post is Unread.posts.first + {posts} = Unread + return unless posts[ID] + if post is posts.first Unread.lastReadPost = ID Unread.saveLastReadPost() - Unread.posts.rm ID + posts.rm ID if (i = Unread.postsQuotingYou.indexOf post) isnt -1 Unread.postsQuotingYou.splice i, 1 Unread.update() @@ -151,8 +152,8 @@ Unread = {posts} = Unread while post = posts.first + break unless Header.getBottomOf(post.data.nodes.root) > -1 # post is not completely read {ID, data} = post - break unless Header.getBottomOf(data.nodes.root) > -1 # post is not completely read posts.rm ID if Conf['Mark Quotes of You'] and QR.db.get { @@ -179,8 +180,8 @@ Unread = setLine: (force) -> return unless d.hidden or force is true return $.rm Unread.hr unless post = Unread.posts.first - if $.x 'preceding-sibling::div[contains(@class,"replyContainer")]', post.nodes.root # not the first reply - $.before post.nodes.root, Unread.hr + if $.x 'preceding-sibling::div[contains(@class,"replyContainer")]', post.data.nodes.root # not the first reply + $.before post.data.nodes.root, Unread.hr update: <% if (type === 'crx') { %>(dontrepeat) <% } %>-> count = Unread.posts.length diff --git a/src/Quotelinks/QuoteThreading.coffee b/src/Quotelinks/QuoteThreading.coffee index 077dde1e7..7b77a13a3 100755 --- a/src/Quotelinks/QuoteThreading.coffee +++ b/src/Quotelinks/QuoteThreading.coffee @@ -45,12 +45,16 @@ QuoteThreading = 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: -> {posts} = g return if @isClone or not QuoteThreading.enabled - Unread.posts.push @ if Conf['Unread Count'] - return if @thread.OP is @ or !(post = posts[@fullID]) or post.isHidden # Filtered + Unread.posts.push @ if Conf['Unread Count'] + return if @thread.OP is @ or @isHidden # Filtered keys = [] len = g.BOARD.ID.length + 1 @@ -90,11 +94,11 @@ QuoteThreading = return true unless Conf['Unread Count'] - if posts[post.ID] - posts.after post, @ + if post = posts[post.ID] + posts.after post, posts[@ID] else - posts.prepend @ + posts.prepend posts[@ID] return true From 8454ed099c22a91a766e507a83f8f0fb08f17886 Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Thu, 16 Jan 2014 16:52:21 -0700 Subject: [PATCH 17/19] There is always a QR.db in appchan. --- builds/4chan-X.user.js | 3 --- builds/crx/script.js | 3 --- src/Monitoring/Unread.coffee | 1 - 3 files changed, 7 deletions(-) diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index db4c49811..7c1656039 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -9973,9 +9973,6 @@ }, addPostQuotingYou: function(post) { var quotelink, _i, _len, _ref; - if (!QR.db) { - return; - } _ref = post.nodes.quotelinks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { quotelink = _ref[_i]; diff --git a/builds/crx/script.js b/builds/crx/script.js index d7c282fa4..c5bc6054b 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -9956,9 +9956,6 @@ }, addPostQuotingYou: function(post) { var quotelink, _i, _len, _ref; - if (!QR.db) { - return; - } _ref = post.nodes.quotelinks; for (_i = 0, _len = _ref.length; _i < _len; _i++) { quotelink = _ref[_i]; diff --git a/src/Monitoring/Unread.coffee b/src/Monitoring/Unread.coffee index 6b5989a68..1814c9a29 100755 --- a/src/Monitoring/Unread.coffee +++ b/src/Monitoring/Unread.coffee @@ -100,7 +100,6 @@ Unread = Unread.update() addPostQuotingYou: (post) -> - return unless QR.db for quotelink in post.nodes.quotelinks when QR.db.get Get.postDataFromLink quotelink Unread.postsQuotingYou.push post Unread.openNotification post From 22ab0a4a12e32a502b27459fd7ba2e5b40d7155c Mon Sep 17 00:00:00 2001 From: thebladeee Date: Thu, 16 Jan 2014 15:09:24 -0500 Subject: [PATCH 18/19] Update Nyafuu & Add Love is Over --- src/Archive/Redirect.coffee | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Archive/Redirect.coffee b/src/Archive/Redirect.coffee index a69dbb292..bacd0ea02 100755 --- a/src/Archive/Redirect.coffee +++ b/src/Archive/Redirect.coffee @@ -61,8 +61,8 @@ Redirect = software: "foolfuuka" , name: "Nyafuu" - boards: ["c", "w", "wg"] - files: ["c", "w", "wg"] + boards: ["c", "e", "w", "wg"] + files: ["c", "e", "w", "wg"] data: domain: "archive.nyafuu.org" http: true @@ -113,6 +113,15 @@ Redirect = https: true withCredentials: true software: "foolfuuka" + , + name: "Love is Over" + boards: ["d", "i"], + files: ["d", "i"] + data: + domain: "loveisover.me" + http: true + https: true + software: "foolfuuka" ] to: (dest, data) -> From 90f780fff3927abde96a4f80d3ee09db2e4df61d Mon Sep 17 00:00:00 2001 From: Zixaphir Date: Fri, 17 Jan 2014 13:10:52 -0700 Subject: [PATCH 19/19] build --- LICENSE | 2 +- builds/4chan-X.user.js | 16 +++++++++++++--- builds/crx/script.js | 16 +++++++++++++--- 3 files changed, 27 insertions(+), 7 deletions(-) diff --git a/LICENSE b/LICENSE index 6bb57545a..6d1b0a850 100755 --- a/LICENSE +++ b/LICENSE @@ -1,5 +1,5 @@ /* -* 4chan X - Version 1.3.2 - 2014-01-16 +* 4chan X - Version 1.3.2 - 2014-01-17 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js index 7c1656039..4959536ae 100644 --- a/builds/4chan-X.user.js +++ b/builds/4chan-X.user.js @@ -22,7 +22,7 @@ // ==/UserScript== /* -* 4chan X - Version 1.3.2 - 2014-01-16 +* 4chan X - Version 1.3.2 - 2014-01-17 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -10198,8 +10198,8 @@ } }, { name: "Nyafuu", - boards: ["c", "w", "wg"], - files: ["c", "w", "wg"], + boards: ["c", "e", "w", "wg"], + files: ["c", "e", "w", "wg"], data: { domain: "archive.nyafuu.org", http: true, @@ -10256,6 +10256,16 @@ withCredentials: true, software: "foolfuuka" } + }, { + name: "Love is Over", + boards: ["d", "i"], + files: ["d", "i"], + data: { + domain: "loveisover.me", + http: true, + https: true, + software: "foolfuuka" + } } ], to: function(dest, data) { diff --git a/builds/crx/script.js b/builds/crx/script.js index c5bc6054b..859700681 100644 --- a/builds/crx/script.js +++ b/builds/crx/script.js @@ -1,6 +1,6 @@ // Generated by CoffeeScript /* -* 4chan X - Version 1.3.2 - 2014-01-16 +* 4chan X - Version 1.3.2 - 2014-01-17 * * Licensed under the MIT license. * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE @@ -10187,8 +10187,8 @@ } }, { name: "Nyafuu", - boards: ["c", "w", "wg"], - files: ["c", "w", "wg"], + boards: ["c", "e", "w", "wg"], + files: ["c", "e", "w", "wg"], data: { domain: "archive.nyafuu.org", http: true, @@ -10245,6 +10245,16 @@ withCredentials: true, software: "foolfuuka" } + }, { + name: "Love is Over", + boards: ["d", "i"], + files: ["d", "i"], + data: { + domain: "loveisover.me", + http: true, + https: true, + software: "foolfuuka" + } } ], to: function(dest, data) {