4chan-x/src/Posting/Captcha.fixes.coffee

157 lines
4.7 KiB
CoffeeScript

Captcha.fixes =
imageKeys: '789456123uiojklm'.split('').concat(['Comma', 'Period'])
imageKeys16: '7890uiopjkl'.split('').concat(['Semicolon', 'm', 'Comma', 'Period', 'Slash'])
css: '''
.rc-imageselect-target > div:focus, .rc-image-tile-target:focus {
outline: 2px solid #4a90e2;
}
.rc-imageselect-target td:focus {
box-shadow: inset 0 0 0 2px #4a90e2;
outline: none;
}
.rc-button-default:focus {
box-shadow: inset 0 0 0 2px #0063d6;
}
'''
cssNoscript: '''
.fbc-payload-imageselect {
position: relative;
}
.fbc-payload-imageselect > label {
position: absolute;
display: block;
height: 93.3px;
width: 93.3px;
}
label[data-row="0"] {top: 0px;}
label[data-row="1"] {top: 93.3px;}
label[data-row="2"] {top: 186.6px;}
label[data-col="0"] {left: 0px;}
label[data-col="1"] {left: 93.3px;}
label[data-col="2"] {left: 186.6px;}
.fbc-payload-imageselect > input:focus + label {
outline: 2px solid #4a90e2;
}
.fbc-button-verify input:focus {
box-shadow: inset 0 0 0 2px #0063d6;
}
body.focus .fbc {
box-shadow: inset 0 0 0 2px #4a90e2;
}
'''
init: ->
switch location.pathname.split('/')[3]
when 'anchor' then @initMain()
when 'frame' then @initPopup()
when 'fallback' then @initNoscript()
initMain: ->
$.onExists d.body, '#recaptcha-anchor', (checkbox) ->
focus = ->
if d.hasFocus() and d.activeElement in [d.documentElement, d.body]
checkbox.focus()
focus()
$.on window, 'focus', ->
$.queueTask focus
# Remove Privacy and Terms links from tab order.
for a in $$ '.rc-anchor-pt a'
a.tabIndex = -1
return
initPopup: ->
$.addStyle @css
@fixImages()
new MutationObserver(=> @fixImages()).observe d.body, {childList: true, subtree: true}
$.on d, 'keydown', @keybinds.bind(@)
initNoscript: ->
@noscript = true
data = if (token = $('.fbc-verification-token > textarea')?.value) then {token} else {working: true}
new Connection(window.parent, '*').send data
d.body.classList.toggle 'focus', d.hasFocus()
$.on window, 'focus blur', -> d.body.classList.toggle 'focus', d.hasFocus()
@images = $$ '.fbc-payload-imageselect > input'
@width = 3
return unless @images.length is 9
$.addStyle @cssNoscript
@addLabels()
$.on d, 'keydown', @keybinds.bind(@)
$.on $('.fbc-imageselect-challenge > form'), 'submit', @checkForm.bind(@)
fixImages: ->
@images = $$ '.rc-image-tile-target'
@images = $$ '.rc-imageselect-target > div, .rc-imageselect-target td' unless @images.length
@width = $$('.rc-imageselect-target tr:first-of-type td').length or Math.round(Math.sqrt @images.length)
for img in @images
img.tabIndex = 0
if @images.length is 9
@addTooltips @images
else
@addTooltips16 @images
addLabels: ->
imageSelect = $ '.fbc-payload-imageselect'
labels = for checkbox, i in @images
checkbox.id = "checkbox-#{i}"
label = $.el 'label',
htmlFor: checkbox.id
label.dataset.row = i // 3
label.dataset.col = i % 3
$.after checkbox, label
label
@addTooltips labels
addTooltips: (nodes) ->
for node, i in nodes
node.title = "#{@imageKeys[i]} or #{@imageKeys[i+9][0].toUpperCase()}#{@imageKeys[i+9][1..]}"
return
addTooltips16: (nodes) ->
for key, i in @imageKeys16
if i % 4 < @width and (node = nodes[nodes.length - (4 - i//4)*@width + (i % 4)])
node.title = "#{key[0].toUpperCase()}#{key[1..]}"
return
checkForm: (e) ->
n = 0
n++ for checkbox in @images when checkbox.checked
e.preventDefault() if n is 0
keybinds: (e) ->
return unless @images and doc.contains(@images[0])
n = @images.length
w = @width
last = n + w - 1
reload = $ '#recaptcha-reload-button, .fbc-button-reload'
verify = $ '#recaptcha-verify-button, .fbc-button-verify > input'
x = @images.indexOf d.activeElement
if x < 0
x = if d.activeElement is verify then last else n
key = Keybinds.keyCode e
if !@noscript and key is 'Space' and x < n
@images[x].click()
else if n is 9 and (i = @imageKeys.indexOf key) >= 0
@images[i % 9].click()
verify.focus()
else if n isnt 9 and (i = @imageKeys16.indexOf key) >= 0 and i % 4 < w and (img = @images[n - (4 - i//4)*w + (i % 4)])
img.click()
verify.focus()
else if dx = {'Up': n, 'Down': w, 'Left': last, 'Right': 1}[key]
x = (x + dx) % (n + w)
if n < x < last
x = if dx is last then n else last
(@images[x] or (if x is n then reload) or (if x is last then verify)).focus()
else
return
e.preventDefault()
e.stopPropagation()