Basic implementation of the mutation method macro.

See http://www.w3.org/TR/dom/#mutation-method-macro

This decreases by ~30% the count of mutation observations.
There's most likely room for improvements, and maybe fixes.

Also fix an apparently old bug: thread unexpanding stopped at stubs.
This commit is contained in:
Nicolas Stepien 2012-02-18 00:54:17 +01:00
parent 0181eb7532
commit 1eece6a652
2 changed files with 108 additions and 110 deletions

View File

@ -71,8 +71,7 @@
*/ */
(function() { (function() {
var $, $$, DAY, Favicon, HOUR, MINUTE, Main, NAMESPACE, SECOND, Time, VERSION, anonymize, conf, config, d, engine, expandComment, expandThread, filter, flatten, g, getTitle, imgExpand, imgGif, imgHover, key, keybinds, log, nav, options, qr, quoteBacklink, quoteIndicators, quoteInline, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, strikethroughQuotes, threadHiding, threadStats, threading, titlePost, ui, unread, unxify, updater, val, watcher, _base, var $, $$, DAY, Favicon, HOUR, MINUTE, Main, NAMESPACE, SECOND, Time, VERSION, anonymize, conf, config, d, engine, expandComment, expandThread, filter, flatten, g, getTitle, imgExpand, imgGif, imgHover, key, keybinds, log, nav, options, qr, quoteBacklink, quoteIndicators, quoteInline, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, strikethroughQuotes, threadHiding, threadStats, threading, titlePost, ui, unread, unxify, updater, val, watcher, _base;
__slice = Array.prototype.slice;
config = { config = {
main: { main: {
@ -189,18 +188,16 @@
conf = {}; conf = {};
(flatten = function(parent, obj) { (flatten = function(parent, obj) {
var key, val, _results; var key, val;
if (obj instanceof Array) { if (obj instanceof Array) {
return conf[parent] = obj[0]; conf[parent] = obj[0];
} else if (typeof obj === 'object') { } else if (typeof obj === 'object') {
_results = [];
for (key in obj) { for (key in obj) {
val = obj[key]; val = obj[key];
_results.push(flatten(key, val)); flatten(key, val);
} }
return _results;
} else { } else {
return conf[parent] = obj; conf[parent] = obj;
} }
})(null, config); })(null, config);
@ -393,9 +390,6 @@
if (root == null) root = d.body; if (root == null) root = d.body;
return d.evaluate(path, root, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue; return d.evaluate(path, root, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
}, },
tn: function(s) {
return d.createTextNode(s);
},
replace: function(root, el) { replace: function(root, el) {
return root.parentNode.replaceChild(el, root); return root.parentNode.replaceChild(el, root);
}, },
@ -408,22 +402,30 @@
rm: function(el) { rm: function(el) {
return el.parentNode.removeChild(el); return el.parentNode.removeChild(el);
}, },
add: function() { tn: function(s) {
var child, children, parent, _i, _len; return d.createTextNode(s);
parent = arguments[0], children = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
for (_i = 0, _len = children.length; _i < _len; _i++) {
child = children[_i];
parent.appendChild(child);
}
}, },
prepend: function(parent, child) { nodes: function(nodes) {
return parent.insertBefore(child, parent.firstChild); var frag, node, _i, _len;
if (!(nodes instanceof Array)) return nodes;
frag = d.createDocumentFragment();
for (_i = 0, _len = nodes.length; _i < _len; _i++) {
node = nodes[_i];
frag.appendChild(node);
}
return frag;
},
add: function(parent, children) {
return parent.appendChild($.nodes(children));
},
prepend: function(parent, children) {
return parent.insertBefore($.nodes(children), parent.firstChild);
}, },
after: function(root, el) { after: function(root, el) {
return root.parentNode.insertBefore(el, root.nextSibling); return root.parentNode.insertBefore($.nodes(el), root.nextSibling);
}, },
before: function(root, el) { before: function(root, el) {
return root.parentNode.insertBefore(el, root); return root.parentNode.insertBefore($.nodes(el), root);
}, },
el: function(tag, properties) { el: function(tag, properties) {
var el; var el;
@ -678,14 +680,10 @@
if (quote.getAttribute('href') === quote.hash) { if (quote.getAttribute('href') === quote.hash) {
quote.pathname = "/" + g.BOARD + "/res/" + threadID; quote.pathname = "/" + g.BOARD + "/res/" + threadID;
} }
if (quote.hash.slice(1) === threadID) quote.innerHTML += '&nbsp;(OP)';
if (conf['Quote Preview']) {
$.on(quote, 'mouseover', quotePreview.mouseover);
$.on(quote, 'mousemove', ui.hover);
$.on(quote, 'mouseout', quotePreview.mouseout);
}
if (conf['Quote Inline']) $.on(quote, 'click', quoteInline.toggle);
} }
quoteIndicators.node(bq);
if (conf['Quote Preview']) quotePreview.node(bq);
if (conf['Quote Inline']) quoteInline.node(bq);
return $.replace(a.parentNode.parentNode, bq); return $.replace(a.parentNode.parentNode, bq);
} }
}; };
@ -742,10 +740,10 @@
} }
})(); })();
table = $.x("following::br[@clear]/preceding::table[" + num + "]", a); table = $.x("following::br[@clear]/preceding::table[" + num + "]", a);
while ((prev = table.previousSibling) && (prev.nodeName === 'TABLE')) { while ((prev = table.previousSibling) && (prev.nodeName !== 'A')) {
$.rm(prev); $.rm(prev);
} }
_ref2 = $$('.op a.backlink'); _ref2 = $$('.backlink', $('.op', thread));
_results = []; _results = [];
for (_i = 0, _len = _ref2.length; _i < _len; _i++) { for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
backlink = _ref2[_i]; backlink = _ref2[_i];
@ -759,7 +757,7 @@
} }
}, },
parse: function(req, pathname, thread, a) { parse: function(req, pathname, thread, a) {
var body, frag, href, link, next, quote, reply, _i, _j, _len, _len2, _ref, _ref2; var body, href, link, next, nodes, quote, reply, _i, _j, _len, _len2, _ref, _ref2;
if (req.status !== 200) { if (req.status !== 200) {
a.textContent = "" + req.status + " " + req.statusText; a.textContent = "" + req.status + " " + req.statusText;
$.off(a, 'click', expandThread.cb.toggle); $.off(a, 'click', expandThread.cb.toggle);
@ -769,7 +767,7 @@
body = $.el('body', { body = $.el('body', {
innerHTML: req.responseText innerHTML: req.responseText
}); });
frag = d.createDocumentFragment(); nodes = [];
_ref = $$('.reply', body); _ref = $$('.reply', body);
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
reply = _ref[_i]; reply = _ref[_i];
@ -785,12 +783,12 @@
link = $('.quotejs', reply); link = $('.quotejs', reply);
link.href = "res/" + thread.firstChild.id + "#" + reply.id; link.href = "res/" + thread.firstChild.id + "#" + reply.id;
link.nextSibling.href = "res/" + thread.firstChild.id + "#q" + reply.id; link.nextSibling.href = "res/" + thread.firstChild.id + "#q" + reply.id;
$.add(frag, reply.parentNode.parentNode.parentNode); nodes.push(reply.parentNode.parentNode.parentNode);
} }
while ((next = a.nextSibling) && !next.clear) { while ((next = a.nextSibling) && !next.clear) {
$.rm(next); $.rm(next);
} }
return $.before(next, frag); return $.before(next, nodes);
} }
}; };
@ -1145,7 +1143,7 @@
}); });
$.on(prev, 'click', nav.prev); $.on(prev, 'click', nav.prev);
$.on(next, 'click', nav.next); $.on(next, 'click', nav.next);
$.add(span, prev, $.tn(' '), next); $.add(span, [prev, $.tn(' '), next]);
return $.add(d.body, span); return $.add(d.body, span);
}, },
prev: function() { prev: function() {
@ -2439,7 +2437,7 @@
}; };
}, },
update: function() { update: function() {
var body, frag, id, newPosts, reply, scroll, _i, _len, _ref, _ref2; var body, id, newPosts, nodes, reply, scroll, _i, _len, _ref, _ref2;
if (this.status === 404) { if (this.status === 404) {
updater.timer.textContent = ''; updater.timer.textContent = '';
updater.count.textContent = 404; updater.count.textContent = 404;
@ -2484,14 +2482,14 @@
return; return;
} }
id = ((_ref = $('td[id]', updater.br.previousElementSibling)) != null ? _ref.id : void 0) || 0; id = ((_ref = $('td[id]', updater.br.previousElementSibling)) != null ? _ref.id : void 0) || 0;
frag = d.createDocumentFragment(); nodes = [];
_ref2 = $$('.reply', body).reverse(); _ref2 = $$('.reply', body).reverse();
for (_i = 0, _len = _ref2.length; _i < _len; _i++) { for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
reply = _ref2[_i]; reply = _ref2[_i];
if (reply.id <= id) break; if (reply.id <= id) break;
$.prepend(frag, reply.parentNode.parentNode.parentNode); nodes.push(reply.parentNode.parentNode.parentNode);
} }
newPosts = frag.childNodes.length; newPosts = nodes.length;
scroll = conf['Scrolling'] && updater.scrollBG() && newPosts && updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25; scroll = conf['Scrolling'] && updater.scrollBG() && newPosts && updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25;
if (conf['Verbose']) { if (conf['Verbose']) {
updater.count.textContent = '+' + newPosts; updater.count.textContent = '+' + newPosts;
@ -2501,7 +2499,7 @@
updater.count.className = 'new'; updater.count.className = 'new';
} }
} }
$.before(updater.br, frag); $.before(updater.br, nodes.reverse());
if (scroll) return updater.br.previousSibling.scrollIntoView(); if (scroll) return updater.br.previousSibling.scrollIntoView();
} }
}, },
@ -2562,9 +2560,9 @@
return $.sync('watched', watcher.refresh); return $.sync('watched', watcher.refresh);
}, },
refresh: function(watched) { refresh: function(watched) {
var board, div, favicon, frag, id, link, props, watchedBoard, x, _i, _j, _len, _len2, _ref, _ref2, _ref3, _results; var board, div, favicon, id, link, nodes, props, watchedBoard, x, _i, _j, _len, _len2, _ref, _ref2, _ref3;
watched || (watched = $.get('watched', {})); watched || (watched = $.get('watched', {}));
frag = d.createDocumentFragment(); nodes = [];
for (board in watched) { for (board in watched) {
_ref = watched[board]; _ref = watched[board];
for (id in _ref) { for (id in _ref) {
@ -2577,8 +2575,8 @@
link = $.el('a', props); link = $.el('a', props);
link.title = link.textContent; link.title = link.textContent;
div = $.el('div'); div = $.el('div');
$.add(div, x, $.tn(' '), link); $.add(div, [x, $.tn(' '), link]);
$.add(frag, div); nodes.push(div);
} }
} }
_ref2 = $$('div:not(.move)', watcher.dialog); _ref2 = $$('div:not(.move)', watcher.dialog);
@ -2586,20 +2584,18 @@
div = _ref2[_i]; div = _ref2[_i];
$.rm(div); $.rm(div);
} }
$.add(watcher.dialog, frag); $.add(watcher.dialog, nodes);
watchedBoard = watched[g.BOARD] || {}; watchedBoard = watched[g.BOARD] || {};
_ref3 = $$('img.favicon'); _ref3 = $$('img.favicon');
_results = [];
for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) { for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) {
favicon = _ref3[_j]; favicon = _ref3[_j];
id = favicon.nextSibling.name; id = favicon.nextSibling.name;
if (id in watchedBoard) { if (id in watchedBoard) {
_results.push(favicon.src = Favicon["default"]); favicon.src = Favicon["default"];
} else { } else {
_results.push(favicon.src = Favicon.empty); favicon.src = Favicon.empty;
} }
} }
return _results;
}, },
cb: { cb: {
toggle: function() { toggle: function() {
@ -2692,14 +2688,16 @@
}; };
}, },
node: function(root) { node: function(root) {
var img, link, span, _i, _len, _ref; var img, link, nodes, span, _i, _len, _ref;
if (root.className === 'inline' || !(span = $('.filesize', root))) return; if (root.className === 'inline' || !(span = $('.filesize', root))) return;
img = span.nextElementSibling.nextElementSibling; img = span.nextElementSibling.nextElementSibling;
nodes = [];
_ref = sauce.links; _ref = sauce.links;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
link = _ref[_i]; link = _ref[_i];
$.add(span, $.tn(' '), link(img)); nodes.push($.tn(' '), link(img));
} }
return $.add(span, nodes);
} }
}; };
@ -2850,7 +2848,7 @@
return g.callbacks.push(this.node); return g.callbacks.push(this.node);
}, },
node: function(root) { node: function(root) {
var a, container, el, id, link, qid, quote, quotes, _i, _len, _ref, _results; var a, container, el, id, link, qid, quote, quotes, _i, _len, _ref;
if (/\binline\b/.test(root.className)) return; if (/\binline\b/.test(root.className)) return;
quotes = {}; quotes = {};
_ref = $$('.quotelink', root); _ref = $$('.quotelink', root);
@ -2864,7 +2862,6 @@
className: root.hidden ? 'filtered backlink' : 'backlink', className: root.hidden ? 'filtered backlink' : 'backlink',
textContent: quoteBacklink.funk(id) textContent: quoteBacklink.funk(id)
}); });
_results = [];
for (qid in quotes) { for (qid in quotes) {
if (!(el = $.id(qid)) || el.className === 'op' && !conf['OP Backlinks']) { if (!(el = $.id(qid)) || el.className === 'op' && !conf['OP Backlinks']) {
continue; continue;
@ -2879,9 +2876,8 @@
root = $('.reportbutton', el) || $('span[id]', el); root = $('.reportbutton', el) || $('span[id]', el);
$.after(root, container); $.after(root, container);
} }
_results.push($.add(container, $.tn(' '), link)); $.add(container, [$.tn(' '), link]);
} }
return _results;
} }
}; };
@ -2890,16 +2886,14 @@
return g.callbacks.push(this.node); return g.callbacks.push(this.node);
}, },
node: function(root) { node: function(root) {
var quote, _i, _len, _ref, _results; var quote, _i, _len, _ref;
_ref = $$('.quotelink, .backlink', root); _ref = $$('.quotelink, .backlink', root);
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quote = _ref[_i]; quote = _ref[_i];
if (!quote.hash) continue; if (!quote.hash) continue;
quote.removeAttribute('onclick'); quote.removeAttribute('onclick');
_results.push($.on(quote, 'click', quoteInline.toggle)); $.on(quote, 'click', quoteInline.toggle);
} }
return _results;
}, },
toggle: function(e) { toggle: function(e) {
var id; var id;
@ -3106,12 +3100,12 @@
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
quote = _ref[_i]; quote = _ref[_i];
if (conf['Indicate OP quote'] && quote.hash.slice(1) === tid) { if (conf['Indicate OP quote'] && quote.hash.slice(1) === tid) {
quote.innerHTML += '&nbsp;(OP)'; $.add(quote, $.tn('\u00A0(OP)'));
return; return;
} }
path = quote.pathname; path = quote.pathname;
if (conf['Indicate Cross-thread Quotes'] && path.lastIndexOf("/" + tid) === -1 && path.indexOf("/" + g.BOARD + "/") === 0) { if (conf['Indicate Cross-thread Quotes'] && path.lastIndexOf("/" + tid) === -1 && path.indexOf("/" + g.BOARD + "/") === 0) {
quote.innerHTML += '&nbsp;(Cross-thread)'; $.add(quote, $.tn('\u00A0(Cross-thread)'));
} }
} }
} }
@ -3130,8 +3124,7 @@
innerHTML: '[&nbsp;!&nbsp;]', innerHTML: '[&nbsp;!&nbsp;]',
href: 'javascript:;' href: 'javascript:;'
}); });
$.after(span, a); $.after(span, [$.tn(' '), a]);
$.after(span, $.tn(' '));
} }
return $.on(a, 'click', reportButton.report); return $.on(a, 'click', reportButton.report);
}, },
@ -3372,24 +3365,20 @@
return imgExpand.toggle(this); return imgExpand.toggle(this);
}, },
all: function() { all: function() {
var thumb, _i, _j, _len, _len2, _ref, _ref2, _results, _results2; var thumb, _i, _j, _len, _len2, _ref, _ref2;
imgExpand.on = this.checked; imgExpand.on = this.checked;
if (imgExpand.on) { if (imgExpand.on) {
_ref = $$('img[md5]'); _ref = $$('img[md5]');
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
thumb = _ref[_i]; thumb = _ref[_i];
_results.push(imgExpand.expand(thumb)); imgExpand.expand(thumb);
} }
return _results;
} else { } else {
_ref2 = $$('img[md5][hidden]'); _ref2 = $$('img[md5][hidden]');
_results2 = [];
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
thumb = _ref2[_j]; thumb = _ref2[_j];
_results2.push(imgExpand.contract(thumb)); imgExpand.contract(thumb);
} }
return _results2;
} }
}, },
typeChange: function() { typeChange: function() {

View File

@ -123,6 +123,7 @@ conf = {}
flatten key, val flatten key, val
else # string or number else # string or number
conf[parent] = obj conf[parent] = obj
return
) null, config ) null, config
NAMESPACE = '4chan_x.' NAMESPACE = '4chan_x.'
@ -275,8 +276,6 @@ $.extend $,
x: (path, root=d.body) -> x: (path, root=d.body) ->
d.evaluate(path, root, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null). d.evaluate(path, root, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).
singleNodeValue singleNodeValue
tn: (s) ->
d.createTextNode s
replace: (root, el) -> replace: (root, el) ->
root.parentNode.replaceChild el, root root.parentNode.replaceChild el, root
addClass: (el, className) -> addClass: (el, className) ->
@ -285,16 +284,23 @@ $.extend $,
el.classList.remove className el.classList.remove className
rm: (el) -> rm: (el) ->
el.parentNode.removeChild el el.parentNode.removeChild el
add: (parent, children...) -> tn: (s) ->
for child in children d.createTextNode s
parent.appendChild child nodes: (nodes) ->
return unless nodes instanceof Array
prepend: (parent, child) -> return nodes
parent.insertBefore child, parent.firstChild frag = d.createDocumentFragment()
for node in nodes
frag.appendChild node
frag
add: (parent, children) ->
parent.appendChild $.nodes children
prepend: (parent, children) ->
parent.insertBefore $.nodes(children), parent.firstChild
after: (root, el) -> after: (root, el) ->
root.parentNode.insertBefore el, root.nextSibling root.parentNode.insertBefore $.nodes(el), root.nextSibling
before: (root, el) -> before: (root, el) ->
root.parentNode.insertBefore el, root root.parentNode.insertBefore $.nodes(el), root
el: (tag, properties) -> el: (tag, properties) ->
el = d.createElement tag el = d.createElement tag
$.extend el, properties if properties $.extend el, properties if properties
@ -496,14 +502,11 @@ expandComment =
for quote in $$ '.quotelink', bq for quote in $$ '.quotelink', bq
if quote.getAttribute('href') is quote.hash if quote.getAttribute('href') is quote.hash
quote.pathname = "/#{g.BOARD}/res/#{threadID}" quote.pathname = "/#{g.BOARD}/res/#{threadID}"
if quote.hash[1..] is threadID quoteIndicators.node bq
quote.innerHTML += '&nbsp;(OP)' if conf['Quote Preview']
if conf['Quote Preview'] quotePreview.node bq
$.on quote, 'mouseover', quotePreview.mouseover if conf['Quote Inline']
$.on quote, 'mousemove', ui.hover quoteInline.node bq
$.on quote, 'mouseout', quotePreview.mouseout
if conf['Quote Inline']
$.on quote, 'click', quoteInline.toggle
$.replace a.parentNode.parentNode, bq $.replace a.parentNode.parentNode, bq
expandThread = expandThread =
@ -545,9 +548,9 @@ expandThread =
when 't' then 1 when 't' then 1
else 5 else 5
table = $.x "following::br[@clear]/preceding::table[#{num}]", a table = $.x "following::br[@clear]/preceding::table[#{num}]", a
while (prev = table.previousSibling) and (prev.nodeName is 'TABLE') while (prev = table.previousSibling) and (prev.nodeName isnt 'A')
$.rm prev $.rm prev
for backlink in $$ '.op a.backlink' for backlink in $$ '.backlink', $ '.op', thread
$.rm backlink if !$.id backlink.hash[1..] $.rm backlink if !$.id backlink.hash[1..]
@ -562,7 +565,7 @@ expandThread =
body = $.el 'body', body = $.el 'body',
innerHTML: req.responseText innerHTML: req.responseText
frag = d.createDocumentFragment() nodes = []
for reply in $$ '.reply', body for reply in $$ '.reply', body
for quote in $$ '.quotelink', reply for quote in $$ '.quotelink', reply
if (href = quote.getAttribute('href')) is quote.hash #add pathname to normal quotes if (href = quote.getAttribute('href')) is quote.hash #add pathname to normal quotes
@ -572,11 +575,11 @@ expandThread =
link = $ '.quotejs', reply link = $ '.quotejs', reply
link.href = "res/#{thread.firstChild.id}##{reply.id}" link.href = "res/#{thread.firstChild.id}##{reply.id}"
link.nextSibling.href = "res/#{thread.firstChild.id}#q#{reply.id}" link.nextSibling.href = "res/#{thread.firstChild.id}#q#{reply.id}"
$.add frag, reply.parentNode.parentNode.parentNode nodes.push reply.parentNode.parentNode.parentNode
# eat everything, then replace with fresh full posts # eat everything, then replace with fresh full posts
while (next = a.nextSibling) and not next.clear #br[clear] while (next = a.nextSibling) and not next.clear #br[clear]
$.rm next $.rm next
$.before next, frag $.before next, nodes
replyHiding = replyHiding =
init: -> init: ->
@ -828,7 +831,7 @@ nav =
$.on prev, 'click', nav.prev $.on prev, 'click', nav.prev
$.on next, 'click', nav.next $.on next, 'click', nav.next
$.add span, prev, $.tn(' '), next $.add span, [prev, $.tn(' '), next]
$.add d.body, span $.add d.body, span
prev: -> prev: ->
@ -1973,13 +1976,13 @@ updater =
return return
id = $('td[id]', updater.br.previousElementSibling)?.id or 0 id = $('td[id]', updater.br.previousElementSibling)?.id or 0
frag = d.createDocumentFragment() nodes = []
for reply in $$('.reply', body).reverse() for reply in $$('.reply', body).reverse()
if reply.id <= id #make sure to not insert older posts if reply.id <= id #make sure to not insert older posts
break break
$.prepend frag, reply.parentNode.parentNode.parentNode #table nodes.push reply.parentNode.parentNode.parentNode #table
newPosts = frag.childNodes.length newPosts = nodes.length
scroll = conf['Scrolling'] && updater.scrollBG() && newPosts && scroll = conf['Scrolling'] && updater.scrollBG() && newPosts &&
updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25 updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25
if conf['Verbose'] if conf['Verbose']
@ -1989,7 +1992,7 @@ updater =
else else
updater.count.className = 'new' updater.count.className = 'new'
$.before updater.br, frag $.before updater.br, nodes.reverse()
if scroll if scroll
updater.br.previousSibling.scrollIntoView() updater.br.previousSibling.scrollIntoView()
@ -2043,7 +2046,7 @@ watcher =
refresh: (watched) -> refresh: (watched) ->
watched or= $.get 'watched', {} watched or= $.get 'watched', {}
frag = d.createDocumentFragment() nodes = []
for board of watched for board of watched
for id, props of watched[board] for id, props of watched[board]
x = $.el 'a', x = $.el 'a',
@ -2054,12 +2057,12 @@ watcher =
link.title = link.textContent link.title = link.textContent
div = $.el 'div' div = $.el 'div'
$.add div, x, $.tn(' '), link $.add div, [x, $.tn(' '), link]
$.add frag, div nodes.push div
for div in $$ 'div:not(.move)', watcher.dialog for div in $$ 'div:not(.move)', watcher.dialog
$.rm div $.rm div
$.add watcher.dialog, frag $.add watcher.dialog, nodes
watchedBoard = watched[g.BOARD] or {} watchedBoard = watched[g.BOARD] or {}
for favicon in $$ 'img.favicon' for favicon in $$ 'img.favicon'
@ -2068,6 +2071,7 @@ watcher =
favicon.src = Favicon.default favicon.src = Favicon.default
else else
favicon.src = Favicon.empty favicon.src = Favicon.empty
return
cb: cb:
toggle: -> toggle: ->
@ -2139,9 +2143,10 @@ sauce =
node: (root) -> node: (root) ->
return if root.className is 'inline' or not span = $ '.filesize', root return if root.className is 'inline' or not span = $ '.filesize', root
img = span.nextElementSibling.nextElementSibling img = span.nextElementSibling.nextElementSibling
nodes = []
for link in sauce.links for link in sauce.links
$.add span, $.tn(' '), link img nodes.push $.tn(' '), link img
return $.add span, nodes
revealSpoilers = revealSpoilers =
init: -> init: ->
@ -2273,7 +2278,8 @@ quoteBacklink =
container = $.el 'span', className: 'container' container = $.el 'span', className: 'container'
root = $('.reportbutton', el) or $('span[id]', el) root = $('.reportbutton', el) or $('span[id]', el)
$.after root, container $.after root, container
$.add container, $.tn(' '), link $.add container, [$.tn(' '), link]
return
quoteInline = quoteInline =
init: -> init: ->
@ -2283,6 +2289,7 @@ quoteInline =
continue unless quote.hash continue unless quote.hash
quote.removeAttribute 'onclick' quote.removeAttribute 'onclick'
$.on quote, 'click', quoteInline.toggle $.on quote, 'click', quoteInline.toggle
return
toggle: (e) -> toggle: (e) ->
return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0 return if e.shiftKey or e.altKey or e.ctrlKey or e.metaKey or e.button isnt 0
e.preventDefault() e.preventDefault()
@ -2435,12 +2442,14 @@ quoteIndicators =
tid = g.THREAD_ID or $.x('ancestor::div', root).firstChild.id tid = g.THREAD_ID or $.x('ancestor::div', root).firstChild.id
for quote in $$ '.quotelink', root for quote in $$ '.quotelink', root
if conf['Indicate OP quote'] and quote.hash[1..] is tid if conf['Indicate OP quote'] and quote.hash[1..] is tid
quote.innerHTML += '&nbsp;(OP)' # \u00A0 is nbsp
$.add quote, $.tn '\u00A0(OP)'
return return
path = quote.pathname path = quote.pathname
#if quote leads to a different thread id and is located on the same board (index 0) #if quote leads to a different thread id and is located on the same board (index 0)
if conf['Indicate Cross-thread Quotes'] and path.lastIndexOf("/#{tid}") is -1 and path.indexOf("/#{g.BOARD}/") is 0 if conf['Indicate Cross-thread Quotes'] and path.lastIndexOf("/#{tid}") is -1 and path.indexOf("/#{g.BOARD}/") is 0
quote.innerHTML += '&nbsp;(Cross-thread)' # \u00A0 is nbsp
$.add quote, $.tn '\u00A0(Cross-thread)'
return return
reportButton = reportButton =
@ -2453,8 +2462,7 @@ reportButton =
className: 'reportbutton' className: 'reportbutton'
innerHTML: '[&nbsp;!&nbsp;]' innerHTML: '[&nbsp;!&nbsp;]'
href: 'javascript:;' href: 'javascript:;'
$.after span, a $.after span, [$.tn(' '), a]
$.after span, $.tn(' ')
$.on a, 'click', reportButton.report $.on a, 'click', reportButton.report
report: -> report: ->
url = "http://sys.4chan.org/#{g.BOARD}/imgboard.php?mode=report&no=#{$.x('preceding-sibling::input', @).name}" url = "http://sys.4chan.org/#{g.BOARD}/imgboard.php?mode=report&no=#{$.x('preceding-sibling::input', @).name}"
@ -2647,6 +2655,7 @@ imgExpand =
else #contract else #contract
for thumb in $$ 'img[md5][hidden]' for thumb in $$ 'img[md5][hidden]'
imgExpand.contract thumb imgExpand.contract thumb
return
typeChange: -> typeChange: ->
switch @value switch @value
when 'full' when 'full'