Fix some stupid threadupdater issues, more navigate from catalog js

This commit is contained in:
Zixaphir 2014-03-01 14:46:37 -07:00
parent 292299d43c
commit a0c24fd06d
6 changed files with 101 additions and 124 deletions

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.4.0 - 2014-02-28 * 4chan X - Version 1.4.0 - 2014-03-01
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/Spittie/4chan-x/blob/master/LICENSE * https://github.com/Spittie/4chan-x/blob/master/LICENSE

View File

@ -24,7 +24,7 @@
// ==/UserScript== // ==/UserScript==
/* /*
* 4chan X - Version 1.4.0 - 2014-02-28 * 4chan X - Version 1.4.0 - 2014-03-01
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/Spittie/4chan-x/blob/master/LICENSE * https://github.com/Spittie/4chan-x/blob/master/LICENSE
@ -2783,7 +2783,7 @@
} else if (e.altKey) { } else if (e.altKey) {
Index.togglePin(thread); Index.togglePin(thread);
} else { } else {
return; Navigate.navigate.call(this);
} }
return e.preventDefault(); return e.preventDefault();
}, },
@ -9676,7 +9676,7 @@
node: function() { node: function() {
ThreadUpdater.thread = this; ThreadUpdater.thread = this;
ThreadUpdater.root = this.OP.nodes.root.parentNode; ThreadUpdater.root = this.OP.nodes.root.parentNode;
ThreadUpdater.lastPost = +Object.keys(this.posts).sort().slice(-1)[0]; ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
ThreadUpdater.cb.interval.call($.el('input', { ThreadUpdater.cb.interval.call($.el('input', {
value: Conf['Interval'] value: Conf['Interval']
})); }));
@ -9923,17 +9923,8 @@
if (!count) { if (!count) {
ThreadUpdater.set('status', null, null); ThreadUpdater.set('status', null, null);
ThreadUpdater.outdateCount++; ThreadUpdater.outdateCount++;
} else { sendEvent();
ThreadUpdater.set('status', "+" + count, 'new'); return;
ThreadUpdater.outdateCount = 0;
if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
if (!ThreadUpdater.audio) {
ThreadUpdater.audio = $.el('audio', {
src: ThreadUpdater.beep
});
}
ThreadUpdater.audio.play();
}
} }
ThreadUpdater.set('status', "+" + count, 'new'); ThreadUpdater.set('status', "+" + count, 'new');
ThreadUpdater.outdateCount = 0; ThreadUpdater.outdateCount = 0;
@ -12818,7 +12809,10 @@
delete g.THREADID; delete g.THREADID;
QR.link.textContent = 'Start a Thread'; QR.link.textContent = 'Start a Thread';
$.off(d, 'ThreadUpdate', QR.statusCheck); $.off(d, 'ThreadUpdate', QR.statusCheck);
return $.on(d, 'IndexRefresh', QR.generatePostableThreadsList); $.on(d, 'IndexRefresh', QR.generatePostableThreadsList);
if (Conf['Index Mode'] === 'catalog') {
return $.addClass(doc, 'catalog-mode');
}
}, },
thread: function() { thread: function() {
g.THREADID = +window.location.pathname.split('/')[3]; g.THREADID = +window.location.pathname.split('/')[3];
@ -12827,7 +12821,10 @@
} }
QR.link.textContent = 'Reply to Thread'; QR.link.textContent = 'Reply to Thread';
$.on(d, 'ThreadUpdate', QR.statusCheck); $.on(d, 'ThreadUpdate', QR.statusCheck);
return $.off(d, 'IndexRefresh', QR.generatePostableThreadsList); $.off(d, 'IndexRefresh', QR.generatePostableThreadsList);
if (Conf['Index Mode'] === 'catalog') {
return $.rmClass(doc, 'catalog-mode');
}
} }
}[g.VIEW](); }[g.VIEW]();
}, },
@ -12885,7 +12882,7 @@
style = d.cookie.match(new RegExp("\b" + type + "\_style\=([^;]+);\b")); style = d.cookie.match(new RegExp("\b" + type + "\_style\=([^;]+);\b"));
return ["" + type + "_style", (style ? style[1] : base)]; return ["" + type + "_style", (style ? style[1] : base)];
}; };
style = findStyle.apply(null, (sfw ? ['ws', 'Yotsuba B New'] : ['nws', 'Yotsuba New'])); style = sfw ? findStyle('ws', 'Yotsuba B New') : findStyle('nws', 'Yotsuba New');
$.globalEval("var style_group = '" + style[0] + "'"); $.globalEval("var style_group = '" + style[0] + "'");
$('link[title=switch]', d.head).href = $("link[title='" + style[1] + "']", d.head).href; $('link[title=switch]', d.head).href = $("link[title='" + style[1] + "']", d.head).href;
return Main.setClass(); return Main.setClass();
@ -12899,16 +12896,15 @@
return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title; return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title;
}, },
navigate: function(e) { navigate: function(e) {
var boardID, indexMode, indexSort, load, pageNum, path, threadID, view, _ref; var boardID, indexMode, indexSort, load, pageNum, path, threadID, view, _, _ref, _ref1;
if (this.hostname !== 'boards.4chan.org' || window.location.hostname === 'rs.4chan.org' || (e && (e.shiftKey || e.ctrlKey || (e.type === 'click' && e.button !== 0)))) { if (this.hostname !== 'boards.4chan.org' || window.location.hostname === 'rs.4chan.org') {
return;
}
if (e && (e.shiftKey || e.ctrlKey || (e.type === 'click' && e.button !== 0))) {
return; return;
} }
$.addClass(Index.button, 'fa-spin'); $.addClass(Index.button, 'fa-spin');
path = this.pathname.split('/'); _ref = this.pathname.split('/'), _ = _ref[0], boardID = _ref[1], view = _ref[2], threadID = _ref[3];
if (path[0] === '') {
path.shift();
}
boardID = path[0], view = path[1], threadID = path[2];
if ('f' === boardID || 'f' === g.BOARD.ID) { if ('f' === boardID || 'f' === g.BOARD.ID) {
return; return;
} }
@ -12917,6 +12913,7 @@
} }
Navigate.title = function() {}; Navigate.title = function() {};
delete Index.pageNum; delete Index.pageNum;
$.rmAll(Header.hover);
path = this.pathname; path = this.pathname;
if (this.hash) { if (this.hash) {
path += this.hash; path += this.hash;
@ -12931,17 +12928,13 @@
pageNum = view; pageNum = view;
view = 'index'; view = 'index';
} }
_ref = this.dataset, indexMode = _ref.indexMode, indexSort = _ref.indexSort; _ref1 = this.dataset, indexMode = _ref1.indexMode, indexSort = _ref1.indexSort;
if (indexMode && Conf['Index Mode'] !== indexMode) { if (indexMode && Conf['Index Mode'] !== indexMode) {
$.set('Index Mode', indexMode); $.set('Index Mode', Conf['Index Mode'] = Index.selectMode.value = indexMode);
Conf['Index Mode'] = indexMode;
Index.selectMode.value = indexMode;
Index.cb.mode(); Index.cb.mode();
} }
if (indexSort && Conf['Index Sort'] !== indexSort) { if (indexSort && Conf['Index Sort'] !== indexSort) {
$.set('Index Sort', indexSort); $.set('Index Sort', Conf['Index Sort'] = Index.selectSort.value = indexSort);
Conf['Index Sort'] = indexSort;
Index.selectSort.value = indexSort;
Index.cb.sort(); Index.cb.sort();
} }
if (view === g.VIEW && boardID === g.BOARD.ID) { if (view === g.VIEW && boardID === g.BOARD.ID) {
@ -12966,19 +12959,18 @@
} }
if (view === 'index') { if (view === 'index') {
return Index.update(pageNum); return Index.update(pageNum);
} else {
Navigate.updateSFW(Favicon.SFW);
load = Navigate.load;
Navigate.req = $.ajax("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", {
onabort: load,
onloadend: load
});
return setTimeout((function() {
if (Navigate.req && !Navigate.notice) {
return Navigate.notice = new Notice('info', 'Loading thread...');
}
}), 3 * $.SECOND);
} }
Navigate.updateSFW(Favicon.SFW);
load = Navigate.load;
Navigate.req = $.ajax("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", {
onabort: load,
onloadend: load
});
return setTimeout((function() {
if (Navigate.req && !Navigate.notice) {
return Navigate.notice = new Notice('info', 'Loading thread...');
}
}), 3 * $.SECOND);
}, },
load: function(e) { load: function(e) {
var err, notice, req; var err, notice, req;

View File

@ -1,6 +1,6 @@
// Generated by CoffeeScript // Generated by CoffeeScript
/* /*
* 4chan X - Version 1.4.0 - 2014-02-28 * 4chan X - Version 1.4.0 - 2014-03-01
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/Spittie/4chan-x/blob/master/LICENSE * https://github.com/Spittie/4chan-x/blob/master/LICENSE
@ -2842,7 +2842,7 @@
} else if (e.altKey) { } else if (e.altKey) {
Index.togglePin(thread); Index.togglePin(thread);
} else { } else {
return; Navigate.navigate.call(this);
} }
return e.preventDefault(); return e.preventDefault();
}, },
@ -9691,7 +9691,7 @@
node: function() { node: function() {
ThreadUpdater.thread = this; ThreadUpdater.thread = this;
ThreadUpdater.root = this.OP.nodes.root.parentNode; ThreadUpdater.root = this.OP.nodes.root.parentNode;
ThreadUpdater.lastPost = +Object.keys(this.posts).sort().slice(-1)[0]; ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
ThreadUpdater.cb.interval.call($.el('input', { ThreadUpdater.cb.interval.call($.el('input', {
value: Conf['Interval'] value: Conf['Interval']
})); }));
@ -9938,17 +9938,8 @@
if (!count) { if (!count) {
ThreadUpdater.set('status', null, null); ThreadUpdater.set('status', null, null);
ThreadUpdater.outdateCount++; ThreadUpdater.outdateCount++;
} else { sendEvent();
ThreadUpdater.set('status', "+" + count, 'new'); return;
ThreadUpdater.outdateCount = 0;
if (Conf['Beep'] && d.hidden && Unread.posts && !Unread.posts.length) {
if (!ThreadUpdater.audio) {
ThreadUpdater.audio = $.el('audio', {
src: ThreadUpdater.beep
});
}
ThreadUpdater.audio.play();
}
} }
ThreadUpdater.set('status', "+" + count, 'new'); ThreadUpdater.set('status', "+" + count, 'new');
ThreadUpdater.outdateCount = 0; ThreadUpdater.outdateCount = 0;
@ -12832,7 +12823,10 @@
delete g.THREADID; delete g.THREADID;
QR.link.textContent = 'Start a Thread'; QR.link.textContent = 'Start a Thread';
$.off(d, 'ThreadUpdate', QR.statusCheck); $.off(d, 'ThreadUpdate', QR.statusCheck);
return $.on(d, 'IndexRefresh', QR.generatePostableThreadsList); $.on(d, 'IndexRefresh', QR.generatePostableThreadsList);
if (Conf['Index Mode'] === 'catalog') {
return $.addClass(doc, 'catalog-mode');
}
}, },
thread: function() { thread: function() {
g.THREADID = +window.location.pathname.split('/')[3]; g.THREADID = +window.location.pathname.split('/')[3];
@ -12841,7 +12835,10 @@
} }
QR.link.textContent = 'Reply to Thread'; QR.link.textContent = 'Reply to Thread';
$.on(d, 'ThreadUpdate', QR.statusCheck); $.on(d, 'ThreadUpdate', QR.statusCheck);
return $.off(d, 'IndexRefresh', QR.generatePostableThreadsList); $.off(d, 'IndexRefresh', QR.generatePostableThreadsList);
if (Conf['Index Mode'] === 'catalog') {
return $.rmClass(doc, 'catalog-mode');
}
} }
}[g.VIEW](); }[g.VIEW]();
}, },
@ -12899,7 +12896,7 @@
style = d.cookie.match(new RegExp("\b" + type + "\_style\=([^;]+);\b")); style = d.cookie.match(new RegExp("\b" + type + "\_style\=([^;]+);\b"));
return ["" + type + "_style", (style ? style[1] : base)]; return ["" + type + "_style", (style ? style[1] : base)];
}; };
style = findStyle.apply(null, (sfw ? ['ws', 'Yotsuba B New'] : ['nws', 'Yotsuba New'])); style = sfw ? findStyle('ws', 'Yotsuba B New') : findStyle('nws', 'Yotsuba New');
$.globalEval("var style_group = '" + style[0] + "'"); $.globalEval("var style_group = '" + style[0] + "'");
$('link[title=switch]', d.head).href = $("link[title='" + style[1] + "']", d.head).href; $('link[title=switch]', d.head).href = $("link[title='" + style[1] + "']", d.head).href;
return Main.setClass(); return Main.setClass();
@ -12913,16 +12910,15 @@
return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title; return $('.boardTitle').textContent = d.title = "/" + board + "/ - " + title;
}, },
navigate: function(e) { navigate: function(e) {
var boardID, indexMode, indexSort, load, pageNum, path, threadID, view, _ref; var boardID, indexMode, indexSort, load, pageNum, path, threadID, view, _, _ref, _ref1;
if (this.hostname !== 'boards.4chan.org' || window.location.hostname === 'rs.4chan.org' || (e && (e.shiftKey || e.ctrlKey || (e.type === 'click' && e.button !== 0)))) { if (this.hostname !== 'boards.4chan.org' || window.location.hostname === 'rs.4chan.org') {
return;
}
if (e && (e.shiftKey || e.ctrlKey || (e.type === 'click' && e.button !== 0))) {
return; return;
} }
$.addClass(Index.button, 'fa-spin'); $.addClass(Index.button, 'fa-spin');
path = this.pathname.split('/'); _ref = this.pathname.split('/'), _ = _ref[0], boardID = _ref[1], view = _ref[2], threadID = _ref[3];
if (path[0] === '') {
path.shift();
}
boardID = path[0], view = path[1], threadID = path[2];
if ('f' === boardID || 'f' === g.BOARD.ID) { if ('f' === boardID || 'f' === g.BOARD.ID) {
return; return;
} }
@ -12931,6 +12927,7 @@
} }
Navigate.title = function() {}; Navigate.title = function() {};
delete Index.pageNum; delete Index.pageNum;
$.rmAll(Header.hover);
path = this.pathname; path = this.pathname;
if (this.hash) { if (this.hash) {
path += this.hash; path += this.hash;
@ -12945,17 +12942,13 @@
pageNum = view; pageNum = view;
view = 'index'; view = 'index';
} }
_ref = this.dataset, indexMode = _ref.indexMode, indexSort = _ref.indexSort; _ref1 = this.dataset, indexMode = _ref1.indexMode, indexSort = _ref1.indexSort;
if (indexMode && Conf['Index Mode'] !== indexMode) { if (indexMode && Conf['Index Mode'] !== indexMode) {
$.set('Index Mode', indexMode); $.set('Index Mode', Conf['Index Mode'] = Index.selectMode.value = indexMode);
Conf['Index Mode'] = indexMode;
Index.selectMode.value = indexMode;
Index.cb.mode(); Index.cb.mode();
} }
if (indexSort && Conf['Index Sort'] !== indexSort) { if (indexSort && Conf['Index Sort'] !== indexSort) {
$.set('Index Sort', indexSort); $.set('Index Sort', Conf['Index Sort'] = Index.selectSort.value = indexSort);
Conf['Index Sort'] = indexSort;
Index.selectSort.value = indexSort;
Index.cb.sort(); Index.cb.sort();
} }
if (view === g.VIEW && boardID === g.BOARD.ID) { if (view === g.VIEW && boardID === g.BOARD.ID) {
@ -12980,19 +12973,18 @@
} }
if (view === 'index') { if (view === 'index') {
return Index.update(pageNum); return Index.update(pageNum);
} else {
Navigate.updateSFW(Favicon.SFW);
load = Navigate.load;
Navigate.req = $.ajax("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", {
onabort: load,
onloadend: load
});
return setTimeout((function() {
if (Navigate.req && !Navigate.notice) {
return Navigate.notice = new Notice('info', 'Loading thread...');
}
}), 3 * $.SECOND);
} }
Navigate.updateSFW(Favicon.SFW);
load = Navigate.load;
Navigate.req = $.ajax("//a.4cdn.org/" + boardID + "/res/" + threadID + ".json", {
onabort: load,
onloadend: load
});
return setTimeout((function() {
if (Navigate.req && !Navigate.notice) {
return Navigate.notice = new Notice('info', 'Loading thread...');
}
}), 3 * $.SECOND);
}, },
load: function(e) { load: function(e) {
var err, notice, req; var err, notice, req;

View File

@ -203,7 +203,7 @@ Index =
else if e.altKey else if e.altKey
Index.togglePin thread Index.togglePin thread
else else
return Navigate.navigate.call @
e.preventDefault() e.preventDefault()
onOver: (e) -> onOver: (e) ->

View File

@ -38,7 +38,7 @@ Navigate =
g.threads.forEach (thread) -> thread.collect() g.threads.forEach (thread) -> thread.collect()
QuoteBacklink.containers = {} QuoteBacklink.containers = {}
$.rmAll $('.board') $.rmAll $ '.board'
features: [ features: [
['Thread Excerpt', ThreadExcerpt] ['Thread Excerpt', ThreadExcerpt]
@ -102,12 +102,14 @@ Navigate =
QR.link.textContent = 'Start a Thread' QR.link.textContent = 'Start a Thread'
$.off d, 'ThreadUpdate', QR.statusCheck $.off d, 'ThreadUpdate', QR.statusCheck
$.on d, 'IndexRefresh', QR.generatePostableThreadsList $.on d, 'IndexRefresh', QR.generatePostableThreadsList
$.addClass doc, 'catalog-mode' if Conf['Index Mode'] is 'catalog'
thread: -> thread: ->
g.THREADID = +window.location.pathname.split('/')[3] g.THREADID = +window.location.pathname.split('/')[3]
return if oldView is g.VIEW return if oldView is g.VIEW
QR.link.textContent = 'Reply to Thread' QR.link.textContent = 'Reply to Thread'
$.on d, 'ThreadUpdate', QR.statusCheck $.on d, 'ThreadUpdate', QR.statusCheck
$.off d, 'IndexRefresh', QR.generatePostableThreadsList $.off d, 'IndexRefresh', QR.generatePostableThreadsList
$.rmClass doc, 'catalog-mode' if Conf['Index Mode'] is 'catalog'
}[g.VIEW]() }[g.VIEW]()
updateBoard: (boardID) -> updateBoard: (boardID) ->
@ -150,10 +152,10 @@ Navigate =
style = d.cookie.match new RegExp "\b#{type}\_style\=([^;]+);\b" style = d.cookie.match new RegExp "\b#{type}\_style\=([^;]+);\b"
return ["#{type}_style", (if style then style[1] else base)] return ["#{type}_style", (if style then style[1] else base)]
style = findStyle (if sfw style = if sfw
['ws', 'Yotsuba B New'] findStyle 'ws', 'Yotsuba B New'
else else
['nws', 'Yotsuba New'])... findStyle 'nws', 'Yotsuba New'
$.globalEval "var style_group = '#{style[0]}'" $.globalEval "var style_group = '#{style[0]}'"
@ -166,20 +168,19 @@ Navigate =
$('.boardTitle').textContent = d.title = "/#{board}/ - #{title}" $('.boardTitle').textContent = d.title = "/#{board}/ - #{title}"
navigate: (e) -> navigate: (e) ->
return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org' or return if @hostname isnt 'boards.4chan.org' or window.location.hostname is 'rs.4chan.org'
(e and (e.shiftKey or e.ctrlKey or (e.type is 'click' and e.button isnt 0))) # Not simply a left click return if e and (e.shiftKey or e.ctrlKey or (e.type is 'click' and e.button isnt 0)) # Not simply a left click
$.addClass Index.button, 'fa-spin' $.addClass Index.button, 'fa-spin'
path = @pathname.split '/' [_, boardID, view, threadID] = @pathname.split '/'
path.shift() if path[0] is ''
[boardID, view, threadID] = path
return if 'f' in [boardID, g.BOARD.ID] return if 'f' in [boardID, g.BOARD.ID]
e.preventDefault() if e e.preventDefault() if e
Navigate.title = -> return Navigate.title = -> return
delete Index.pageNum delete Index.pageNum
$.rmAll Header.hover
path = @pathname path = @pathname
path += @hash if @hash path += @hash if @hash
@ -195,18 +196,16 @@ Navigate =
{indexMode, indexSort} = @dataset {indexMode, indexSort} = @dataset
if indexMode and Conf['Index Mode'] isnt indexMode if indexMode and Conf['Index Mode'] isnt indexMode
$.set 'Index Mode', indexMode $.set 'Index Mode', Conf['Index Mode'] = Index.selectMode.value = indexMode
Conf['Index Mode'] = indexMode
Index.selectMode.value = indexMode
Index.cb.mode() Index.cb.mode()
if indexSort and Conf['Index Sort'] isnt indexSort if indexSort and Conf['Index Sort'] isnt indexSort
$.set 'Index Sort', indexSort $.set 'Index Sort', Conf['Index Sort'] = Index.selectSort.value = indexSort
Conf['Index Sort'] = indexSort
Index.selectSort.value = indexSort
Index.cb.sort() Index.cb.sort()
if view is g.VIEW and boardID is g.BOARD.ID if view is g.VIEW and boardID is g.BOARD.ID
Navigate.updateContext view Navigate.updateContext view
else # We've navigated somewhere we weren't before! else # We've navigated somewhere we weren't before!
Navigate.disconnect() Navigate.disconnect()
Navigate.updateContext view Navigate.updateContext view
@ -220,20 +219,19 @@ Navigate =
Navigate.title = -> Navigate.updateBoard boardID Navigate.title = -> Navigate.updateBoard boardID
if view is 'index' if view is 'index'
Index.update pageNum return Index.update pageNum
# Moving from index to thread or thread to thread # Moving from index to thread or thread to thread
else Navigate.updateSFW Favicon.SFW
Navigate.updateSFW Favicon.SFW {load} = Navigate
{load} = Navigate Navigate.req = $.ajax "//a.4cdn.org/#{boardID}/res/#{threadID}.json",
Navigate.req = $.ajax "//a.4cdn.org/#{boardID}/res/#{threadID}.json", onabort: load
onabort: load onloadend: load
onloadend: load
setTimeout (-> setTimeout (->
if Navigate.req and !Navigate.notice if Navigate.req and !Navigate.notice
Navigate.notice = new Notice 'info', 'Loading thread...' Navigate.notice = new Notice 'info', 'Loading thread...'
), 3 * $.SECOND ), 3 * $.SECOND
load: (e) -> load: (e) ->
$.rmClass Index.button, 'fa-spin' $.rmClass Index.button, 'fa-spin'

View File

@ -95,7 +95,7 @@ ThreadUpdater =
node: -> node: ->
ThreadUpdater.thread = @ ThreadUpdater.thread = @
ThreadUpdater.root = @OP.nodes.root.parentNode ThreadUpdater.root = @OP.nodes.root.parentNode
ThreadUpdater.lastPost = +Object.keys(@posts).sort()[-1..][0] ThreadUpdater.lastPost = +@posts.keys[@posts.keys.length - 1]
ThreadUpdater.cb.interval.call $.el 'input', value: Conf['Interval'] ThreadUpdater.cb.interval.call $.el 'input', value: Conf['Interval']
@ -321,13 +321,8 @@ ThreadUpdater =
unless count unless count
ThreadUpdater.set 'status', null, null ThreadUpdater.set 'status', null, null
ThreadUpdater.outdateCount++ ThreadUpdater.outdateCount++
else sendEvent()
ThreadUpdater.set 'status', "+#{count}", 'new' return
ThreadUpdater.outdateCount = 0
if Conf['Beep'] and d.hidden and Unread.posts and !Unread.posts.length
unless ThreadUpdater.audio
ThreadUpdater.audio = $.el 'audio', src: ThreadUpdater.beep
ThreadUpdater.audio.play()
ThreadUpdater.set 'status', "+#{count}", 'new' ThreadUpdater.set 'status', "+#{count}", 'new'
ThreadUpdater.outdateCount = 0 ThreadUpdater.outdateCount = 0