From e028273eed35603e4edd2e6b20a587438001d05a Mon Sep 17 00:00:00 2001 From: ccd0 Date: Sat, 13 Dec 2014 07:56:36 -0800 Subject: [PATCH] Unify captcha module interfaces. --- src/Posting/Captcha.noscript.coffee | 81 ++++++++++++++++++++--------- src/Posting/Captcha.v2.coffee | 27 +++++++--- src/Posting/QR.coffee | 33 ++++-------- src/Posting/QR.post.coffee | 6 +-- 4 files changed, 89 insertions(+), 58 deletions(-) diff --git a/src/Posting/Captcha.noscript.coffee b/src/Posting/Captcha.noscript.coffee index 4d62ca118..8fc005de6 100644 --- a/src/Posting/Captcha.noscript.coffee +++ b/src/Posting/Captcha.noscript.coffee @@ -1,7 +1,6 @@ Captcha.noscript = - lifetime: 120 * $.SECOND + lifetime: 2 * $.MINUTE iframeURL: '//www.google.com/recaptcha/api/fallback?k=<%= meta.recaptchaKey %>' - timers: {} init: -> return if d.cookie.indexOf('pass_enabled=1') >= 0 @@ -20,7 +19,9 @@ Captcha.noscript = $.on input, 'blur', QR.focusout $.on input, 'focus', QR.focusin $.on input, 'keydown', @keydown.bind @ - $.on @nodes.container, 'click', @reload.bind(@, true) + $.on @nodes.container, 'click', => + @reload() + @nodes.input.focus() @conn = new Connection null, "#{location.protocol}//www.google.com", challenge: @load.bind @ @@ -37,7 +38,7 @@ Captcha.noscript = $.sync 'captchas', @sync @beforeSetup() - @setup() if Conf['Auto-load captcha'] + @setup() initFrame: -> conn = new Connection window.top, "#{location.protocol}//boards.4chan.org", @@ -51,8 +52,10 @@ Captcha.noscript = error = $('.fbc-error')?.textContent conn.send {challenge, token, error} + timers: {} + cb: - focus: -> QR.captcha.setup() + focus: -> QR.captcha.setup false, true beforeSetup: -> {container, input} = @nodes @@ -60,38 +63,51 @@ Captcha.noscript = input.value = '' input.placeholder = 'Focus to load reCAPTCHA' @count() - $.on input, 'focus', @cb.focus + $.on input, 'focus click', @cb.focus - setup: -> + needed: -> + captchaCount = @captchas.length + captchaCount++ if QR.req + postsCount = QR.posts.length + postsCount = 0 if postsCount is 1 and !Conf['Auto-load captcha'] and !QR.posts[0].com and !QR.posts[0].file + captchaCount < postsCount + + onNewPost: -> + + onPostChange: -> + + setup: (focus, force) -> + return unless @isEnabled and (@needed() or force) if !@nodes.iframe @nodes.iframe = $.el 'iframe', id: 'qr-captcha-iframe' src: @iframeURL - delete @iframeUsed $.add d.body, @nodes.iframe @conn.target = @nodes.iframe.contentWindow - else if @iframeUsed or !@nodes.img + else if !@occupied @nodes.iframe.src = @iframeURL - delete @iframeUsed - else if !@nodes.img.complete - @conn.send queryChallenge: null + @occupied = true + @nodes.input.focus() if focus afterSetup: -> {container, input} = @nodes container.hidden = false input.placeholder = 'Verification' @count() - $.off input, 'focus', @cb.focus + $.off input, 'focus click', @cb.focus if QR.nodes.el.getBoundingClientRect().bottom > doc.clientHeight QR.nodes.el.style.top = null QR.nodes.el.style.bottom = '0px' destroy: -> - $.rm @nodes.img + return unless @isEnabled + $.rm @nodes.img if @nodes.img delete @nodes.img - $.rm @nodes.iframe + $.rm @nodes.iframe if @nodes.iframe delete @nodes.iframe + delete @occupied + @unflag() @beforeSetup() sync: (captchas=[]) -> @@ -115,14 +131,14 @@ Captcha.noscript = response = @nodes.input.value if /\S/.test response @conn.send {response} - @iframeUsed = true save: (token) -> + delete @occupied @nodes.input.value = '' if @submitCB @submitCB token delete @submitCB - if Conf['Auto-load captcha'] then @reload() else @destroy() + if @needed() then @reload() else @destroy() else $.forceSync 'captchas' @captchas.push @@ -133,11 +149,22 @@ Captcha.noscript = @reload() error: (message) -> + @occupied = true @nodes.input.value = '' - QR.error "CAPTCHA Error: #{message}" if @submitCB @submitCB() delete @submitCB + QR.error "Captcha Error: #{message}" + + notify: (el) -> + if Conf['Captcha Warning Notifications'] and !d.hidden + QR.notify el + else + $.addClass @nodes.input, 'error' + $.one @nodes.input, 'keydown', @unflag.bind @ + + unflag: -> + $.rmClass @nodes.input, 'error' clear: -> return unless @captchas.length @@ -152,6 +179,7 @@ Captcha.noscript = load: (src) -> {container, input, img} = @nodes + @occupied = true @timeout = Date.now() + @lifetime unless img img = @nodes.img = new Image @@ -160,8 +188,8 @@ Captcha.noscript = img.src = src input.value = '' @clear() - clearTimeout @timers.reload - @timers.reload = setTimeout @reload.bind(@), @lifetime + clearTimeout @timers.expire + @timers.expire = setTimeout @expire.bind(@), @lifetime count: -> count = if @captchas then @captchas.length else 0 @@ -179,15 +207,20 @@ Captcha.noscript = if @captchas.length @timers.clear = setTimeout @clear.bind(@), @captchas[0].timeout - Date.now() - reload: (focus) -> + expire: -> return unless @nodes.iframe + if @needed() or d.activeElement is @nodes.input + @reload() + else + @destroy() + + reload: -> @nodes.iframe.src = @iframeURL - delete @iframeUsed - @nodes.input.focus() if focus + @occupied = true keydown: (e) -> if e.keyCode is 8 and not @nodes.input.value - @reload() + if @nodes.iframe then @reload() else @setup() else if e.keyCode is 13 and e.shiftKey @sendResponse() else diff --git a/src/Posting/Captcha.v2.coffee b/src/Posting/Captcha.v2.coffee index 56ea98183..27c6ec63b 100644 --- a/src/Posting/Captcha.v2.coffee +++ b/src/Posting/Captcha.v2.coffee @@ -1,4 +1,6 @@ Captcha.v2 = + lifetime: 2 * $.MINUTE + init: -> return if d.cookie.indexOf('pass_enabled=1') >= 0 return unless @isEnabled = !!$.id 'g-recaptcha' @@ -27,11 +29,14 @@ Captcha.v2 = needed: -> captchaCount = @captchas.length - captchaCount++ if @nodes.container and !@timeouts.destroy + captchaCount++ if QR.req @postsCount = QR.posts.length @postsCount = 0 if @postsCount is 1 and !Conf['Auto-load captcha'] and !QR.posts[0].com and !QR.posts[0].file captchaCount < @postsCount + onNewPost: -> + @setup() + onPostChange: -> @setup() if @postsCount is 0 @postsCount = 0 if QR.posts.length is 1 and !Conf['Auto-load captcha'] and !QR.posts[0].com and !QR.posts[0].file @@ -51,7 +56,11 @@ Captcha.v2 = delete @timeouts.destroy return @reload() - return if @nodes.container + if @nodes.container + if @shouldFocus and iframe = $ 'textarea', @nodes.container + iframe.focus() + delete @shouldFocus + return @nodes.container = $.el 'div', className: 'captcha-container' $.prepend @nodes.root, @nodes.container @@ -116,22 +125,21 @@ Captcha.v2 = getOne: -> @clear() if captcha = @captchas.shift() - @count() $.set 'captchas', @captchas + @count() captcha.response else null save: (pasted) -> $.forceSync 'captchas' - reload = (QR.cooldown.auto or Conf['Post on Captcha Completion']) and @needed() @captchas.push response: $('textarea', @nodes.container).value - timeout: (if pasted then @setupTime else Date.now()) + 2 * $.MINUTE - @count() + timeout: (if pasted then @setupTime else Date.now()) + @lifetime $.set 'captchas', @captchas + @count() - if reload + if (QR.cooldown.auto or Conf['Post on Captcha Completion']) and @needed() @shouldFocus = true @reload() else @@ -143,6 +151,9 @@ Captcha.v2 = QR.submit() if Conf['Post on Captcha Completion'] and !QR.cooldown.auto + notify: (el) -> + QR.notify el + clear: -> return unless @captchas.length $.forceSync 'captchas' @@ -161,7 +172,7 @@ Captcha.v2 = if @captchas.length @timeouts.clear = setTimeout @clear.bind(@), @captchas[0].timeout - Date.now() - reload: (focus) -> + reload: -> $.globalEval ''' (function() { var container = document.querySelector("#qr .captcha-container"); diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee index 00c761864..ce99c775f 100644 --- a/src/Posting/QR.coffee +++ b/src/Posting/QR.coffee @@ -95,9 +95,9 @@ QR = open: -> if QR.nodes + QR.captcha.setup() if QR.nodes.el.hidden QR.nodes.el.hidden = false QR.unhide() - QR.captcha.setup() unless QR.captcha is Captcha.noscript return try QR.dialog() @@ -114,8 +114,6 @@ QR = QR.cleanNotifications() d.activeElement.blur() $.rmClass QR.nodes.el, 'dump' - if QR.captcha is Captcha.noscript and !Conf['Captcha Warning Notifications'] - $.rmClass QR.captcha.nodes.input, 'error' if QR.captcha.isEnabled if Conf['QR Shortcut'] $.toggleClass $('.qr-shortcut'), 'disabled' new QR.post true @@ -123,8 +121,7 @@ QR = post.delete() QR.cooldown.auto = false QR.status() - if QR.captcha isnt Captcha.noscript or (QR.captcha.isEnabled and not Conf['Auto-load captcha']) - QR.captcha.destroy() + QR.captcha.destroy() focusin: -> QR.captcha.setup() if $.hasClass(QR.nodes.el, 'autohide') and !$.hasClass(QR.nodes.el, 'focus') $.addClass QR.nodes.el, 'focus' @@ -135,6 +132,7 @@ QR = $.addClass QR.nodes.el, 'autohide' QR.nodes.autohide.checked = true unhide: -> + QR.captcha.setup() if $.hasClass(QR.nodes.el, 'autohide') and !$.hasClass(QR.nodes.el, 'focus') $.rmClass QR.nodes.el, 'autohide' QR.nodes.autohide.checked = false toggleHide: -> @@ -150,20 +148,10 @@ QR = else el = err el.removeAttribute 'style' - captchaErr = QR.captcha.isEnabled and /captcha|verification/i.test el.textContent - if captchaErr and QR.captcha is Captcha.noscript - if QR.captcha.captchas.length is 0 - # Focus the captcha input on captcha error. - QR.captcha.nodes.input.focus() - QR.captcha.setup() - if Conf['Captcha Warning Notifications'] and !d.hidden - QR.notify el - else - $.addClass QR.captcha.nodes.input, 'error' - $.on QR.captcha.nodes.input, 'keydown', -> - $.rmClass QR.captcha.nodes.input, 'error' + if QR.captcha.isEnabled and /captcha|verification/i.test el.textContent + QR.captcha.setup true + QR.captcha.notify el else - QR.captcha.setup true if captchaErr and QR.captcha isnt Captcha.noscript QR.notify el alert el.textContent if d.hidden @@ -567,7 +555,7 @@ QR = QR.cooldown.init() QR.captcha.init() $.add d.body, dialog - QR.captcha.setup() unless QR.captcha is Captcha.noscript + QR.captcha.setup() # Create a custom event when the QR dialog is first initialized. # Use it to extend the QR's functionalities, or for XTRM RICE. @@ -794,6 +782,7 @@ QR = else true QR.cooldown.addDelay post, +m[1] + QR.captcha.setup (d.activeElement is QR.nodes.status) else # stop auto-posting QR.cooldown.auto = false QR.status() @@ -838,8 +827,8 @@ QR = icon: Favicon.logo notif.onclick = -> QR.open() - QR.captcha.nodes.input.focus() if QR.captcha is Captcha.noscript window.focus() + QR.captcha.setup true notif.onshow = -> setTimeout -> notif.close() @@ -848,10 +837,8 @@ QR = unless Conf['Persistent QR'] or postsCount QR.close() else - if QR.captcha is Captcha.noscript and QR.posts.length > 1 and QR.captcha.isEnabled and QR.captcha.captchas.length is 0 - QR.captcha.setup() post.rm() - QR.captcha.setup true unless QR.captcha is Captcha.noscript + QR.captcha.setup (d.activeElement is QR.nodes.status) QR.cooldown.add req.uploadEndTime, threadID, postID diff --git a/src/Posting/QR.post.coffee b/src/Posting/QR.post.coffee index 76ca6be56..c37d2ed2c 100644 --- a/src/Posting/QR.post.coffee +++ b/src/Posting/QR.post.coffee @@ -70,7 +70,7 @@ QR.post = class @select() if select @unlock() # Post count temporarily off by 1 when called from QR.post.rm - $.queueTask -> QR.captcha.setup() unless QR.captcha is Captcha.noscript + $.queueTask -> QR.captcha.onNewPost() rm: -> @delete() @@ -133,7 +133,7 @@ QR.post = class QR.status() when 'com' @nodes.span.textContent = @com - QR.captcha.onPostChange() unless QR.captcha is Captcha.noscript + QR.captcha.onPostChange() QR.characterCount() # Disable auto-posting if you're typing in the first post # during the last 5 seconds of the cooldown. @@ -162,7 +162,7 @@ QR.post = class @filename = file.name @filesize = $.bytesToString file.size @nodes.label.hidden = false if QR.spoiler - QR.captcha.onPostChange() unless QR.captcha is Captcha.noscript + QR.captcha.onPostChange() URL.revokeObjectURL @URL if @ is QR.selected @showFileData()