Take messaging between iframes out of the qr code, get ready for ajaxing with images.4chan.org

This commit is contained in:
Nicolas Stepien 2012-02-14 21:57:13 +01:00
parent 6d41588e00
commit dea285d389
2 changed files with 355 additions and 313 deletions

View File

@ -71,7 +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, quoteDR, quoteInline, quoteOP, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, strikethroughQuotes, threadHiding, threadStats, threading, titlePost, ui, unread, 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, message, nav, options, qr, quoteBacklink, quoteDR, quoteInline, quoteOP, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, strikethroughQuotes, threadHiding, threadStats, threading, titlePost, ui, unread, updater, val, watcher, _base,
__slice = Array.prototype.slice; __slice = Array.prototype.slice;
config = { config = {
@ -1191,7 +1191,7 @@
qr = { qr = {
init: function() { init: function() {
var form, iframe, link, loadChecking; var form, link;
if (!$.id('recaptcha_challenge_field_holder')) return; if (!$.id('recaptcha_challenge_field_holder')) return;
if (conf['Hide Original Post Form']) { if (conf['Hide Original Post Form']) {
link = $.el('h1', { link = $.el('h1', {
@ -1205,26 +1205,6 @@
$.before(form, link); $.before(form, link);
} }
g.callbacks.push(this.node); g.callbacks.push(this.node);
iframe = $.el('iframe', {
id: 'iframe',
hidden: true,
src: 'http://sys.4chan.org/robots.txt'
});
$.on(iframe, 'error', function() {
return this.src = this.src;
});
loadChecking = function(iframe) {
if (!qr.status.ready) {
iframe.src = 'about:blank';
return setTimeout((function() {
return iframe.src = 'http://sys.4chan.org/robots.txt';
}), 250);
}
};
$.on(iframe, 'load', function() {
if (this.src !== 'about:blank') return setTimeout(loadChecking, 500, this);
});
$.add(d.body, iframe);
if (conf['Persistent QR']) { if (conf['Persistent QR']) {
qr.dialog(); qr.dialog();
if (conf['Auto Hide QR']) qr.hide(); if (conf['Auto Hide QR']) qr.hide();
@ -1249,9 +1229,9 @@
close: function() { close: function() {
var i, spoiler, _i, _len, _ref; var i, spoiler, _i, _len, _ref;
qr.el.hidden = true; qr.el.hidden = true;
qr.message.send({ message.send({
req: 'abort' req: 'abort'
}); }, 'sys');
d.activeElement.blur(); d.activeElement.blur();
$.removeClass(qr.el, 'dump'); $.removeClass(qr.el, 'dump');
_ref = qr.replies; _ref = qr.replies;
@ -1721,7 +1701,6 @@
qr.status(); qr.status();
qr.cooldown.init(); qr.cooldown.init();
qr.captcha.init(); qr.captcha.init();
qr.message.init();
$.add(d.body, qr.el); $.add(d.body, qr.el);
e = d.createEvent('CustomEvent'); e = d.createEvent('CustomEvent');
e.initEvent('QRDialogCreation', true, false); e.initEvent('QRDialogCreation', true, false);
@ -1735,9 +1714,9 @@
qr.status(); qr.status();
return; return;
} }
qr.message.send({ message.send({
req: 'abort' req: 'abort'
}); }, 'sys');
reply = qr.replies[0]; reply = qr.replies[0];
if (!(reply.com || reply.file)) { if (!(reply.com || reply.file)) {
err = 'No file selected.'; err = 'No file selected.';
@ -1795,12 +1774,12 @@
file.name = reply.file.name; file.name = reply.file.name;
file.type = reply.file.type; file.type = reply.file.type;
post.upfile = file; post.upfile = file;
return qr.message.send(post); return message.send(post, 'sys');
}; };
reader.readAsBinaryString(reply.file); reader.readAsBinaryString(reply.file);
return; return;
} }
return qr.message.send(post); return message.send(post, 'sys');
}, },
response: function(html) { response: function(html) {
var b, err, node, persona, postNumber, reply, thread, _, _ref; var b, err, node, persona, postNumber, reply, thread, _, _ref;
@ -1852,66 +1831,10 @@
qr.status(); qr.status();
return qr.resetFileInput(); return qr.resetFileInput();
}, },
message: {
init: function() {
var code, ready, script;
code = function(e) {
var data, host;
data = e.data;
if (!data.changeContext) return;
delete data.changeContext;
host = location.hostname;
if (host === 'boards.4chan.org') {
return document.getElementById('iframe').contentWindow.postMessage(data, '*');
} else if (host === 'sys.4chan.org') {
return parent.postMessage(data, '*');
}
};
script = $.el('script', {
textContent: "window.addEventListener('message'," + code + ",false)"
});
ready = function() {
$.add(d.documentElement, script);
if (location.hostname === 'sys.4chan.org') {
qr.message.send({
req: 'status',
ready: true
});
}
return $.rm(script);
};
if (d.documentElement) {
return ready();
} else {
return $.ready(ready);
}
},
send: function(data) {
data.changeContext = true;
data.qr = true;
return postMessage(data, '*');
},
receive: function(data) {
var _ref;
switch (data.req) {
case 'abort':
if ((_ref = qr.ajax) != null) _ref.abort();
return qr.message.send({
req: 'status'
});
case 'response':
return qr.response(data.html);
case 'status':
return qr.status(data);
default:
return qr.message.post(data);
}
},
post: function(data) { post: function(data) {
var boundary, callbacks, form, i, name, opts, parts, toBin, url, val; var boundary, callbacks, form, i, name, opts, parts, toBin, url, val;
url = "http://sys.4chan.org/" + data.board + "/post"; url = "http://sys.4chan.org/" + data.board + "/post";
delete data.board; delete data.board;
delete data.qr;
if (engine === 'gecko' && data.upfile) { if (engine === 'gecko' && data.upfile) {
if (!data.binary) { if (!data.binary) {
toBin = function(data, name, val) { toBin = function(data, name, val) {
@ -1921,7 +1844,7 @@
r = new FileReader(); r = new FileReader();
r.onload = function() { r.onload = function() {
data[name] = r.result; data[name] = r.result;
if (!--i) return qr.message.post(data); if (!--i) return qr.post(data);
}; };
return r.readAsBinaryString(bb.getBlob('text/plain')); return r.readAsBinaryString(bb.getBlob('text/plain'));
}; };
@ -1965,7 +1888,7 @@
} }
callbacks = { callbacks = {
onload: function() { onload: function() {
return qr.message.send({ return message.send({
req: 'response', req: 'response',
html: this.response html: this.response
}); });
@ -1976,13 +1899,13 @@
type: 'post', type: 'post',
upCallbacks: { upCallbacks: {
onload: function() { onload: function() {
return qr.message.send({ return message.send({
req: 'status', req: 'status',
progress: '...' progress: '...'
}); });
}, },
onprogress: function(e) { onprogress: function(e) {
return qr.message.send({ return message.send({
req: 'status', req: 'status',
progress: "" + (Math.round(e.loaded / e.total * 100)) + "%" progress: "" + (Math.round(e.loaded / e.total * 100)) + "%"
}); });
@ -1996,7 +1919,6 @@
} }
return qr.ajax = $.ajax(url, callbacks, opts); return qr.ajax = $.ajax(url, callbacks, opts);
} }
}
}; };
options = { options = {
@ -2430,9 +2352,9 @@
d.title = d.title.match(/^.+-/)[0] + ' 404'; d.title = d.title.match(/^.+-/)[0] + ' 404';
} }
unread.update(true); unread.update(true);
qr.message.send({ message.send({
req: 'abort' req: 'abort'
}); }, 'sys');
qr.status(); qr.status();
Favicon.update(); Favicon.update();
return; return;
@ -3488,6 +3410,113 @@
} }
}; };
message = {
init: function() {
var code, script;
$.on(window, 'message', message.receive);
$.ready(function() {
var domain, domains, iframe, _i, _len, _results;
if (location.hostname !== 'boards.4chan.org') return;
domains = [];
if (conf['Quick Reply']) domains.push('sys');
if (conf['Image Expansion'] || conf['Sauce']) domains.push('images');
_results = [];
for (_i = 0, _len = domains.length; _i < _len; _i++) {
domain = domains[_i];
iframe = $.el('iframe', {
id: domain,
hidden: true,
src: "http://" + domain + ".4chan.org/robots.txt"
});
$.on(iframe, 'error', message.loadControl);
$.on(iframe, 'load', message.loadControl);
_results.push($.add(d.body, iframe));
}
return _results;
});
code = function(e) {
var data;
data = e.data;
if (!data.changeContext) return;
delete data.changeContext;
if (location.hostname === 'boards.4chan.org') {
return document.getElementById(data.iframe).contentWindow.postMessage(data, '*');
} else {
return parent.postMessage(data, '*');
}
};
script = $.el('script', {
textContent: "window.addEventListener('message'," + code + ",false)"
});
return $.ready(function() {
var host;
$.add(d.documentElement, script);
host = location.hostname;
if (host === 'sys.4chan.org') {
message.send({
req: 'status',
ready: true
});
}
if (host !== 'boards.4chan.org') {
message.send({
req: 'iframeLoad',
id: location.hostname.split('.')[0]
});
}
return $.rm(script);
});
},
loadControl: function() {
var _this = this;
return setTimeout((function() {
if (_this.src === 'about:blank' || message[_this.id] === 'ready') return;
_this.src = 'about:blank';
return setTimeout((function() {
return _this.src = "http://" + _this.id + ".4chan.org/robots.txt";
}), 250);
}), 1000);
},
receive: function(e) {
var data, version;
data = e.data;
if (data.iframe) {
if (!data.changeContext) message.handle(data);
return;
}
version = data.version;
if (version && version !== VERSION && confirm('An updated version of 4chan X is available, would you like to install it now?')) {
return window.location = "https://raw.github.com/mayhemydg/4chan-x/" + version + "/4chan_x.user.js";
}
},
send: function(data, iframe) {
data.changeContext = true;
data.iframe = iframe || 'boards';
return postMessage(data, '*');
},
handle: function(data) {
var req, _ref;
req = data.req;
delete data.req;
delete data.iframe;
switch (req) {
case 'iframeLoad':
return message[data.id] = 'ready';
case 'abort':
if ((_ref = qr.ajax) != null) _ref.abort();
return message.send({
req: 'status'
});
case 'response':
return qr.response(data.html);
case 'status':
return qr.status(data);
default:
return qr.post(data);
}
}
};
Main = { Main = {
init: function() { init: function() {
var cutoff, hiddenThreads, id, now, pathname, temp, timestamp, _ref; var cutoff, hiddenThreads, id, now, pathname, temp, timestamp, _ref;
@ -3499,11 +3528,9 @@
} else { } else {
g.PAGENUM = parseInt(temp) || 0; g.PAGENUM = parseInt(temp) || 0;
} }
$.on(window, 'message', Main.message); message.init();
if (location.hostname === 'sys.4chan.org') { if (location.hostname === 'sys.4chan.org') {
if (location.pathname === '/robots.txt') { if (/report/.test(location.search)) {
qr.message.init();
} else if (/report/.test(location.search)) {
$.ready(function() { $.ready(function() {
return $.on($('#recaptcha_response_field'), 'keydown', function(e) { return $.on($('#recaptcha_response_field'), 'keydown', function(e) {
if (e.keyCode === 8 && !e.target.value) { if (e.keyCode === 8 && !e.target.value) {
@ -3619,16 +3646,6 @@
return $.on(d, 'DOMNodeInserted', Main.addStyle); return $.on(d, 'DOMNodeInserted', Main.addStyle);
} }
}, },
message: function(e) {
var data, version;
data = e.data;
version = data.version;
if (data.qr && !data.changeContext) {
return qr.message.receive(data);
} else if (version && version !== VERSION && confirm('An updated version of 4chan X is available, would you like to install it now?')) {
return window.location = "https://raw.github.com/mayhemydg/4chan-x/" + version + "/4chan_x.user.js";
}
},
node: function(e) { node: function(e) {
var callback, target, _i, _len, _ref, _results; var callback, target, _i, _len, _ref, _results;
target = e.target; target = e.target;

View File

@ -880,19 +880,6 @@ qr =
$.before form, link $.before form, link
g.callbacks.push @node g.callbacks.push @node
iframe = $.el 'iframe',
id: 'iframe'
hidden: true
src: 'http://sys.4chan.org/robots.txt'
$.on iframe, 'error', -> @src = @src
# Greasemonkey ghetto fix
loadChecking = (iframe) ->
unless qr.status.ready
iframe.src = 'about:blank'
setTimeout (-> iframe.src = 'http://sys.4chan.org/robots.txt'), 250
$.on iframe, 'load', -> unless @src is 'about:blank' then setTimeout loadChecking, 500, @
$.add d.body, iframe
if conf['Persistent QR'] if conf['Persistent QR']
qr.dialog() qr.dialog()
qr.hide() if conf['Auto Hide QR'] qr.hide() if conf['Auto Hide QR']
@ -914,7 +901,7 @@ qr =
qr.dialog() qr.dialog()
close: -> close: ->
qr.el.hidden = true qr.el.hidden = true
qr.message.send req: 'abort' message.send req: 'abort', 'sys'
d.activeElement.blur() d.activeElement.blur()
$.removeClass qr.el, 'dump' $.removeClass qr.el, 'dump'
for i in qr.replies for i in qr.replies
@ -1287,7 +1274,6 @@ qr =
qr.status() qr.status()
qr.cooldown.init() qr.cooldown.init()
qr.captcha.init() qr.captcha.init()
qr.message.init()
$.add d.body, qr.el $.add d.body, qr.el
# Create a custom event when the QR dialog is first initialized. # Create a custom event when the QR dialog is first initialized.
@ -1302,7 +1288,7 @@ qr =
qr.cooldown.auto = !qr.cooldown.auto qr.cooldown.auto = !qr.cooldown.auto
qr.status() qr.status()
return return
qr.message.send req: 'abort' message.send req: 'abort', 'sys'
reply = qr.replies[0] reply = qr.replies[0]
# prevent errors # prevent errors
@ -1371,11 +1357,11 @@ qr =
file.name = reply.file.name file.name = reply.file.name
file.type = reply.file.type file.type = reply.file.type
post.upfile = file post.upfile = file
qr.message.send post message.send post, 'sys'
reader.readAsBinaryString reply.file reader.readAsBinaryString reply.file
return return
qr.message.send post message.send post, 'sys'
response: (html) -> response: (html) ->
unless b = $ 'td b', $.el('a', innerHTML: html) unless b = $ 'td b', $.el('a', innerHTML: html)
@ -1427,54 +1413,11 @@ qr =
qr.status() qr.status()
qr.resetFileInput() qr.resetFileInput()
message:
init: ->
# http://code.google.com/p/chromium/issues/detail?id=20773
# Let content scripts see other frames (instead of them being undefined)
# To access the parent, we have to break out of the sandbox and evaluate
# in the global context.
code = (e) ->
{data} = e
return unless data.changeContext
delete data.changeContext
host = location.hostname
if host is 'boards.4chan.org'
document.getElementById('iframe').contentWindow.postMessage data, '*'
else if host is 'sys.4chan.org'
parent.postMessage data, '*'
script = $.el 'script', textContent: "window.addEventListener('message',#{code},false)"
ready = ->
$.add d.documentElement, script
if location.hostname is 'sys.4chan.org'
qr.message.send req: 'status', ready: true
$.rm script
# Chrome can access the documentElement on document-start
if d.documentElement
ready()
# other browsers will have to wait
else $.ready ready
send: (data) ->
data.changeContext = true
data.qr = true
postMessage data, '*'
receive: (data) ->
switch data.req
when 'abort'
qr.ajax?.abort()
qr.message.send req: 'status'
when 'response' # xhr response
qr.response data.html
when 'status'
qr.status data
else
qr.message.post data # Reply object: we're posting
post: (data) -> post: (data) ->
url = "http://sys.4chan.org/#{data.board}/post" url = "http://sys.4chan.org/#{data.board}/post"
# Do not append these values to the form. # Do not append that value to the form.
delete data.board delete data.board
delete data.qr
# File with filename upload fix from desuwa # File with filename upload fix from desuwa
if engine is 'gecko' and data.upfile if engine is 'gecko' and data.upfile
@ -1487,7 +1430,7 @@ qr =
r.onload = -> r.onload = ->
data[name] = r.result data[name] = r.result
unless --i unless --i
qr.message.post data qr.post data
r.readAsBinaryString bb.getBlob 'text/plain' r.readAsBinaryString bb.getBlob 'text/plain'
i = Object.keys(data).length i = Object.keys(data).length
for name, val of data for name, val of data
@ -1522,7 +1465,7 @@ qr =
callbacks = callbacks =
onload: -> onload: ->
qr.message.send message.send
req: 'response' req: 'response'
html: @response html: @response
opts = opts =
@ -1530,11 +1473,11 @@ qr =
type: 'post' type: 'post'
upCallbacks: upCallbacks:
onload: -> onload: ->
qr.message.send message.send
req: 'status' req: 'status'
progress: '...' progress: '...'
onprogress: (e) -> onprogress: (e) ->
qr.message.send message.send
req: 'status' req: 'status'
progress: "#{Math.round e.loaded / e.total * 100}%" progress: "#{Math.round e.loaded / e.total * 100}%"
if boundary if boundary
@ -1921,7 +1864,7 @@ updater =
else else
d.title = d.title.match(/^.+-/)[0] + ' 404' d.title = d.title.match(/^.+-/)[0] + ' 404'
unread.update true unread.update true
qr.message.send req: 'abort' message.send req: 'abort', 'sys'
qr.status() qr.status()
Favicon.update() Favicon.update()
return return
@ -2713,6 +2656,98 @@ imgExpand =
resize: -> resize: ->
imgExpand.style.innerHTML = ".fitheight img[md5] + img {max-height:#{d.body.clientHeight}px;}" imgExpand.style.innerHTML = ".fitheight img[md5] + img {max-height:#{d.body.clientHeight}px;}"
message =
init: ->
$.on window, 'message', message.receive
$.ready ->
return if location.hostname isnt 'boards.4chan.org'
domains = []
if conf['Quick Reply']
domains.push 'sys'
if conf['Image Expansion'] or conf['Sauce']
domains.push 'images'
for domain in domains
iframe = $.el 'iframe',
id: domain
hidden: true
src: "http://#{domain}.4chan.org/robots.txt"
$.on iframe, 'error', message.loadControl
$.on iframe, 'load', message.loadControl
$.add d.body, iframe
# http://code.google.com/p/chromium/issues/detail?id=20773
# Let content scripts see other frames (instead of them being undefined)
# To access the parent, we have to break out of the sandbox and evaluate
# in the global context.
code = (e) ->
{data} = e
return unless data.changeContext
delete data.changeContext
if location.hostname is 'boards.4chan.org'
document.getElementById(data.iframe).contentWindow.postMessage data, '*'
else
parent.postMessage data, '*'
script = $.el 'script',
textContent: "window.addEventListener('message',#{code},false)"
$.ready ->
$.add d.documentElement, script
host = location.hostname
if host is 'sys.4chan.org'
message.send req: 'status', ready: true
if host isnt 'boards.4chan.org'
message.send req: 'iframeLoad', id: location.hostname.split('.')[0]
$.rm script
loadControl: ->
# Make sure the iframe has loaded correctly.
# This is necessary for Greasemonkey users.
setTimeout (=>
return if @src is 'about:blank' or message[@id] is 'ready'
@src = 'about:blank'
setTimeout (=>
@src = "http://#{@id}.4chan.org/robots.txt"
), 250
), 1000
receive: (e) ->
{data} = e
if data.iframe
unless data.changeContext
message.handle data
return
{version} = data
if version and version isnt VERSION and confirm 'An updated version of 4chan X is available, would you like to install it now?'
window.location = "https://raw.github.com/mayhemydg/4chan-x/#{version}/4chan_x.user.js"
send: (data, iframe) ->
data.changeContext = true
data.iframe = iframe or 'boards'
postMessage data, '*'
handle: (data) ->
{req} = data
delete data.req
delete data.iframe
switch req
when 'iframeLoad'
message[data.id] = 'ready'
when 'abort'
qr.ajax?.abort()
message.send req: 'status'
when 'response' # xhr response
qr.response data.html
when 'status'
qr.status data
else
# Reply object: we're posting
qr.post data
Main = Main =
init: -> init: ->
pathname = location.pathname[1..].split('/') pathname = location.pathname[1..].split('/')
@ -2723,12 +2758,10 @@ Main =
else else
g.PAGENUM = parseInt(temp) or 0 g.PAGENUM = parseInt(temp) or 0
$.on window, 'message', Main.message message.init()
if location.hostname is 'sys.4chan.org' if location.hostname is 'sys.4chan.org'
if location.pathname is '/robots.txt' if /report/.test location.search
qr.message.init()
else if /report/.test location.search
$.ready -> $.ready ->
$.on $('#recaptcha_response_field'), 'keydown', (e) -> $.on $('#recaptcha_response_field'), 'keydown', (e) ->
window.location = 'javascript:Recaptcha.reload()' if e.keyCode is 8 and not e.target.value window.location = 'javascript:Recaptcha.reload()' if e.keyCode is 8 and not e.target.value
@ -2887,14 +2920,6 @@ Main =
else # XXX fox else # XXX fox
$.on d, 'DOMNodeInserted', Main.addStyle $.on d, 'DOMNodeInserted', Main.addStyle
message: (e) ->
{data} = e
{version} = data
if data.qr and not data.changeContext
qr.message.receive data
else if version and version isnt VERSION and confirm 'An updated version of 4chan X is available, would you like to install it now?'
window.location = "https://raw.github.com/mayhemydg/4chan-x/#{version}/4chan_x.user.js"
node: (e) -> node: (e) ->
{target} = e {target} = e
return unless target.nodeName is 'TABLE' return unless target.nodeName is 'TABLE'