diff --git a/4chan_x.user.js b/4chan_x.user.js index 26b98a863..16e57db55 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -2246,6 +2246,7 @@ Unread.foresee.push(postID); } if (g.REPLY && Conf['Thread Updater'] && Conf['Auto Update This']) { + Updater.unsuccessfulFetchCount = 0; Updater.update(); } QR.status(); @@ -2567,7 +2568,7 @@ Updater = { init: function() { var checkbox, checked, dialog, html, input, name, title, _i, _len, _ref; - html = "
-" + Conf['Interval'] + "
"; + html = '
'; checkbox = Config.updater.checkbox; for (name in checkbox) { title = checkbox[name][1]; @@ -2575,11 +2576,13 @@ html += "
"; } checked = Conf['Auto Update'] ? 'checked' : ''; - html += "
"; + html += "
"; dialog = UI.dialog('updater', 'bottom: 0; right: 0;', html); this.count = $('#count', dialog); this.timer = $('#timer', dialog); this.thread = $.id("t" + g.THREAD_ID); + this.unsuccessfulFetchCount = 0; + this.lastModified = '0'; _ref = $$('input', dialog); for (_i = 0, _len = _ref.length; _i < _len; _i++) { input = _ref[_i]; @@ -2598,21 +2601,22 @@ Conf[input.name] = input.checked; } } else if (input.name === 'Interval') { + input.value = Conf['Interval']; $.on(input, 'input', this.cb.interval); + this.cb.interval.call(input); } else if (input.type === 'button') { $.on(input, 'click', this.update); } } - $.add(d.body, dialog); - this.retryCoef = 10; - return this.lastModified = 0; + return $.add(d.body, dialog); }, cb: { interval: function() { var val; val = parseInt(this.value, 10); - this.value = val > 0 ? val : 1; - return $.cb.value.call(this); + this.value = val > 5 ? val : 5; + $.cb.value.call(this); + return Updater.timer.textContent = "-" + (Updater.getInterval()); }, verbose: function() { if (Conf['Verbose']) { @@ -2641,7 +2645,7 @@ }; }, update: function() { - var count, doc, id, lastPost, nodes, reply, scroll, _i, _len, _ref, _ref1; + var count, doc, id, lastPost, nodes, reply, scroll, _i, _len, _ref, _ref1, _ref2; if (this.status === 404) { Updater.timer.textContent = ''; Updater.count.textContent = 404; @@ -2658,15 +2662,15 @@ return; } if ((_ref = this.status) !== 0 && _ref !== 200 && _ref !== 304) { - Updater.retryCoef += 10 * (Updater.retryCoef < 120); if (Conf['Verbose']) { Updater.count.textContent = this.statusText; Updater.count.className = 'warning'; } + Updater.unsuccessfulFetchCount++; return; } - Updater.retryCoef = 10; - Updater.timer.textContent = "-" + Conf['Interval']; + Updater.unsuccessfulFetchCount++; + Updater.timer.textContent = "-" + (Updater.getInterval()); /* Status Code 304: Not modified By sending the `If-Modified-Since` header we get a proper status code, and no response. @@ -2674,7 +2678,7 @@ and won't load images and scripts when parsing the response. */ - if (this.status === 304) { + if ((_ref1 = this.status) === 0 || _ref1 === 304) { if (Conf['Verbose']) { Updater.count.textContent = '+0'; Updater.count.className = null; @@ -2687,44 +2691,52 @@ lastPost = Updater.thread.lastElementChild; id = lastPost.id.slice(2); nodes = []; - _ref1 = $$('.replyContainer', doc).reverse(); - for (_i = 0, _len = _ref1.length; _i < _len; _i++) { - reply = _ref1[_i]; + _ref2 = $$('.replyContainer', doc).reverse(); + for (_i = 0, _len = _ref2.length; _i < _len; _i++) { + reply = _ref2[_i]; if (reply.id.slice(2) <= id) { break; } nodes.push(reply); } count = nodes.length; - scroll = Conf['Scrolling'] && Updater.scrollBG() && count && lastPost.getBoundingClientRect().bottom - d.documentElement.clientHeight < 25; if (Conf['Verbose']) { Updater.count.textContent = "+" + count; Updater.count.className = count ? 'new' : null; } + if (!count) { + return; + } + Updater.unsuccessfulFetchCount = 0; + Updater.timer.textContent = "-" + (Updater.getInterval()); + scroll = Conf['Scrolling'] && Updater.scrollBG() && lastPost.getBoundingClientRect().bottom - d.documentElement.clientHeight < 25; $.add(Updater.thread, nodes.reverse()); if (scroll) { return nodes[0].scrollIntoView(); } } }, + getInterval: function() { + var i, j; + i = +Conf['Interval']; + j = Math.min(this.unsuccessfulFetchCount, 9); + return Math.max(i, [5, 10, 15, 20, 30, 60, 90, 120, 300, 600][j]); + }, timeout: function() { var n; Updater.timeoutID = setTimeout(Updater.timeout, 1000); n = 1 + Number(Updater.timer.textContent); if (n === 0) { return Updater.update(); - } else if (n === Updater.retryCoef) { - Updater.retryCoef += 10 * (Updater.retryCoef < 120); - return Updater.retry(); + } else if (n === Updater.getInterval()) { + Updater.unsuccessfulFetchCount++; + Updater.count.textContent = 'Retry'; + Updater.count.className = null; + return Updater.update(); } else { return Updater.timer.textContent = n; } }, - retry: function() { - this.count.textContent = 'Retry'; - this.count.className = null; - return this.update(); - }, update: function() { var url, _ref; Updater.timer.textContent = 0; @@ -5087,6 +5099,9 @@ body.unscroll {\ border: none;\ background: transparent;\ }\ +#updater input[type=number] {\ + width: 4em;\ +}\ .new {\ background: lime;\ }\ diff --git a/changelog b/changelog index 8e462e5c9..00bcd8b04 100644 --- a/changelog +++ b/changelog @@ -1,4 +1,7 @@ master +- Mayhem + The updater's refresh interval will now increase gradually in inactive threads. + The updater's refresh interval is now limited to 5 seconds minimum. 2.33.8 - Mayhem diff --git a/script.coffee b/script.coffee index 9091549f9..696b4d779 100644 --- a/script.coffee +++ b/script.coffee @@ -1715,6 +1715,7 @@ QR = if g.REPLY and (Conf['Unread Count'] or Conf['Unread Favicon']) Unread.foresee.push postID if g.REPLY and Conf['Thread Updater'] and Conf['Auto Update This'] + Updater.unsuccessfulFetchCount = 0 Updater.update() QR.status() @@ -2000,7 +2001,7 @@ Options = Updater = init: -> - html = "
-#{Conf['Interval']}
" + html = '
' {checkbox} = Config.updater for name of checkbox title = checkbox[name][1] @@ -2010,7 +2011,7 @@ Updater = checked = if Conf['Auto Update'] then 'checked' else '' html += "
-
+
" dialog = UI.dialog 'updater', 'bottom: 0; right: 0;', html @@ -2019,6 +2020,9 @@ Updater = @timer = $ '#timer', dialog @thread = $.id "t#{g.THREAD_ID}" + @unsuccessfulFetchCount = 0 + @lastModified = '0' + for input in $$ 'input', dialog if input.type is 'checkbox' $.on input, 'click', $.cb.checked @@ -2034,20 +2038,20 @@ Updater = # Required for the QR's update after posting. Conf[input.name] = input.checked else if input.name is 'Interval' + input.value = Conf['Interval'] $.on input, 'input', @cb.interval + @cb.interval.call input else if input.type is 'button' $.on input, 'click', @update $.add d.body, dialog - @retryCoef = 10 - @lastModified = 0 - cb: interval: -> val = parseInt @value, 10 - @value = if val > 0 then val else 1 + @value = if val > 5 then val else 5 $.cb.value.call @ + Updater.timer.textContent = "-#{Updater.getInterval()}" verbose: -> if Conf['Verbose'] Updater.count.textContent = '+0' @@ -2084,14 +2088,14 @@ Updater = return unless @status in [0, 200, 304] # XXX 304 -> 0 in Opera - Updater.retryCoef += 10 * (Updater.retryCoef < 120) if Conf['Verbose'] Updater.count.textContent = @statusText Updater.count.className = 'warning' + Updater.unsuccessfulFetchCount++ return - Updater.retryCoef = 10 - Updater.timer.textContent = "-#{Conf['Interval']}" + Updater.unsuccessfulFetchCount++ + Updater.timer.textContent = "-#{Updater.getInterval()}" ### Status Code 304: Not modified @@ -2099,7 +2103,8 @@ Updater = This saves bandwidth for both the user and the servers, avoid unnecessary computation, and won't load images and scripts when parsing the response. ### - if @status is 304 + if @status in [0, 304] + # XXX 304 -> 0 in Opera if Conf['Verbose'] Updater.count.textContent = '+0' Updater.count.className = null @@ -2116,38 +2121,44 @@ Updater = break if reply.id[2..] <= id #make sure to not insert older posts nodes.push reply - count = nodes.length - scroll = Conf['Scrolling'] && Updater.scrollBG() && count && - lastPost.getBoundingClientRect().bottom - d.documentElement.clientHeight < 25 + count = nodes.length if Conf['Verbose'] Updater.count.textContent = "+#{count}" Updater.count.className = if count then 'new' else null + return unless count + + Updater.unsuccessfulFetchCount = 0 + Updater.timer.textContent = "-#{Updater.getInterval()}" + scroll = Conf['Scrolling'] && Updater.scrollBG() && + lastPost.getBoundingClientRect().bottom - d.documentElement.clientHeight < 25 $.add Updater.thread, nodes.reverse() if scroll nodes[0].scrollIntoView() + getInterval: -> + i = +Conf['Interval'] + j = Math.min @unsuccessfulFetchCount, 9 + Math.max i, [5, 10, 15, 20, 30, 60, 90, 120, 300, 600][j] + timeout: -> Updater.timeoutID = setTimeout Updater.timeout, 1000 n = 1 + Number Updater.timer.textContent if n is 0 Updater.update() - else if n is Updater.retryCoef - Updater.retryCoef += 10 * (Updater.retryCoef < 120) - Updater.retry() + else if n is Updater.getInterval() + Updater.unsuccessfulFetchCount++ + Updater.count.textContent = 'Retry' + Updater.count.className = null + Updater.update() else Updater.timer.textContent = n - retry: -> - @count.textContent = 'Retry' - @count.className = null - @update() - update: -> Updater.timer.textContent = 0 Updater.request?.abort() - #fool the cache + # Fool the cache. url = location.pathname + '?' + Date.now() Updater.request = $.ajax url, onload: Updater.cb.update, headers: 'If-Modified-Since': Updater.lastModified @@ -4005,6 +4016,9 @@ body.unscroll { border: none; background: transparent; } +#updater input[type=number] { + width: 4em; +} .new { background: lime; }