diff --git a/4chan_x.js b/4chan_x.js
index ac8680af2..5694cc216 100644
--- a/4chan_x.js
+++ b/4chan_x.js
@@ -7,6 +7,7 @@
// @license MIT; http://en.wikipedia.org/wiki/Mit_license
// @include http://boards.4chan.org/*
// @include http://sys.4chan.org/*
+// @include file://*
// @updateURL http://userscripts.org/scripts/source/51412.meta.js
// ==/UserScript==
@@ -71,6 +72,7 @@
'404 Redirect': [true, 'Redirect dead threads'],
'Anonymize': [false, 'Make everybody anonymous'],
'Auto Watch': [true, 'Automatically watch threads that you start'],
+ 'Auto Watch Reply': [false, 'Automatically watch threads that you reply to'],
'Comment Expansion': [true, 'Expand too long comments'],
'Cooldown': [false, 'Prevent \'flood detected\' errors (buggy)'],
'Image Auto-Gif': [false, 'Animate gif thumbnails'],
@@ -92,8 +94,7 @@
'Thread Navigation': [true, 'Navigate to previous / next thread'],
'Thread Updater': [true, 'Update threads'],
'Thread Watcher': [true, 'Bookmark threads'],
- 'Unread Count': [true, 'Show unread post count in tab title'],
- 'Watch on Reply': [false, 'Automatically watch threads you reply to']
+ 'Unread Count': [true, 'Show unread post count in tab title']
},
textarea: {
flavors: ['http://regex.info/exif.cgi?url=', 'http://iqdb.org/?url=', 'http://tineye.com/search?url=', '#http://saucenao.com/search.php?db=999&url='].join('\n')
@@ -171,7 +172,7 @@
} else {
el.style.bottom = '0px';
}
- el.querySelector('div.move').addEventListener('mousedown', ui.dragstart, true);
+ el.querySelector('div.move').addEventListener('mousedown', ui.dragstart, false);
if ((_ref3 = el.querySelector('div.move a[name=close]')) != null) {
_ref3.addEventListener('click', (function() {
return el.parentNode.removeChild(el);
@@ -988,15 +989,11 @@
}
},
message: function(e) {
- var data, dialog, error;
+ var data, dialog;
data = e.data;
dialog = $('#qr');
if (data) {
- error = $.el('span', {
- className: 'error',
- textContent: data
- });
- $.append(dialog, error);
+ $('#error').textContent = data;
qr.autohide.unset();
} else {
if (dialog) {
@@ -1024,59 +1021,36 @@
return _results;
},
submit: function(e) {
- var form, isQR, recaptcha, span, thread, threads, value, _i, _len;
+ var form, id, isQR, op;
form = e.target;
isQR = form.parentNode.id === 'qr';
- if ($.config('Watch on Reply') && $.config('Thread Watcher')) {
+ if ($.config('Auto Watch Reply') && $.config('Thread Watcher')) {
if (g.REPLY && $('img.favicon').src === Favicon.empty) {
watcher.watch(null, g.THREAD_ID);
} else {
- value = $('input[name=resto]').value;
- threads = $$('div.op');
- for (_i = 0, _len = threads.length; _i < _len; _i++) {
- thread = threads[_i];
- if (thread.id === value && $('img.favicon', thread).src === Favicon.empty) {
- watcher.watch(thread, value);
- }
+ id = $('input[name=resto]').value;
+ op = d.getElementById(id);
+ if ($('img.favicon', op).src === Favicon.empty) {
+ watcher.watch(op, id);
}
}
}
if (isQR) {
- if (span = this.nextSibling) {
- $.remove(span);
- }
+ $('#error').textContent = '';
}
if ($.config('Cooldown')) {
if (qr.cooldown()) {
e.preventDefault();
alert('Stop posting so often!');
if (isQR) {
- span = $.el('span', {
- className: 'error',
- textContent: 'Stop posting so often!'
- });
- $.append(this.parentNode, span);
+ $('#error').textContent = 'Stop posting so often!';
}
return;
}
}
- recaptcha = $('input[name=recaptcha_response_field]', this);
- if (recaptcha.value) {
- qr.sage = $('input[name=email]', form).value === 'sage';
- if (isQR) {
- return qr.autohide.set();
- }
- } else {
- e.preventDefault();
- alert('You forgot to type in the verification.');
- recaptcha.focus();
- if (isQR) {
- span = $.el('span', {
- className: 'error',
- textContent: 'You forgot to type in the verification.'
- });
- return $.append(this.parentNode, span);
- }
+ qr.sage = $('input[name=email]', form).value === 'sage';
+ if (isQR) {
+ return qr.autohide.set();
}
},
quote: function(e) {
@@ -1156,35 +1130,35 @@
}
},
dialog: function(link) {
- var clone, dialog, el, html, resto, script, xpath, _i, _len, _ref;
- html = "
";
+ var MAX_FILE_SIZE, THREAD_ID, clone, dialog, el, html, spoiler;
+ MAX_FILE_SIZE = $('input[name="MAX_FILE_SIZE"]').value;
+ THREAD_ID = g.THREAD_ID || link.pathname.split('/').pop();
+ html = "
";
dialog = ui.dialog('qr', {
top: '0px',
left: '0px'
}, html);
- el = $('input[title=autohide]', dialog);
+ $.bind($('input[name=name]', dialog), 'mousedown', function(e) {
+ return e.stopPropagation();
+ });
+ el = $('#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];
- $.remove(script);
- }
- clone.target = 'iframe';
- $.bind(clone, 'submit', qr.cb.submit);
- $.bind($('input[name=recaptcha_response_field]', clone), 'keydown', Recaptcha.listener);
- if (!g.REPLY) {
- xpath = 'preceding::span[@class="postername"][1]/preceding::input[1]';
- resto = $.el('input', {
- type: 'hidden',
- name: 'resto',
- value: $.x(xpath, link).name
+ if ($('.postarea label')) {
+ spoiler = $.el('label', {
+ innerHTML: " [ Spoiler Image?]"
});
- $.before(clone.lastChild, resto);
+ $.after($('input[name=email]', dialog), spoiler);
}
- $.append(dialog, clone);
+ clone = $('#recaptcha_widget_div').cloneNode(true);
+ $.append($('#qr_captcha', dialog), clone);
+ $.extend($('input[name=recaptcha_response_field]', clone), {
+ placeholder: 'Verification',
+ className: 'inputtext',
+ required: true
+ });
+ $.bind($('form', dialog), 'submit', qr.cb.submit);
+ $.bind($('input[name=recaptcha_response_field]', clone), 'keydown', Recaptcha.listener);
$.append(d.body, dialog);
- dialog.style.width = dialog.offsetWidth;
return dialog;
},
persist: function() {
@@ -2347,18 +2321,62 @@
#qr > div.move {\
text-align: right;\
}\
- #qr > form > div, /* ad */\
- #qr #recaptcha_table td:nth-of-type(3), /* captcha logos */\
- #qr td.rules {\
+ #qr > div.move > input[name=name] {\
+ float: left;\
+ }\
+ #qr #recaptcha_table td:nth-of-type(3) {/* captcha logos */\
display: none;\
}\
+ #qr {\
+ width: 302px;\
+ }\
+ #qr form, #qr #com_submit, #qr input[type="file"] {\
+ margin: 0;\
+ }\
+ #qr textarea {\
+ width: 302px;\
+ height: 80px;\
+ }\
+ #qr *:not(input):not(textarea) {\
+ padding: 0 !important;\
+ }\
#qr.auto:not(:hover) form {\
display: none;\
}\
- #qr span.error {\
- position: absolute;\
- bottom: 0;\
- left: 0;\
+ /* http://stackoverflow.com/questions/2610497/change-an-inputs-html5-placeholder-color-with-css */\
+ #qr input:-webkit-input-placeholder {\
+ color: grey;\
+ }\
+ #qr input:-moz-placeholder {\
+ color: grey;\
+ }\
+ /* qr reCAPTCHA */\
+ #qr_captcha input {\
+ border: 1px solid #AAA !important;\
+ margin-top: 2px;\
+ padding: 2px 4px 3px;\
+ }\
+ #qr tr {\
+ height: auto;\
+ }\
+ #qr .recaptchatable #recaptcha_image {\
+ border: 1px solid #AAA !important;\
+ }\
+ #qr #recaptcha_reload, #qr #recaptcha_switch_audio, #qr #recaptcha_whatsthis {\
+ height: 0;\
+ width: 0;\
+ padding: 10px 6px !important;\
+ margin-left: -16px;\
+ position: relative;\
+ }\
+ #recaptcha_reload {\
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAcUlEQVQY02P4z4AKGYKhNJQKYzgIZjxn+I8kwdCGrAkuwRAOZrUwhKBL7GP4ziCPYg8jROI/wzQ0B1yBSXiiCKeBjAMbhab+P0gExFCHu3o3QxzIwSC/MCC5+hPDezDdjOzB/ww/wYw9DCGoPt+CHjQAYxCCmpNUoxoAAAAASUVORK5CYII=) no-repeat center;\
+ }\
+ #recaptcha_switch_audio {\
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAVUlEQVQYV42NMQ6AMAwDPbTQjQEE//8OPCqkhgZXMJBTJMc3BCjBJrlA6uNL1Np6MTordq+N+cLAotHKlxhk/4lMjMu43M9z4CKRmSoJEarqxDOTHidPWTEdrdlTpwAAAABJRU5ErkJggg==) no-repeat center;\
+ }\
+ #recaptcha_whatsthis {\
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAk0lEQVQYV3WMsQ3CMBBFf0ECmYDJqIkFk0TpkcgEUCeegWzADoi0yQbm3cUFBeifrX/vWZZ2f+K4UlDURCKtcua4VfpK64oJDg/a66zFe1hFpN7AHWvnIprY8nPSk9zpVxcTLYukmXZynEWp3peXLpxV9CrF1L6OtDGL2kTB1QBmPTj2pIEUJkwdNehNBpphxOZ3PgIeQ0jaC7S6AAAAAElFTkSuQmCC) no-repeat center;\
}\
\
#updater {\
diff --git a/Cakefile b/Cakefile
index f02647b2c..96e71dc1c 100644
--- a/Cakefile
+++ b/Cakefile
@@ -18,6 +18,6 @@ build = ->
task 'dev', ->
build()
- fs.watchFile INFILE, (curr, prev) ->
+ fs.watchFile INFILE, interval: 250, (curr, prev) ->
if curr.mtime > prev.mtime
build()
diff --git a/script.coffee b/script.coffee
index bae7c8d90..c1aad2961 100644
--- a/script.coffee
+++ b/script.coffee
@@ -15,6 +15,7 @@ config =
'404 Redirect': [true, 'Redirect dead threads']
'Anonymize': [false, 'Make everybody anonymous']
'Auto Watch': [true, 'Automatically watch threads that you start']
+ 'Auto Watch Reply': [false, 'Automatically watch threads that you reply to']
'Comment Expansion': [true, 'Expand too long comments']
'Cooldown': [false, 'Prevent \'flood detected\' errors (buggy)']
'Image Auto-Gif': [false, 'Animate gif thumbnails']
@@ -37,7 +38,6 @@ config =
'Thread Updater': [true, 'Update threads']
'Thread Watcher': [true, 'Bookmark threads']
'Unread Count': [true, 'Show unread post count in tab title']
- 'Watch on Reply': [false, 'Automatically watch threads you reply to']
textarea:
flavors: [
'http://regex.info/exif.cgi?url='
@@ -96,7 +96,7 @@ ui =
top = localStorage["#{id}Top"] ? top
if left then el.style.left = left else el.style.right = '0px'
if top then el.style.top = top else el.style.bottom = '0px'
- el.querySelector('div.move').addEventListener 'mousedown', ui.dragstart, true
+ el.querySelector('div.move').addEventListener 'mousedown', ui.dragstart, false
el.querySelector('div.move a[name=close]')?.addEventListener 'click',
(-> el.parentNode.removeChild(el)), true
el
@@ -751,10 +751,7 @@ qr =
{data} = e
dialog = $ '#qr'
if data # error message
- error = $.el 'span',
- className: 'error'
- textContent: data
- $.append dialog, error
+ $('#error').textContent = data
qr.autohide.unset()
else # success
if dialog
@@ -777,19 +774,17 @@ qr =
form = e.target
isQR = form.parentNode.id == 'qr'
- if $.config('Watch on Reply') and $.config('Thread Watcher')
+ if $.config('Auto Watch Reply') and $.config('Thread Watcher')
if g.REPLY and $('img.favicon').src is Favicon.empty
watcher.watch null, g.THREAD_ID
else
- value = $('input[name=resto]').value
- threads = $$ 'div.op'
- for thread in threads
- if thread.id is value and $('img.favicon', thread).src is Favicon.empty
- watcher.watch thread, value
+ id = $('input[name=resto]').value
+ op = d.getElementById id
+ if $('img.favicon', op).src is Favicon.empty
+ watcher.watch op, id
if isQR
- if span = @nextSibling
- $.remove span
+ $('#error').textContent = ''
if $.config 'Cooldown'
# check if we've posted on this board in another tab
@@ -798,28 +793,13 @@ qr =
alert 'Stop posting so often!'
if isQR
- span = $.el 'span',
- className: 'error'
- textContent: 'Stop posting so often!'
- $.append @parentNode, span
+ $('#error').textContent = 'Stop posting so often!'
return
- recaptcha = $('input[name=recaptcha_response_field]', this)
- if recaptcha.value
- qr.sage = $('input[name=email]', form).value == 'sage'
- if isQR
- qr.autohide.set()
- else
- e.preventDefault()
- alert 'You forgot to type in the verification.'
- recaptcha.focus()
-
- if isQR
- span = $.el 'span',
- className: 'error'
- textContent: 'You forgot to type in the verification.'
- $.append @parentNode, span
+ qr.sage = $('input[name=email]', form).value == 'sage'
+ if isQR
+ qr.autohide.set()
quote: (e) ->
e.preventDefault()
@@ -889,32 +869,51 @@ qr =
clearInterval qr.cooldownIntervalID
dialog: (link) ->
- html = ""
+ #maybe should be global
+ MAX_FILE_SIZE = $('input[name="MAX_FILE_SIZE"]').value
+ THREAD_ID = g.THREAD_ID or link.pathname.split('/').pop()
+ html = "
+
+
+
+
+
+
+
+
+
+
+
+
+ "
dialog = ui.dialog 'qr', top: '0px', left: '0px', html
- el = $ 'input[title=autohide]', dialog
+
+ $.bind $('input[name=name]', dialog), 'mousedown', (e) -> e.stopPropagation()
+ el = $ '#autohide', dialog
$.bind el, 'click', qr.cb.autohide
- clone = $('form[name=post]').cloneNode(true)
- for script in $$ 'script', clone
- $.remove script
- clone.target = 'iframe'
- $.bind clone, 'submit', qr.cb.submit
+ if $ '.postarea label'
+ spoiler = $.el 'label',
+ innerHTML: " [ Spoiler Image?]"
+ $.after $('input[name=email]', dialog), spoiler
+
+ # TODO try w/o cloning
+ clone = $('#recaptcha_widget_div').cloneNode(true)
+ $.append $('#qr_captcha', dialog), clone
+ $.extend $('input[name=recaptcha_response_field]', clone),
+ placeholder: 'Verification'
+ className: 'inputtext'
+ required: true
+
+ $.bind $('form', dialog), 'submit', qr.cb.submit
$.bind $('input[name=recaptcha_response_field]', clone), 'keydown', Recaptcha.listener
- if not g.REPLY
- #figure out which thread we're replying to
- xpath = 'preceding::span[@class="postername"][1]/preceding::input[1]'
- resto = $.el 'input',
- type: 'hidden'
- name: 'resto'
- value: $.x(xpath, link).name
-
- # place resto before table to let userstyles know we're responding to a thread
- $.before clone.lastChild, resto
-
- $.append dialog, clone
$.append d.body, dialog
- dialog.style.width = dialog.offsetWidth # lock
dialog
@@ -1829,18 +1828,62 @@ main =
#qr > div.move {
text-align: right;
}
- #qr > form > div, /* ad */
- #qr #recaptcha_table td:nth-of-type(3), /* captcha logos */
- #qr td.rules {
+ #qr > div.move > input[name=name] {
+ float: left;
+ }
+ #qr #recaptcha_table td:nth-of-type(3) {/* captcha logos */
display: none;
}
+ #qr {
+ width: 302px;
+ }
+ #qr form, #qr #com_submit, #qr input[type="file"] {
+ margin: 0;
+ }
+ #qr textarea {
+ width: 302px;
+ height: 80px;
+ }
+ #qr *:not(input):not(textarea) {
+ padding: 0 !important;
+ }
#qr.auto:not(:hover) form {
display: none;
}
- #qr span.error {
- position: absolute;
- bottom: 0;
- left: 0;
+ /* http://stackoverflow.com/questions/2610497/change-an-inputs-html5-placeholder-color-with-css */
+ #qr input:-webkit-input-placeholder {
+ color: grey;
+ }
+ #qr input:-moz-placeholder {
+ color: grey;
+ }
+ /* qr reCAPTCHA */
+ #qr_captcha input {
+ border: 1px solid #AAA !important;
+ margin-top: 2px;
+ padding: 2px 4px 3px;
+ }
+ #qr tr {
+ height: auto;
+ }
+ #qr .recaptchatable #recaptcha_image {
+ border: 1px solid #AAA !important;
+ }
+ #qr #recaptcha_reload, #qr #recaptcha_switch_audio, #qr #recaptcha_whatsthis {
+ height: 0;
+ width: 0;
+ padding: 10px 6px !important;
+ margin-left: -16px;
+ position: relative;
+ }
+ #recaptcha_reload {
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAcUlEQVQY02P4z4AKGYKhNJQKYzgIZjxn+I8kwdCGrAkuwRAOZrUwhKBL7GP4ziCPYg8jROI/wzQ0B1yBSXiiCKeBjAMbhab+P0gExFCHu3o3QxzIwSC/MCC5+hPDezDdjOzB/ww/wYw9DCGoPt+CHjQAYxCCmpNUoxoAAAAASUVORK5CYII=) no-repeat center;
+ }
+ #recaptcha_switch_audio {
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAVUlEQVQYV42NMQ6AMAwDPbTQjQEE//8OPCqkhgZXMJBTJMc3BCjBJrlA6uNL1Np6MTordq+N+cLAotHKlxhk/4lMjMu43M9z4CKRmSoJEarqxDOTHidPWTEdrdlTpwAAAABJRU5ErkJggg==) no-repeat center;
+ }
+ #recaptcha_whatsthis {
+ background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAQAAAD8fJRsAAAAk0lEQVQYV3WMsQ3CMBBFf0ECmYDJqIkFk0TpkcgEUCeegWzADoi0yQbm3cUFBeifrX/vWZZ2f+K4UlDURCKtcua4VfpK64oJDg/a66zFe1hFpN7AHWvnIprY8nPSk9zpVxcTLYukmXZynEWp3peXLpxV9CrF1L6OtDGL2kTB1QBmPTj2pIEUJkwdNehNBpphxOZ3PgIeQ0jaC7S6AAAAAElFTkSuQmCC) no-repeat center;
}
#updater {