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,150 +1831,93 @@
qr.status(); qr.status();
return qr.resetFileInput(); return qr.resetFileInput();
}, },
message: { post: function(data) {
init: function() { var boundary, callbacks, form, i, name, opts, parts, toBin, url, val;
var code, ready, script; url = "http://sys.4chan.org/" + data.board + "/post";
code = function(e) { delete data.board;
var data, host; if (engine === 'gecko' && data.upfile) {
data = e.data; if (!data.binary) {
if (!data.changeContext) return; toBin = function(data, name, val) {
delete data.changeContext; var bb, r;
host = location.hostname; bb = new MozBlobBuilder();
if (host === 'boards.4chan.org') { bb.append(val);
return document.getElementById('iframe').contentWindow.postMessage(data, '*'); r = new FileReader();
} else if (host === 'sys.4chan.org') { r.onload = function() {
return parent.postMessage(data, '*'); data[name] = r.result;
} if (!--i) return qr.post(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) {
var boundary, callbacks, form, i, name, opts, parts, toBin, url, val;
url = "http://sys.4chan.org/" + data.board + "/post";
delete data.board;
delete data.qr;
if (engine === 'gecko' && data.upfile) {
if (!data.binary) {
toBin = function(data, name, val) {
var bb, r;
bb = new MozBlobBuilder();
bb.append(val);
r = new FileReader();
r.onload = function() {
data[name] = r.result;
if (!--i) return qr.message.post(data);
};
return r.readAsBinaryString(bb.getBlob('text/plain'));
}; };
i = Object.keys(data).length; return r.readAsBinaryString(bb.getBlob('text/plain'));
for (name in data) { };
val = data[name]; i = Object.keys(data).length;
if (typeof val === 'object') { for (name in data) {
toBin(data.upfile, 'name', data.upfile.name); val = data[name];
} else if (typeof val === 'boolean') { if (typeof val === 'object') {
if (val) { toBin(data.upfile, 'name', data.upfile.name);
toBin(data, name, String(val)); } else if (typeof val === 'boolean') {
} else { if (val) {
i--; toBin(data, name, String(val));
}
} else { } else {
toBin(data, name, val); i--;
} }
} } else {
data.board = url.split('/')[3]; toBin(data, name, val);
data.binary = true;
return;
}
delete data.binary;
boundary = '-------------SMCD' + Date.now();
parts = [];
parts.push('Content-Disposition: form-data; name="upfile"; filename="' + data.upfile.name + '"\r\n' + 'Content-Type: ' + data.upfile.type + '\r\n\r\n' + data.upfile.buffer + '\r\n');
delete data.upfile;
for (name in data) {
val = data[name];
if (val) {
parts.push('Content-Disposition: form-data; name="' + name + '"\r\n\r\n' + val + '\r\n');
} }
} }
form = '--' + boundary + '\r\n' + parts.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n'; data.board = url.split('/')[3];
} else { data.binary = true;
form = new FormData(); return;
for (name in data) { }
val = data[name]; delete data.binary;
if (val) form.append(name, val); boundary = '-------------SMCD' + Date.now();
parts = [];
parts.push('Content-Disposition: form-data; name="upfile"; filename="' + data.upfile.name + '"\r\n' + 'Content-Type: ' + data.upfile.type + '\r\n\r\n' + data.upfile.buffer + '\r\n');
delete data.upfile;
for (name in data) {
val = data[name];
if (val) {
parts.push('Content-Disposition: form-data; name="' + name + '"\r\n\r\n' + val + '\r\n');
} }
} }
callbacks = { form = '--' + boundary + '\r\n' + parts.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n';
} else {
form = new FormData();
for (name in data) {
val = data[name];
if (val) form.append(name, val);
}
}
callbacks = {
onload: function() {
return message.send({
req: 'response',
html: this.response
});
}
};
opts = {
form: form,
type: 'post',
upCallbacks: {
onload: function() { onload: function() {
return qr.message.send({ return message.send({
req: 'response', req: 'status',
html: this.response progress: '...'
});
},
onprogress: function(e) {
return message.send({
req: 'status',
progress: "" + (Math.round(e.loaded / e.total * 100)) + "%"
}); });
} }
};
opts = {
form: form,
type: 'post',
upCallbacks: {
onload: function() {
return qr.message.send({
req: 'status',
progress: '...'
});
},
onprogress: function(e) {
return qr.message.send({
req: 'status',
progress: "" + (Math.round(e.loaded / e.total * 100)) + "%"
});
}
}
};
if (boundary) {
opts.headers = {
'Content-Type': 'multipart/form-data;boundary=' + boundary
};
} }
return qr.ajax = $.ajax(url, callbacks, opts); };
if (boundary) {
opts.headers = {
'Content-Type': 'multipart/form-data;boundary=' + boundary
};
} }
return qr.ajax = $.ajax(url, callbacks, opts);
} }
}; };
@ -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,121 +1413,78 @@ qr =
qr.status() qr.status()
qr.resetFileInput() qr.resetFileInput()
message: post: (data) ->
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) -> url = "http://sys.4chan.org/#{data.board}/post"
# Do not append that value to the form.
delete data.board
url = "http://sys.4chan.org/#{data.board}/post" # File with filename upload fix from desuwa
# Do not append these values to the form. if engine is 'gecko' and data.upfile
delete data.board # All of this is fucking retarded.
delete data.qr unless data.binary
toBin = (data, name, val) ->
# File with filename upload fix from desuwa bb = new MozBlobBuilder()
if engine is 'gecko' and data.upfile bb.append val
# All of this is fucking retarded. r = new FileReader()
unless data.binary r.onload = ->
toBin = (data, name, val) -> data[name] = r.result
bb = new MozBlobBuilder() unless --i
bb.append val qr.post data
r = new FileReader() r.readAsBinaryString bb.getBlob 'text/plain'
r.onload = -> i = Object.keys(data).length
data[name] = r.result for name, val of data
unless --i if typeof val is 'object' # File. toBin the filename.
qr.message.post data toBin data.upfile, 'name', data.upfile.name
r.readAsBinaryString bb.getBlob 'text/plain' else if typeof val is 'boolean'
i = Object.keys(data).length if val
for name, val of data toBin data, name, String val
if typeof val is 'object' # File. toBin the filename.
toBin data.upfile, 'name', data.upfile.name
else if typeof val is 'boolean'
if val
toBin data, name, String val
else
i--
else else
toBin data, name, val i--
data.board = url.split('/')[3] else
data.binary = true toBin data, name, val
return data.board = url.split('/')[3]
data.binary = true
return
delete data.binary delete data.binary
boundary = '-------------SMCD' + Date.now(); boundary = '-------------SMCD' + Date.now();
parts = [] parts = []
parts.push 'Content-Disposition: form-data; name="upfile"; filename="' + data.upfile.name + '"\r\n' + 'Content-Type: ' + data.upfile.type + '\r\n\r\n' + data.upfile.buffer + '\r\n' parts.push 'Content-Disposition: form-data; name="upfile"; filename="' + data.upfile.name + '"\r\n' + 'Content-Type: ' + data.upfile.type + '\r\n\r\n' + data.upfile.buffer + '\r\n'
delete data.upfile delete data.upfile
for name, val of data for name, val of data
parts.push 'Content-Disposition: form-data; name="' + name + '"\r\n\r\n' + val + '\r\n' if val parts.push 'Content-Disposition: form-data; name="' + name + '"\r\n\r\n' + val + '\r\n' if val
form = '--' + boundary + '\r\n' + parts.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n' form = '--' + boundary + '\r\n' + parts.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n'
else else
form = new FormData() form = new FormData()
for name, val of data for name, val of data
form.append name, val if val form.append name, val if val
callbacks = callbacks =
onload: ->
message.send
req: 'response'
html: @response
opts =
form: form
type: 'post'
upCallbacks:
onload: -> onload: ->
qr.message.send message.send
req: 'response' req: 'status'
html: @response progress: '...'
opts = onprogress: (e) ->
form: form message.send
type: 'post' req: 'status'
upCallbacks: progress: "#{Math.round e.loaded / e.total * 100}%"
onload: -> if boundary
qr.message.send opts.headers =
req: 'status' 'Content-Type': 'multipart/form-data;boundary=' + boundary
progress: '...'
onprogress: (e) ->
qr.message.send
req: 'status'
progress: "#{Math.round e.loaded / e.total * 100}%"
if boundary
opts.headers =
'Content-Type': 'multipart/form-data;boundary=' + boundary
qr.ajax = $.ajax url, callbacks, opts qr.ajax = $.ajax url, callbacks, opts
options = options =
init: -> init: ->
@ -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'