Index.coffee

UGGHHH, I'm not satisfied with this.
This commit is contained in:
Zixaphir 2015-01-08 23:30:40 -07:00
parent 2dd17b5803
commit 6080ae3fe5
4 changed files with 161 additions and 87 deletions

View File

@ -2696,7 +2696,7 @@
(function() {
var reqs;
reqs = {};
return $.cache = function(url, cb, options) {
$.cache = function(url, cb, options) {
var err, req, rm;
if (req = reqs[url]) {
if (req.readyState === 4) {
@ -2734,6 +2734,14 @@
req.callbacks = [cb];
return reqs[url] = req;
};
return $.cleanCache = function(testf) {
var url;
for (url in reqs) {
if (testf(url)) {
delete reqs[url];
}
}
};
})();
$.cb = {
@ -4762,7 +4770,7 @@
Index = {
showHiddenThreads: false,
init: function() {
var input, label, modeEntry, name, refNavEntry, repliesEntry, returnLink, select, sortEntry, targetEntry, threadNumEntry, threadsNumInput, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
var anchorEntry, input, label, modeEntry, name, pinEntry, refNavEntry, repliesEntry, returnLink, select, sortEntry, targetEntry, threadNumEntry, threadsNumInput, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
if (g.BOARD.ID === 'f' || !Conf['JSON Navigation']) {
return;
}
@ -4835,23 +4843,25 @@
$.on(threadsNumInput, 'change', $.cb.value);
$.on(threadsNumInput, 'change', this.cb.threadsNum);
targetEntry = {
el: $.el('label', {
innerHTML: '<input type=checkbox name="Open threads in a new tab"> Open threads in a new tab',
title: 'Catalog-only setting.'
})
el: UI.checkbox('Open threads in a new tab', 'Open threads in a new tab')
};
repliesEntry = {
el: $.el('label', {
innerHTML: '<input type=checkbox name="Show Replies"> Show replies'
})
el: UI.checkbox('Show Replies', 'Show replies')
};
pinEntry = {
el: UI.checkbox('Pin Watched Threads', 'Pin watched threads')
};
anchorEntry = {
el: UI.checkbox('Anchor Hidden Threads', 'Anchor hidden threads')
};
refNavEntry = {
el: $.el('label', {
innerHTML: '<input type=checkbox name="Refreshed Navigation"> Refreshed navigation',
title: 'Refresh index when navigating through pages.'
})
el: UI.checkbox('Refreshed Navigation', 'Refreshed navigation')
};
_ref1 = [targetEntry, repliesEntry, refNavEntry];
targetEntry.el.title = 'Catalog-only setting.';
pinEntry.el.title = 'Move watched threads to the start of the index.';
anchorEntry.el.title = 'Move hidden threads to the end of the index.';
refNavEntry.el.title = 'Refresh index when navigating through pages.';
_ref1 = [targetEntry, repliesEntry, pinEntry, anchorEntry, refNavEntry];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
label = _ref1[_j];
input = label.el.firstChild;
@ -4864,6 +4874,10 @@
break;
case 'Show Replies':
$.on(input, 'change', this.cb.replies);
break;
case 'Pin Watched Threads':
case 'Anchor Hidden Threads':
$.on(input, 'change', this.cb.sort);
}
}
Header.menu.addEntry({
@ -4871,7 +4885,7 @@
textContent: 'Index Navigation'
}),
order: 98,
subEntries: [threadNumEntry, targetEntry, repliesEntry, refNavEntry]
subEntries: [threadNumEntry, targetEntry, repliesEntry, pinEntry, anchorEntry, refNavEntry]
});
$.addClass(doc, 'index-loading');
this.root = $.el('div', {
@ -4960,6 +4974,7 @@
}
board = $('.board');
$.replace(board, Index.root);
$.event('PostsInserted');
return d.implementation.createDocument(null, null, null).appendChild(board);
});
return $.asap((function() {
@ -4978,7 +4993,7 @@
if (Index.req || Conf['Index Mode'] !== 'infinite' || (window.scrollY <= doc.scrollHeight - (300 + window.innerHeight)) || g.VIEW === 'thread') {
return;
}
Index.currentPage = (Index.currentPage || Index.getCurrentPage()) + 1;
Index.currentPage = Index.getCurrentPage() + 1;
if (Index.currentPage >= Index.pagesNum) {
return Index.endNotice();
}
@ -5023,8 +5038,7 @@
$.event('CloseMenu');
return Index.togglePin(thread);
};
$.on(this.el, 'click', this.cb);
return true;
return $.on(this.el, 'click', this.cb);
}
});
}
@ -5056,13 +5070,12 @@
thread = g.threads[this.parentNode.dataset.fullID];
if (e.shiftKey) {
PostHiding.toggle(thread.OP);
return e.preventDefault();
} else if (e.altKey) {
Index.togglePin(thread);
return e.preventDefault();
} else {
return Navigate.navigate.call(this, e);
}
return e.preventDefault();
},
onOver: function(e) {
var el, nodes;
@ -5111,13 +5124,18 @@
},
cycleSortType: function() {
var i, option, type, types, _i, _len;
types = [];
i = 0;
while (option = Index.selectSort.options[i++]) {
if (!option.disabled) {
types.push(option);
types = (function() {
var _i, _len, _ref, _results;
_ref = Index.selectSort.options;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
option = _ref[_i];
if (!option.disabled) {
_results.push(option);
}
}
}
return _results;
})();
for (i = _i = 0, _len = types.length; _i < _len; i = ++_i) {
type = types[i];
if (type.selected) {
@ -5256,6 +5274,7 @@
}
switch (e.target.nodeName) {
case 'BUTTON':
e.target.blur();
a = e.target.parentNode;
break;
case 'A':
@ -5318,6 +5337,10 @@
return Header.scrollToIfNeeded(Index.navLinks);
},
getCurrentPage: function() {
var _ref;
if ((_ref = Conf['Index Mode']) === 'all pages' || _ref === 'catalog') {
return 1;
}
if (Conf['Index Mode'] === 'infinite' && Index.currentPage) {
return Index.currentPage;
}
@ -5550,6 +5573,9 @@
return Index.scrollToIndex();
},
parse: function(pages, pageNum) {
$.cleanCache(function(url) {
return /^\/\/a\.4cdn\.org\//.test(url);
});
Index.parseThreadList(pages);
Index.buildThreads();
Index.sort();
@ -5761,20 +5787,28 @@
Index.sortOnTop(function(thread) {
return thread.isSticky;
});
return Index.sortOnTop(function(thread) {
return thread.isOnTop || thread.isPinned;
Index.sortOnTop(function(thread) {
return thread.isOnTop || Conf['Pin Watched Threads'] && ThreadWatcher.isWatched(thread);
});
if (Conf['Anchor Hidden Threads']) {
return Index.sortOnTop(function(thread) {
return !thread.isHidden;
});
}
},
sortOnTop: function(match) {
var i, offset, thread, _i, _len, _ref;
var bottomThreads, i, offset, thread, topThreads, _i, _len, _ref;
offset = 0;
topThreads = [];
bottomThreads = [];
_ref = Index.sortedThreads;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
thread = _ref[i];
if (match(thread)) {
Index.sortedThreads.splice(offset++, 0, Index.sortedThreads.splice(i, 1)[0]);
(match(thread) ? topThreads : bottomThreads).push(thread);
}
}
return Index.sortedThreads = topThreads.push.apply(topThreads, bottomThreads);
},
buildIndex: function(infinite) {
var i, max, nodes, pageNum, sortedThreads, thread, threads, threadsPerPage;

View File

@ -2668,7 +2668,7 @@
(function() {
var reqs;
reqs = {};
return $.cache = function(url, cb, options) {
$.cache = function(url, cb, options) {
var err, req, rm;
if (req = reqs[url]) {
if (req.readyState === 4) {
@ -2706,6 +2706,14 @@
req.callbacks = [cb];
return reqs[url] = req;
};
return $.cleanCache = function(testf) {
var url;
for (url in reqs) {
if (testf(url)) {
delete reqs[url];
}
}
};
})();
$.cb = {
@ -4791,7 +4799,7 @@
Index = {
showHiddenThreads: false,
init: function() {
var input, label, modeEntry, name, refNavEntry, repliesEntry, returnLink, select, sortEntry, targetEntry, threadNumEntry, threadsNumInput, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
var anchorEntry, input, label, modeEntry, name, pinEntry, refNavEntry, repliesEntry, returnLink, select, sortEntry, targetEntry, threadNumEntry, threadsNumInput, _i, _j, _k, _len, _len1, _len2, _ref, _ref1, _ref2;
if (g.BOARD.ID === 'f' || !Conf['JSON Navigation']) {
return;
}
@ -4864,23 +4872,25 @@
$.on(threadsNumInput, 'change', $.cb.value);
$.on(threadsNumInput, 'change', this.cb.threadsNum);
targetEntry = {
el: $.el('label', {
innerHTML: '<input type=checkbox name="Open threads in a new tab"> Open threads in a new tab',
title: 'Catalog-only setting.'
})
el: UI.checkbox('Open threads in a new tab', 'Open threads in a new tab')
};
repliesEntry = {
el: $.el('label', {
innerHTML: '<input type=checkbox name="Show Replies"> Show replies'
})
el: UI.checkbox('Show Replies', 'Show replies')
};
pinEntry = {
el: UI.checkbox('Pin Watched Threads', 'Pin watched threads')
};
anchorEntry = {
el: UI.checkbox('Anchor Hidden Threads', 'Anchor hidden threads')
};
refNavEntry = {
el: $.el('label', {
innerHTML: '<input type=checkbox name="Refreshed Navigation"> Refreshed navigation',
title: 'Refresh index when navigating through pages.'
})
el: UI.checkbox('Refreshed Navigation', 'Refreshed navigation')
};
_ref1 = [targetEntry, repliesEntry, refNavEntry];
targetEntry.el.title = 'Catalog-only setting.';
pinEntry.el.title = 'Move watched threads to the start of the index.';
anchorEntry.el.title = 'Move hidden threads to the end of the index.';
refNavEntry.el.title = 'Refresh index when navigating through pages.';
_ref1 = [targetEntry, repliesEntry, pinEntry, anchorEntry, refNavEntry];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
label = _ref1[_j];
input = label.el.firstChild;
@ -4893,6 +4903,10 @@
break;
case 'Show Replies':
$.on(input, 'change', this.cb.replies);
break;
case 'Pin Watched Threads':
case 'Anchor Hidden Threads':
$.on(input, 'change', this.cb.sort);
}
}
Header.menu.addEntry({
@ -4900,7 +4914,7 @@
textContent: 'Index Navigation'
}),
order: 98,
subEntries: [threadNumEntry, targetEntry, repliesEntry, refNavEntry]
subEntries: [threadNumEntry, targetEntry, repliesEntry, pinEntry, anchorEntry, refNavEntry]
});
$.addClass(doc, 'index-loading');
this.root = $.el('div', {
@ -4989,6 +5003,7 @@
}
board = $('.board');
$.replace(board, Index.root);
$.event('PostsInserted');
return d.implementation.createDocument(null, null, null).appendChild(board);
});
return $.asap((function() {
@ -5007,7 +5022,7 @@
if (Index.req || Conf['Index Mode'] !== 'infinite' || (window.scrollY <= doc.scrollHeight - (300 + window.innerHeight)) || g.VIEW === 'thread') {
return;
}
Index.currentPage = (Index.currentPage || Index.getCurrentPage()) + 1;
Index.currentPage = Index.getCurrentPage() + 1;
if (Index.currentPage >= Index.pagesNum) {
return Index.endNotice();
}
@ -5052,8 +5067,7 @@
$.event('CloseMenu');
return Index.togglePin(thread);
};
$.on(this.el, 'click', this.cb);
return true;
return $.on(this.el, 'click', this.cb);
}
});
}
@ -5085,13 +5099,12 @@
thread = g.threads[this.parentNode.dataset.fullID];
if (e.shiftKey) {
PostHiding.toggle(thread.OP);
return e.preventDefault();
} else if (e.altKey) {
Index.togglePin(thread);
return e.preventDefault();
} else {
return Navigate.navigate.call(this, e);
}
return e.preventDefault();
},
onOver: function(e) {
var el, nodes;
@ -5140,13 +5153,18 @@
},
cycleSortType: function() {
var i, option, type, types, _i, _len;
types = [];
i = 0;
while (option = Index.selectSort.options[i++]) {
if (!option.disabled) {
types.push(option);
types = (function() {
var _i, _len, _ref, _results;
_ref = Index.selectSort.options;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
option = _ref[_i];
if (!option.disabled) {
_results.push(option);
}
}
}
return _results;
})();
for (i = _i = 0, _len = types.length; _i < _len; i = ++_i) {
type = types[i];
if (type.selected) {
@ -5285,6 +5303,7 @@
}
switch (e.target.nodeName) {
case 'BUTTON':
e.target.blur();
a = e.target.parentNode;
break;
case 'A':
@ -5347,6 +5366,10 @@
return Header.scrollToIfNeeded(Index.navLinks);
},
getCurrentPage: function() {
var _ref;
if ((_ref = Conf['Index Mode']) === 'all pages' || _ref === 'catalog') {
return 1;
}
if (Conf['Index Mode'] === 'infinite' && Index.currentPage) {
return Index.currentPage;
}
@ -5579,6 +5602,9 @@
return Index.scrollToIndex();
},
parse: function(pages, pageNum) {
$.cleanCache(function(url) {
return /^\/\/a\.4cdn\.org\//.test(url);
});
Index.parseThreadList(pages);
Index.buildThreads();
Index.sort();
@ -5790,20 +5816,28 @@
Index.sortOnTop(function(thread) {
return thread.isSticky;
});
return Index.sortOnTop(function(thread) {
return thread.isOnTop || thread.isPinned;
Index.sortOnTop(function(thread) {
return thread.isOnTop || Conf['Pin Watched Threads'] && ThreadWatcher.isWatched(thread);
});
if (Conf['Anchor Hidden Threads']) {
return Index.sortOnTop(function(thread) {
return !thread.isHidden;
});
}
},
sortOnTop: function(match) {
var i, offset, thread, _i, _len, _ref;
var bottomThreads, i, offset, thread, topThreads, _i, _len, _ref;
offset = 0;
topThreads = [];
bottomThreads = [];
_ref = Index.sortedThreads;
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
thread = _ref[i];
if (match(thread)) {
Index.sortedThreads.splice(offset++, 0, Index.sortedThreads.splice(i, 1)[0]);
(match(thread) ? topThreads : bottomThreads).push(thread);
}
}
return Index.sortedThreads = topThreads.push.apply(topThreads, bottomThreads);
},
buildIndex: function(infinite) {
var i, max, nodes, pageNum, sortedThreads, thread, threads, threadsPerPage;

View File

@ -48,21 +48,18 @@ Index =
$.on threadsNumInput, 'change', $.cb.value
$.on threadsNumInput, 'change', @cb.threadsNum
targetEntry =
el: $.el 'label',
innerHTML: '<input type=checkbox name="Open threads in a new tab"> Open threads in a new tab'
title: 'Catalog-only setting.'
targetEntry = el: UI.checkbox 'Open threads in a new tab', 'Open threads in a new tab'
repliesEntry = el: UI.checkbox 'Show Replies', 'Show replies'
pinEntry = el: UI.checkbox 'Pin Watched Threads', 'Pin watched threads'
anchorEntry = el: UI.checkbox 'Anchor Hidden Threads', 'Anchor hidden threads'
refNavEntry = el: UI.checkbox 'Refreshed Navigation', 'Refreshed navigation'
repliesEntry =
el: $.el 'label',
innerHTML: '<input type=checkbox name="Show Replies"> Show replies'
targetEntry.el.title = 'Catalog-only setting.'
pinEntry.el.title = 'Move watched threads to the start of the index.'
anchorEntry.el.title = 'Move hidden threads to the end of the index.'
refNavEntry.el.title = 'Refresh index when navigating through pages.'
refNavEntry =
el: $.el 'label',
innerHTML: '<input type=checkbox name="Refreshed Navigation"> Refreshed navigation'
title: 'Refresh index when navigating through pages.'
for label in [targetEntry, repliesEntry, refNavEntry]
for label in [targetEntry, repliesEntry, pinEntry, anchorEntry, refNavEntry]
input = label.el.firstChild
{name} = input
input.checked = Conf[name]
@ -72,12 +69,14 @@ Index =
$.on input, 'change', @cb.target
when 'Show Replies'
$.on input, 'change', @cb.replies
when 'Pin Watched Threads', 'Anchor Hidden Threads'
$.on input, 'change', @cb.sort
Header.menu.addEntry
el: $.el 'span',
textContent: 'Index Navigation'
order: 98
subEntries: [threadNumEntry, targetEntry, repliesEntry, refNavEntry]
subEntries: [threadNumEntry, targetEntry, repliesEntry, pinEntry, anchorEntry, refNavEntry]
$.addClass doc, 'index-loading'
@ -156,6 +155,7 @@ Index =
board = $ '.board'
$.replace board, Index.root
$.event 'PostsInserted'
# Hacks:
# - When removing an element from the document during page load,
# its ancestors will still be correctly created inside of it.
@ -174,7 +174,7 @@ Index =
scroll: ->
return if Index.req or Conf['Index Mode'] isnt 'infinite' or (window.scrollY <= doc.scrollHeight - (300 + window.innerHeight)) or g.VIEW is 'thread'
Index.currentPage = (Index.currentPage or Index.getCurrentPage()) + 1 # Avoid having to pushState to keep track of the current page
Index.currentPage = Index.getCurrentPage() + 1 # Avoid having to pushState to keep track of the current page
return Index.endNotice() if Index.currentPage >= Index.pagesNum
Index.buildIndex true
@ -205,7 +205,6 @@ Index =
$.event 'CloseMenu'
Index.togglePin thread
$.on @el, 'click', @cb
true
threadNode: ->
return if g.VIEW isnt 'index'
@ -222,12 +221,11 @@ Index =
thread = g.threads[@parentNode.dataset.fullID]
if e.shiftKey
PostHiding.toggle thread.OP
e.preventDefault()
else if e.altKey
Index.togglePin thread
e.preventDefault()
else
Navigate.navigate.call @, e
return Navigate.navigate.call @, e
e.preventDefault()
onOver: (e) ->
# 4chan's less than stellar CSS forces us to include a .post and .postInfo
@ -271,10 +269,7 @@ Index =
$.event 'change', null, Index.selectMode
cycleSortType: ->
types = []
i = 0
while option = Index.selectSort.options[i++]
types.push option if !option.disabled
types = (option for option in Index.selectSort.options when not option.disabled)
for type, i in types
break if type.selected
types[(i + 1) % types.length].selected = true
@ -375,6 +370,7 @@ Index =
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0
switch e.target.nodeName
when 'BUTTON'
e.target.blur()
a = e.target.parentNode
when 'A'
a = e.target
@ -420,6 +416,8 @@ Index =
Header.scrollToIfNeeded Index.navLinks
getCurrentPage: ->
if Conf['Index Mode'] in ['all pages', 'catalog']
return 1
if Conf['Index Mode'] is 'infinite' and Index.currentPage
return Index.currentPage
+window.location.pathname.split('/')[2] or 1
@ -607,6 +605,7 @@ Index =
Index.scrollToIndex()
parse: (pages, pageNum) ->
$.cleanCache (url) -> /^\/\/a\.4cdn\.org\//.test url
Index.parseThreadList pages
Index.buildThreads()
Index.sort()
@ -644,7 +643,6 @@ Index =
thread.setCount 'file', threadData.images + !!threadData.ext, threadData.imagelimit
thread.setStatus 'Sticky', !!threadData.sticky
thread.setStatus 'Closed', !!threadData.closed
else
thread = new Thread threadData.no, g.BOARD
threads.push thread
@ -764,13 +762,17 @@ Index =
# Sticky threads
Index.sortOnTop (thread) -> thread.isSticky
# Highlighted threads
Index.sortOnTop (thread) -> thread.isOnTop or thread.isPinned
Index.sortOnTop (thread) -> thread.isOnTop or Conf['Pin Watched Threads'] and ThreadWatcher.isWatched thread
# Non-hidden threads
Index.sortOnTop((thread) -> !thread.isHidden) if Conf['Anchor Hidden Threads']
sortOnTop: (match) ->
offset = 0
topThreads = []
bottomThreads = []
for thread, i in Index.sortedThreads when match thread
Index.sortedThreads.splice offset++, 0, Index.sortedThreads.splice(i, 1)[0]
return
(if match thread then topThreads else bottomThreads).push thread
Index.sortedThreads = topThreads.push bottomThreads...
buildIndex: (infinite) ->
{sortedThreads} = Index

View File

@ -83,6 +83,10 @@ do ->
$.on req, 'abort error', rm
req.callbacks = [cb]
reqs[url] = req
$.cleanCache = (testf) ->
for url of reqs when testf url
delete reqs[url]
return
$.cb =
checked: ->