rewrite qr; encapsulate, html5 postmessage
This commit is contained in:
parent
dda969cac7
commit
0181da694f
411
4chan_x.js
411
4chan_x.js
@ -56,7 +56,7 @@
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var $, $$, DAY, a, arr, as, autoWatch, autohide, b, board, callback, changeCheckbox, changeValue, clearHidden, closeQR, config, cooldown, cutoff, d, delform, down, editSauce, el, expand, expandComment, expandThread, formSubmit, g, getConfig, getThread, getTime, hide, hideReply, hideThread, href, html, i, id, iframe, iframeLoad, imageClick, imageExpand, imageExpandClick, imageHover, imageResize, imageThumb, imageToggle, imageType, imageTypeChange, img, inAfter, inBefore, input, inputs, keyModeInsert, keyModeNormal, keydown, keypress, l1, lastChecked, log, m, mv, n, navbotr, navtopr, nodeInserted, now, omitted, onloadComment, onloadThread, option, options, parseResponse, pathname, qrListener, qrText, quickReply, recaptcha, recaptchaListener, recaptchaReload, redirect, replace, replyNav, report, request, rm, scroll, scrollThread, show, showReply, showThread, slice, span, src, start, stopPropagation, temp, text, textContent, thread, threadF, threads, tn, tzOffset, ui, up, updateAuto, updateCallback, updateFavicon, updateInterval, updateNow, updateTime, updateTitle, updateVerbose, updaterMake, watch, watchX, watcher, watcherUpdate, x, zeroPad, _, _base, _i, _j, _k, _l, _len, _len2, _len3, _len4, _len5, _len6, _len7, _m, _n, _ref, _ref2, _ref3, _ref4, _ref5;
|
||||
var $, $$, DAY, a, arr, as, autoWatch, callback, changeCheckbox, changeValue, clearHidden, closeQR, config, cooldown, cutoff, d, delform, down, editSauce, el, expand, expandComment, expandThread, g, getConfig, getThread, getTime, hide, hideReply, hideThread, href, html, i, id, imageClick, imageExpand, imageExpandClick, imageHover, imageResize, imageThumb, imageToggle, imageType, imageTypeChange, img, inAfter, inBefore, input, inputs, keyModeInsert, keyModeNormal, keydown, keypress, l1, lastChecked, log, m, mv, n, navbotr, navtopr, nodeInserted, now, omitted, onloadComment, onloadThread, option, options, parseResponse, pathname, qr, recaptcha, recaptchaListener, recaptchaReload, redirect, replace, replyNav, report, request, rm, scroll, scrollThread, show, showReply, showThread, slice, span, src, start, stopPropagation, temp, text, textContent, threadF, threads, tn, tzOffset, ui, up, updateAuto, updateCallback, updateFavicon, updateInterval, updateNow, updateTime, updateTitle, updateVerbose, updaterMake, watch, watchX, watcher, watcherUpdate, x, zeroPad, _i, _j, _k, _l, _len, _len2, _len3, _len4, _len5, _len6, _len7, _m, _n, _ref, _ref2, _ref3, _ref4;
|
||||
var __slice = Array.prototype.slice;
|
||||
if (typeof console != "undefined" && console !== null) {
|
||||
log = console.log;
|
||||
@ -241,6 +241,29 @@
|
||||
return object;
|
||||
};
|
||||
$.extend($, {
|
||||
addClass: function(el, className) {
|
||||
return el.className += ' ' + className;
|
||||
},
|
||||
removeClass: function(el, className) {
|
||||
return el.className = el.className.replace(' ' + className, '');
|
||||
},
|
||||
rm: function(el) {
|
||||
return el.parentNode.removeChild(el);
|
||||
},
|
||||
append: function(parent, child) {
|
||||
return parent.appendChild(child);
|
||||
},
|
||||
before: function(root, el) {
|
||||
return root.parentNode.insertBefore(el, root);
|
||||
},
|
||||
el: function(tag, properties) {
|
||||
var el;
|
||||
el = d.createElement(tag);
|
||||
if (properties) {
|
||||
$.extend(el, properties);
|
||||
}
|
||||
return el;
|
||||
},
|
||||
bind: function(el, eventType, handler) {
|
||||
return el.addEventListener(eventType, handler, true);
|
||||
},
|
||||
@ -387,17 +410,6 @@
|
||||
return n;
|
||||
}
|
||||
};
|
||||
autohide = function() {
|
||||
var klass, qr;
|
||||
qr = $('#qr');
|
||||
klass = qr.className;
|
||||
if (this.checked) {
|
||||
klass += ' auto';
|
||||
} else {
|
||||
klass = klass.replace(' auto', '');
|
||||
}
|
||||
return qr.className = klass;
|
||||
};
|
||||
autoWatch = function() {
|
||||
var autoText;
|
||||
autoText = $('textarea', this).value.slice(0, 25);
|
||||
@ -500,28 +512,6 @@
|
||||
}
|
||||
}
|
||||
};
|
||||
formSubmit = function(e) {
|
||||
var recaptcha, span, _ref;
|
||||
if (span = this.nextSibling) {
|
||||
rm(span);
|
||||
}
|
||||
recaptcha = $('input[name=recaptcha_response_field]', this);
|
||||
if (recaptcha.value) {
|
||||
if ((_ref = $('#qr input[title=autohide]:not(:checked)')) != null) {
|
||||
_ref.click();
|
||||
}
|
||||
return g.sage = $('#qr input[name=email]').value === 'sage' ? true : false;
|
||||
} else {
|
||||
e.preventDefault();
|
||||
span = n('span', {
|
||||
className: 'error',
|
||||
textContent: 'You forgot to type in the verification.'
|
||||
});
|
||||
mv(span, this.parentNode);
|
||||
alert('You forgot to type in the verification.');
|
||||
return recaptcha.focus();
|
||||
}
|
||||
};
|
||||
hideReply = function(reply) {
|
||||
var a, div, name, p, table, trip, _ref;
|
||||
if (p = this.parentNode) {
|
||||
@ -576,42 +566,6 @@
|
||||
return inBefore(div, a);
|
||||
}
|
||||
};
|
||||
iframeLoad = function() {
|
||||
var auto, error, f, qr, span, submit, _ref, _ref2;
|
||||
if (g.iframe = !g.iframe) {
|
||||
return;
|
||||
}
|
||||
$('iframe').src = 'about:blank';
|
||||
qr = $('#qr');
|
||||
if (error = GM_getValue('error')) {
|
||||
span = n('span', {
|
||||
textContent: error,
|
||||
className: 'error'
|
||||
});
|
||||
mv(span, qr);
|
||||
if ((_ref = $('input[title=autohide]:checked', qr)) != null) {
|
||||
_ref.click();
|
||||
}
|
||||
} else if (g.REPLY && getConfig('Persistent QR')) {
|
||||
$('textarea', qr).value = '';
|
||||
$('input[name=recaptcha_response_field]', qr).value = '';
|
||||
f = $('input[type=file]', qr).parentNode;
|
||||
f.innerHTML = f.innerHTML;
|
||||
submit = $('input[type=submit]', qr);
|
||||
submit.value = g.sage ? 60 : 30;
|
||||
submit.disabled = true;
|
||||
window.setTimeout(cooldown, 1000);
|
||||
auto = submit.previousSibling.lastChild;
|
||||
if (auto.checked) {
|
||||
if ((_ref2 = $('input[title=autohide]:checked', qr)) != null) {
|
||||
_ref2.click();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
rm(qr);
|
||||
}
|
||||
return recaptchaReload();
|
||||
};
|
||||
imageHover = {
|
||||
init: function() {
|
||||
var img;
|
||||
@ -830,9 +784,14 @@
|
||||
}
|
||||
}
|
||||
if (e.shiftKey) {
|
||||
return quickReply(qrLink);
|
||||
$.append(d.body, qr.dialog(qrLink));
|
||||
return $('#qr textarea').focus();
|
||||
} else {
|
||||
return quickReply(qrLink, qrText(qrLink));
|
||||
e = {
|
||||
preventDefault: function() {},
|
||||
target: qrLink
|
||||
};
|
||||
return qr.cb.quote(e);
|
||||
}
|
||||
break;
|
||||
case "J":
|
||||
@ -926,7 +885,7 @@
|
||||
}
|
||||
};
|
||||
nodeInserted = function(e) {
|
||||
var callback, qr, target, _i, _len, _ref, _results;
|
||||
var callback, dialog, target, _i, _len, _ref, _results;
|
||||
target = e.target;
|
||||
if (target.nodeName === 'TABLE') {
|
||||
_ref = g.callbacks;
|
||||
@ -936,9 +895,9 @@
|
||||
_results.push(callback(target));
|
||||
}
|
||||
return _results;
|
||||
} else if (target.id === 'recaptcha_challenge_field' && (qr = $('#qr'))) {
|
||||
$('#recaptcha_image img', qr).src = "http://www.google.com/recaptcha/api/image?c=" + target.value;
|
||||
return $('#recaptcha_challenge_field', qr).value = target.value;
|
||||
} else if (target.id === 'recaptcha_challenge_field' && (dialog = $('#qr'))) {
|
||||
$('#recaptcha_image img', dialog).src = "http://www.google.com/recaptcha/api/image?c=" + target.value;
|
||||
return $('#recaptcha_challenge_field', dialog).value = target.value;
|
||||
}
|
||||
};
|
||||
onloadComment = function(responseText, a, href) {
|
||||
@ -1029,73 +988,200 @@
|
||||
opbq = $('blockquote', body);
|
||||
return [replies, opbq];
|
||||
};
|
||||
qrListener = function(e) {
|
||||
var link, text;
|
||||
e.preventDefault();
|
||||
link = e.target;
|
||||
text = qrText(link);
|
||||
return quickReply(link, text);
|
||||
};
|
||||
qrText = function(link) {
|
||||
var id, s, selection, text, _ref;
|
||||
text = '>>' + link.parentNode.id.match(/\d+$/)[0] + '\n';
|
||||
selection = window.getSelection();
|
||||
id = (_ref = x('preceding::span[@id][1]', selection.anchorNode)) != null ? _ref.id : void 0;
|
||||
if ((s = selection.toString()) && (id === link.parentNode.id)) {
|
||||
text += ">" + s;
|
||||
}
|
||||
return text;
|
||||
};
|
||||
quickReply = function(link, text) {
|
||||
var auto, autoBox, clone, form, html, input, qr, script, submit, textarea, xpath, _i, _len, _ref, _ref2;
|
||||
if (!(qr = $('#qr'))) {
|
||||
html = "<div class=move>Quick Reply <input type=checkbox title=autohide><a name=close title=close>X</a></div>";
|
||||
qr = ui.dialog('qr', 'topleft', html);
|
||||
$('input[title=autohide]', qr).addEventListener('click', autohide, true);
|
||||
form = $('form[name=post]');
|
||||
clone = form.cloneNode(true);
|
||||
qr = {
|
||||
init: function() {
|
||||
var iframe;
|
||||
g.callbacks.push(qr.cb.node);
|
||||
iframe = $.el('iframe', {
|
||||
name: 'iframe'
|
||||
});
|
||||
$.append(d.body, iframe);
|
||||
$.bind(iframe, 'load', qr.cb.load);
|
||||
$.bind(window, 'message', qr.cb.messageTop);
|
||||
return $('#recaptcha_response_field').id = '';
|
||||
},
|
||||
autohide: {
|
||||
set: function() {
|
||||
var _ref;
|
||||
return (_ref = $('#qr input[title=autohide]:not(:checked)')) != null ? _ref.click() : void 0;
|
||||
},
|
||||
unset: function() {
|
||||
var _ref;
|
||||
return (_ref = $('#qr input[title=autohide]:checked')) != null ? _ref.click() : void 0;
|
||||
}
|
||||
},
|
||||
cb: {
|
||||
autohide: function(e) {
|
||||
var dialog;
|
||||
dialog = $('#qr');
|
||||
if (this.checked) {
|
||||
return $.addClass(dialog, 'auto');
|
||||
} else {
|
||||
return $.removeClass(dialog, 'auto');
|
||||
}
|
||||
},
|
||||
load: function(e) {
|
||||
return e.target.contentWindow.postMessage('', '*');
|
||||
},
|
||||
messageIframe: function(e) {
|
||||
var message;
|
||||
message = $('table b').firstChild.textContent;
|
||||
e.source.postMessage(message, '*');
|
||||
return window.location = 'about:blank';
|
||||
},
|
||||
messageTop: function(e) {
|
||||
var data, dialog, error;
|
||||
data = e.data;
|
||||
dialog = $('#qr');
|
||||
if (data === 'Post successful!') {
|
||||
if (dialog) {
|
||||
if (getConfig('Persistent QR')) {
|
||||
qr.refresh(dialog);
|
||||
} else {
|
||||
$.rm(dialog);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error = $.el('span', {
|
||||
className: 'error',
|
||||
textContent: data
|
||||
});
|
||||
$.append(dialog, error);
|
||||
qr.autohide.unset();
|
||||
}
|
||||
return recaptchaReload();
|
||||
},
|
||||
node: function(root) {
|
||||
var quote, quotes, _i, _len, _results;
|
||||
quotes = $$('a.quotejs:not(:first-child)', root);
|
||||
_results = [];
|
||||
for (_i = 0, _len = quotes.length; _i < _len; _i++) {
|
||||
quote = quotes[_i];
|
||||
_results.push($.bind(quote, 'click', qr.cb.quote));
|
||||
}
|
||||
return _results;
|
||||
},
|
||||
submit: function(e) {
|
||||
var recaptcha, span;
|
||||
if (span = this.nextSibling) {
|
||||
$.rm(span);
|
||||
}
|
||||
recaptcha = $('input[name=recaptcha_response_field]', this);
|
||||
if (recaptcha.value) {
|
||||
qr.autohide.set();
|
||||
return g.sage = $('#qr input[name=email]').value === 'sage';
|
||||
} else {
|
||||
e.preventDefault();
|
||||
span = $.el('span', {
|
||||
className: 'error',
|
||||
textContent: 'You forgot to type in the verification.'
|
||||
});
|
||||
$.append(this.parentNode, span);
|
||||
alert('You forgot to type in the verification.');
|
||||
return recaptcha.focus();
|
||||
}
|
||||
},
|
||||
quote: function(e) {
|
||||
var dialog, id, s, selection, selectionID, ta, target, text, _ref;
|
||||
e.preventDefault();
|
||||
target = e.target;
|
||||
if (!(dialog = $('#qr'))) {
|
||||
dialog = qr.dialog(target);
|
||||
}
|
||||
id = target.textContent;
|
||||
text = ">>" + id + "\n";
|
||||
selection = window.getSelection();
|
||||
if (s = selection.toString()) {
|
||||
selectionID = (_ref = x('preceding::input[@type="checkbox"][1]', selection.anchorNode)) != null ? _ref.name : void 0;
|
||||
if (selectionID === id) {
|
||||
text += ">" + s + "\n";
|
||||
}
|
||||
}
|
||||
ta = $('textarea', dialog);
|
||||
ta.focus();
|
||||
return ta.value += text;
|
||||
},
|
||||
refresh: function(dialog) {
|
||||
var auto, f, submit, _ref;
|
||||
$('textarea', dialog).value = '';
|
||||
$('input[name=recaptcha_response_field]', dialog).value = '';
|
||||
f = $('input[type=file]', dialog).parentNode;
|
||||
f.innerHTML = f.innerHTML;
|
||||
submit = $('input[type=submit]', qr);
|
||||
submit.value = g.sage ? 60 : 30;
|
||||
submit.disabled = true;
|
||||
window.setTimeout(cooldown, 1000);
|
||||
auto = submit.previousSibling.lastChild;
|
||||
if (auto.checked) {
|
||||
return (_ref = $('input[title=autohide]:checked', qr)) != null ? _ref.click() : void 0;
|
||||
}
|
||||
}
|
||||
},
|
||||
dialog: function(link) {
|
||||
var auto, autobox, clone, dialog, el, html, input, script, submit, xpath, _i, _len, _ref;
|
||||
html = "<div class=move>Quick Reply <input type=checkbox title=autohide> <a name=close title=close>X</a></div>";
|
||||
dialog = ui.dialog('qr', {
|
||||
top: '0px',
|
||||
left: '0px'
|
||||
}, html);
|
||||
el = $('input[title=autohide]', dialog);
|
||||
$.bind(el, 'click', qr.cb.autohide);
|
||||
clone = $('form[name=post]').cloneNode(true);
|
||||
_ref = $$('script', clone);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
script = _ref[_i];
|
||||
rm(script);
|
||||
$.rm(script);
|
||||
}
|
||||
m($('input[name=recaptcha_response_field]', clone), {
|
||||
listener: ['keydown', recaptchaListener]
|
||||
});
|
||||
m(clone, {
|
||||
listener: ['submit', formSubmit],
|
||||
target: 'iframe'
|
||||
});
|
||||
clone.target = 'iframe';
|
||||
$.bind(clone, 'submit', qr.cb.submit);
|
||||
$.bind($('input[name=recaptcha_response_field]', clone), 'keydown', recaptchaListener);
|
||||
if (!g.REPLY) {
|
||||
xpath = 'preceding::span[@class="postername"][1]/preceding::input[1]';
|
||||
input = n('input', {
|
||||
input = $.el('input', {
|
||||
type: 'hidden',
|
||||
name: 'resto',
|
||||
value: x(xpath, link).name
|
||||
});
|
||||
mv(input, clone);
|
||||
$.append(clone, input);
|
||||
} else if (getConfig('Persistent QR')) {
|
||||
submit = $('input[type=submit]', clone);
|
||||
auto = n('label', {
|
||||
auto = $.el('label', {
|
||||
textContent: 'Auto'
|
||||
});
|
||||
autoBox = n('input', {
|
||||
autobox = $.el('input', {
|
||||
type: 'checkbox'
|
||||
});
|
||||
mv(autoBox, auto);
|
||||
inBefore(submit, auto);
|
||||
$.append(auto, autobox);
|
||||
$.before(submit, auto);
|
||||
}
|
||||
$.append(dialog, clone);
|
||||
$.append(d.body, dialog);
|
||||
dialog.style.width = dialog.offsetWidth;
|
||||
return dialog;
|
||||
},
|
||||
persist: function() {
|
||||
$.append(d.body, qr.dialog());
|
||||
return qr.autohide.set();
|
||||
},
|
||||
sys: function() {
|
||||
var board, html, id, recaptcha, thread, _, _base, _ref, _ref2;
|
||||
$.bind(window, 'message', qr.cb.messageIframe);
|
||||
if (recaptcha = $('#recaptcha_response_field')) {
|
||||
$.bind(recaptcha, 'keydown', recaptchaListener);
|
||||
}
|
||||
if (getConfig('Auto Watch')) {
|
||||
html = $('b').innerHTML;
|
||||
_ref = html.match(/<!-- thread:(\d+),no:(\d+) -->/), _ = _ref[0], thread = _ref[1], id = _ref[2];
|
||||
if (thread === '0') {
|
||||
_ref2 = $('meta', d).content.match(/4chan.org\/(\w+)\//), _ = _ref2[0], board = _ref2[1];
|
||||
(_base = g.watched)[board] || (_base[board] = []);
|
||||
g.watched[board].push({
|
||||
id: id,
|
||||
text: GM_getValue('autoText')
|
||||
});
|
||||
return GM_setValue('watched', JSON.stringify(g.watched));
|
||||
}
|
||||
}
|
||||
mv(clone, qr);
|
||||
mv(qr, d.body);
|
||||
qr.style.width = qr.offsetWidth;
|
||||
}
|
||||
if ((_ref2 = $('input[title=autohide]:checked', qr)) != null) {
|
||||
_ref2.click();
|
||||
}
|
||||
textarea = $('textarea', qr);
|
||||
textarea.focus();
|
||||
if (text) {
|
||||
return textarea.value += text;
|
||||
}
|
||||
};
|
||||
recaptchaListener = function(e) {
|
||||
@ -1484,7 +1570,6 @@
|
||||
favDefault: ((_ref = $('link[rel="shortcut icon"]', d)) != null ? _ref.href : void 0) || '',
|
||||
favEmpty: 'http://static.4chan.org/image/favicon-dis.ico',
|
||||
flavors: ['http://regex.info/exif.cgi?url=', 'http://iqdb.org/?url=', 'http://saucenao.com/search.php?db=999&url=', 'http://tineye.com/search?url='].join('\n'),
|
||||
iframe: false,
|
||||
watched: JSON.parse(GM_getValue('watched', '{}')),
|
||||
xhrs: []
|
||||
};
|
||||
@ -1504,31 +1589,6 @@
|
||||
if ($.isDST()) {
|
||||
g.chanOffset -= 1;
|
||||
}
|
||||
if (location.hostname.split('.')[0] === 'sys') {
|
||||
if (recaptcha = $('#recaptcha_response_field')) {
|
||||
m(recaptcha, {
|
||||
listener: ['keydown', recaptchaListener]
|
||||
});
|
||||
} else if (b = $('table font b')) {
|
||||
GM_setValue('error', b.firstChild.textContent);
|
||||
} else {
|
||||
GM_setValue('error', '');
|
||||
if (getConfig('Auto Watch')) {
|
||||
html = $('b').innerHTML;
|
||||
_ref2 = html.match(/<!-- thread:(\d+),no:(\d+) -->/), _ = _ref2[0], thread = _ref2[1], id = _ref2[2];
|
||||
if (thread === '0') {
|
||||
board = $('meta', d).content.match(/4chan.org\/(\w+)\//)[1];
|
||||
(_base = g.watched)[board] || (_base[board] = []);
|
||||
g.watched[board].push({
|
||||
id: id,
|
||||
text: GM_getValue('autoText')
|
||||
});
|
||||
GM_setValue('watched', JSON.stringify(g.watched));
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
lastChecked = GM_getValue('lastChecked', 0);
|
||||
now = getTime();
|
||||
DAY = 24 * 60 * 60;
|
||||
@ -1628,6 +1688,10 @@
|
||||
background: lime;\
|
||||
}\
|
||||
');
|
||||
if (location.hostname === 'sys.4chan.org') {
|
||||
qr.sys();
|
||||
return;
|
||||
}
|
||||
if (navtopr = $('#navtopr a')) {
|
||||
a = n('a', {
|
||||
textContent: '4chan X',
|
||||
@ -1647,9 +1711,9 @@
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
_ref3 = $$('#recaptcha_table a');
|
||||
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
|
||||
el = _ref3[_i];
|
||||
_ref2 = $$('#recaptcha_table a');
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
el = _ref2[_i];
|
||||
el.tabIndex = 1;
|
||||
}
|
||||
recaptcha = $('#recaptcha_response_field');
|
||||
@ -1677,9 +1741,9 @@
|
||||
innerHTML: "<select id=imageType name=imageType><option>full</option><option>fit width</option><option>fit screen</option></select> <label>Expand Images<input type=checkbox id=imageExpand></label>"
|
||||
});
|
||||
imageType = GM_getValue('imageType', 'full');
|
||||
_ref4 = $$("option", expand);
|
||||
for (_j = 0, _len2 = _ref4.length; _j < _len2; _j++) {
|
||||
option = _ref4[_j];
|
||||
_ref3 = $$("option", expand);
|
||||
for (_j = 0, _len2 = _ref3.length; _j < _len2; _j++) {
|
||||
option = _ref3[_j];
|
||||
if (option.textContent === imageType) {
|
||||
option.selected = true;
|
||||
break;
|
||||
@ -1719,7 +1783,7 @@
|
||||
}
|
||||
if (getConfig('Localize Time')) {
|
||||
g.callbacks.push(function(root) {
|
||||
var date, day, dotw, hour, min_sec, month, s, span, spans, year, _i, _len, _ref, _results;
|
||||
var date, day, dotw, hour, min_sec, month, s, span, spans, year, _, _i, _len, _ref, _results;
|
||||
spans = $$('span[id^=no]', root);
|
||||
_results = [];
|
||||
for (_i = 0, _len = spans.length; _i < _len; _i++) {
|
||||
@ -1779,7 +1843,7 @@
|
||||
}
|
||||
if (getConfig('Reply Hiding')) {
|
||||
g.callbacks.push(function(root) {
|
||||
var next, obj, td, tds, _i, _len, _results;
|
||||
var id, next, obj, td, tds, _i, _len, _results;
|
||||
tds = $$('td.doubledash', root);
|
||||
_results = [];
|
||||
for (_i = 0, _len = tds.length; _i < _len; _i++) {
|
||||
@ -1807,23 +1871,7 @@
|
||||
});
|
||||
}
|
||||
if (getConfig('Quick Reply')) {
|
||||
iframe = n('iframe', {
|
||||
name: 'iframe',
|
||||
listener: ['load', iframeLoad]
|
||||
});
|
||||
hide(iframe);
|
||||
mv(iframe, d.body);
|
||||
g.callbacks.push(function(root) {
|
||||
var quote, quotes, _i, _len, _results;
|
||||
quotes = $$('a.quotejs:not(:first-child)', root);
|
||||
_results = [];
|
||||
for (_i = 0, _len = quotes.length; _i < _len; _i++) {
|
||||
quote = quotes[_i];
|
||||
_results.push(quote.addEventListener('click', qrListener, true));
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
recaptcha.id = '';
|
||||
qr.init();
|
||||
}
|
||||
if (getConfig('Quick Report')) {
|
||||
g.callbacks.push(function(root) {
|
||||
@ -1939,8 +1987,7 @@
|
||||
updaterMake();
|
||||
}
|
||||
if (getConfig('Quick Reply') && getConfig('Persistent QR')) {
|
||||
quickReply();
|
||||
$('#qr input[title=autohide]').click();
|
||||
qr.persist();
|
||||
}
|
||||
if (getConfig('Post in Title')) {
|
||||
if (!(text = $('span.filetitle').textContent)) {
|
||||
@ -2036,9 +2083,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
_ref5 = g.callbacks;
|
||||
for (_n = 0, _len7 = _ref5.length; _n < _len7; _n++) {
|
||||
callback = _ref5[_n];
|
||||
_ref4 = g.callbacks;
|
||||
for (_n = 0, _len7 = _ref4.length; _n < _len7; _n++) {
|
||||
callback = _ref4[_n];
|
||||
callback();
|
||||
}
|
||||
d.body.addEventListener('DOMNodeInserted', nodeInserted, true);
|
||||
|
||||
313
script.coffee
313
script.coffee
@ -143,12 +143,26 @@ $.extend = (object, properties) ->
|
||||
object
|
||||
|
||||
$.extend $,
|
||||
addClass: (el, className) ->
|
||||
el.className += ' ' + className
|
||||
removeClass: (el, className) ->
|
||||
el.className = el.className.replace ' ' + className, ''
|
||||
rm: (el) ->
|
||||
el.parentNode.removeChild el
|
||||
append: (parent, child) ->
|
||||
parent.appendChild child
|
||||
before: (root, el) ->
|
||||
root.parentNode.insertBefore el, root
|
||||
el: (tag, properties) ->
|
||||
el = d.createElement tag
|
||||
$.extend el, properties if properties
|
||||
el
|
||||
bind: (el, eventType, handler) ->
|
||||
el.addEventListener eventType, handler, true
|
||||
unbind: (el, eventType, handler) ->
|
||||
el.removeEventListener eventType, handler, true
|
||||
isDST: ->
|
||||
# XXX this should be isDSTinNY
|
||||
# XXX this should check for DST in NY
|
||||
###
|
||||
http://en.wikipedia.org/wiki/Daylight_saving_time_in_the_United_States
|
||||
Since 2007, daylight saving time starts on the second Sunday of March
|
||||
@ -249,15 +263,6 @@ zeroPad = (n) ->
|
||||
if n < 10 then '0' + n else n
|
||||
|
||||
#funks
|
||||
autohide = ->
|
||||
qr = $ '#qr'
|
||||
klass = qr.className
|
||||
if @checked
|
||||
klass += ' auto'
|
||||
else
|
||||
klass = klass.replace(' auto', '')
|
||||
qr.className = klass
|
||||
|
||||
autoWatch = ->
|
||||
#TODO look for subject
|
||||
autoText = $('textarea', this).value.slice(0, 25)
|
||||
@ -345,22 +350,6 @@ getThread = ->
|
||||
if bottom > 0 #we have not scrolled past
|
||||
return [thread, i]
|
||||
|
||||
formSubmit = (e) ->
|
||||
if span = @nextSibling
|
||||
rm span
|
||||
recaptcha = $('input[name=recaptcha_response_field]', this)
|
||||
if recaptcha.value
|
||||
$('#qr input[title=autohide]:not(:checked)')?.click()
|
||||
g.sage = if $('#qr input[name=email]').value is 'sage' then true else false
|
||||
else
|
||||
e.preventDefault()
|
||||
span = n 'span',
|
||||
className: 'error'
|
||||
textContent: 'You forgot to type in the verification.'
|
||||
mv span, @parentNode
|
||||
alert 'You forgot to type in the verification.'
|
||||
recaptcha.focus()
|
||||
|
||||
hideReply = (reply) ->
|
||||
if p = @parentNode
|
||||
reply = p.nextSibling
|
||||
@ -406,35 +395,6 @@ hideThread = (div) ->
|
||||
listener: ['click', showThread]
|
||||
inBefore div, a
|
||||
|
||||
iframeLoad = ->
|
||||
if g.iframe = !g.iframe
|
||||
return
|
||||
$('iframe').src = 'about:blank'
|
||||
qr = $ '#qr'
|
||||
if error = GM_getValue 'error'
|
||||
span = n 'span',
|
||||
textContent: error
|
||||
className: 'error'
|
||||
mv span, qr
|
||||
$('input[title=autohide]:checked', qr)?.click()
|
||||
else if g.REPLY and getConfig 'Persistent QR'
|
||||
$('textarea', qr).value = ''
|
||||
$('input[name=recaptcha_response_field]', qr).value = ''
|
||||
# XXX file.value = '' doesn't work in opera
|
||||
f = $('input[type=file]', qr).parentNode
|
||||
f.innerHTML = f.innerHTML
|
||||
submit = $ 'input[type=submit]', qr
|
||||
submit.value = if g.sage then 60 else 30
|
||||
submit.disabled = true
|
||||
window.setTimeout cooldown, 1000
|
||||
auto = submit.previousSibling.lastChild
|
||||
if auto.checked
|
||||
#unhide the qr so you know it's ready for the next item
|
||||
$('input[title=autohide]:checked', qr)?.click()
|
||||
else
|
||||
rm qr
|
||||
recaptchaReload()
|
||||
|
||||
imageHover =
|
||||
init: ->
|
||||
img = n 'img', id: 'iHover'
|
||||
@ -615,9 +575,14 @@ keyModeNormal = (e) ->
|
||||
unless qrLink = $ 'td.replyhl span[id] a:not(:first-child)', thread
|
||||
qrLink = $ "span#nothread#{thread.id} a:not(:first-child)", thread
|
||||
if e.shiftKey
|
||||
quickReply qrLink
|
||||
$.append d.body, qr.dialog qrLink
|
||||
$('#qr textarea').focus()
|
||||
else
|
||||
quickReply qrLink, qrText qrLink
|
||||
# qrLink.click() doesn't work, so use this hack
|
||||
e =
|
||||
preventDefault: ->
|
||||
target: qrLink
|
||||
qr.cb.quote e
|
||||
when "J"
|
||||
if e.shiftKey
|
||||
if not g.REPLY then [root] = getThread()
|
||||
@ -687,9 +652,9 @@ nodeInserted = (e) ->
|
||||
if target.nodeName is 'TABLE'
|
||||
for callback in g.callbacks
|
||||
callback target
|
||||
else if target.id is 'recaptcha_challenge_field' and qr = $ '#qr'
|
||||
$('#recaptcha_image img', qr).src = "http://www.google.com/recaptcha/api/image?c=" + target.value
|
||||
$('#recaptcha_challenge_field', qr).value = target.value
|
||||
else if target.id is 'recaptcha_challenge_field' and dialog = $ '#qr'
|
||||
$('#recaptcha_image img', dialog).src = "http://www.google.com/recaptcha/api/image?c=" + target.value
|
||||
$('#recaptcha_challenge_field', dialog).value = target.value
|
||||
|
||||
onloadComment = (responseText, a, href) ->
|
||||
[_, op, id] = href.match /(\d+)#(\d+)/
|
||||
@ -760,63 +725,169 @@ parseResponse = (responseText) ->
|
||||
opbq = $ 'blockquote', body
|
||||
return [replies, opbq]
|
||||
|
||||
qrListener = (e) ->
|
||||
e.preventDefault()
|
||||
link = e.target
|
||||
text = qrText link
|
||||
quickReply link, text
|
||||
qr =
|
||||
init: ->
|
||||
g.callbacks.push qr.cb.node
|
||||
iframe = $.el 'iframe',
|
||||
name: 'iframe'
|
||||
$.append d.body, iframe
|
||||
$.bind iframe, 'load', qr.cb.load
|
||||
$.bind window, 'message', qr.cb.messageTop
|
||||
|
||||
qrText = (link) ->
|
||||
#we can't just use textContent b/c of the xxxs. goddamit moot.
|
||||
text = '>>' + link.parentNode.id.match(/\d+$/)[0] + '\n'
|
||||
#hack - nuke id so it doesn't grab focus when reloading
|
||||
$('#recaptcha_response_field').id = ''
|
||||
|
||||
selection = window.getSelection()
|
||||
id = x('preceding::span[@id][1]', selection.anchorNode)?.id
|
||||
if (s = selection.toString()) and (id is link.parentNode.id)
|
||||
text += ">#{s}"
|
||||
autohide:
|
||||
set: ->
|
||||
$('#qr input[title=autohide]:not(:checked)')?.click()
|
||||
unset: ->
|
||||
$('#qr input[title=autohide]:checked')?.click()
|
||||
|
||||
text
|
||||
cb:
|
||||
autohide: (e) ->
|
||||
dialog = $ '#qr'
|
||||
if @checked
|
||||
$.addClass dialog, 'auto'
|
||||
else
|
||||
$.removeClass dialog, 'auto'
|
||||
|
||||
quickReply = (link, text) ->
|
||||
unless qr = $ '#qr'
|
||||
html = "<div class=move>Quick Reply <input type=checkbox title=autohide><a name=close title=close>X</a></div>"
|
||||
qr = ui.dialog 'qr', 'topleft', html
|
||||
$('input[title=autohide]', qr).addEventListener 'click', autohide, true
|
||||
load: (e) ->
|
||||
e.target.contentWindow.postMessage '', '*'
|
||||
|
||||
form = $ 'form[name=post]'
|
||||
clone = form.cloneNode true
|
||||
#remove recaptcha scripts
|
||||
messageIframe: (e) ->
|
||||
message = $('table b').firstChild.textContent
|
||||
e.source.postMessage message, '*'
|
||||
window.location = 'about:blank'
|
||||
|
||||
messageTop: (e) ->
|
||||
{data} = e
|
||||
dialog = $ '#qr'
|
||||
if data is 'Post successful!'
|
||||
if dialog
|
||||
if getConfig 'Persistent QR'
|
||||
qr.refresh dialog
|
||||
else
|
||||
$.rm dialog
|
||||
else
|
||||
error = $.el 'span',
|
||||
className: 'error'
|
||||
textContent: data
|
||||
$.append dialog, error
|
||||
qr.autohide.unset()
|
||||
|
||||
recaptchaReload()
|
||||
|
||||
node: (root) ->
|
||||
quotes = $$ 'a.quotejs:not(:first-child)', root
|
||||
for quote in quotes
|
||||
$.bind quote, 'click', qr.cb.quote
|
||||
|
||||
submit: (e) ->
|
||||
if span = @nextSibling
|
||||
$.rm span
|
||||
recaptcha = $('input[name=recaptcha_response_field]', this)
|
||||
if recaptcha.value
|
||||
qr.autohide.set()
|
||||
g.sage = $('#qr input[name=email]').value == 'sage'
|
||||
else
|
||||
e.preventDefault()
|
||||
span = $.el 'span',
|
||||
className: 'error'
|
||||
textContent: 'You forgot to type in the verification.'
|
||||
$.append @parentNode, span
|
||||
alert 'You forgot to type in the verification.'
|
||||
recaptcha.focus()
|
||||
|
||||
quote: (e) ->
|
||||
e.preventDefault()
|
||||
{target} = e
|
||||
unless dialog = $ '#qr'
|
||||
dialog = qr.dialog target
|
||||
|
||||
id = target.textContent
|
||||
text = ">>#{id}\n"
|
||||
|
||||
selection = window.getSelection()
|
||||
if s = selection.toString()
|
||||
selectionID = x('preceding::input[@type="checkbox"][1]', selection.anchorNode)?.name
|
||||
if selectionID == id
|
||||
text += ">#{s}\n"
|
||||
|
||||
ta = $ 'textarea', dialog
|
||||
ta.focus()
|
||||
ta.value += text
|
||||
|
||||
refresh: (dialog) ->
|
||||
$('textarea', dialog).value = ''
|
||||
$('input[name=recaptcha_response_field]', dialog).value = ''
|
||||
# XXX file.value = '' doesn't work in opera
|
||||
f = $('input[type=file]', dialog).parentNode
|
||||
f.innerHTML = f.innerHTML
|
||||
submit = $ 'input[type=submit]', qr
|
||||
submit.value = if g.sage then 60 else 30
|
||||
submit.disabled = true
|
||||
window.setTimeout cooldown, 1000
|
||||
auto = submit.previousSibling.lastChild
|
||||
if auto.checked
|
||||
#unhide the qr so you know it's ready for the next item
|
||||
$('input[title=autohide]:checked', qr)?.click()
|
||||
|
||||
dialog: (link) ->
|
||||
html = "<div class=move>Quick Reply <input type=checkbox title=autohide> <a name=close title=close>X</a></div>"
|
||||
dialog = ui.dialog 'qr', top: '0px', left: '0px', html
|
||||
el = $ 'input[title=autohide]', dialog
|
||||
$.bind el, 'click', qr.cb.autohide
|
||||
|
||||
clone = $('form[name=post]').cloneNode(true)
|
||||
for script in $$ 'script', clone
|
||||
rm script
|
||||
m $('input[name=recaptcha_response_field]', clone),
|
||||
listener: ['keydown', recaptchaListener]
|
||||
m clone,
|
||||
listener: ['submit', formSubmit]
|
||||
target: 'iframe'
|
||||
$.rm script
|
||||
clone.target = 'iframe'
|
||||
$.bind clone, 'submit', qr.cb.submit
|
||||
$.bind $('input[name=recaptcha_response_field]', clone), 'keydown', recaptchaListener
|
||||
|
||||
if not g.REPLY
|
||||
#figure out which thread we're replying to
|
||||
xpath = 'preceding::span[@class="postername"][1]/preceding::input[1]'
|
||||
input = n 'input',
|
||||
input = $.el 'input',
|
||||
type: 'hidden'
|
||||
name: 'resto'
|
||||
value: x(xpath, link).name
|
||||
mv input, clone
|
||||
$.append clone, input
|
||||
else if getConfig 'Persistent QR'
|
||||
submit = $ 'input[type=submit]', clone
|
||||
auto = n 'label',
|
||||
auto = $.el 'label',
|
||||
textContent: 'Auto'
|
||||
autoBox = n 'input',
|
||||
autobox = $.el 'input',
|
||||
type: 'checkbox'
|
||||
mv autoBox, auto
|
||||
inBefore submit, auto
|
||||
mv clone, qr
|
||||
mv qr, d.body
|
||||
qr.style.width = qr.offsetWidth #lock
|
||||
$.append auto, autobox
|
||||
$.before submit, auto
|
||||
|
||||
$('input[title=autohide]:checked', qr)?.click()
|
||||
textarea = $('textarea', qr)
|
||||
textarea.focus()
|
||||
if text then textarea.value += text
|
||||
$.append dialog, clone
|
||||
$.append d.body, dialog
|
||||
dialog.style.width = dialog.offsetWidth # lock
|
||||
|
||||
dialog
|
||||
|
||||
persist: ->
|
||||
$.append d.body, qr.dialog()
|
||||
qr.autohide.set()
|
||||
|
||||
sys: ->
|
||||
$.bind window, 'message', qr.cb.messageIframe
|
||||
if recaptcha = $ '#recaptcha_response_field'
|
||||
# post reporting
|
||||
$.bind recaptcha, 'keydown', recaptchaListener
|
||||
if getConfig 'Auto Watch'
|
||||
html = $('b').innerHTML
|
||||
[_, thread, id] = html.match(/<!-- thread:(\d+),no:(\d+) -->/)
|
||||
if thread is '0'
|
||||
[_, board] = $('meta', d).content.match(/4chan.org\/(\w+)\//)
|
||||
g.watched[board] or= []
|
||||
g.watched[board].push {
|
||||
id: id,
|
||||
text: GM_getValue 'autoText'
|
||||
}
|
||||
GM_setValue 'watched', JSON.stringify g.watched
|
||||
|
||||
recaptchaListener = (e) ->
|
||||
if e.keyCode is 8 and @value is ''
|
||||
@ -1127,7 +1198,6 @@ g =
|
||||
'http://saucenao.com/search.php?db=999&url='
|
||||
'http://tineye.com/search?url='
|
||||
].join '\n'
|
||||
iframe: false
|
||||
watched: JSON.parse(GM_getValue('watched', '{}'))
|
||||
xhrs: []
|
||||
g.favHalo = if /ws/.test g.favDefault then 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAZklEQVR4XrWRQQoAIQwD+6L97j7Ih9WTQQxhDqJQCk4Mranuvqod6LgwawSqSuUmWSPw/UNlJlnDAmA2ARjABLYj8ZyCzJHHqOg+GdAKZmKPIQUzuYrxicHqEgHzP9g7M0+hj45sAnRWxtPj3zSPAAAAAElFTkSuQmCC' else 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEUAAABmzDP///8AAABet0i+AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII='
|
||||
@ -1145,26 +1215,6 @@ tzOffset = (new Date()).getTimezoneOffset() / 60
|
||||
g.chanOffset = 5 - tzOffset# 4chan = EST = GMT -5
|
||||
if $.isDST() then g.chanOffset -= 1
|
||||
|
||||
if location.hostname.split('.')[0] is 'sys'
|
||||
if recaptcha = $ '#recaptcha_response_field'
|
||||
m recaptcha, listener: ['keydown', recaptchaListener]
|
||||
else if b = $ 'table font b'
|
||||
GM_setValue 'error', b.firstChild.textContent
|
||||
else
|
||||
GM_setValue 'error', ''
|
||||
if getConfig 'Auto Watch'
|
||||
html = $('b').innerHTML
|
||||
[_, thread, id] = html.match(/<!-- thread:(\d+),no:(\d+) -->/)
|
||||
if thread is '0'
|
||||
board = $('meta', d).content.match(/4chan.org\/(\w+)\//)[1]
|
||||
g.watched[board] or= []
|
||||
g.watched[board].push {
|
||||
id: id,
|
||||
text: GM_getValue 'autoText'
|
||||
}
|
||||
GM_setValue 'watched', JSON.stringify g.watched
|
||||
return
|
||||
|
||||
lastChecked = GM_getValue('lastChecked', 0)
|
||||
now = getTime()
|
||||
DAY = 24 * 60 * 60
|
||||
@ -1263,6 +1313,9 @@ GM_addStyle '
|
||||
}
|
||||
'
|
||||
|
||||
if location.hostname is 'sys.4chan.org'
|
||||
qr.sys()
|
||||
return
|
||||
if navtopr = $ '#navtopr a'
|
||||
a = n 'a',
|
||||
textContent: '4chan X'
|
||||
@ -1388,20 +1441,7 @@ if getConfig 'Reply Hiding'
|
||||
hideReply(next)
|
||||
|
||||
if getConfig 'Quick Reply'
|
||||
iframe = n 'iframe',
|
||||
name: 'iframe'
|
||||
listener: ['load', iframeLoad]
|
||||
hide(iframe)
|
||||
mv iframe, d.body
|
||||
|
||||
g.callbacks.push (root) ->
|
||||
quotes = $$('a.quotejs:not(:first-child)', root)
|
||||
for quote in quotes
|
||||
quote.addEventListener('click', qrListener, true)
|
||||
|
||||
#hack - nuke id so it doesn't grab focus when reloading
|
||||
recaptcha.id = ''
|
||||
|
||||
qr.init()
|
||||
|
||||
if getConfig 'Quick Report'
|
||||
g.callbacks.push (root) ->
|
||||
@ -1481,8 +1521,7 @@ if g.REPLY
|
||||
if getConfig 'Thread Updater'
|
||||
updaterMake()
|
||||
if getConfig('Quick Reply') and getConfig 'Persistent QR'
|
||||
quickReply()
|
||||
$('#qr input[title=autohide]').click()
|
||||
qr.persist()
|
||||
if getConfig 'Post in Title'
|
||||
unless text = $('span.filetitle').textContent
|
||||
text = $('blockquote').textContent
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user