visualcaptcha 0.0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/lib/generators/templates/partial.erb +20 -0
- data/lib/generators/visual_captcha_generator.rb +13 -0
- data/lib/visualcaptcha.rb +111 -0
- data/lib/visualcaptcha/controller.rb +15 -0
- data/lib/visualcaptcha/engine.rb +10 -0
- data/lib/visualcaptcha/utils.rb +11 -0
- data/lib/visualcaptcha/version.rb +3 -0
- data/lib/visualcaptcha/view.rb +37 -0
- data/vendor/assets/images/accessibility.png +0 -0
- data/vendor/assets/images/accessibility@2x.png +0 -0
- data/vendor/assets/images/airplane.png +0 -0
- data/vendor/assets/images/airplane@2x.png +0 -0
- data/vendor/assets/images/balloons.png +0 -0
- data/vendor/assets/images/balloons@2x.png +0 -0
- data/vendor/assets/images/camera.png +0 -0
- data/vendor/assets/images/camera@2x.png +0 -0
- data/vendor/assets/images/car.png +0 -0
- data/vendor/assets/images/car@2x.png +0 -0
- data/vendor/assets/images/cat.png +0 -0
- data/vendor/assets/images/cat@2x.png +0 -0
- data/vendor/assets/images/chair.png +0 -0
- data/vendor/assets/images/chair@2x.png +0 -0
- data/vendor/assets/images/clip.png +0 -0
- data/vendor/assets/images/clip@2x.png +0 -0
- data/vendor/assets/images/clock.png +0 -0
- data/vendor/assets/images/clock@2x.png +0 -0
- data/vendor/assets/images/cloud.png +0 -0
- data/vendor/assets/images/cloud@2x.png +0 -0
- data/vendor/assets/images/computer.png +0 -0
- data/vendor/assets/images/computer@2x.png +0 -0
- data/vendor/assets/images/dropzone-edit.png +0 -0
- data/vendor/assets/images/dropzone.png +0 -0
- data/vendor/assets/images/dropzone@2x-edit.png +0 -0
- data/vendor/assets/images/dropzone@2x.png +0 -0
- data/vendor/assets/images/envelope.png +0 -0
- data/vendor/assets/images/envelope@2x.png +0 -0
- data/vendor/assets/images/eye.png +0 -0
- data/vendor/assets/images/eye@2x.png +0 -0
- data/vendor/assets/images/flag.png +0 -0
- data/vendor/assets/images/flag@2x.png +0 -0
- data/vendor/assets/images/folder.png +0 -0
- data/vendor/assets/images/folder@2x.png +0 -0
- data/vendor/assets/images/foot.png +0 -0
- data/vendor/assets/images/foot@2x.png +0 -0
- data/vendor/assets/images/graph.png +0 -0
- data/vendor/assets/images/graph@2x.png +0 -0
- data/vendor/assets/images/house.png +0 -0
- data/vendor/assets/images/house@2x.png +0 -0
- data/vendor/assets/images/key.png +0 -0
- data/vendor/assets/images/key@2x.png +0 -0
- data/vendor/assets/images/lamp.png +0 -0
- data/vendor/assets/images/lamp@2x.png +0 -0
- data/vendor/assets/images/leaf.png +0 -0
- data/vendor/assets/images/leaf@2x.png +0 -0
- data/vendor/assets/images/lock.png +0 -0
- data/vendor/assets/images/lock@2x.png +0 -0
- data/vendor/assets/images/magnifying-glass.png +0 -0
- data/vendor/assets/images/magnifying-glass@2x.png +0 -0
- data/vendor/assets/images/man.png +0 -0
- data/vendor/assets/images/man@2x.png +0 -0
- data/vendor/assets/images/music-note.png +0 -0
- data/vendor/assets/images/music-note@2x.png +0 -0
- data/vendor/assets/images/pants.png +0 -0
- data/vendor/assets/images/pants@2x.png +0 -0
- data/vendor/assets/images/pencil.png +0 -0
- data/vendor/assets/images/pencil@2x.png +0 -0
- data/vendor/assets/images/printer.png +0 -0
- data/vendor/assets/images/printer@2x.png +0 -0
- data/vendor/assets/images/robot.png +0 -0
- data/vendor/assets/images/robot@2x.png +0 -0
- data/vendor/assets/images/scissors.png +0 -0
- data/vendor/assets/images/scissors@2x.png +0 -0
- data/vendor/assets/images/sunglasses.png +0 -0
- data/vendor/assets/images/sunglasses@2x.png +0 -0
- data/vendor/assets/images/tag.png +0 -0
- data/vendor/assets/images/tag@2x.png +0 -0
- data/vendor/assets/images/tree.png +0 -0
- data/vendor/assets/images/tree@2x.png +0 -0
- data/vendor/assets/images/truck.png +0 -0
- data/vendor/assets/images/truck@2x.png +0 -0
- data/vendor/assets/images/tshirt.png +0 -0
- data/vendor/assets/images/tshirt@2x.png +0 -0
- data/vendor/assets/images/umbrella.png +0 -0
- data/vendor/assets/images/umbrella@2x.png +0 -0
- data/vendor/assets/images/woman.png +0 -0
- data/vendor/assets/images/woman@2x.png +0 -0
- data/vendor/assets/images/world.png +0 -0
- data/vendor/assets/images/world@2x.png +0 -0
- data/vendor/assets/javascripts/visualcaptcha.js +161 -0
- data/vendor/assets/stylesheets/visualcaptcha.css +128 -0
- metadata +163 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ODcyY2Q2MjhiOGJhMjY2YjZhZmU2ODc2NzY3YzE0NTk2OTAwYmYwNw==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MzFhZDZiNjg3ODRhYzQ3OTYxNDYzMTU1YzE2ODY4MzUyZGFiNjY5MA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmNiZTljYjdmMmE1ZTQyM2E3ZTk1YmRlMjk3Yzg4ZmNhYWVkODUxZjNkMDZh
|
10
|
+
YjcwYzA3ZTUzNmZkMThmYzUyOGIzZWJlYTQ4YjM5MzlmNWIyMDgyYjRkZWNh
|
11
|
+
ZDU5NTIxZDEwNzU1N2Y5NjE1ODQ3ZmIxNGUwZTBlOTQ1NzA4NzQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzRiNTYwYmJkYjU0NzQ5YjAzZWIxNTQxMmI3OTIxNWJjZGNjYTkzZmYxNTM2
|
14
|
+
ZWU3MWU4MzY2MTdkODBhZThmNjBiZGI4YTU3YTQzYTY2ZTc3OWRlYWZiZTE0
|
15
|
+
MmI5ZjViMGZlMWJmYzE3MDlmZjM1NTU2MmMyZDM4Y2RlZGE0M2M=
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Trevor Kimenye
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# Visualcaptcha
|
2
|
+
|
3
|
+
This Gem is ruby version of emotionLoop's PHP Visual Captcha
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'visualcaptcha'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install visualcaptcha
|
18
|
+
|
19
|
+
## Setup
|
20
|
+
|
21
|
+
After installation, follow these simple steps to setup the plugin. The setup will depend on the version of rails your application is using.
|
22
|
+
|
23
|
+
$ rails generate visual_captcha
|
24
|
+
|
25
|
+
This project requires jquery-ui so you should add it to the application.js
|
26
|
+
|
27
|
+
//= require jquery.ui.all
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
###Controller Based
|
32
|
+
|
33
|
+
We have only enabled a controller based flow at the moment - as this is the simplest use case required
|
34
|
+
|
35
|
+
In the view file within the form tags add this code
|
36
|
+
|
37
|
+
<%= show_visual_captcha(:type => :vertical) %>
|
38
|
+
|
39
|
+
Add the following line in the file "app/controllers/application.rb"
|
40
|
+
|
41
|
+
ApplicationController < ActionController::Base
|
42
|
+
include VisualCaptcha::ControllerHelpers
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
1. Fork it
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
50
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
52
|
+
5. Create new Pull Request
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<link rel="stylesheet" href="/assets/visualcaptcha.css" />
|
2
|
+
<div class="eL-captcha clearfix <%%= captcha_options[:type] %>">
|
3
|
+
<p class="eL-explanation <%%= captcha_options[:type] %>">
|
4
|
+
Drag the <strong><%%= challenge.answer.title %></strong> to the circle on the side.
|
5
|
+
</p>
|
6
|
+
<div class="eL-possibilities <%%= captcha_options[:type] %> clearfix">
|
7
|
+
<%% challenge.options.each do |option| %>
|
8
|
+
<img src="/assets/<%%= option.image %>" class="vc-<%%= option.encrypted %>" data-value="<%%= option.encrypted %>" />
|
9
|
+
<%% end %>
|
10
|
+
</div>
|
11
|
+
<div class="eL-where2go <%%= captcha_options[:type] %> clearfix">
|
12
|
+
</div>
|
13
|
+
</div>
|
14
|
+
<script src="/assets/visualcaptcha.js"></script>
|
15
|
+
<script type="text/javascript">
|
16
|
+
window.vCVals = {
|
17
|
+
'f' : $('.eL-captcha').closest('form').attr('id'),
|
18
|
+
'n' : 'captcha-value'
|
19
|
+
}
|
20
|
+
</script>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rails/generators'
|
2
|
+
|
3
|
+
class VisualCaptchaGenerator < Rails::Generators::Base
|
4
|
+
include Rails::Generators::Migration
|
5
|
+
|
6
|
+
def self.source_root
|
7
|
+
@source_root ||= File.expand_path(File.join(File.dirname(__FILE__), 'templates/'))
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_partial
|
11
|
+
template "partial.erb", File.join('app/views', 'visual_captcha', "_visual_captcha.erb")
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require "visualcaptcha/version"
|
2
|
+
require "visualcaptcha/engine"
|
3
|
+
|
4
|
+
module VisualCaptcha
|
5
|
+
autoload :ViewHelper, 'visualcaptcha/view'
|
6
|
+
autoload :ControllerHelpers, 'visualcaptcha/controller'
|
7
|
+
autoload :Utils, 'visualcaptcha/utils'
|
8
|
+
|
9
|
+
def self.setup
|
10
|
+
yield self
|
11
|
+
end
|
12
|
+
|
13
|
+
class Option
|
14
|
+
|
15
|
+
attr_accessor :id, :image, :title, :encrypted
|
16
|
+
|
17
|
+
def initialize(id, image, title)
|
18
|
+
@id = id
|
19
|
+
@image = image
|
20
|
+
@title = title
|
21
|
+
@encrypted = VisualCaptcha::Utils.generate_key(id)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
class Challenge
|
27
|
+
attr_accessor :answer, :options
|
28
|
+
|
29
|
+
def initialize(answer, options=nil)
|
30
|
+
@answer = answer
|
31
|
+
@options = options
|
32
|
+
@options << answer
|
33
|
+
@options.shuffle!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Captcha
|
38
|
+
|
39
|
+
attr_accessor :number
|
40
|
+
|
41
|
+
def initialize(number=4)
|
42
|
+
@number = number
|
43
|
+
@answers = [
|
44
|
+
Option.new('airplane', 'airplane.png', 'Airplane'),
|
45
|
+
Option.new('balloons', 'balloons.png', 'Balloons'),
|
46
|
+
Option.new('camera', 'camera.png', 'Camera'),
|
47
|
+
Option.new('car', 'car.png', 'Car'),
|
48
|
+
Option.new('cat', 'cat.png', 'Cat'),
|
49
|
+
Option.new('chair', 'chair.png', 'Chair'),
|
50
|
+
Option.new('clip', 'clip.png', 'Clip'),
|
51
|
+
Option.new('clock', 'clock.png', 'Clock'),
|
52
|
+
Option.new('cloud', 'cloud.png', 'Cloud'),
|
53
|
+
Option.new('computer', 'computer.png', 'Computer'),
|
54
|
+
Option.new('envelope', 'envelope.png', 'Envelope'),
|
55
|
+
Option.new('eye', 'eye.png', 'Eye'),
|
56
|
+
Option.new('flag', 'flag.png', 'Flag'),
|
57
|
+
Option.new('folder', 'folder.png', 'Folder'),
|
58
|
+
Option.new('foot', 'foot.png', 'Foot'),
|
59
|
+
Option.new('graph', 'graph.png', 'Graph'),
|
60
|
+
Option.new('house', 'house.png', 'House'),
|
61
|
+
Option.new('key', 'key.png', 'Key'),
|
62
|
+
Option.new('lamp', 'lamp.png', 'Lamp'),
|
63
|
+
Option.new('leaf', 'leaf.png', 'Leaf'),
|
64
|
+
Option.new('lock', 'lock.png', 'Lock'),
|
65
|
+
Option.new('magnifying-glass', 'magnifying-glass.png', 'Magnifying Glass'),
|
66
|
+
Option.new('man', 'man.png', 'Man'),
|
67
|
+
Option.new('music-note', 'music-note.png', 'Music Note'),
|
68
|
+
Option.new('pants', 'pants.png', 'Pants'),
|
69
|
+
Option.new('pencil', 'pencil.png', 'Pencil'),
|
70
|
+
Option.new('printer', 'printer.png', 'Printer'),
|
71
|
+
Option.new('robot', 'robot.png', 'Robot'),
|
72
|
+
Option.new('scissors', 'scissors.png', 'Scissors'),
|
73
|
+
Option.new('sunglasses', 'sunglasses.png', 'Sunglasses'),
|
74
|
+
Option.new('tag', 'tag.png', 'Tag'),
|
75
|
+
Option.new('tree', 'tree.png', 'Tree'),
|
76
|
+
Option.new('truck', 'truck.png', 'Truck'),
|
77
|
+
Option.new('tshirt', 'tshirt.png', 'T-Shirt'),
|
78
|
+
Option.new('umbrella', 'umbrella.png', 'Umbrella'),
|
79
|
+
Option.new('woman', 'woman.png', 'Woman'),
|
80
|
+
Option.new('world', 'world.png', 'World')
|
81
|
+
]
|
82
|
+
|
83
|
+
#@$this->answers = array(
|
84
|
+
# 'tshirt' => array(self::$imagesPath . 'tshirt.png', 'T-Shirt'),
|
85
|
+
# 'umbrella' => array(self::$imagesPath . 'umbrella.png', 'Umbrella'),
|
86
|
+
# 'woman' => array(self::$imagesPath . 'woman.png', 'Woman'),
|
87
|
+
# 'world' => array(self::$imagesPath . 'world.png', 'World'),
|
88
|
+
#);
|
89
|
+
end
|
90
|
+
|
91
|
+
def build
|
92
|
+
#shuffle the options
|
93
|
+
opts = @answers.shuffle
|
94
|
+
|
95
|
+
#pick a random answer
|
96
|
+
answer = opts.sample
|
97
|
+
opts.reject! { |c| c.id == answer.id }
|
98
|
+
others = []
|
99
|
+
|
100
|
+
#pick the remaining clues
|
101
|
+
(1..@number-1).to_a.each_with_index do |c,i|
|
102
|
+
|
103
|
+
possible = opts.sample
|
104
|
+
others << possible
|
105
|
+
opts.reject! { |c| c.id == possible.id }
|
106
|
+
end
|
107
|
+
#return the challenge
|
108
|
+
Challenge.new(answer,others)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module VisualCaptcha
|
2
|
+
module ControllerHelpers
|
3
|
+
def visual_captcha_valid?
|
4
|
+
return true if Rails.env.test?
|
5
|
+
|
6
|
+
if params["captcha-value"]
|
7
|
+
challenge = session[:captcha]
|
8
|
+
result = challenge.answer.encrypted == params["captcha-value"]
|
9
|
+
return result
|
10
|
+
else
|
11
|
+
return false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module VisualCaptcha
|
2
|
+
module ViewHelper
|
3
|
+
|
4
|
+
def show_visual_captcha(options = {})
|
5
|
+
options = sanitize_options(options)
|
6
|
+
|
7
|
+
#key = visual_captcha_key('captcha')
|
8
|
+
|
9
|
+
number = options[:type] == "type-0" ? 5 : 4
|
10
|
+
captcha = VisualCaptcha::Captcha.new(number)
|
11
|
+
challenge = captcha.build
|
12
|
+
|
13
|
+
session[:captcha] = challenge
|
14
|
+
|
15
|
+
render :partial => 'visual_captcha/visual_captcha', :locals => { :captcha_options => options, :challenge => challenge }
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def sanitize_options(options)
|
21
|
+
if options[:type] == :vertical
|
22
|
+
options[:type] = "type-1"
|
23
|
+
else
|
24
|
+
options[:type] = "type-0"
|
25
|
+
end
|
26
|
+
options
|
27
|
+
end
|
28
|
+
|
29
|
+
def visual_captcha_key(key_name = nil)
|
30
|
+
if key_name.nil?
|
31
|
+
session[:captcha] ||= VisualCaptcha::Utils.generate_key(session[:id].to_s, 'captcha')
|
32
|
+
else
|
33
|
+
VisualCaptcha::Utils.generate_key(session[:id].to_s, key_name)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,161 @@
|
|
1
|
+
/**
|
2
|
+
* visualCaptchaHTML class by emotionLoop - 2013.03.28
|
3
|
+
*
|
4
|
+
* This file handles the JS for the main visualCaptcha class.
|
5
|
+
*
|
6
|
+
* This license applies to this file and others without reference to any other license.
|
7
|
+
*
|
8
|
+
* @author emotionLoop | http://emotionloop.com
|
9
|
+
* @link http://visualcaptcha.net
|
10
|
+
* @package visualCaptcha
|
11
|
+
* @license GNU GPL v3
|
12
|
+
* @version 4.0.3
|
13
|
+
*/
|
14
|
+
$(document).ready(function() {
|
15
|
+
var isMobile = false;
|
16
|
+
var isRetina = false;
|
17
|
+
var supportsAudio = false;
|
18
|
+
|
19
|
+
var uAgent = navigator.userAgent.toLowerCase();
|
20
|
+
|
21
|
+
// Check if the user agent is a mobile one
|
22
|
+
if ( uAgent.indexOf('iphone') !== -1 || uAgent.indexOf('ipad') !== -1 || uAgent.indexOf('ipod') !== -1 ||
|
23
|
+
uAgent.indexOf('android') !== -1 ||
|
24
|
+
uAgent.indexOf('windows phone') !== -1 || uAgent.indexOf('windows ce') !== -1 ||
|
25
|
+
uAgent.indexOf('bada') !== -1 ||
|
26
|
+
uAgent.indexOf('meego') !== -1 ||
|
27
|
+
uAgent.indexOf('palm') !== -1 ||
|
28
|
+
uAgent.indexOf('blackberry') !== -1 ||
|
29
|
+
uAgent.indexOf('nokia') !== -1 || uAgent.indexOf('symbian') !== -1 ||
|
30
|
+
uAgent.indexOf('pocketpc') !== -1 ||
|
31
|
+
uAgent.indexOf('smartphone') !== -1 ||
|
32
|
+
uAgent.indexOf('mobile') !== -1 ) {
|
33
|
+
isMobile = true;
|
34
|
+
}
|
35
|
+
|
36
|
+
// Check if the device is retina-like
|
37
|
+
if ( window.devicePixelRatio && window.devicePixelRatio > 1 ) {
|
38
|
+
isRetina = true;
|
39
|
+
}
|
40
|
+
|
41
|
+
// Check if the device supports audio, for accessibility
|
42
|
+
try {
|
43
|
+
var audioElement = document.createElement('audio');
|
44
|
+
if ( audioElement.canPlayType ) {
|
45
|
+
supportsAudio = true;
|
46
|
+
}
|
47
|
+
} catch(e) {}
|
48
|
+
|
49
|
+
// If the device is retina-like, update the img src's and the dropzone class
|
50
|
+
if ( isRetina ) {
|
51
|
+
$('div.eL-captcha img').each(function(index, element) {
|
52
|
+
if ( ! $(element).attr('src') ) return;
|
53
|
+
|
54
|
+
var newImageSRC = $(element).attr('src').replace(/(.+)(\.\w{3,4})$/, "$1@2x$2");
|
55
|
+
$.ajax({
|
56
|
+
url: newImageSRC,
|
57
|
+
type: "HEAD",
|
58
|
+
success: function() {
|
59
|
+
$(element).attr('src', newImageSRC);
|
60
|
+
}
|
61
|
+
});
|
62
|
+
});
|
63
|
+
|
64
|
+
$('div.eL-captcha > div.eL-where2go').addClass('retina');
|
65
|
+
}
|
66
|
+
|
67
|
+
if ( ! supportsAudio ) {
|
68
|
+
$('div.eL-captcha > .eL-accessibility').hide();
|
69
|
+
} else {
|
70
|
+
$('div.eL-captcha > p.eL-accessibility a').on('click touchstart', function(event) {
|
71
|
+
event.preventDefault();
|
72
|
+
|
73
|
+
if ( ! $('div.eL-captcha > div.eL-accessibility').is(':visible') ) {
|
74
|
+
$('div.eL-captcha > div.eL-accessibility > audio').each(function() {
|
75
|
+
this.load();
|
76
|
+
this.play();
|
77
|
+
});
|
78
|
+
|
79
|
+
if ( ! $('#' + window.vCVals.a).length ) {
|
80
|
+
var validAccessibleElement = '<input type="text" name="' + window.vCVals.a + '" id="' + window.vCVals.a + '" value="">';
|
81
|
+
$('div.eL-captcha > div.eL-accessibility > p').after(validAccessibleElement);
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
85
|
+
$('div.eL-captcha > p.eL-explanation').stop().slideToggle('fast');
|
86
|
+
$('div.eL-captcha > div.eL-possibilities').stop().slideToggle('fast');
|
87
|
+
$('div.eL-captcha > div.eL-where2go').stop().slideToggle('fast');
|
88
|
+
$('div.eL-captcha > div.eL-accessibility').stop().slideToggle('fast');
|
89
|
+
});
|
90
|
+
}
|
91
|
+
|
92
|
+
if ( ! isMobile ) {// If it's not mobile, load normal drag/drop behavior
|
93
|
+
debugger;
|
94
|
+
$('div.eL-captcha > div.eL-possibilities > img').draggable({ opacity: 0.6, revert: 'invalid' });
|
95
|
+
$('div.eL-captcha > div.eL-possibilities').droppable({
|
96
|
+
drop: function(event, ui) {
|
97
|
+
if ( ! $('#' + window.vCVals.n).length ) {
|
98
|
+
return false;
|
99
|
+
}
|
100
|
+
if ( $('#' + window.vCVals.n).val() == $(ui.draggable).data('value') ) {
|
101
|
+
$('#' + window.vCVals.n).remove();
|
102
|
+
}
|
103
|
+
$('div.eL-captcha > div.eL-where2go').droppable('enable');
|
104
|
+
},
|
105
|
+
accept: 'div.eL-captcha > div.eL-possibilities > img'
|
106
|
+
});
|
107
|
+
|
108
|
+
$('div.eL-captcha > div.eL-where2go').droppable({
|
109
|
+
drop: function(event, ui) {
|
110
|
+
if ( $('#' + window.vCVals.n).length ) {
|
111
|
+
return false;
|
112
|
+
}
|
113
|
+
var validElement = '<input type="hidden" name="' + window.vCVals.n + '" id="' + window.vCVals.n + '" readonly="readonly" value="' + $(ui.draggable).data('value') + '">';
|
114
|
+
$('#' + window.vCVals.f).append(validElement);
|
115
|
+
$(this).droppable('disable');
|
116
|
+
},
|
117
|
+
accept: 'div.eL-captcha > div.eL-possibilities > img'
|
118
|
+
});
|
119
|
+
} else {// If it's mobile, we're going to make it possible to just tap an image and move it to the drop area automagically
|
120
|
+
$('div.eL-captcha > div.eL-possibilities > img').on('click touchstart', function() {// Add tap behavior, but keep click in case that also works. There is no "duplication" problem since this code won't run twice
|
121
|
+
var xPos = $('div.eL-captcha > div.eL-where2go').offset().left - 5;
|
122
|
+
var yPos = $('div.eL-captcha > div.eL-where2go').offset().top;
|
123
|
+
var wDim = $('div.eL-captcha > div.eL-where2go').width();
|
124
|
+
var hDim = $('div.eL-captcha > div.eL-where2go').height();
|
125
|
+
var iwDim = $(this).width();
|
126
|
+
var ihDim = $(this).height();
|
127
|
+
|
128
|
+
// If it was dragged already to the droppable zone, move it back to the beginning
|
129
|
+
if ($(this).css('position') == 'absolute') {
|
130
|
+
if ( ! $('#' + window.vCVals.n).length ) {
|
131
|
+
return false;
|
132
|
+
}
|
133
|
+
if ( $('#' + window.vCVals.n).val() == $(this).data('value') ) {
|
134
|
+
$('#' + window.vCVals.n).remove();
|
135
|
+
}
|
136
|
+
|
137
|
+
$(this).css({
|
138
|
+
'position': 'relative',
|
139
|
+
'left': 'auto',
|
140
|
+
'top': 'auto'
|
141
|
+
});
|
142
|
+
} else {
|
143
|
+
if ( $('#' + window.vCVals.n).length ) {
|
144
|
+
return false;
|
145
|
+
}
|
146
|
+
var validElement = '<input type="hidden" name="' + window.vCVals.n + '" id="' + window.vCVals.n + '" readonly="readonly" value="' + $(this).data('value') + '">';
|
147
|
+
$('#' + window.vCVals.f).append(validElement);
|
148
|
+
|
149
|
+
// Calculate the middle of hte
|
150
|
+
var xPos2Go = Math.round(xPos + (wDim/2) - (iwDim/2));
|
151
|
+
var yPos2Go = Math.round(yPos + (hDim/2) - (ihDim/2));
|
152
|
+
|
153
|
+
$(this).css({
|
154
|
+
'position': 'absolute',
|
155
|
+
'left': xPos2Go,
|
156
|
+
'top': yPos2Go
|
157
|
+
});
|
158
|
+
}
|
159
|
+
});
|
160
|
+
}
|
161
|
+
});
|
@@ -0,0 +1,128 @@
|
|
1
|
+
/**
|
2
|
+
* visualCaptchaHTML class by emotionLoop - 2013.03.28
|
3
|
+
*
|
4
|
+
* This file handles the CSS for the main wCaptcha class.
|
5
|
+
*
|
6
|
+
* This license applies to this file and others without reference to any other license.
|
7
|
+
*
|
8
|
+
* @author emotionLoop | http://emotionloop.com
|
9
|
+
* @link http://visualcaptcha.net
|
10
|
+
* @package visualCaptcha
|
11
|
+
* @license GNU GPL v3
|
12
|
+
* @version 4.0.3
|
13
|
+
*/
|
14
|
+
div.eL-captcha.type-1 {
|
15
|
+
margin: 10px 0 10px 10px;
|
16
|
+
padding: 0;
|
17
|
+
display: block;
|
18
|
+
width: 200px;
|
19
|
+
}
|
20
|
+
div.eL-captcha > div.eL-possibilities.type-1 {
|
21
|
+
margin: 0;
|
22
|
+
padding: 14px 0 0 0;
|
23
|
+
display: block;
|
24
|
+
width: 100px;
|
25
|
+
float: left;
|
26
|
+
height: 46px;
|
27
|
+
}
|
28
|
+
div.eL-captcha > div.eL-possibilities.type-1 > img {
|
29
|
+
padding: 0 4px 4px 4px !important;
|
30
|
+
}
|
31
|
+
div.eL-captcha > div.eL-where2go.type-1 {
|
32
|
+
margin: 0 !important;
|
33
|
+
}
|
34
|
+
|
35
|
+
div.eL-captcha.type-0 {
|
36
|
+
margin: 0 0 10px 0;
|
37
|
+
padding: 0;
|
38
|
+
display: block;
|
39
|
+
width: 320px;
|
40
|
+
}
|
41
|
+
div.eL-captcha > div.eL-possibilities.type-0 {
|
42
|
+
margin: 0;
|
43
|
+
padding: 34px 0 0 0;
|
44
|
+
display: block;
|
45
|
+
width: 200px;
|
46
|
+
float: left;
|
47
|
+
height: 66px;
|
48
|
+
}
|
49
|
+
|
50
|
+
div.eL-captcha > div.eL-possibilities > img {
|
51
|
+
width: 32px;
|
52
|
+
height: 32px;
|
53
|
+
display: block;
|
54
|
+
float: left;
|
55
|
+
margin: 0;
|
56
|
+
padding: 0 4px;
|
57
|
+
z-index: 5;
|
58
|
+
}
|
59
|
+
div.eL-captcha > div.eL-where2go {
|
60
|
+
margin: 0 0 0 20px;
|
61
|
+
padding: 0;
|
62
|
+
display: block;
|
63
|
+
width: 100px;
|
64
|
+
background: transparent url('/assets/dropzone.png') center center no-repeat;
|
65
|
+
float: left;
|
66
|
+
height: 100px;
|
67
|
+
}
|
68
|
+
div.eL-captcha > div.eL-where2go.retina {
|
69
|
+
background-image: url('/assets/dropzone@2x.png');
|
70
|
+
background-size: 90px 90px;
|
71
|
+
}
|
72
|
+
div.eL-captcha > p.eL-accessibility {
|
73
|
+
font-size: 10px;
|
74
|
+
text-align: right;
|
75
|
+
display: block;
|
76
|
+
float: right;
|
77
|
+
clear: both;
|
78
|
+
}
|
79
|
+
div.eL-captcha > p.eL-accessibility img {
|
80
|
+
width: 16px;
|
81
|
+
height: 16px;
|
82
|
+
}
|
83
|
+
div.eL-captcha > div.eL-accessibility {
|
84
|
+
font-size: 12px;
|
85
|
+
text-align: left;
|
86
|
+
display: none;
|
87
|
+
clear: left;
|
88
|
+
float: left;
|
89
|
+
margin-bottom: 10px;
|
90
|
+
width: 300px;
|
91
|
+
overflow: auto;
|
92
|
+
}
|
93
|
+
div.eL-captcha > div.eL-accessibility.type-1 {
|
94
|
+
width: 180px;
|
95
|
+
}
|
96
|
+
div.eL-captcha > div.eL-accessibility > p {
|
97
|
+
width: 100%;
|
98
|
+
}
|
99
|
+
div.eL-captcha > div.eL-accessibility > input {
|
100
|
+
display: block;
|
101
|
+
padding: 5px;
|
102
|
+
width: 90%;
|
103
|
+
margin: 10px 0;
|
104
|
+
font-size: 1em;
|
105
|
+
border: 1px solid #CCC;
|
106
|
+
color: #333;
|
107
|
+
}
|
108
|
+
div.eL-captcha > div.eL-accessibility > audio {
|
109
|
+
visibility: hidden;
|
110
|
+
clear: both;
|
111
|
+
}
|
112
|
+
|
113
|
+
div.eL-captcha .clearfix,
|
114
|
+
div.eL-captcha.clearfix {
|
115
|
+
zoom: 1;
|
116
|
+
}
|
117
|
+
div.eL-captcha .clearfix:before,
|
118
|
+
div.eL-captcha .clearfix:after,
|
119
|
+
div.eL-captcha.clearfix:before,
|
120
|
+
div.eL-captcha.clearfix:after {
|
121
|
+
display: table;
|
122
|
+
line-height: 0;
|
123
|
+
content: "";
|
124
|
+
}
|
125
|
+
div.eL-captcha .clearfix:after,
|
126
|
+
div.eL-captcha.clearfix:after {
|
127
|
+
clear: both;
|
128
|
+
}
|
metadata
ADDED
@@ -0,0 +1,163 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: visualcaptcha
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Trevor Kimenye
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-06-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: railties
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: jquery-ui-rails
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ! '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description: A captcha that uses images instead of garbled text
|
42
|
+
email:
|
43
|
+
- trevor@sprout.co.ke
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- lib/generators/templates/partial.erb
|
49
|
+
- lib/generators/visual_captcha_generator.rb
|
50
|
+
- lib/visualcaptcha/controller.rb
|
51
|
+
- lib/visualcaptcha/engine.rb
|
52
|
+
- lib/visualcaptcha/utils.rb
|
53
|
+
- lib/visualcaptcha/version.rb
|
54
|
+
- lib/visualcaptcha/view.rb
|
55
|
+
- lib/visualcaptcha.rb
|
56
|
+
- vendor/assets/images/accessibility.png
|
57
|
+
- vendor/assets/images/accessibility@2x.png
|
58
|
+
- vendor/assets/images/airplane.png
|
59
|
+
- vendor/assets/images/airplane@2x.png
|
60
|
+
- vendor/assets/images/balloons.png
|
61
|
+
- vendor/assets/images/balloons@2x.png
|
62
|
+
- vendor/assets/images/camera.png
|
63
|
+
- vendor/assets/images/camera@2x.png
|
64
|
+
- vendor/assets/images/car.png
|
65
|
+
- vendor/assets/images/car@2x.png
|
66
|
+
- vendor/assets/images/cat.png
|
67
|
+
- vendor/assets/images/cat@2x.png
|
68
|
+
- vendor/assets/images/chair.png
|
69
|
+
- vendor/assets/images/chair@2x.png
|
70
|
+
- vendor/assets/images/clip.png
|
71
|
+
- vendor/assets/images/clip@2x.png
|
72
|
+
- vendor/assets/images/clock.png
|
73
|
+
- vendor/assets/images/clock@2x.png
|
74
|
+
- vendor/assets/images/cloud.png
|
75
|
+
- vendor/assets/images/cloud@2x.png
|
76
|
+
- vendor/assets/images/computer.png
|
77
|
+
- vendor/assets/images/computer@2x.png
|
78
|
+
- vendor/assets/images/dropzone-edit.png
|
79
|
+
- vendor/assets/images/dropzone.png
|
80
|
+
- vendor/assets/images/dropzone@2x-edit.png
|
81
|
+
- vendor/assets/images/dropzone@2x.png
|
82
|
+
- vendor/assets/images/envelope.png
|
83
|
+
- vendor/assets/images/envelope@2x.png
|
84
|
+
- vendor/assets/images/eye.png
|
85
|
+
- vendor/assets/images/eye@2x.png
|
86
|
+
- vendor/assets/images/flag.png
|
87
|
+
- vendor/assets/images/flag@2x.png
|
88
|
+
- vendor/assets/images/folder.png
|
89
|
+
- vendor/assets/images/folder@2x.png
|
90
|
+
- vendor/assets/images/foot.png
|
91
|
+
- vendor/assets/images/foot@2x.png
|
92
|
+
- vendor/assets/images/graph.png
|
93
|
+
- vendor/assets/images/graph@2x.png
|
94
|
+
- vendor/assets/images/house.png
|
95
|
+
- vendor/assets/images/house@2x.png
|
96
|
+
- vendor/assets/images/key.png
|
97
|
+
- vendor/assets/images/key@2x.png
|
98
|
+
- vendor/assets/images/lamp.png
|
99
|
+
- vendor/assets/images/lamp@2x.png
|
100
|
+
- vendor/assets/images/leaf.png
|
101
|
+
- vendor/assets/images/leaf@2x.png
|
102
|
+
- vendor/assets/images/lock.png
|
103
|
+
- vendor/assets/images/lock@2x.png
|
104
|
+
- vendor/assets/images/magnifying-glass.png
|
105
|
+
- vendor/assets/images/magnifying-glass@2x.png
|
106
|
+
- vendor/assets/images/man.png
|
107
|
+
- vendor/assets/images/man@2x.png
|
108
|
+
- vendor/assets/images/music-note.png
|
109
|
+
- vendor/assets/images/music-note@2x.png
|
110
|
+
- vendor/assets/images/pants.png
|
111
|
+
- vendor/assets/images/pants@2x.png
|
112
|
+
- vendor/assets/images/pencil.png
|
113
|
+
- vendor/assets/images/pencil@2x.png
|
114
|
+
- vendor/assets/images/printer.png
|
115
|
+
- vendor/assets/images/printer@2x.png
|
116
|
+
- vendor/assets/images/robot.png
|
117
|
+
- vendor/assets/images/robot@2x.png
|
118
|
+
- vendor/assets/images/scissors.png
|
119
|
+
- vendor/assets/images/scissors@2x.png
|
120
|
+
- vendor/assets/images/sunglasses.png
|
121
|
+
- vendor/assets/images/sunglasses@2x.png
|
122
|
+
- vendor/assets/images/tag.png
|
123
|
+
- vendor/assets/images/tag@2x.png
|
124
|
+
- vendor/assets/images/tree.png
|
125
|
+
- vendor/assets/images/tree@2x.png
|
126
|
+
- vendor/assets/images/truck.png
|
127
|
+
- vendor/assets/images/truck@2x.png
|
128
|
+
- vendor/assets/images/tshirt.png
|
129
|
+
- vendor/assets/images/tshirt@2x.png
|
130
|
+
- vendor/assets/images/umbrella.png
|
131
|
+
- vendor/assets/images/umbrella@2x.png
|
132
|
+
- vendor/assets/images/woman.png
|
133
|
+
- vendor/assets/images/woman@2x.png
|
134
|
+
- vendor/assets/images/world.png
|
135
|
+
- vendor/assets/images/world@2x.png
|
136
|
+
- vendor/assets/javascripts/visualcaptcha.js
|
137
|
+
- vendor/assets/stylesheets/visualcaptcha.css
|
138
|
+
- LICENSE.txt
|
139
|
+
- README.md
|
140
|
+
homepage: https://github.com/kimenye/visualcaptcha
|
141
|
+
licenses: []
|
142
|
+
metadata: {}
|
143
|
+
post_install_message:
|
144
|
+
rdoc_options: []
|
145
|
+
require_paths:
|
146
|
+
- lib
|
147
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ! '>='
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
|
+
requirements:
|
154
|
+
- - ! '>='
|
155
|
+
- !ruby/object:Gem::Version
|
156
|
+
version: '0'
|
157
|
+
requirements: []
|
158
|
+
rubyforge_project:
|
159
|
+
rubygems_version: 2.0.3
|
160
|
+
signing_key:
|
161
|
+
specification_version: 4
|
162
|
+
summary: A captcha that uses images instead of garbled text
|
163
|
+
test_files: []
|