We should now be able to tell when the QR is focused even when within the captcha <iframe>. No longer need to hold open QR when there is a captcha.
227 lines
5.8 KiB
CoffeeScript
227 lines
5.8 KiB
CoffeeScript
Captcha.noscript =
|
|
lifetime: 2 * $.MINUTE
|
|
iframeURL: '//www.google.com/recaptcha/api/fallback?k=<%= meta.recaptchaKey %>'
|
|
|
|
init: ->
|
|
return if d.cookie.indexOf('pass_enabled=1') >= 0
|
|
return unless @isEnabled = !!$.id 'g-recaptcha'
|
|
|
|
container = $.el 'div',
|
|
className: 'captcha-img'
|
|
title: 'Reload reCAPTCHA'
|
|
input = $.el 'input',
|
|
className: 'captcha-input field'
|
|
title: 'Verification'
|
|
autocomplete: 'off'
|
|
spellcheck: false
|
|
@nodes = {container, input}
|
|
|
|
$.on input, 'keydown', @keydown.bind @
|
|
$.on @nodes.container, 'click', =>
|
|
@reload()
|
|
@nodes.input.focus()
|
|
|
|
@conn = new Connection null, "#{location.protocol}//www.google.com",
|
|
challenge: @load.bind @
|
|
token: @save.bind @
|
|
error: @error.bind @
|
|
|
|
$.addClass QR.nodes.el, 'has-captcha'
|
|
$.after QR.nodes.com.parentNode, [container, input]
|
|
|
|
@captchas = []
|
|
$.get 'captchas', [], ({captchas}) ->
|
|
QR.captcha.sync captchas
|
|
QR.captcha.clear()
|
|
$.sync 'captchas', @sync
|
|
|
|
@beforeSetup()
|
|
@setup()
|
|
|
|
initFrame: ->
|
|
conn = new Connection window.top, "#{location.protocol}//boards.4chan.org",
|
|
queryChallenge: ->
|
|
conn.send {challenge}
|
|
response: (response) ->
|
|
$.id('response').value = response
|
|
$('.fbc-challenge > form').submit()
|
|
challenge = $('.fbc-payload > img')?.src
|
|
token = $('.fbc-verification-token > textarea')?.value
|
|
error = $('.fbc-error')?.textContent
|
|
conn.send {challenge, token, error}
|
|
|
|
timers: {}
|
|
|
|
cb:
|
|
focus: -> QR.captcha.setup false, true
|
|
|
|
beforeSetup: ->
|
|
{container, input} = @nodes
|
|
container.hidden = true
|
|
input.value = ''
|
|
input.placeholder = 'Focus to load reCAPTCHA'
|
|
@count()
|
|
$.on input, 'focus click', @cb.focus
|
|
|
|
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
|
|
$.add d.body, @nodes.iframe
|
|
@conn.target = @nodes.iframe.contentWindow
|
|
else if !@occupied
|
|
@nodes.iframe.src = @iframeURL
|
|
@occupied = true
|
|
@nodes.input.focus() if focus
|
|
|
|
afterSetup: ->
|
|
{container, input} = @nodes
|
|
container.hidden = false
|
|
input.placeholder = 'Verification'
|
|
@count()
|
|
$.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: ->
|
|
return unless @isEnabled
|
|
$.rm @nodes.img if @nodes.img
|
|
delete @nodes.img
|
|
$.rm @nodes.iframe if @nodes.iframe
|
|
delete @nodes.iframe
|
|
delete @occupied
|
|
@unflag()
|
|
@beforeSetup()
|
|
|
|
sync: (captchas=[]) ->
|
|
QR.captcha.captchas = captchas
|
|
QR.captcha.count()
|
|
|
|
getOne: ->
|
|
@clear()
|
|
if captcha = @captchas.shift()
|
|
@count()
|
|
$.set 'captchas', @captchas
|
|
captcha.response
|
|
else if /\S/.test @nodes.input.value
|
|
(cb) =>
|
|
@submitCB = cb
|
|
@sendResponse()
|
|
else
|
|
null
|
|
|
|
sendResponse: ->
|
|
response = @nodes.input.value
|
|
if /\S/.test response
|
|
@conn.send {response}
|
|
|
|
save: (token) ->
|
|
delete @occupied
|
|
@nodes.input.value = ''
|
|
if @submitCB
|
|
@submitCB token
|
|
delete @submitCB
|
|
if @needed() then @reload() else @destroy()
|
|
else
|
|
$.forceSync 'captchas'
|
|
@captchas.push
|
|
response: token
|
|
timeout: @timeout
|
|
@count()
|
|
$.set 'captchas', @captchas
|
|
@reload()
|
|
|
|
error: (message) ->
|
|
@occupied = true
|
|
@nodes.input.value = ''
|
|
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
|
|
$.forceSync 'captchas'
|
|
now = Date.now()
|
|
for captcha, i in @captchas
|
|
break if captcha.timeout > now
|
|
return unless i
|
|
@captchas = @captchas[i..]
|
|
@count()
|
|
$.set 'captchas', @captchas
|
|
|
|
load: (src) ->
|
|
{container, input, img} = @nodes
|
|
@occupied = true
|
|
@timeout = Date.now() + @lifetime
|
|
unless img
|
|
img = @nodes.img = new Image
|
|
$.one img, 'load', @afterSetup.bind @
|
|
$.add container, img
|
|
img.src = src
|
|
input.value = ''
|
|
@clear()
|
|
clearTimeout @timers.expire
|
|
@timers.expire = setTimeout @expire.bind(@), @lifetime
|
|
|
|
count: ->
|
|
count = if @captchas then @captchas.length else 0
|
|
placeholder = @nodes.input.placeholder.replace /\ \(.*\)$/, ''
|
|
placeholder += switch count
|
|
when 0
|
|
if placeholder is 'Verification' then ' (Shift + Enter to cache)' else ''
|
|
when 1
|
|
' (1 cached captcha)'
|
|
else
|
|
" (#{count} cached captchas)"
|
|
@nodes.input.placeholder = placeholder
|
|
@nodes.input.alt = count # For XTRM RICE.
|
|
clearTimeout @timers.clear
|
|
if @captchas.length
|
|
@timers.clear = setTimeout @clear.bind(@), @captchas[0].timeout - Date.now()
|
|
|
|
expire: ->
|
|
return unless @nodes.iframe
|
|
if @needed() or d.activeElement is @nodes.input
|
|
@reload()
|
|
else
|
|
@destroy()
|
|
|
|
reload: ->
|
|
@nodes.iframe.src = @iframeURL
|
|
@occupied = true
|
|
|
|
keydown: (e) ->
|
|
if e.keyCode is 8 and not @nodes.input.value
|
|
if @nodes.iframe then @reload() else @setup()
|
|
else if e.keyCode is 13 and e.shiftKey
|
|
@sendResponse()
|
|
else
|
|
return
|
|
e.preventDefault()
|