From 106fc313af7c55f7dcb39747829fce10ef47cb5d Mon Sep 17 00:00:00 2001 From: James Campos Date: Wed, 7 Sep 2011 12:42:30 -0700 Subject: [PATCH] rm qr --- 4chan_x.user.js | 334 ++---------------------------------------------- script.coffee | 308 +------------------------------------------- 2 files changed, 15 insertions(+), 627 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 2cfc53d80..e75108a62 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -60,7 +60,7 @@ */ (function() { - var $, $$, DAY, Favicon, HOUR, MINUTE, NAMESPACE, QR, SECOND, Time, anonymize, conf, config, cooldown, d, expandComment, expandThread, firstRun, g, getTitle, imgExpand, imgGif, imgHover, imgPreloading, key, keybinds, log, main, nav, nodeInserted, options, qr, quoteBacklink, quoteInline, quoteOP, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, threadHiding, threadStats, threading, titlePost, ui, unread, updater, val, watcher, _ref; + var $, $$, DAY, Favicon, HOUR, MINUTE, NAMESPACE, QR, SECOND, Time, anonymize, conf, config, cooldown, d, expandComment, expandThread, firstRun, g, getTitle, imgExpand, imgGif, imgHover, imgPreloading, key, keybinds, log, main, nav, nodeInserted, options, quoteBacklink, quoteInline, quoteOP, quotePreview, redirect, replyHiding, reportButton, revealSpoilers, sauce, threadHiding, threadStats, threading, titlePost, ui, unread, updater, val, watcher, _ref; var __slice = Array.prototype.slice; config = { main: { @@ -1596,6 +1596,13 @@ $.bind(recaptcha, 'keydown', QR.keydown); return; } + /* + 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. + */ return $.globalEval(function() { var data, href, node, textContent, _ref; $ = function(css) { @@ -1615,331 +1622,6 @@ }); } }; - qr = { - init: function() { - var iframe; - g.callbacks.push(qr.node); - $.bind(window, 'message', qr.message); - $.bind($('#recaptcha_challenge_field_holder'), 'DOMNodeInserted', qr.captchaNode); - qr.captchaTime = Date.now(); - qr.spoiler = $('.postarea label') ? '' : ''; - qr.acceptFiles = $('.rules').textContent.match(/: (.+) /)[1].replace(/\w+/g, function(type) { - switch (type) { - case 'JPG': - return 'image/JPEG'; - case 'PDF': - return 'application/' + type; - default: - return 'image/' + type; - } - }); - iframe = $.el('iframe', { - name: 'iframe', - hidden: true - }); - $.add(d.body, iframe); - return $('#recaptcha_response_field').id = ''; - }, - attach: function() { - var fileDiv; - fileDiv = $.el('div', { - innerHTML: "X" - }); - $.bind(fileDiv.firstChild, 'change', qr.validateFileSize); - $.bind(fileDiv.lastChild, 'click', (function() { - return $.rm(this.parentNode); - })); - return $.add($('#files', qr.el), fileDiv); - }, - attachNext: function() { - var file, fileDiv, oldFile; - fileDiv = $.rm($('#files div', qr.el)); - file = fileDiv.firstChild; - oldFile = $('#qr_form input[type=file]', qr.el); - return $.replace(oldFile, file); - }, - autoPost: function() { - if (qr.el && $('#auto', qr.el).checked) { - return qr.submit.call($('form', qr.el)); - } - }, - captchaNode: function(e) { - if (!qr.el) { - return; - } - val = e.target.value; - $('img', qr.el).src = "http://www.google.com/recaptcha/api/image?c=" + val; - qr.challenge = val; - return qr.captchaTime = Date.now(); - }, - captchaKeydown: function(e) { - var captchas; - if (!(e.keyCode === 13 && this.value)) { - return; - } - captchas = $.get('captchas', []); - captchas.push({ - challenge: qr.challenge, - response: this.value, - time: qr.captchaTime - }); - $.set('captchas', captchas); - $('#captchas', qr.el).textContent = captchas.length + ' captchas'; - Recaptcha.reload(); - this.value = ''; - if (!$('textarea', qr.el).value && !$('input[type=file]', qr.el).files.length) { - return e.preventDefault(); - } - }, - close: function() { - $.rm(qr.el); - return qr.el = null; - }, - dialog: function(link) { - var THREAD_ID, c, email, html, m, name, pwd, submitDisabled, submitValue; - c = d.cookie; - name = (m = c.match(/4chan_name=([^;]+)/)) ? decodeURIComponent(m[1]) : ''; - email = (m = c.match(/4chan_email=([^;]+)/)) ? decodeURIComponent(m[1]) : ''; - pwd = (m = c.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $('input[name=pwd]').value; - submitValue = $('#com_submit').value; - submitDisabled = $('#com_submit').disabled ? 'disabled' : ''; - THREAD_ID = g.THREAD_ID || $.x('ancestor::div[@class="thread"]/div', link).id; - qr.challenge = $('#recaptcha_challenge_field').value; - html = " X
Quick Reply
" + qr.spoiler + "
" + ($.get('captchas', []).length) + " captchas
attach another file
"; - qr.el = ui.dialog('qr', { - top: '0px', - left: '0px' - }, html); - $.bind($('input[name=name]', qr.el), 'mousedown', function(e) { - return e.stopPropagation(); - }); - $.bind($('input[name=upfile]', qr.el), 'change', qr.validateFileSize); - $.bind($('#close', qr.el), 'click', qr.close); - $.bind($('form', qr.el), 'submit', qr.submit); - $.bind($('#attach', qr.el), 'click', qr.attach); - $.bind($('img', qr.el), 'click', Recaptcha.reload); - $.bind($('#dummy', qr.el), 'keydown', Recaptcha.listener); - $.bind($('#dummy', qr.el), 'keydown', qr.captchaKeydown); - return $.add(d.body, qr.el); - }, - message: function(e) { - var data, duration, fileCount; - $('iframe[name=iframe]').src = 'about:blank'; - fileCount = $('#files', qr.el).childElementCount; - data = e.data; - if (data) { - data = JSON.parse(data); - $.extend($('#error', qr.el), data); - $('#recaptcha_response_field', qr.el).value = ''; - $('#autohide', qr.el).checked = false; - if (data.textContent === 'You seem to have mistyped the verification.') { - setTimeout(qr.autoPost, 1000); - } else if (data.textContent === 'Error: Duplicate file entry detected.' && fileCount) { - $('textarea', qr.el).value += '\n' + data.textContent + ' ' + data.href; - qr.attachNext(); - setTimeout(qr.autoPost, 1000); - } - return; - } - if (qr.el) { - if (g.REPLY && (conf['Persistent QR'] || fileCount)) { - qr.refresh(); - if (fileCount) { - qr.attachNext(); - } - } else { - qr.close(); - } - } - if (conf['Cooldown']) { - duration = qr.sage ? 60 : 30; - $.set(g.BOARD + '/cooldown', Date.now() + duration * 1000); - return cooldown.start(); - } - }, - node: function(root) { - var quote; - quote = $('a.quotejs:not(:first-child)', root); - return $.bind(quote, 'click', qr.quote); - }, - postInvalid: function() { - var captcha, captchas, content, cutoff, dummy, response; - content = $('textarea', qr.el).value || $('input[type=file]', qr.el).files.length; - if (!content) { - return 'Error: No text entered.'; - } - /* - captchas expire after 5 hours (emperically verified). cutoff 5 minutes - before then, b/c posting takes time. - */ - cutoff = Date.now() - 5 * HOUR + 5 * MINUTE; - captchas = $.get('captchas', []); - while (captcha = captchas.shift()) { - if (captcha.time > cutoff) { - break; - } - } - $.set('captchas', captchas); - $('#captchas', qr.el).textContent = captchas.length + ' captchas'; - if (!captcha) { - dummy = $('#dummy', qr.el); - if (!(response = dummy.value)) { - return 'You forgot to type in the verification'; - } - captcha = { - challenge: qr.challenge, - response: response - }; - dummy.value = ''; - Recaptcha.reload(); - } - $('#recaptcha_challenge_field', qr.el).value = captcha.challenge; - $('#recaptcha_response_field', qr.el).value = captcha.response; - return false; - }, - quote: function(e) { - var id, s, selection, selectionID, ta, text, _ref; - if (e) { - e.preventDefault(); - } - if (qr.el) { - $('#autohide', qr.el).checked = false; - } else { - qr.dialog(this); - } - id = this.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) { - s = s.replace(/\n/g, '\n>'); - text += ">" + s + "\n"; - } - } - ta = $('textarea', qr.el); - ta.focus(); - return ta.value += text; - }, - refresh: function() { - var m, newFile, oldFile, _ref; - $('[name=sub]', qr.el).value = ''; - $('[name=email]', qr.el).value = (m = d.cookie.match(/4chan_email=([^;]+)/)) ? decodeURIComponent(m[1]) : ''; - $('[name=com]', qr.el).value = ''; - $('[name=recaptcha_response_field]', qr.el).value = ''; - if (!conf['Remember Spoiler']) { - if ((_ref = $('[name=spoiler]', qr.el)) != null) { - _ref.checked = false; - } - } - oldFile = $('[type=file]', qr.el); - newFile = $.el('input', { - type: 'file', - name: 'upfile', - accept: qr.acceptFiles - }); - return $.replace(oldFile, newFile); - }, - submit: function(e) { - var id, msg, op; - if (msg = qr.postInvalid()) { - if (typeof e.preventDefault === "function") { - e.preventDefault(); - } - alert(msg); - if (msg === 'You forgot to type in the verification.') { - $('#dummy', qr.el).focus(); - } - return; - } - if (conf['Auto Watch Reply'] && conf['Thread Watcher']) { - if (g.REPLY && $('img.favicon').src === Favicon.empty) { - watcher.watch(null, g.THREAD_ID); - } else { - id = $('input[name=resto]', qr.el).value; - op = $.id(id); - if ($('img.favicon', op).src === Favicon.empty) { - watcher.watch(op, id); - } - } - } - if (!e) { - this.submit(); - } - $('#error', qr.el).textContent = ''; - if (conf['Auto Hide QR']) { - $('#autohide', qr.el).checked = true; - } - return qr.sage = /sage/i.test($('input[name=email]', this).value); - }, - sys: function() { - var c, duration, id, noko, recaptcha, sage, search, thread, url, watch, _, _ref, _ref2; - if (recaptcha = $('#recaptcha_response_field')) { - $.bind(recaptcha, 'keydown', Recaptcha.listener); - return; - } - /* - 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. - */ - $.globalEval(function() { - var data, href, node, textContent, _ref; - if (node = (_ref = document.querySelector('table font b')) != null ? _ref.firstChild : void 0) { - textContent = node.textContent, href = node.href; - data = JSON.stringify({ - textContent: textContent, - href: href - }); - } else { - data = ''; - } - return parent.postMessage(data, '*'); - }); - c = (_ref = $('b')) != null ? _ref.lastChild : void 0; - if (!(c && c.nodeType === 8)) { - return; - } - _ref2 = c.textContent.match(/thread:(\d+),no:(\d+)/), _ = _ref2[0], thread = _ref2[1], id = _ref2[2]; - search = location.search; - cooldown = /cooldown/.test(search); - noko = /noko/.test(search); - sage = /sage/.test(search); - watch = /watch/.test(search); - url = "http://boards.4chan.org/" + g.BOARD; - if (watch && thread === '0') { - url += "/res/" + id + "?watch"; - } else if (noko) { - url += '/res/'; - url += thread === '0' ? id : thread; - } - if (cooldown) { - duration = Date.now() + (sage ? 60 : 30) * 1000; - url += '?cooldown=' + duration; - } - if (noko) { - url += '#' + id; - } - return window.location = url; - }, - validateFileSize: function(e) { - var file; - if (!(this.files[0].size > $('input[name=MAX_FILE_SIZE]').value)) { - return; - } - file = $.el('input', { - type: 'file', - name: 'upfile', - accept: qr.acceptFiles - }); - $.bind(file, 'change', qr.validateFileSize); - $.replace(this, file); - $('#error', qr.el).textContent = 'Error: File too large.'; - return alert('Error: File too large.'); - } - }; threading = { init: function() { var node; diff --git a/script.coffee b/script.coffee index 9318b205a..6aba38e80 100644 --- a/script.coffee +++ b/script.coffee @@ -1222,6 +1222,13 @@ QR = if recaptcha = $ '#recaptcha_response_field' #post reporting $.bind recaptcha, 'keydown', QR.keydown return + ### + 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. + ### $.globalEval -> $ = (css) -> document.querySelector css if node = $('table font b')?.firstChild @@ -1234,307 +1241,6 @@ QR = #parent will blank us on message receival; #if we're not an iframe, we won't get blanked -qr = - # TODO - # error handling / logging - # persistent captcha - # rm Recaptcha - # email reverts - init: -> - g.callbacks.push qr.node - $.bind window, 'message', qr.message - $.bind $('#recaptcha_challenge_field_holder'), 'DOMNodeInserted', qr.captchaNode - qr.captchaTime = Date.now() - - qr.spoiler = if $('.postarea label') then '' else '' - qr.acceptFiles = $('.rules').textContent.match(/: (.+) /)[1].replace /\w+/g, (type) -> - switch type - when 'JPG' - 'image/JPEG' - when 'PDF' - 'application/' + type - else - 'image/' + type - - iframe = $.el 'iframe', - name: 'iframe' - hidden: true - $.add d.body, iframe - - #hack - nuke id so it doesn't grab focus when reloading - $('#recaptcha_response_field').id = '' - - attach: -> - fileDiv = $.el 'div', innerHTML: "X" - $.bind fileDiv.firstChild, 'change', qr.validateFileSize - $.bind fileDiv.lastChild, 'click', (-> $.rm @parentNode) - $.add $('#files', qr.el), fileDiv - - attachNext: -> - fileDiv = $.rm $('#files div', qr.el) - file = fileDiv.firstChild - oldFile = $ '#qr_form input[type=file]', qr.el - $.replace oldFile, file - - autoPost: -> - if qr.el and $('#auto', qr.el).checked - qr.submit.call $ 'form', qr.el - - captchaNode: (e) -> - return unless qr.el - val = e.target.value - $('img', qr.el).src = "http://www.google.com/recaptcha/api/image?c=" + val - qr.challenge = val - qr.captchaTime = Date.now() - - captchaKeydown: (e) -> - return unless e.keyCode is 13 and @value #enter, captcha filled - - captchas = $.get 'captchas', [] - captchas.push - challenge: qr.challenge - response: @value - time: qr.captchaTime - $.set 'captchas', captchas - $('#captchas', qr.el).textContent = captchas.length + ' captchas' - Recaptcha.reload() - @value = '' - - if !$('textarea', qr.el).value and !$('input[type=file]', qr.el).files.length - e.preventDefault() - - close: -> - $.rm qr.el - qr.el = null - - dialog: (link) -> - c = d.cookie - name = if m = c.match(/4chan_name=([^;]+)/) then decodeURIComponent m[1] else '' - email = if m = c.match(/4chan_email=([^;]+)/) then decodeURIComponent m[1] else '' - pwd = if m = c.match(/4chan_pass=([^;]+)/) then decodeURIComponent m[1] else $('input[name=pwd]').value - submitValue = $('#com_submit').value - submitDisabled = if $('#com_submit').disabled then 'disabled' else '' - #FIXME inlined cross-thread quotes - THREAD_ID = g.THREAD_ID or $.x('ancestor::div[@class="thread"]/div', link).id - qr.challenge = $('#recaptcha_challenge_field').value - - html = " - X - -
- - Quick Reply -
-
-
- - - - -
#{qr.spoiler}
-
-
-
-
#{$.get('captchas', []).length} captchas
-
-
-
-
attach another file
-
- - " - qr.el = ui.dialog 'qr', top: '0px', left: '0px', html - - $.bind $('input[name=name]', qr.el), 'mousedown', (e) -> e.stopPropagation() - $.bind $('input[name=upfile]', qr.el), 'change', qr.validateFileSize - $.bind $('#close', qr.el), 'click', qr.close - $.bind $('form', qr.el), 'submit', qr.submit - $.bind $('#attach', qr.el), 'click', qr.attach - $.bind $('img', qr.el), 'click', Recaptcha.reload - $.bind $('#dummy', qr.el), 'keydown', Recaptcha.listener - $.bind $('#dummy', qr.el), 'keydown', qr.captchaKeydown - - $.add d.body, qr.el - - message: (e) -> - $('iframe[name=iframe]').src = 'about:blank' - fileCount = $('#files', qr.el).childElementCount - - {data} = e - if data # error message - data = JSON.parse data - $.extend $('#error', qr.el), data - $('#recaptcha_response_field', qr.el).value = '' - $('#autohide', qr.el).checked = false - if data.textContent is 'You seem to have mistyped the verification.' - setTimeout qr.autoPost, 1000 - else if data.textContent is 'Error: Duplicate file entry detected.' and fileCount - $('textarea', qr.el).value += '\n' + data.textContent + ' ' + data.href - qr.attachNext() - setTimeout qr.autoPost, 1000 - return - - if qr.el - if g.REPLY and (conf['Persistent QR'] or fileCount) - qr.refresh() - if fileCount - qr.attachNext() - else - qr.close() - if conf['Cooldown'] - duration = if qr.sage then 60 else 30 - $.set g.BOARD+'/cooldown', Date.now() + duration * 1000 - cooldown.start() - - node: (root) -> - quote = $ 'a.quotejs:not(:first-child)', root - $.bind quote, 'click', qr.quote - - postInvalid: -> - content = $('textarea', qr.el).value or $('input[type=file]', qr.el).files.length - return 'Error: No text entered.' unless content - - ### - captchas expire after 5 hours (emperically verified). cutoff 5 minutes - before then, b/c posting takes time. - ### - - cutoff = Date.now() - 5*HOUR + 5*MINUTE - captchas = $.get 'captchas', [] - while captcha = captchas.shift() - if captcha.time > cutoff - break - $.set 'captchas', captchas - - $('#captchas', qr.el).textContent = captchas.length + ' captchas' - - unless captcha - dummy = $ '#dummy', qr.el - return 'You forgot to type in the verification' unless response = dummy.value - captcha = - challenge: qr.challenge - response: response - dummy.value = '' - Recaptcha.reload() - - $('#recaptcha_challenge_field', qr.el).value = captcha.challenge - $('#recaptcha_response_field', qr.el).value = captcha.response - - false - - quote: (e) -> - e.preventDefault() if e - - if qr.el - $('#autohide', qr.el).checked = false - else - qr.dialog @ - - id = @textContent - text = ">>#{id}\n" - - selection = window.getSelection() - if s = selection.toString() - selectionID = $.x('preceding::input[@type="checkbox"][1]', selection.anchorNode)?.name - if selectionID == id - s = s.replace /\n/g, '\n>' - text += ">#{s}\n" - - ta = $ 'textarea', qr.el - ta.focus() - ta.value += text - - refresh: -> - $('[name=sub]', qr.el).value = '' - $('[name=email]', qr.el).value = if m = d.cookie.match(/4chan_email=([^;]+)/) then decodeURIComponent m[1] else '' - $('[name=com]', qr.el).value = '' - $('[name=recaptcha_response_field]', qr.el).value = '' - $('[name=spoiler]', qr.el)?.checked = false unless conf['Remember Spoiler'] - # XXX opera doesn't allow resetting file inputs w/ file.value = '' - oldFile = $ '[type=file]', qr.el - newFile = $.el 'input', type: 'file', name: 'upfile', accept: qr.acceptFiles - $.replace oldFile, newFile - - submit: (e) -> - #XXX `e` won't exist if we're here from `qr.submit.call form`. - if msg = qr.postInvalid() - e.preventDefault?() - alert msg - if msg is 'You forgot to type in the verification.' - $('#dummy', qr.el).focus() - return - - if conf['Auto Watch Reply'] and conf['Thread Watcher'] - if g.REPLY and $('img.favicon').src is Favicon.empty - watcher.watch null, g.THREAD_ID - else - id = $('input[name=resto]', qr.el).value - op = $.id id - if $('img.favicon', op).src is Favicon.empty - watcher.watch op, id - - if !e then @submit() - $('#error', qr.el).textContent = '' - $('#autohide', qr.el).checked = true if conf['Auto Hide QR'] - qr.sage = /sage/i.test $('input[name=email]', @).value - - sys: -> - if recaptcha = $ '#recaptcha_response_field' #post reporting - $.bind recaptcha, 'keydown', Recaptcha.listener - return - - ### - 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. - ### - $.globalEval -> - if node = document.querySelector('table font b')?.firstChild - {textContent, href} = node - data = JSON.stringify {textContent, href} - else - data = '' - parent.postMessage data, '*' - - c = $('b')?.lastChild - - return unless c and c.nodeType is 8 #comment node - - [_, thread, id] = c.textContent.match(/thread:(\d+),no:(\d+)/) - - {search} = location - cooldown = /cooldown/.test search - noko = /noko/ .test search - sage = /sage/ .test search - watch = /watch/ .test search - - url = "http://boards.4chan.org/#{g.BOARD}" - - if watch and thread is '0' - url += "/res/#{id}?watch" - else if noko - url += '/res/' - url += if thread is '0' then id else thread - if cooldown - duration = Date.now() + (if sage then 60 else 30) * 1000 - url += '?cooldown=' + duration - if noko - url += '#' + id - - window.location = url - - validateFileSize: (e) -> - return unless @files[0].size > $('input[name=MAX_FILE_SIZE]').value - - file = $.el 'input', type: 'file', name: 'upfile', accept: qr.acceptFiles - $.bind file, 'change', qr.validateFileSize - $.replace @, file - - $('#error', qr.el).textContent = 'Error: File too large.' - alert 'Error: File too large.' - threading = init: -> # don't thread image controls