From b090ad73474e905e76cb9ce4af97ffa7358f12a3 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 1 Mar 2012 18:29:26 +0100 Subject: [PATCH 01/11] Release 2.28.0. --- 4chan_x.user.js | 6 +++--- Cakefile | 2 +- changelog | 4 +++- latest.js | 2 +- script.coffee | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index ed337dab3..89e89222c 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan x -// @version 2.27.1 +// @version 2.28.0 // @namespace aeosynth // @description Adds various features. // @copyright 2009-2011 James Campos @@ -20,7 +20,7 @@ * Copyright (c) 2009-2011 James Campos * Copyright (c) 2012 Nicolas Stepien * http://mayhemydg.github.com/4chan-x/ - * 4chan X 2.27.1 + * 4chan X 2.28.0 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -209,7 +209,7 @@ NAMESPACE = '4chan_x.'; - VERSION = '2.27.1'; + VERSION = '2.28.0'; SECOND = 1000; diff --git a/Cakefile b/Cakefile index cfbec6a85..aa2716dd6 100644 --- a/Cakefile +++ b/Cakefile @@ -2,7 +2,7 @@ {exec} = require 'child_process' fs = require 'fs' -VERSION = '2.27.1' +VERSION = '2.28.0' HEADER = """ // ==UserScript== diff --git a/changelog b/changelog index 9cf7de130..efe730803 100644 --- a/changelog +++ b/changelog @@ -1,4 +1,6 @@ master + +2.28.0 - ahodesuka Reply/Thread File Info Formatting: - Link: %l, %L (Original file names are shown inside threads). @@ -6,7 +8,7 @@ master - Resolution/PDF: %r - Original filename: %n, %N. - noface - Update imagelimit for mlp. + Update imagelimit for /mlp/. Fix stubs if poster has unique ID. - Mayhem You can now filter or highlight admin/mod posts. diff --git a/latest.js b/latest.js index 22d1d4f89..337aa53b1 100644 --- a/latest.js +++ b/latest.js @@ -1 +1 @@ -postMessage({version:'2.27.1'},'*'); +postMessage({version:'2.28.0'},'*'); diff --git a/script.coffee b/script.coffee index a3d0a2d6f..f1ed0859e 100644 --- a/script.coffee +++ b/script.coffee @@ -161,7 +161,7 @@ conf = {} ) null, config NAMESPACE = '4chan_x.' -VERSION = '2.27.1' +VERSION = '2.28.0' SECOND = 1000 MINUTE = 60*SECOND HOUR = 60*MINUTE From 0f6d6079028e76c6f064a2fce19458b9900bb5a4 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 2 Mar 2012 22:31:53 +0100 Subject: [PATCH 02/11] Actually useful error alerts. --- 4chan_x.user.js | 4 +++- script.coffee | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 89e89222c..5f4fb14c5 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -3890,7 +3890,9 @@ callback(node); } } catch (err) { - if (notify) alert(err.message); + if (notify) { + alert("4chan X error: " + err.message + "\nhttp://mayhemydg.github.com/4chan-x/#bug-report\n\n" + err.stack); + } } } }, diff --git a/script.coffee b/script.coffee index f1ed0859e..da72d9f53 100644 --- a/script.coffee +++ b/script.coffee @@ -3195,7 +3195,7 @@ Main = try callback node for node in nodes catch err - alert err.message if notify + alert "4chan X error: #{err.message}\nhttp://mayhemydg.github.com/4chan-x/#bug-report\n\n#{err.stack}" if notify return observer: (mutations) -> nodes = [] From 63f48aeba6278e62b86b8bd10a44d7569c9f1472 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 02:35:21 +0100 Subject: [PATCH 03/11] Preparse posts; global performance improvements. This is mostly efficient when parsing multiple posts at once (when opening a thread, or expanding a thread if mutation observers are working). --- 4chan_x.user.js | 276 +++++++++++++++++++++++++++--------------------- script.coffee | 244 +++++++++++++++++++++++------------------- 2 files changed, 287 insertions(+), 233 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 5f4fb14c5..9e2680ae7 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -72,7 +72,7 @@ */ (function() { - var $, $$, DAY, Favicon, FileInfo, 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, updater, val, watcher, _base; + var $, $$, DAY, Favicon, FileInfo, 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, quoteDR, quoteInline, quoteOP, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, strikethroughQuotes, threadHiding, threadStats, threading, titlePost, ui, unread, updater, val, watcher, _base; config = { main: { @@ -575,8 +575,9 @@ if (Object.keys(this.filters).length) return g.callbacks.push(this.node); }, createFilter: function(regexp, op, hl, top) { - return function(root, value, isOP) { - var firstThread, thisThread; + return function(post, value) { + var el, firstThread, isOP, thisThread; + el = post.el, isOP = post.isOP; if (isOP && op === 'no' || !isOP && op === 'only') return false; if (typeof regexp === 'string') { if (regexp !== value) return false; @@ -585,12 +586,12 @@ } if (hl) { if (isOP) { - $.addClass(root, hl); + $.addClass(el, hl); } else { - $.addClass(root.parentNode, hl); + $.addClass(el.parentNode, hl); } if (isOP && top && !g.REPLY) { - thisThread = root.parentNode; + thisThread = el.parentNode; if (firstThread = $('div[class=op]')) { $.before(firstThread.parentNode, [thisThread, thisThread.nextElementSibling]); } @@ -598,86 +599,85 @@ return false; } if (isOP) { - if (!g.REPLY) threadHiding.hideHide(root.parentNode); + if (!g.REPLY) threadHiding.hideHide(el.parentNode); } else { - replyHiding.hideHide(root); + replyHiding.hideHide(el); } return true; }; }, - node: function(root) { - var Filter, isOP, key, klass, value, _i, _len, _ref; - klass = root.className; - if (/\binlined\b/.test(klass)) return; - if (!(isOP = klass === 'op')) root = $('td[id]', root); + node: function(post) { + var Filter, key, value, _i, _len, _ref; + if (post.isInlined) return; for (key in filter.filters) { - value = filter[key](root, isOP); + value = filter[key](post); if (value === false) continue; _ref = filter.filters[key]; for (_i = 0, _len = _ref.length; _i < _len; _i++) { Filter = _ref[_i]; - if (Filter(root, value, isOP)) return; + if (Filter(post, value)) return; } } }, - name: function(root, isOP) { + name: function(post) { var name; - name = isOP ? $('.postername', root) : $('.commentpostername', root); + name = post.isOP ? $('.postername', post.el) : $('.commentpostername', post.el); return name.textContent; }, - tripcode: function(root) { + tripcode: function(post) { var trip; - if (trip = $('.postertrip', root)) return trip.textContent; + if (trip = $('.postertrip', post.el)) return trip.textContent; return false; }, - mod: function(root, isOP) { + mod: function(post) { var mod; - if (mod = (isOP ? $('.commentpostername', root) : $('.commentpostername ~ .commentpostername', root))) { + if (mod = (post.isOP ? $('.commentpostername', post.el) : $('.commentpostername ~ .commentpostername', post.el))) { return mod.textContent; } return false; }, - email: function(root) { + email: function(post) { var mail; - if (mail = $('.linkmail', root)) return mail.href; + if (mail = $('.linkmail', post.el)) return mail.href; return false; }, - subject: function(root, isOP) { + subject: function(post) { var sub; - sub = isOP ? $('.filetitle', root) : $('.replytitle', root); + sub = post.isOP ? $('.filetitle', post.el) : $('.replytitle', post.el); return sub.textContent; }, - comment: function(root) { - var data, i, len, nodes, text; + comment: function(post) { + var data, i, nodes, text, _ref; text = []; - nodes = d.evaluate('.//br|.//text()', root.lastChild, null, 7, null); - i = 0; - len = nodes.snapshotLength; - while (i < len) { - text.push((data = nodes.snapshotItem(i++).data) ? data : '\n'); + nodes = d.evaluate('.//br|.//text()', post.bq, null, 7, null); + for (i = 0, _ref = nodes.snapshotLength; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { + text.push((data = nodes.snapshotItem(i).data) ? data : '\n'); } return text.join(''); }, - filename: function(root) { + filename: function(post) { var file; - if (file = $('.filesize > span', root)) return file.title; + if (file = $('span', post.filesize)) return file.title; return false; }, - dimensions: function(root) { - var match, span; - if ((span = $('.filesize', root)) && (match = span.textContent.match(/\d+x\d+/))) { + dimensions: function(post) { + var filesize, match; + filesize = post.filesize; + if (filesize && (match = filesize.textContent.match(/\d+x\d+/))) { return match[0]; } return false; }, - filesize: function(root) { + filesize: function(post) { var img; - if (img = $('img[md5]', root)) return img.alt; + img = post.img; + if (img) return img.alt; return false; }, - md5: function(root) { + md5: function(post) { var img; - if (img = $('img[md5]', root)) return img.getAttribute('md5'); + img = post.img; + if (img) return img.getAttribute('md5'); return false; } }; @@ -686,15 +686,15 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var el, quote, _i, _len, _ref; - if (root.className === 'inline') return; - _ref = $$('.quotelink', root); + if (post.isInlined) return; + _ref = post.quotes; for (_i = 0, _len = _ref.length; _i < _len; _i++) { quote = _ref[_i]; if ((el = $.id(quote.hash.slice(1))) && el.parentNode.parentNode.parentNode.hidden) { $.addClass(quote, 'filtered'); - if (conf['Recursive Filtering']) root.hidden = true; + if (conf['Recursive Filtering']) post.root.hidden = true; } } } @@ -866,9 +866,10 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var a, dd, id, reply; - if (!(dd = $('.doubledash', root))) return; + if (post["class"]) return; + dd = $('.doubledash', post.root); dd.className = 'replyhider'; a = $.el('a', { textContent: '[ - ]', @@ -1312,8 +1313,8 @@ $.on(d, 'dragstart', qr.drag); return $.on(d, 'dragend', qr.drag); }, - node: function(root) { - return $.on($('.quotejs + .quotejs', root), 'click', qr.quote); + node: function(post) { + return $.on($('.quotejs + .quotejs', post.el), 'click', qr.quote); }, open: function() { if (qr.el) { @@ -2745,11 +2746,11 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var name, trip; - name = $('.commentpostername, .postername', root); + name = $('.commentpostername, .postername', post.el); name.textContent = 'Anonymous'; - if (trip = $('.postertrip', root)) { + if (trip = $('.postertrip', post.el)) { if (trip.parentNode.nodeName === 'A') { return $.rm(trip.parentNode); } else { @@ -2797,17 +2798,18 @@ }); }; }, - node: function(root) { - var img, link, nodes, span, _i, _len, _ref; - if (root.className === 'inline' || !(span = $('.filesize', root))) return; - img = span.nextElementSibling.nextElementSibling; + node: function(post) { + var img, link, nodes, _i, _len, _ref; + img = post.img; + if (post["class"] === 'inline' || !img) return; + img = img.parentNode; nodes = []; _ref = sauce.links; for (_i = 0, _len = _ref.length; _i < _len; _i++) { link = _ref[_i]; nodes.push($.tn(' '), link(img)); } - return $.add(span, nodes); + return $.add(post.filesize, nodes); } }; @@ -2815,11 +2817,12 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var img; - if (!(img = $('img[alt^=Spoil]', root)) || root.className === 'inline') { - return; - } + img = { + post: post + }; + if (!(img && /^Spoil/.test(img.alt)) || post["class"] === 'inline') return; img.removeAttribute('height'); img.removeAttribute('width'); return img.src = "http://thumbs.4chan.org" + (img.parentNode.pathname.replace(/src(\/\d+).+$/, 'thumb$1s.jpg')); @@ -2844,10 +2847,10 @@ }; return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var node, time; - if (root.className === 'inline') return; - node = $('.posttime', root) || $('span[id]', root).previousSibling; + if (post["class"] === 'inline') return; + node = $('.posttime', post.el) || $('span[id]', post.el).previousSibling; Time.date = Time.parse(node); time = $.el('time', { textContent: ' ' + Time.funk(Time) + ' ' @@ -2937,9 +2940,9 @@ this.setFormats(); return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var fullname, link, node, regexp, resolution, shortname, size, type, unit, _, _ref; - if (root.className === 'inline' || !(node = $('.filesize', root))) return; + if (post["class"] === 'inline' || !(node = post.filesize)) return; type = node.childElementCount === 2 ? 0 : 1; regexp = type ? /^File: (<.+>)-\((?:Spoiler Image, )?([\d\.]+) (\w+), (\d+x\d+|PDF)/ : /^File: (<.+>)-\((?:Spoiler Image, )?([\d\.]+) (\w+), (\d+x\d+|PDF), ([^<]+)/; _ref = node.innerHTML.match(regexp), _ = _ref[0], link = _ref[1], size = _ref[2], unit = _ref[3], resolution = _ref[4], fullname = _ref[5], shortname = _ref[6]; @@ -3059,20 +3062,19 @@ quoteBacklink.funk = Function('id', "return '" + format + "'"); return g.callbacks.push(this.node); }, - node: function(root) { - var a, container, el, id, link, qid, quote, quotes, _i, _len, _ref; - if (/\binline\b/.test(root.className)) return; + node: function(post) { + var a, container, el, link, qid, quote, quotes, root, _i, _len, _ref; + if (post.isInlined) return; quotes = {}; - _ref = $$('.quotelink', root); + _ref = post.quotes; for (_i = 0, _len = _ref.length; _i < _len; _i++) { quote = _ref[_i]; if (qid = quote.hash.slice(1)) quotes[qid] = true; } - id = $('input', root).name; a = $.el('a', { - href: "#" + id, - className: root.hidden ? 'filtered backlink' : 'backlink', - textContent: quoteBacklink.funk(id) + href: "#" + post.id, + className: post.root.hidden ? 'filtered backlink' : 'backlink', + textContent: quoteBacklink.funk(post.id) }); for (qid in quotes) { if (!(el = $.id(qid)) || el.className === 'op' && !conf['OP Backlinks']) { @@ -3097,9 +3099,9 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var quote, _i, _len, _ref; - _ref = $$('.quotelink, .backlink', root); + _ref = post.quotes.concat(post.backlinks); for (_i = 0, _len = _ref.length; _i < _len; _i++) { quote = _ref[_i]; if (!quote.hash) continue; @@ -3223,9 +3225,9 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var quote, _i, _len, _ref; - _ref = $$('.quotelink, .backlink', root); + _ref = post.quotes.concat(post.backlinks); for (_i = 0, _len = _ref.length; _i < _len; _i++) { quote = _ref[_i]; if (quote.hash) $.on(quote, 'mouseover', quotePreview.mouseover); @@ -3301,24 +3303,36 @@ } }; - quoteIndicators = { + quoteOP = { init: function() { return g.callbacks.push(this.node); }, - node: function(root) { - var hash, path, quote, tid, _i, _len, _ref; - if (root.className === 'inline') return; - tid = g.THREAD_ID || $.x('ancestor::div[contains(@class,"thread")]', root).firstChild.id; - _ref = $$('.quotelink', root); + node: function(post) { + var quote, _i, _len, _ref; + if (post["class"] === 'inline') return; + _ref = post.quotes; for (_i = 0, _len = _ref.length; _i < _len; _i++) { quote = _ref[_i]; - if (!(hash = quote.hash.slice(1))) continue; - if (conf['Indicate OP quote'] && hash === tid) { + if (quote.hash.slice(1) === post.threadId) { $.add(quote, $.tn('\u00A0(OP)')); - continue; } - path = quote.pathname; - if (conf['Indicate Cross-thread Quotes'] && path.lastIndexOf("/" + tid) === -1 && path.indexOf("/" + g.BOARD + "/") === 0) { + } + } + }; + + quoteDR = { + init: function() { + return g.callbacks.push(this.node); + }, + node: function(post) { + var path, quote, _i, _len, _ref; + if (post["class"] === 'inline') return; + _ref = post.quotes; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + quote = _ref[_i]; + if (!quote.hash) continue; + path = quote.pathname.split('/'); + if (path[1] === g.BOARD && path[3] !== post.threadId) { $.add(quote, $.tn('\u00A0(Cross-thread)')); } } @@ -3329,16 +3343,15 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { - var a, span; - if (!(a = $('.reportbutton', root))) { - span = $('span[id]', root); + node: function(post) { + var a; + if (!(a = $('.reportbutton', post.el))) { a = $.el('a', { className: 'reportbutton', innerHTML: '[ ! ]', href: 'javascript:;' }); - $.after(span, [$.tn(' '), a]); + $.after($('span[id]', post.el), [$.tn(' '), a]); } return $.on(a, 'click', reportButton.report); }, @@ -3372,11 +3385,11 @@ })(); return g.callbacks.push(this.node); }, - node: function(root) { + node: function(post) { var imgcount; - if (/\binline\b/.test(root.className)) return; + if (post.isInlined) return; $.id('postcount').textContent = ++threadStats.posts; - if (!$('img[md5]', root)) return; + if (!post.img) return; imgcount = $.id('imagecount'); imgcount.textContent = ++threadStats.images; if (threadStats.images > threadStats.imgLimit) { @@ -3393,9 +3406,9 @@ return g.callbacks.push(this.node); }, replies: [], - node: function(root) { - if (root.hidden || root.className) return; - unread.replies.push(root); + node: function(post) { + if (post.root.hidden || post["class"]) return; + unread.replies.push(post.root); return unread.update(); }, scroll: function() { @@ -3530,10 +3543,9 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { - var thumb; - if (!(thumb = $('img[md5]', root))) return; - return $.on(thumb, 'mouseover', imgHover.mouseover); + node: function(post) { + if (!post.img) return; + return $.on(post.img, 'mouseover', imgHover.mouseover); }, mouseover: function() { ui.el = $.el('img', { @@ -3565,14 +3577,14 @@ init: function() { return g.callbacks.push(this.node); }, - node: function(root) { - var img, src, thumb; - if (root.hidden || !(thumb = $('img[md5]', root))) return; - src = thumb.parentNode.href; + node: function(post) { + var img, src; + if (post.root.hidden || post.img) return; + src = post.img.parentNode.href; if (/gif$/.test(src) && !/spoiler/.test(src)) { img = $.el('img'); $.on(img, 'load', function() { - return thumb.src = src; + return post.img.src = src; }); return img.src = src; } @@ -3584,12 +3596,12 @@ g.callbacks.push(this.node); return imgExpand.dialog(); }, - node: function(root) { - var a, thumb; - if (!(thumb = $('img[md5]', root))) return; - a = thumb.parentNode; + node: function(post) { + var a; + if (!post.img) return; + a = post.img.parentNode; $.on(a, 'click', imgExpand.cb.toggle); - if (imgExpand.on && !root.hidden && root.className !== 'inline') { + if (imgExpand.on && !post.root.hidden && post["class"] !== 'inline') { return imgExpand.expand(a.firstChild); } }, @@ -3814,9 +3826,8 @@ if (conf['Quote Inline']) quoteInline.init(); if (conf['Quote Preview']) quotePreview.init(); if (conf['Quote Backlinks']) quoteBacklink.init(); - if (conf['Indicate OP quote'] || conf['Indicate Cross-thread Quotes']) { - quoteIndicators.init(); - } + if (conf['Indicate OP quote']) quoteOP.init(); + if (conf['Indicate Cross-thread Quotes']) quoteDR.init(); return $.ready(Main.ready); }, ready: function() { @@ -3880,14 +3891,33 @@ } }, node: function(nodes, notify) { - var callback, node, _i, _j, _len, _len2, _ref; + var callback, klass, node, post, posts, _i, _j, _k, _len, _len2, _len3, _ref; + posts = []; + for (_i = 0, _len = nodes.length; _i < _len; _i++) { + node = nodes[_i]; + klass = node.className; + posts.push({ + root: node, + el: klass === 'op' ? node : $('td[id]', node), + "class": klass, + id: $('input', node).name, + threadId: g.THREAD_ID || $.x('ancestor::div[contains(@class,"thread")]', node).firstChild.id, + isOP: klass === 'op', + isInlined: /\binlined\b/.test(klass), + filesize: $('.filesize', node), + img: $('img[md5]', node), + quotes: $$('.quotelink', node), + backlinks: $$('.backlink', node), + bq: node.lastChild + }); + } _ref = g.callbacks; - for (_i = 0, _len = _ref.length; _i < _len; _i++) { - callback = _ref[_i]; + for (_j = 0, _len2 = _ref.length; _j < _len2; _j++) { + callback = _ref[_j]; try { - for (_j = 0, _len2 = nodes.length; _j < _len2; _j++) { - node = nodes[_j]; - callback(node); + for (_k = 0, _len3 = posts.length; _k < _len3; _k++) { + post = posts[_k]; + callback(post); } } catch (err) { if (notify) { diff --git a/script.coffee b/script.coffee index da72d9f53..f42c16664 100644 --- a/script.coffee +++ b/script.coffee @@ -499,7 +499,8 @@ filter = g.callbacks.push @node createFilter: (regexp, op, hl, top) -> - (root, value, isOP) -> + (post, value) -> + {el, isOP} = post if isOP and op is 'no' or !isOP and op is 'only' return false if typeof regexp is 'string' @@ -510,12 +511,12 @@ filter = return false if hl if isOP - $.addClass root, hl + $.addClass el, hl else - $.addClass root.parentNode, hl + $.addClass el.parentNode, hl if isOP and top and not g.REPLY # Put the highlighted OPs' threads on top of the board pages... - thisThread = root.parentNode + thisThread = el.parentNode # ...before the first non highlighted thread. if firstThread = $ 'div[class=op]' $.before firstThread.parentNode, [thisThread, thisThread.nextElementSibling] @@ -523,78 +524,76 @@ filter = return false if isOP unless g.REPLY - threadHiding.hideHide root.parentNode + threadHiding.hideHide el.parentNode else - replyHiding.hideHide root + replyHiding.hideHide el true - node: (root) -> - klass = root.className - return if /\binlined\b/.test klass - unless isOP = klass is 'op' - root = $ 'td[id]', root + node: (post) -> + return if post.isInlined for key of filter.filters - value = filter[key] root, isOP + value = filter[key] post if value is false # Continue if there's nothing to filter (no tripcode for example). continue for Filter in filter.filters[key] - if Filter root, value, isOP + if Filter post, value return - name: (root, isOP) -> - name = if isOP then $ '.postername', root else $ '.commentpostername', root + name: (post) -> + name = if post.isOP then $ '.postername', post.el else $ '.commentpostername', post.el name.textContent - tripcode: (root) -> - if trip = $ '.postertrip', root + tripcode: (post) -> + if trip = $ '.postertrip', post.el return trip.textContent false - mod: (root, isOP) -> - if mod = (if isOP then $ '.commentpostername', root else $ '.commentpostername ~ .commentpostername', root) + mod: (post) -> + if mod = (if post.isOP then $ '.commentpostername', post.el else $ '.commentpostername ~ .commentpostername', post.el) return mod.textContent false - email: (root) -> - if mail = $ '.linkmail', root + email: (post) -> + if mail = $ '.linkmail', post.el return mail.href false - subject: (root, isOP) -> - sub = if isOP then $ '.filetitle', root else $ '.replytitle', root + subject: (post) -> + sub = if post.isOP then $ '.filetitle', post.el else $ '.replytitle', post.el sub.textContent - comment: (root) -> + comment: (post) -> text = [] # XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE is 7 - nodes = d.evaluate './/br|.//text()', root.lastChild, null, 7, null - i = 0 - len = nodes.snapshotLength - while i < len - text.push if data = nodes.snapshotItem(i++).data then data else '\n' + nodes = d.evaluate './/br|.//text()', post.bq, null, 7, null + for i in [0...nodes.snapshotLength] + text.push if data = nodes.snapshotItem(i).data then data else '\n' text.join '' - filename: (root) -> - if file = $ '.filesize > span', root + filename: (post) -> + if file = $ 'span', post.filesize return file.title false - dimensions: (root) -> - if (span = $ '.filesize', root) and match = span.textContent.match /\d+x\d+/ + dimensions: (post) -> + {filesize} = post + if filesize and match = filesize.textContent.match /\d+x\d+/ return match[0] return false - filesize: (root) -> - if img = $ 'img[md5]', root + filesize: (post) -> + {img} = post + if img return img.alt false - md5: (root) -> - if img = $ 'img[md5]', root + md5: (post) -> + {img} = post + if img return img.getAttribute 'md5' false strikethroughQuotes = init: -> g.callbacks.push @node - node: (root) -> - return if root.className is 'inline' - for quote in $$ '.quotelink', root + node: (post) -> + return if post.isInlined + for quote in post.quotes if (el = $.id quote.hash[1..]) and el.parentNode.parentNode.parentNode.hidden $.addClass quote, 'filtered' - root.hidden = true if conf['Recursive Filtering'] + post.root.hidden = true if conf['Recursive Filtering'] return expandComment = @@ -711,8 +710,9 @@ replyHiding = init: -> g.callbacks.push @node - node: (root) -> - return unless dd = $ '.doubledash', root + node: (post) -> + return if post.class + dd = $ '.doubledash', post.root dd.className = 'replyhider' a = $.el 'a', textContent: '[ - ]' @@ -755,8 +755,8 @@ replyHiding = if conf['Show Stubs'] name = $('.commentpostername', reply).textContent - uid = $('.posteruid', reply)?.textContent or '' - trip = $('.postertrip', reply)?.textContent or '' + uid = $('.posteruid', reply)?.textContent or '' + trip = $('.postertrip', reply)?.textContent or '' div = $.el 'div', className: 'stub' @@ -1037,8 +1037,8 @@ qr = $.on d, 'dragstart', qr.drag $.on d, 'dragend', qr.drag - node: (root) -> - $.on $('.quotejs + .quotejs', root), 'click', qr.quote + node: (post) -> + $.on $('.quotejs + .quotejs', post.el), 'click', qr.quote open: -> if qr.el @@ -2264,10 +2264,10 @@ watcher = anonymize = init: -> g.callbacks.push @node - node: (root) -> - name = $ '.commentpostername, .postername', root + node: (post) -> + name = $ '.commentpostername, .postername', post.el name.textContent = 'Anonymous' - if trip = $ '.postertrip', root + if trip = $ '.postertrip', post.el if trip.parentNode.nodeName is 'A' $.rm trip.parentNode else @@ -2302,19 +2302,22 @@ sauce = target: '_blank' textContent: domain - node: (root) -> - return if root.className is 'inline' or not span = $ '.filesize', root - img = span.nextElementSibling.nextElementSibling + node: (post) -> + {img} = post + return if post.class is 'inline' or not img + img = img.parentNode nodes = [] for link in sauce.links nodes.push $.tn(' '), link img - $.add span, nodes + $.add post.filesize, nodes revealSpoilers = init: -> g.callbacks.push @node - node: (root) -> - return if not (img = $ 'img[alt^=Spoil]', root) or root.className is 'inline' + node: (post) -> + img = {post} + if not (img and /^Spoil/.test img.alt) or post.class is 'inline' + return img.removeAttribute 'height' img.removeAttribute 'width' img.src = "http://thumbs.4chan.org#{img.parentNode.pathname.replace(/src(\/\d+).+$/, 'thumb$1s.jpg')}" @@ -2341,10 +2344,10 @@ Time = new Date year, month, day, hour, min g.callbacks.push @node - node: (root) -> - return if root.className is 'inline' + node: (post) -> + return if post.class is 'inline' # .posttime exists on every board except /f/ - node = $('.posttime', root) or $('span[id]', root).previousSibling + node = $('.posttime', post.el) or $('span[id]', post.el).previousSibling Time.date = Time.parse node time = $.el 'time', textContent: ' ' + Time.funk(Time) + ' ' @@ -2402,8 +2405,8 @@ FileInfo = return if g.BOARD is 'f' @setFormats() g.callbacks.push @node - node: (root) -> - return if root.className is 'inline' or not node = $ '.filesize', root + node: (post) -> + return if post.class is 'inline' or not node = post.filesize type = if node.childElementCount is 2 then 0 else 1 regexp = if type @@ -2484,20 +2487,18 @@ quoteBacklink = format = conf['backlink'].replace /%id/g, "' + id + '" quoteBacklink.funk = Function 'id', "return '#{format}'" g.callbacks.push @node - node: (root) -> - return if /\binline\b/.test root.className + node: (post) -> + return if post.isInlined quotes = {} - for quote in $$ '.quotelink', root + for quote in post.quotes # Don't process >>>/b/. if qid = quote.hash[1..] # Duplicate quotes get overwritten. quotes[qid] = true - # OP or reply id. - id = $('input', root).name a = $.el 'a', - href: "##{id}" - className: if root.hidden then 'filtered backlink' else 'backlink' - textContent: quoteBacklink.funk id + href: "##{post.id}" + className: if post.root.hidden then 'filtered backlink' else 'backlink' + textContent: quoteBacklink.funk post.id for qid of quotes # Don't backlink the OP. continue if !(el = $.id qid) or el.className is 'op' and !conf['OP Backlinks'] @@ -2516,8 +2517,8 @@ quoteBacklink = quoteInline = init: -> g.callbacks.push @node - node: (root) -> - for quote in $$ '.quotelink, .backlink', root + node: (post) -> + for quote in post.quotes.concat post.backlinks continue unless quote.hash quote.removeAttribute 'onclick' $.on quote, 'click', quoteInline.toggle @@ -2608,8 +2609,8 @@ quoteInline = quotePreview = init: -> g.callbacks.push @node - node: (root) -> - for quote in $$ '.quotelink, .backlink', root + node: (post) -> + for quote in post.quotes.concat post.backlinks $.on quote, 'mouseover', quotePreview.mouseover if quote.hash return mouseover: (e) -> @@ -2668,23 +2669,29 @@ quotePreview = if conf['File Info Formatting'] FileInfo.node qp -quoteIndicators = +quoteOP = init: -> g.callbacks.push @node - node: (root) -> - return if root.className is 'inline' - # We use contains() so that it works with hidden threads - tid = g.THREAD_ID or $.x('ancestor::div[contains(@class,"thread")]', root).firstChild.id - for quote in $$ '.quotelink', root - unless hash = quote.hash[1..] - continue - if conf['Indicate OP quote'] and hash is tid + node: (post) -> + return if post.class is 'inline' + for quote in post.quotes + if quote.hash[1..] is post.threadId # \u00A0 is nbsp $.add quote, $.tn '\u00A0(OP)' + return + +quoteDR = + init: -> + g.callbacks.push @node + node: (post) -> + return if post.class is 'inline' + for quote in post.quotes + unless quote.hash + # Make sure this isn't a link to the board we're on. continue - path = quote.pathname - #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 + path = quote.pathname.split '/' + # If quote leads to a different thread id and is located on the same board. + if path[1] is g.BOARD and path[3] isnt post.threadId # \u00A0 is nbsp $.add quote, $.tn '\u00A0(Cross-thread)' return @@ -2692,14 +2699,13 @@ quoteIndicators = reportButton = init: -> g.callbacks.push @node - node: (root) -> - if not a = $ '.reportbutton', root - span = $ 'span[id]', root + node: (post) -> + if not a = $ '.reportbutton', post.el a = $.el 'a', className: 'reportbutton' innerHTML: '[ ! ]' href: 'javascript:;' - $.after span, [$.tn(' '), a] + $.after $('span[id]', post.el), [$.tn(' '), a] $.on a, 'click', reportButton.report report: -> url = "http://sys.4chan.org/#{g.BOARD}/imgboard.php?mode=report&no=#{$.x('preceding-sibling::input', @).name}" @@ -2722,10 +2728,10 @@ threadStats = else 151 g.callbacks.push @node - node: (root) -> - return if /\binline\b/.test root.className + node: (post) -> + return if post.isInlined $.id('postcount').textContent = ++threadStats.posts - return unless $ 'img[md5]', root + return unless post.img imgcount = $.id 'imagecount' imgcount.textContent = ++threadStats.images if threadStats.images > threadStats.imgLimit @@ -2740,9 +2746,9 @@ unread = replies: [] - node: (root) -> - return if root.hidden or root.className - unread.replies.push root + node: (post) -> + return if post.root.hidden or post.class + unread.replies.push post.root unread.update() scroll: -> @@ -2848,9 +2854,9 @@ redirect = imgHover = init: -> g.callbacks.push @node - node: (root) -> - return unless thumb = $ 'img[md5]', root - $.on thumb, 'mouseover', imgHover.mouseover + node: (post) -> + return unless post.img + $.on post.img, 'mouseover', imgHover.mouseover mouseover: -> ui.el = $.el 'img' id: 'ihover' @@ -2874,14 +2880,14 @@ imgHover = imgGif = init: -> g.callbacks.push @node - node: (root) -> - return if root.hidden or !thumb = $ 'img[md5]', root - src = thumb.parentNode.href + node: (post) -> + return if post.root.hidden or post.img + src = post.img.parentNode.href if /gif$/.test(src) and !/spoiler/.test src img = $.el 'img' $.on img, 'load', -> # Replace the thumbnail once the GIF has finished loading. - thumb.src = src + post.img.src = src img.src = src imgExpand = @@ -2889,11 +2895,11 @@ imgExpand = g.callbacks.push @node imgExpand.dialog() - node: (root) -> - return unless thumb = $ 'img[md5]', root - a = thumb.parentNode + node: (post) -> + return unless post.img + a = post.img.parentNode $.on a, 'click', imgExpand.cb.toggle - if imgExpand.on and !root.hidden and root.className isnt 'inline' + if imgExpand.on and !post.root.hidden and post.class isnt 'inline' imgExpand.expand a.firstChild cb: toggle: (e) -> @@ -3103,8 +3109,11 @@ Main = if conf['Quote Backlinks'] quoteBacklink.init() - if conf['Indicate OP quote'] or conf['Indicate Cross-thread Quotes'] - quoteIndicators.init() + if conf['Indicate OP quote'] + quoteOP.init() + + if conf['Indicate Cross-thread Quotes'] + quoteDR.init() $.ready Main.ready @@ -3162,7 +3171,6 @@ Main = if conf['Index Navigation'] nav.init() - nodes = $$ '.op, a + table', form Main.node nodes, true @@ -3191,9 +3199,25 @@ Main = window.location = "https://raw.github.com/mayhemydg/4chan-x/#{version}/4chan_x.user.js" node: (nodes, notify) -> + posts = [] + for node in nodes + klass = node.className + posts.push + root: node + el: if klass is 'op' then node else $ 'td[id]', node + class: klass + id: $('input', node).name + threadId: g.THREAD_ID or $.x('ancestor::div[contains(@class,"thread")]', node).firstChild.id + isOP: klass is 'op' + isInlined: /\binlined\b/.test klass + filesize: $ '.filesize', node + img: $ 'img[md5]', node + quotes: $$ '.quotelink', node + backlinks: $$ '.backlink', node + bq: node.lastChild for callback in g.callbacks try - callback node for node in nodes + callback post for post in posts catch err alert "4chan X error: #{err.message}\nhttp://mayhemydg.github.com/4chan-x/#bug-report\n\n#{err.stack}" if notify return From ad2e396d0440a2d3c24c80bccf85057618a125a0 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 02:46:09 +0100 Subject: [PATCH 04/11] Append backlinks into the container before appending the said container into the post. --- 4chan_x.user.js | 4 +++- script.coffee | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 9e2680ae7..4bff284f1 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -3087,10 +3087,12 @@ container = $.el('span', { className: 'container' }); + $.add(container, [$.tn(' '), link]); root = $('.reportbutton', el) || $('span[id]', el); $.after(root, container); + } else { + $.add(container, [$.tn(' '), link]); } - $.add(container, [$.tn(' '), link]); } } }; diff --git a/script.coffee b/script.coffee index f42c16664..064c05449 100644 --- a/script.coffee +++ b/script.coffee @@ -2509,9 +2509,11 @@ quoteBacklink = $.on link, 'click', quoteInline.toggle unless (container = $ '.container', el) and container.parentNode is el container = $.el 'span', className: 'container' + $.add container, [$.tn(' '), link] root = $('.reportbutton', el) or $('span[id]', el) $.after root, container - $.add container, [$.tn(' '), link] + else + $.add container, [$.tn(' '), link] return quoteInline = From 35abc22d5c904721cb833a2f7ce17e87c807bf6b Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 03:41:56 +0100 Subject: [PATCH 05/11] Slight filter performance and memory improvement. --- 4chan_x.user.js | 64 +++++++++++++++++++++++++++---------------------- script.coffee | 59 ++++++++++++++++++++++++++------------------- 2 files changed, 69 insertions(+), 54 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 4bff284f1..e496fba14 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -575,39 +575,21 @@ if (Object.keys(this.filters).length) return g.callbacks.push(this.node); }, createFilter: function(regexp, op, hl, top) { - return function(post, value) { - var el, firstThread, isOP, thisThread; - el = post.el, isOP = post.isOP; + var test; + test = typeof regexp === 'string' ? function(value) { + return regexp === value; + } : function(value) { + return regexp.test(value); + }; + return function(value, isOP) { if (isOP && op === 'no' || !isOP && op === 'only') return false; - if (typeof regexp === 'string') { - if (regexp !== value) return false; - } else if (!regexp.test(value)) { - return false; - } - if (hl) { - if (isOP) { - $.addClass(el, hl); - } else { - $.addClass(el.parentNode, hl); - } - if (isOP && top && !g.REPLY) { - thisThread = el.parentNode; - if (firstThread = $('div[class=op]')) { - $.before(firstThread.parentNode, [thisThread, thisThread.nextElementSibling]); - } - } - return false; - } - if (isOP) { - if (!g.REPLY) threadHiding.hideHide(el.parentNode); - } else { - replyHiding.hideHide(el); - } + if (!test(value)) return false; + if (hl) return [hl, top]; return true; }; }, node: function(post) { - var Filter, key, value, _i, _len, _ref; + var Filter, el, firstThread, isOP, key, result, thisThread, value, _i, _len, _ref; if (post.isInlined) return; for (key in filter.filters) { value = filter[key](post); @@ -615,7 +597,31 @@ _ref = filter.filters[key]; for (_i = 0, _len = _ref.length; _i < _len; _i++) { Filter = _ref[_i]; - if (Filter(post, value)) return; + if (!(result = Filter(value, isOP))) continue; + isOP = post.isOP, el = post.el; + if (result === true) { + if (isOP) { + if (!g.REPLY) { + threadHiding.hideHide(post.el.parentNode); + } else { + continue; + } + } else { + replyHiding.hideHide(post.el); + } + return; + } + if (isOP) { + $.addClass(el, result[0]); + } else { + $.addClass(el.parentNode, result[0]); + } + if (isOP && result[1] && !g.REPLY) { + thisThread = el.parentNode; + if (firstThread = $('div[class=op]')) { + $.before(firstThread.parentNode, [thisThread, thisThread.nextElementSibling]); + } + } } } }, diff --git a/script.coffee b/script.coffee index 064c05449..694c46a8d 100644 --- a/script.coffee +++ b/script.coffee @@ -499,34 +499,19 @@ filter = g.callbacks.push @node createFilter: (regexp, op, hl, top) -> - (post, value) -> - {el, isOP} = post - if isOP and op is 'no' or !isOP and op is 'only' - return false + test = if typeof regexp is 'string' # MD5 checking - if regexp isnt value - return false - else unless regexp.test value + (value) -> regexp is value + else + (value) -> regexp.test value + (value, isOP) -> + if isOP and op is 'no' or !isOP and op is 'only' + return false + unless test value return false if hl - if isOP - $.addClass el, hl - else - $.addClass el.parentNode, hl - if isOP and top and not g.REPLY - # Put the highlighted OPs' threads on top of the board pages... - thisThread = el.parentNode - # ...before the first non highlighted thread. - if firstThread = $ 'div[class=op]' - $.before firstThread.parentNode, [thisThread, thisThread.nextElementSibling] - # Continue the filter lookup to add more classes or hide it. - return false - if isOP - unless g.REPLY - threadHiding.hideHide el.parentNode - else - replyHiding.hideHide el + return [hl, top] true node: (post) -> @@ -537,9 +522,33 @@ filter = # Continue if there's nothing to filter (no tripcode for example). continue for Filter in filter.filters[key] - if Filter post, value + unless result = Filter value, isOP + continue + {isOP, el} = post + + # Hide + if result is true + if isOP + unless g.REPLY + threadHiding.hideHide post.el.parentNode + else + continue + else + replyHiding.hideHide post.el return + # Highlight + if isOP + $.addClass el, result[0] + else + $.addClass el.parentNode, result[0] + if isOP and result[1] and not g.REPLY + # Put the highlighted OPs' threads on top of the board pages... + thisThread = el.parentNode + # ...before the first non highlighted thread. + if firstThread = $ 'div[class=op]' + $.before firstThread.parentNode, [thisThread, thisThread.nextElementSibling] + name: (post) -> name = if post.isOP then $ '.postername', post.el else $ '.commentpostername', post.el name.textContent From 0ebdb86ea85005b1139bd20b012472f177612ed7 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 03:43:41 +0100 Subject: [PATCH 06/11] Typo. --- 4chan_x.user.js | 2 +- script.coffee | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index e496fba14..b78932bae 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -3911,7 +3911,7 @@ id: $('input', node).name, threadId: g.THREAD_ID || $.x('ancestor::div[contains(@class,"thread")]', node).firstChild.id, isOP: klass === 'op', - isInlined: /\binlined\b/.test(klass), + isInlined: /\binline\b/.test(klass), filesize: $('.filesize', node), img: $('img[md5]', node), quotes: $$('.quotelink', node), diff --git a/script.coffee b/script.coffee index 694c46a8d..69c48da18 100644 --- a/script.coffee +++ b/script.coffee @@ -3220,7 +3220,7 @@ Main = id: $('input', node).name threadId: g.THREAD_ID or $.x('ancestor::div[contains(@class,"thread")]', node).firstChild.id isOP: klass is 'op' - isInlined: /\binlined\b/.test klass + isInlined: /\binline\b/.test klass filesize: $ '.filesize', node img: $ 'img[md5]', node quotes: $$ '.quotelink', node From 82a92c37990d9b25841c11256ceff6d2350c9d05 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 04:23:01 +0100 Subject: [PATCH 07/11] Fixes. --- 4chan_x.user.js | 5 +++-- script.coffee | 7 +++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index b78932bae..351d3c6ad 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -759,7 +759,8 @@ $.replace(a.parentNode.parentNode, bq); if (conf['Quote Preview']) quotePreview.node(bq); if (conf['Quote Inline']) quoteInline.node(bq); - return quoteIndicators.node(bq); + if (conf['Indicate OP quote']) quoteOP.node(bq); + if (conf['Indicate Cross-thread Quotes']) return quoteDR.node(bq); } }; @@ -3587,7 +3588,7 @@ }, node: function(post) { var img, src; - if (post.root.hidden || post.img) return; + if (post.root.hidden || !post.img) return; src = post.img.parentNode.href; if (/gif$/.test(src) && !/spoiler/.test(src)) { img = $.el('img'); diff --git a/script.coffee b/script.coffee index 69c48da18..992ba5366 100644 --- a/script.coffee +++ b/script.coffee @@ -641,7 +641,10 @@ expandComment = quotePreview.node bq if conf['Quote Inline'] quoteInline.node bq - quoteIndicators.node bq + if conf['Indicate OP quote'] + quoteOP.node bq + if conf['Indicate Cross-thread Quotes'] + quoteDR.node bq expandThread = init: -> @@ -2892,7 +2895,7 @@ imgGif = init: -> g.callbacks.push @node node: (post) -> - return if post.root.hidden or post.img + return if post.root.hidden or not post.img src = post.img.parentNode.href if /gif$/.test(src) and !/spoiler/.test src img = $.el 'img' From f77e4b35f9f5e5ae9c8eba88a760f44587c9f9cb Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 04:31:48 +0100 Subject: [PATCH 08/11] Save some hundreads of ms in qr.init. --- 4chan_x.user.js | 13 ++++++++----- script.coffee | 10 ++++++---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 351d3c6ad..b938c53a8 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -1265,7 +1265,7 @@ qr = { init: function() { - var form, iframe, link, loadChecking, script; + var form, iframe, link, loadChecking; if (!$.id('recaptcha_challenge_field_holder')) return; if (conf['Hide Original Post Form']) { link = $.el('h1', { @@ -1306,11 +1306,14 @@ }); $.add(d.head, iframe); } - script = $.el('script', { - textContent: 'Recaptcha.focus_response_field=function(){}' + setTimeout(function() { + var script; + script = $.el('script', { + textContent: 'Recaptcha.focus_response_field=function(){}' + }); + $.add(d.head, script); + return $.rm(script); }); - $.add(d.head, script); - $.rm(script); if (conf['Persistent QR']) { qr.dialog(); if (conf['Auto Hide QR']) qr.hide(); diff --git a/script.coffee b/script.coffee index 992ba5366..59c62feb7 100644 --- a/script.coffee +++ b/script.coffee @@ -1036,10 +1036,12 @@ qr = $.on iframe, 'load', -> if @src isnt 'about:blank' then setTimeout loadChecking, 500, @ $.add d.head, iframe - # Prevent original captcha input from being focused on reload. - script = $.el 'script', textContent: 'Recaptcha.focus_response_field=function(){}' - $.add d.head, script - $.rm script + # This is extemely slow, execute is asynchronously. + setTimeout -> + # Prevent original captcha input from being focused on reload. + script = $.el 'script', textContent: 'Recaptcha.focus_response_field=function(){}' + $.add d.head, script + $.rm script if conf['Persistent QR'] qr.dialog() From 980a5d569c8e0a50e72e92d961aaf59f96b7c2ef Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 05:49:29 +0100 Subject: [PATCH 09/11] Add class 'current' to current board's link in navtop and navbot. Close #302. --- 4chan_x.user.js | 7 ++++++- script.coffee | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index b938c53a8..0a5cc8417 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -3843,7 +3843,7 @@ return $.ready(Main.ready); }, ready: function() { - var MutationObserver, form, nodes, observer; + var MutationObserver, form, nav, nodes, observer, _i, _len, _ref; if (d.title === '4chan - 404') { redirect.init(); return; @@ -3851,6 +3851,11 @@ if (!$.id('navtopr')) return; $.addClass(d.body, "chanx_" + (VERSION.match(/\.(\d+)/)[1])); $.addClass(d.body, engine); + _ref = ['navtop', 'navbot']; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + nav = _ref[_i]; + $.addClass($("a[href$='/" + g.BOARD + "/']", $.id(nav)), 'current'); + } form = $('form[name=delform]'); threading.thread(form.firstElementChild); Favicon.init(); diff --git a/script.coffee b/script.coffee index 59c62feb7..2d476e352 100644 --- a/script.coffee +++ b/script.coffee @@ -3141,6 +3141,8 @@ Main = return $.addClass d.body, "chanx_#{VERSION.match(/\.(\d+)/)[1]}" $.addClass d.body, engine + for nav in ['navtop', 'navbot'] + $.addClass $("a[href$='/#{g.BOARD}/']", $.id nav), 'current' form = $ 'form[name=delform]' threading.thread form.firstElementChild Favicon.init() From 576361aac2bf73324aee8cc34c51d7100a28f6f7 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 05:50:16 +0100 Subject: [PATCH 10/11] Changelog. --- changelog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog b/changelog index efe730803..57d039b0a 100644 --- a/changelog +++ b/changelog @@ -1,4 +1,6 @@ master +- Mayhem + General performance improvements. 2.28.0 - ahodesuka From 93934566e8e8f63c1239c197454dc2c5171d15aa Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 3 Mar 2012 07:27:58 +0100 Subject: [PATCH 11/11] Filter fixes. --- 4chan_x.user.js | 9 ++++----- script.coffee | 7 +++---- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 0a5cc8417..6c15c0c22 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -591,6 +591,7 @@ node: function(post) { var Filter, el, firstThread, isOP, key, result, thisThread, value, _i, _len, _ref; if (post.isInlined) return; + isOP = post.isOP, el = post.el; for (key in filter.filters) { value = filter[key](post); if (value === false) continue; @@ -598,7 +599,6 @@ for (_i = 0, _len = _ref.length; _i < _len; _i++) { Filter = _ref[_i]; if (!(result = Filter(value, isOP))) continue; - isOP = post.isOP, el = post.el; if (result === true) { if (isOP) { if (!g.REPLY) { @@ -655,7 +655,7 @@ comment: function(post) { var data, i, nodes, text, _ref; text = []; - nodes = d.evaluate('.//br|.//text()', post.bq, null, 7, null); + nodes = d.evaluate('.//br|.//text()', post.el.lastChild, null, 7, null); for (i = 0, _ref = nodes.snapshotLength; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { text.push((data = nodes.snapshotItem(i).data) ? data : '\n'); } @@ -3849,7 +3849,7 @@ return; } if (!$.id('navtopr')) return; - $.addClass(d.body, "chanx_" + (VERSION.match(/\.(\d+)/)[1])); + $.addClass(d.body, "chanx_" + (VERSION.split('.')[1])); $.addClass(d.body, engine); _ref = ['navtop', 'navbot']; for (_i = 0, _len = _ref.length; _i < _len; _i++) { @@ -3924,8 +3924,7 @@ filesize: $('.filesize', node), img: $('img[md5]', node), quotes: $$('.quotelink', node), - backlinks: $$('.backlink', node), - bq: node.lastChild + backlinks: $$('.backlink', node) }); } _ref = g.callbacks; diff --git a/script.coffee b/script.coffee index 2d476e352..cad40a7e0 100644 --- a/script.coffee +++ b/script.coffee @@ -516,6 +516,7 @@ filter = node: (post) -> return if post.isInlined + {isOP, el} = post for key of filter.filters value = filter[key] post if value is false @@ -524,7 +525,6 @@ filter = for Filter in filter.filters[key] unless result = Filter value, isOP continue - {isOP, el} = post # Hide if result is true @@ -570,7 +570,7 @@ filter = comment: (post) -> text = [] # XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE is 7 - nodes = d.evaluate './/br|.//text()', post.bq, null, 7, null + nodes = d.evaluate './/br|.//text()', post.el.lastChild, null, 7, null for i in [0...nodes.snapshotLength] text.push if data = nodes.snapshotItem(i).data then data else '\n' text.join '' @@ -3139,7 +3139,7 @@ Main = return if not $.id 'navtopr' return - $.addClass d.body, "chanx_#{VERSION.match(/\.(\d+)/)[1]}" + $.addClass d.body, "chanx_#{VERSION.split('.')[1]}" $.addClass d.body, engine for nav in ['navtop', 'navbot'] $.addClass $("a[href$='/#{g.BOARD}/']", $.id nav), 'current' @@ -3232,7 +3232,6 @@ Main = img: $ 'img[md5]', node quotes: $$ '.quotelink', node backlinks: $$ '.backlink', node - bq: node.lastChild for callback in g.callbacks try callback post for post in posts