ajax_canvas_field 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/README.md +84 -0
- data/Rakefile +1 -0
- data/ajax_canvas_field.gemspec +32 -0
- data/app/assets/images/mouse_left.png +0 -0
- data/app/assets/images/mouse_middle.png +0 -0
- data/app/assets/images/mouse_right.png +0 -0
- data/app/assets/javascripts/ajax_canvas_field.js +192 -0
- data/app/assets/javascripts/ro_canvas_field.js +42 -0
- data/app/assets/stylesheets/ajax_canvas_field.css +24 -0
- data/app/helpers/canvas_field_helper.rb +67 -0
- data/app/views/ajax_canvas_field/_canvas_legend.html.haml +21 -0
- data/assets/images/mouse_left.png +0 -0
- data/assets/images/mouse_middle.png +0 -0
- data/assets/images/mouse_right.png +0 -0
- data/assets/javascripts/ajax_canvas_field.js +192 -0
- data/assets/javascripts/ro_canvas_field.js +42 -0
- data/assets/stylesheets/ajax_canvas_field.css +24 -0
- data/helpers/canvas_field_helper.rb +67 -0
- data/lib/ajax_canvas_field/config.rb +38 -0
- data/lib/ajax_canvas_field/rails/engine.rb +12 -0
- data/lib/ajax_canvas_field/rails/version.rb +5 -0
- data/lib/ajax_canvas_field/rails.rb +7 -0
- data/lib/ajax_canvas_field.rb +2 -0
- data/lib/generators/ajax_canvas_field/ajax_canvas_field_generator.rb +15 -0
- data/lib/generators/ajax_canvas_field/templates/initializer.rb +7 -0
- data/views/ajax_canvas_field/_canvas_legend.html.haml +21 -0
- metadata +101 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: b6473159e106c84c7d22f88082f09673881e75ba
|
4
|
+
data.tar.gz: 19c2ded0fa28248bad6827bd640ad08d3d1b45ba
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7a1804d70527ba1bab761106cbcf05b240d70909bba0b8a181b40c64ec39d30e4f131c86039ea899e019facac4fac3460f476c64cc51636d0ac06f722f250f78
|
7
|
+
data.tar.gz: 8a1b0af731180d5698822a7ed7321a8ed92fefa640ecafffd8abf1508dde7b3115355e5592f6a64dadcc2c64f0c36b357cc2af016fa0580b4a8f10f409688b30
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,84 @@
|
|
1
|
+
# AjaxCanvasField
|
2
|
+
|
3
|
+
|
4
|
+
## Installation
|
5
|
+
|
6
|
+
Add this line to your application's Gemfile:
|
7
|
+
|
8
|
+
```ruby
|
9
|
+
gem 'ajax_canvas_field'
|
10
|
+
```
|
11
|
+
|
12
|
+
And then execute:
|
13
|
+
|
14
|
+
$ bundle
|
15
|
+
|
16
|
+
Or install it yourself as:
|
17
|
+
|
18
|
+
$ gem install ajax_canvas_field
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
There are three tasks you can execute.
|
22
|
+
|
23
|
+
### ATTENTION: Use at your own risk! Back your shit up, before using this!
|
24
|
+
Each will ask you for the file
|
25
|
+
If this gem is installed inside a Rails-Application you just have to written
|
26
|
+
e.g.:
|
27
|
+
```
|
28
|
+
'en' -> for en.yml
|
29
|
+
'de' -> for de.yml
|
30
|
+
...
|
31
|
+
```
|
32
|
+
One will be the master-file (this one will not be changed)
|
33
|
+
and
|
34
|
+
One will be the slave-file (this one will be changed)
|
35
|
+
|
36
|
+
#### Script 1: Interactive
|
37
|
+
```bash
|
38
|
+
rake lit:interactive
|
39
|
+
```
|
40
|
+
This script will ask you for the missing value.
|
41
|
+
It will find every difference and will ask you to fill every hole... yeah.
|
42
|
+
After everything is filled out it will merge the data back into your File.
|
43
|
+
|
44
|
+
#### Script 2: Recent
|
45
|
+
```bash
|
46
|
+
rake lit:recent
|
47
|
+
```
|
48
|
+
REQUIRED: Connection to Git
|
49
|
+
This script will ask you for the missing value.
|
50
|
+
It will find everything you changed in your master-file since you last pushed commit.
|
51
|
+
After everything is filled out it will merge the data back into your File.
|
52
|
+
|
53
|
+
#### Script 3: Cleanup (Deletes something!)
|
54
|
+
```bash
|
55
|
+
rake lit:cleanup
|
56
|
+
```
|
57
|
+
This script will find every key/value inside your slave-file that isn´t present in your master-file.
|
58
|
+
And it will be deleted!!!!
|
59
|
+
|
60
|
+
#### Sometimes the Rake tasks aren't working
|
61
|
+
In this case you can use the Rails-Console and the Class -LostInTranslation-.
|
62
|
+
|
63
|
+
```bash
|
64
|
+
rails c
|
65
|
+
```
|
66
|
+
```
|
67
|
+
LostInTranslation.interactive
|
68
|
+
or
|
69
|
+
LostInTranslation.recent
|
70
|
+
or
|
71
|
+
LostInTranslation.cleanup
|
72
|
+
```
|
73
|
+
|
74
|
+
#### Yet to come
|
75
|
+
I am planning on an integration of Translation APIs.
|
76
|
+
|
77
|
+
## Contributing
|
78
|
+
|
79
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/datyv/lost_in_translation. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
80
|
+
|
81
|
+
|
82
|
+
## License
|
83
|
+
|
84
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'ajax_canvas_field/rails/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = 'ajax_canvas_field'
|
9
|
+
spec.version = AjaxCanvasField::Rails::VERSION
|
10
|
+
spec.authors = ['datyv']
|
11
|
+
spec.email = ['yvesgoizet@gmail.com']
|
12
|
+
|
13
|
+
spec.summary = 'HTML5 CanvasField Support'
|
14
|
+
spec.description = 'Add a CanvasField to point out errors in three different colors'
|
15
|
+
spec.homepage = 'https://github.com/Datyv/ajax_canvas_field'
|
16
|
+
spec.license = 'MIT'
|
17
|
+
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
+
if spec.respond_to?(:metadata)
|
21
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
22
|
+
else
|
23
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
24
|
+
end
|
25
|
+
|
26
|
+
spec.files = `git ls-files -z`.split("\x0")
|
27
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
28
|
+
spec.require_paths = %w[app lib]
|
29
|
+
|
30
|
+
spec.add_development_dependency 'bundler', '~> 1.15'
|
31
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
32
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,192 @@
|
|
1
|
+
document.addEventListener('DOMContentLoaded', function(){
|
2
|
+
var canvas = document.getElementById('canvas_field');
|
3
|
+
var data_fields = document.getElementsByClassName('canvas_data_field');
|
4
|
+
if (canvas) {
|
5
|
+
if (data_fields.length == 0) {
|
6
|
+
console.log('No Data Field found. Please add canvas_data_field in your code!');
|
7
|
+
document.getElementsByClassName('canvas_table')[0].style.display = 'none';
|
8
|
+
canvas.style.display = 'none';
|
9
|
+
} else {
|
10
|
+
canvas.width = canvas.dataset.width;
|
11
|
+
canvas.height = canvas.dataset.height;
|
12
|
+
var context = canvas.getContext('2d'),
|
13
|
+
url = canvas.dataset.url,
|
14
|
+
param = canvas.dataset.strongParam,
|
15
|
+
token = canvas.dataset.token,
|
16
|
+
points = [];
|
17
|
+
|
18
|
+
function refreshAll(e) {
|
19
|
+
points = [];
|
20
|
+
initCircles();
|
21
|
+
}
|
22
|
+
|
23
|
+
function initCircles() {
|
24
|
+
var data_field = document.getElementsByClassName('active canvas_data_field')[0].dataset;
|
25
|
+
var initialData = JSON.parse(data_field.initialData);
|
26
|
+
for (i = 0; i < initialData.length; i++) {
|
27
|
+
var point = buildCircle(initialData[i][1], initialData[i][2], initialData[i][3]);
|
28
|
+
point.database_id = initialData[i][0];
|
29
|
+
points.push(point);
|
30
|
+
}
|
31
|
+
redrawAllCircles();
|
32
|
+
}
|
33
|
+
|
34
|
+
function isPixelCollision(e) {
|
35
|
+
e.preventDefault();
|
36
|
+
|
37
|
+
if (e.type == "contextmenu") return;
|
38
|
+
|
39
|
+
var r = canvas.getBoundingClientRect(),
|
40
|
+
x = e.clientX - r.left,
|
41
|
+
y = e.clientY - r.top,
|
42
|
+
removed = false,
|
43
|
+
i;
|
44
|
+
|
45
|
+
for (i = points.length - 1; i >= 0; --i) {
|
46
|
+
if (context.isPointInPath(points[i], x, y, 'nonzero')) {
|
47
|
+
deleteAjax(i);
|
48
|
+
removed = true;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
if (removed == false) {
|
53
|
+
createAjax(x, y, e);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
function buildCircle(x, y, e) {
|
58
|
+
var c = new Path2D(),
|
59
|
+
offset = 3.5;
|
60
|
+
|
61
|
+
c.arc(x - offset, y - offset, 7, 0, Math.PI * 2);
|
62
|
+
c.color = (typeof e === 'string') ? e : chooseColor(e)
|
63
|
+
c.x = x;
|
64
|
+
c.y = y;
|
65
|
+
return c;
|
66
|
+
}
|
67
|
+
|
68
|
+
function chooseColor(e) {
|
69
|
+
if (e === null) return '#ff0000';
|
70
|
+
switch (e.which) {
|
71
|
+
case 1:
|
72
|
+
return canvas.dataset.leftColor;
|
73
|
+
case 2:
|
74
|
+
return canvas.dataset.middleColor;
|
75
|
+
case 3:
|
76
|
+
return canvas.dataset.rightColor;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
function chooseButton(e) {
|
81
|
+
if (e === null) return null;
|
82
|
+
switch (e.which) {
|
83
|
+
case 1:
|
84
|
+
return 'left';
|
85
|
+
case 2:
|
86
|
+
return 'middle';
|
87
|
+
case 3:
|
88
|
+
return 'right';
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
function deleteAjax(i) {
|
93
|
+
var id = points[i].database_id;
|
94
|
+
$.ajax({
|
95
|
+
type: 'DELETE',
|
96
|
+
url: url + '/' + id,
|
97
|
+
headers: {
|
98
|
+
'Authorization': 'Token token=' + token
|
99
|
+
},
|
100
|
+
dataType: "json",
|
101
|
+
success: function(data) {
|
102
|
+
removeCircle(i, data);
|
103
|
+
},
|
104
|
+
error: function(data) {
|
105
|
+
alert('No connection to Server');
|
106
|
+
}
|
107
|
+
});
|
108
|
+
}
|
109
|
+
|
110
|
+
function removeCircle(i, data) {
|
111
|
+
points.splice(i, 1);
|
112
|
+
redrawAllCircles();
|
113
|
+
}
|
114
|
+
|
115
|
+
function createAjax(x, y, e) {
|
116
|
+
post_data = collectPostData(x, y, e);
|
117
|
+
$.ajax({
|
118
|
+
type: 'POST',
|
119
|
+
url: url,
|
120
|
+
headers: {
|
121
|
+
'Authorization': 'Token token=' + token
|
122
|
+
},
|
123
|
+
data: post_data,
|
124
|
+
dataType: "json",
|
125
|
+
success: function(data) {
|
126
|
+
addCircle(x, y, data, e);
|
127
|
+
},
|
128
|
+
error: function(data) {
|
129
|
+
alert('No connection to Server');
|
130
|
+
}
|
131
|
+
});
|
132
|
+
}
|
133
|
+
|
134
|
+
function collectPostData(x, y, e) {
|
135
|
+
var params = {};
|
136
|
+
var data_field = document.getElementsByClassName('active canvas_data_field')[0].dataset;
|
137
|
+
var additionalData = JSON.parse(data_field.additionalData);
|
138
|
+
params[param] = {
|
139
|
+
x_value: x,
|
140
|
+
y_value: y,
|
141
|
+
button: chooseButton(e)
|
142
|
+
};
|
143
|
+
for (var attrname in additionalData) {
|
144
|
+
params[param][attrname] = additionalData[attrname];
|
145
|
+
}
|
146
|
+
return params;
|
147
|
+
}
|
148
|
+
|
149
|
+
function addCircle(x, y, data, e) {
|
150
|
+
new_point = buildCircle(x, y, e);
|
151
|
+
new_point['database_id'] = data.id;
|
152
|
+
points.push(new_point);
|
153
|
+
redrawAllCircles();
|
154
|
+
}
|
155
|
+
|
156
|
+
function redrawAllCircles() {
|
157
|
+
var tmpData = [];
|
158
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
159
|
+
for (i = 0; i < points.length; i++) {
|
160
|
+
context.fillStyle = points[i].color;
|
161
|
+
context.fill(points[i], 'nonzero');
|
162
|
+
context.stroke(points[i], 'nonzero');
|
163
|
+
|
164
|
+
tmpData.push([points[i].database_id, points[i].x, points[i].y, points[i].color]);
|
165
|
+
}
|
166
|
+
document.getElementsByClassName('active canvas_data_field')[0].dataset.initialData = JSON.stringify(tmpData);
|
167
|
+
}
|
168
|
+
|
169
|
+
canvas.addEventListener('click', isPixelCollision, false);
|
170
|
+
canvas.addEventListener('auxclick', isPixelCollision, false);
|
171
|
+
canvas.addEventListener('contextmenu', isPixelCollision, false);
|
172
|
+
initCircles();
|
173
|
+
|
174
|
+
var tableRows = document.getElementsByClassName('request_row');
|
175
|
+
var markRequestRow = function() {
|
176
|
+
for (var i = 0; i < tableRows.length; i++) {
|
177
|
+
tableRows[i].classList.remove('active');
|
178
|
+
}
|
179
|
+
for (var i = 0; i < data_fields.length; i++) {
|
180
|
+
data_fields[i].classList.remove('active');
|
181
|
+
}
|
182
|
+
this.classList.add('active');
|
183
|
+
this.getElementsByClassName('canvas_data_field')[0].classList.add('active');
|
184
|
+
refreshAll();
|
185
|
+
};
|
186
|
+
|
187
|
+
for (var i = 0; i < tableRows.length; i++) {
|
188
|
+
tableRows[i].addEventListener('click', markRequestRow, false);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}, false);
|
@@ -0,0 +1,42 @@
|
|
1
|
+
var canvases = document.getElementsByClassName('canvas_field');
|
2
|
+
if (canvases) {
|
3
|
+
for (o = 0; o < canvases.length; o++) {
|
4
|
+
var canvas = canvases[o];
|
5
|
+
canvas.width = canvas.dataset.width;
|
6
|
+
canvas.height = canvas.dataset.height;
|
7
|
+
var context = canvas.getContext('2d');
|
8
|
+
var points = [];
|
9
|
+
|
10
|
+
function initCircles() {
|
11
|
+
var initialData = JSON.parse(canvas.dataset.initialData);
|
12
|
+
for (i = 0; i < initialData.length; i++) {
|
13
|
+
var point = buildCircle(initialData[i][1], initialData[i][2], initialData[i][3]);
|
14
|
+
point.database_id = initialData[i][0];
|
15
|
+
points.push(point);
|
16
|
+
}
|
17
|
+
redrawAllCircles();
|
18
|
+
}
|
19
|
+
|
20
|
+
function buildCircle(x, y, e) {
|
21
|
+
var c = new Path2D(),
|
22
|
+
offset = 3.5;
|
23
|
+
|
24
|
+
c.arc(x - offset, y - offset, 7, 0, Math.PI * 2);
|
25
|
+
c.color = (typeof e === 'string') ? e : '#ff0000'
|
26
|
+
c.x = x;
|
27
|
+
c.y = y;
|
28
|
+
return c;
|
29
|
+
}
|
30
|
+
|
31
|
+
function redrawAllCircles() {
|
32
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
33
|
+
for (i = 0; i < points.length; i++) {
|
34
|
+
context.fillStyle = points[i].color;
|
35
|
+
context.fill(points[i], 'nonzero');
|
36
|
+
context.stroke(points[i], 'nonzero');
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
initCircles();
|
41
|
+
}
|
42
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#canvas_field {
|
2
|
+
border: 1px groove lightgrey;
|
3
|
+
}
|
4
|
+
|
5
|
+
.canvas_field {
|
6
|
+
border: 1px groove lightgrey;
|
7
|
+
}
|
8
|
+
|
9
|
+
.canvas_data_field {
|
10
|
+
display: none;
|
11
|
+
}
|
12
|
+
|
13
|
+
.canvas_legend_sub {
|
14
|
+
height: 30px;
|
15
|
+
font-weight: 600;
|
16
|
+
padding-top: 9px;
|
17
|
+
text-align: center;
|
18
|
+
}
|
19
|
+
|
20
|
+
tr.active {
|
21
|
+
-webkit-box-shadow: 0px 0px 25px -2px #967474 inset;
|
22
|
+
-moz-box-shadow: 0px 0px 25px -2px #967474 inset;
|
23
|
+
box-shadow: 0px 0px 25px -2px #967474 inset;
|
24
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CanvasFieldHelper
|
4
|
+
def canvas_field(options = {})
|
5
|
+
url = '/'
|
6
|
+
url += options[:namespace].to_s + '/' if options[:namespace]
|
7
|
+
url += options[:controller] || 'canvas_fields'
|
8
|
+
|
9
|
+
background_url = options[:background_url].blank? ? '' : "url(#{options[:background_url]})"
|
10
|
+
background = "background: #fff #{background_url} no-repeat center top"
|
11
|
+
failure_message = 'Your browser does not support the canvas element.'
|
12
|
+
|
13
|
+
content_tag :canvas, failure_message, id: :canvas_field, data: collect_data(url, options), style: background
|
14
|
+
end
|
15
|
+
|
16
|
+
def canvas_data_field(active = false, options = {})
|
17
|
+
klass = active ? 'active' : ''
|
18
|
+
data = { additional_data: options[:additional_data].to_json,
|
19
|
+
initial_data: options[:initial_data].to_json,
|
20
|
+
content: options[:content] || '' }
|
21
|
+
content_tag(:span, '', class: "#{klass} canvas_data_field", data: data)
|
22
|
+
end
|
23
|
+
|
24
|
+
def canvas_legend_field(options = {})
|
25
|
+
locals = {
|
26
|
+
left_text: options[:left_text] || '',
|
27
|
+
middle_text: options[:middle_text] || '',
|
28
|
+
right_text: options[:right_text] || '',
|
29
|
+
left_color: options[:left_color] || '#ff0000',
|
30
|
+
middle_color: options[:middle_color] || '#00ff00',
|
31
|
+
right_color: options[:right_color] || '#0000ff',
|
32
|
+
no_icon: options[:no_icon] || false,
|
33
|
+
no_header: options[:no_header] || false
|
34
|
+
}
|
35
|
+
render partial: 'ajax_canvas_field/canvas_legend', locals: locals
|
36
|
+
end
|
37
|
+
|
38
|
+
def ro_canvas_field(options = {})
|
39
|
+
background_url = options[:background_url].blank? ? '' : "url(#{options[:background_url]})"
|
40
|
+
background = "background: #fff #{background_url} no-repeat center top"
|
41
|
+
failure_message = 'Your browser does not support the canvas element.'
|
42
|
+
|
43
|
+
content_tag :canvas, failure_message, data: collect_ro_data(options), style: background, class: 'canvas_field'
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def collect_data(url, options)
|
49
|
+
{ url: url,
|
50
|
+
strong_param: options[:param] || options[:controller]&.singularize || 'canvas_field',
|
51
|
+
token: options[:token],
|
52
|
+
width: options[:width] || AjaxCanvasField.config[:default_width],
|
53
|
+
height: options[:height] || AjaxCanvasField.config[:default_height],
|
54
|
+
left_color: options[:left_color] || '#ff0000',
|
55
|
+
middle_color: options[:middle_color] || '#00ff00',
|
56
|
+
right_color: options[:right_color] || '#0000ff' }
|
57
|
+
end
|
58
|
+
|
59
|
+
def collect_ro_data(options)
|
60
|
+
{ width: options[:width] || AjaxCanvasField.config[:default_width],
|
61
|
+
height: options[:height] || AjaxCanvasField.config[:default_height],
|
62
|
+
left_color: options[:left_color] || '#ff0000',
|
63
|
+
middle_color: options[:middle_color] || '#00ff00',
|
64
|
+
right_color: options[:right_color] || '#0000ff',
|
65
|
+
initial_data: options[:initial_data].to_json }
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
%table
|
2
|
+
- unless no_header
|
3
|
+
%thead
|
4
|
+
%tr
|
5
|
+
%th.canvas_legend_sub Linke Maustaste
|
6
|
+
%th.canvas_legend_sub Mittlere Maustaste
|
7
|
+
%th.canvas_legend_sub Rechte Maustaste
|
8
|
+
%tbody
|
9
|
+
- unless no_icon
|
10
|
+
%tr
|
11
|
+
%td.canvas_legend_sub= image_tag('mouse_left.png', size: '50x50')
|
12
|
+
%td.canvas_legend_sub= image_tag('mouse_middle.png', size: '50x50')
|
13
|
+
%td.canvas_legend_sub= image_tag('mouse_right.png', size: '50x50')
|
14
|
+
%tr
|
15
|
+
%td.canvas_legend_sub= left_text
|
16
|
+
%td.canvas_legend_sub= middle_text
|
17
|
+
%td.canvas_legend_sub= right_text
|
18
|
+
%tr
|
19
|
+
%td.canvas_legend_sub{ style: "background-color: #{left_color}" }
|
20
|
+
%td.canvas_legend_sub{ style: "background-color: #{middle_color}" }
|
21
|
+
%td.canvas_legend_sub{ style: "background-color: #{right_color}" }
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,192 @@
|
|
1
|
+
document.addEventListener('DOMContentLoaded', function(){
|
2
|
+
var canvas = document.getElementById('canvas_field');
|
3
|
+
var data_fields = document.getElementsByClassName('canvas_data_field');
|
4
|
+
if (canvas) {
|
5
|
+
if (data_fields.length == 0) {
|
6
|
+
console.log('No Data Field found. Please add canvas_data_field in your code!');
|
7
|
+
document.getElementsByClassName('canvas_table')[0].style.display = 'none';
|
8
|
+
canvas.style.display = 'none';
|
9
|
+
} else {
|
10
|
+
canvas.width = canvas.dataset.width;
|
11
|
+
canvas.height = canvas.dataset.height;
|
12
|
+
var context = canvas.getContext('2d'),
|
13
|
+
url = canvas.dataset.url,
|
14
|
+
param = canvas.dataset.strongParam,
|
15
|
+
token = canvas.dataset.token,
|
16
|
+
points = [];
|
17
|
+
|
18
|
+
function refreshAll(e) {
|
19
|
+
points = [];
|
20
|
+
initCircles();
|
21
|
+
}
|
22
|
+
|
23
|
+
function initCircles() {
|
24
|
+
var data_field = document.getElementsByClassName('active canvas_data_field')[0].dataset;
|
25
|
+
var initialData = JSON.parse(data_field.initialData);
|
26
|
+
for (i = 0; i < initialData.length; i++) {
|
27
|
+
var point = buildCircle(initialData[i][1], initialData[i][2], initialData[i][3]);
|
28
|
+
point.database_id = initialData[i][0];
|
29
|
+
points.push(point);
|
30
|
+
}
|
31
|
+
redrawAllCircles();
|
32
|
+
}
|
33
|
+
|
34
|
+
function isPixelCollision(e) {
|
35
|
+
e.preventDefault();
|
36
|
+
|
37
|
+
if (e.type == "contextmenu") return;
|
38
|
+
|
39
|
+
var r = canvas.getBoundingClientRect(),
|
40
|
+
x = e.clientX - r.left,
|
41
|
+
y = e.clientY - r.top,
|
42
|
+
removed = false,
|
43
|
+
i;
|
44
|
+
|
45
|
+
for (i = points.length - 1; i >= 0; --i) {
|
46
|
+
if (context.isPointInPath(points[i], x, y, 'nonzero')) {
|
47
|
+
deleteAjax(i);
|
48
|
+
removed = true;
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
if (removed == false) {
|
53
|
+
createAjax(x, y, e);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
|
57
|
+
function buildCircle(x, y, e) {
|
58
|
+
var c = new Path2D(),
|
59
|
+
offset = 3.5;
|
60
|
+
|
61
|
+
c.arc(x - offset, y - offset, 7, 0, Math.PI * 2);
|
62
|
+
c.color = (typeof e === 'string') ? e : chooseColor(e)
|
63
|
+
c.x = x;
|
64
|
+
c.y = y;
|
65
|
+
return c;
|
66
|
+
}
|
67
|
+
|
68
|
+
function chooseColor(e) {
|
69
|
+
if (e === null) return '#ff0000';
|
70
|
+
switch (e.which) {
|
71
|
+
case 1:
|
72
|
+
return canvas.dataset.leftColor;
|
73
|
+
case 2:
|
74
|
+
return canvas.dataset.middleColor;
|
75
|
+
case 3:
|
76
|
+
return canvas.dataset.rightColor;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
function chooseButton(e) {
|
81
|
+
if (e === null) return null;
|
82
|
+
switch (e.which) {
|
83
|
+
case 1:
|
84
|
+
return 'left';
|
85
|
+
case 2:
|
86
|
+
return 'middle';
|
87
|
+
case 3:
|
88
|
+
return 'right';
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
function deleteAjax(i) {
|
93
|
+
var id = points[i].database_id;
|
94
|
+
$.ajax({
|
95
|
+
type: 'DELETE',
|
96
|
+
url: url + '/' + id,
|
97
|
+
headers: {
|
98
|
+
'Authorization': 'Token token=' + token
|
99
|
+
},
|
100
|
+
dataType: "json",
|
101
|
+
success: function(data) {
|
102
|
+
removeCircle(i, data);
|
103
|
+
},
|
104
|
+
error: function(data) {
|
105
|
+
alert('No connection to Server');
|
106
|
+
}
|
107
|
+
});
|
108
|
+
}
|
109
|
+
|
110
|
+
function removeCircle(i, data) {
|
111
|
+
points.splice(i, 1);
|
112
|
+
redrawAllCircles();
|
113
|
+
}
|
114
|
+
|
115
|
+
function createAjax(x, y, e) {
|
116
|
+
post_data = collectPostData(x, y, e);
|
117
|
+
$.ajax({
|
118
|
+
type: 'POST',
|
119
|
+
url: url,
|
120
|
+
headers: {
|
121
|
+
'Authorization': 'Token token=' + token
|
122
|
+
},
|
123
|
+
data: post_data,
|
124
|
+
dataType: "json",
|
125
|
+
success: function(data) {
|
126
|
+
addCircle(x, y, data, e);
|
127
|
+
},
|
128
|
+
error: function(data) {
|
129
|
+
alert('No connection to Server');
|
130
|
+
}
|
131
|
+
});
|
132
|
+
}
|
133
|
+
|
134
|
+
function collectPostData(x, y, e) {
|
135
|
+
var params = {};
|
136
|
+
var data_field = document.getElementsByClassName('active canvas_data_field')[0].dataset;
|
137
|
+
var additionalData = JSON.parse(data_field.additionalData);
|
138
|
+
params[param] = {
|
139
|
+
x_value: x,
|
140
|
+
y_value: y,
|
141
|
+
button: chooseButton(e)
|
142
|
+
};
|
143
|
+
for (var attrname in additionalData) {
|
144
|
+
params[param][attrname] = additionalData[attrname];
|
145
|
+
}
|
146
|
+
return params;
|
147
|
+
}
|
148
|
+
|
149
|
+
function addCircle(x, y, data, e) {
|
150
|
+
new_point = buildCircle(x, y, e);
|
151
|
+
new_point['database_id'] = data.id;
|
152
|
+
points.push(new_point);
|
153
|
+
redrawAllCircles();
|
154
|
+
}
|
155
|
+
|
156
|
+
function redrawAllCircles() {
|
157
|
+
var tmpData = [];
|
158
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
159
|
+
for (i = 0; i < points.length; i++) {
|
160
|
+
context.fillStyle = points[i].color;
|
161
|
+
context.fill(points[i], 'nonzero');
|
162
|
+
context.stroke(points[i], 'nonzero');
|
163
|
+
|
164
|
+
tmpData.push([points[i].database_id, points[i].x, points[i].y, points[i].color]);
|
165
|
+
}
|
166
|
+
document.getElementsByClassName('active canvas_data_field')[0].dataset.initialData = JSON.stringify(tmpData);
|
167
|
+
}
|
168
|
+
|
169
|
+
canvas.addEventListener('click', isPixelCollision, false);
|
170
|
+
canvas.addEventListener('auxclick', isPixelCollision, false);
|
171
|
+
canvas.addEventListener('contextmenu', isPixelCollision, false);
|
172
|
+
initCircles();
|
173
|
+
|
174
|
+
var tableRows = document.getElementsByClassName('request_row');
|
175
|
+
var markRequestRow = function() {
|
176
|
+
for (var i = 0; i < tableRows.length; i++) {
|
177
|
+
tableRows[i].classList.remove('active');
|
178
|
+
}
|
179
|
+
for (var i = 0; i < data_fields.length; i++) {
|
180
|
+
data_fields[i].classList.remove('active');
|
181
|
+
}
|
182
|
+
this.classList.add('active');
|
183
|
+
this.getElementsByClassName('canvas_data_field')[0].classList.add('active');
|
184
|
+
refreshAll();
|
185
|
+
};
|
186
|
+
|
187
|
+
for (var i = 0; i < tableRows.length; i++) {
|
188
|
+
tableRows[i].addEventListener('click', markRequestRow, false);
|
189
|
+
}
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}, false);
|
@@ -0,0 +1,42 @@
|
|
1
|
+
var canvases = document.getElementsByClassName('canvas_field');
|
2
|
+
if (canvases) {
|
3
|
+
for (o = 0; o < canvases.length; o++) {
|
4
|
+
var canvas = canvases[o];
|
5
|
+
canvas.width = canvas.dataset.width;
|
6
|
+
canvas.height = canvas.dataset.height;
|
7
|
+
var context = canvas.getContext('2d');
|
8
|
+
var points = [];
|
9
|
+
|
10
|
+
function initCircles() {
|
11
|
+
var initialData = JSON.parse(canvas.dataset.initialData);
|
12
|
+
for (i = 0; i < initialData.length; i++) {
|
13
|
+
var point = buildCircle(initialData[i][1], initialData[i][2], initialData[i][3]);
|
14
|
+
point.database_id = initialData[i][0];
|
15
|
+
points.push(point);
|
16
|
+
}
|
17
|
+
redrawAllCircles();
|
18
|
+
}
|
19
|
+
|
20
|
+
function buildCircle(x, y, e) {
|
21
|
+
var c = new Path2D(),
|
22
|
+
offset = 3.5;
|
23
|
+
|
24
|
+
c.arc(x - offset, y - offset, 7, 0, Math.PI * 2);
|
25
|
+
c.color = (typeof e === 'string') ? e : '#ff0000'
|
26
|
+
c.x = x;
|
27
|
+
c.y = y;
|
28
|
+
return c;
|
29
|
+
}
|
30
|
+
|
31
|
+
function redrawAllCircles() {
|
32
|
+
context.clearRect(0, 0, canvas.width, canvas.height);
|
33
|
+
for (i = 0; i < points.length; i++) {
|
34
|
+
context.fillStyle = points[i].color;
|
35
|
+
context.fill(points[i], 'nonzero');
|
36
|
+
context.stroke(points[i], 'nonzero');
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
initCircles();
|
41
|
+
}
|
42
|
+
}
|
@@ -0,0 +1,24 @@
|
|
1
|
+
#canvas_field {
|
2
|
+
border: 1px groove lightgrey;
|
3
|
+
}
|
4
|
+
|
5
|
+
.canvas_field {
|
6
|
+
border: 1px groove lightgrey;
|
7
|
+
}
|
8
|
+
|
9
|
+
.canvas_data_field {
|
10
|
+
display: none;
|
11
|
+
}
|
12
|
+
|
13
|
+
.canvas_legend_sub {
|
14
|
+
height: 30px;
|
15
|
+
font-weight: 600;
|
16
|
+
padding-top: 9px;
|
17
|
+
text-align: center;
|
18
|
+
}
|
19
|
+
|
20
|
+
tr.active {
|
21
|
+
-webkit-box-shadow: 0px 0px 25px -2px #967474 inset;
|
22
|
+
-moz-box-shadow: 0px 0px 25px -2px #967474 inset;
|
23
|
+
box-shadow: 0px 0px 25px -2px #967474 inset;
|
24
|
+
}
|
@@ -0,0 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CanvasFieldHelper
|
4
|
+
def canvas_field(options = {})
|
5
|
+
url = '/'
|
6
|
+
url += options[:namespace].to_s + '/' if options[:namespace]
|
7
|
+
url += options[:controller] || 'canvas_fields'
|
8
|
+
|
9
|
+
background_url = options[:background_url].blank? ? '' : "url(#{options[:background_url]})"
|
10
|
+
background = "background: #fff #{background_url} no-repeat center top"
|
11
|
+
failure_message = 'Your browser does not support the canvas element.'
|
12
|
+
|
13
|
+
content_tag :canvas, failure_message, id: :canvas_field, data: collect_data(url, options), style: background
|
14
|
+
end
|
15
|
+
|
16
|
+
def canvas_data_field(active = false, options = {})
|
17
|
+
klass = active ? 'active' : ''
|
18
|
+
data = { additional_data: options[:additional_data].to_json,
|
19
|
+
initial_data: options[:initial_data].to_json,
|
20
|
+
content: options[:content] || '' }
|
21
|
+
content_tag(:span, '', class: "#{klass} canvas_data_field", data: data)
|
22
|
+
end
|
23
|
+
|
24
|
+
def canvas_legend_field(options = {})
|
25
|
+
locals = {
|
26
|
+
left_text: options[:left_text] || '',
|
27
|
+
middle_text: options[:middle_text] || '',
|
28
|
+
right_text: options[:right_text] || '',
|
29
|
+
left_color: options[:left_color] || '#ff0000',
|
30
|
+
middle_color: options[:middle_color] || '#00ff00',
|
31
|
+
right_color: options[:right_color] || '#0000ff',
|
32
|
+
no_icon: options[:no_icon] || false,
|
33
|
+
no_header: options[:no_header] || false
|
34
|
+
}
|
35
|
+
render partial: 'ajax_canvas_field/canvas_legend', locals: locals
|
36
|
+
end
|
37
|
+
|
38
|
+
def ro_canvas_field(options = {})
|
39
|
+
background_url = options[:background_url].blank? ? '' : "url(#{options[:background_url]})"
|
40
|
+
background = "background: #fff #{background_url} no-repeat center top"
|
41
|
+
failure_message = 'Your browser does not support the canvas element.'
|
42
|
+
|
43
|
+
content_tag :canvas, failure_message, data: collect_ro_data(options), style: background, class: 'canvas_field'
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def collect_data(url, options)
|
49
|
+
{ url: url,
|
50
|
+
strong_param: options[:param] || options[:controller]&.singularize || 'canvas_field',
|
51
|
+
token: options[:token],
|
52
|
+
width: options[:width] || AjaxCanvasField.config[:default_width],
|
53
|
+
height: options[:height] || AjaxCanvasField.config[:default_height],
|
54
|
+
left_color: options[:left_color] || '#ff0000',
|
55
|
+
middle_color: options[:middle_color] || '#00ff00',
|
56
|
+
right_color: options[:right_color] || '#0000ff' }
|
57
|
+
end
|
58
|
+
|
59
|
+
def collect_ro_data(options)
|
60
|
+
{ width: options[:width] || AjaxCanvasField.config[:default_width],
|
61
|
+
height: options[:height] || AjaxCanvasField.config[:default_height],
|
62
|
+
left_color: options[:left_color] || '#ff0000',
|
63
|
+
middle_color: options[:middle_color] || '#00ff00',
|
64
|
+
right_color: options[:right_color] || '#0000ff',
|
65
|
+
initial_data: options[:initial_data].to_json }
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
module AjaxCanvasField
|
6
|
+
# Configuration defaults
|
7
|
+
@config = {
|
8
|
+
default_height: 470,
|
9
|
+
default_width: 470,
|
10
|
+
default_left_color: '#ff0000',
|
11
|
+
default_middle_color: '#00ff00',
|
12
|
+
default_right_color: '#0000ff'
|
13
|
+
}
|
14
|
+
|
15
|
+
@valid_config_keys = @config.keys
|
16
|
+
|
17
|
+
# Configure through hash
|
18
|
+
def self.configure(opts = {})
|
19
|
+
opts.each { |k, v| @config[k.to_sym] = v if @valid_config_keys.include? k.to_sym }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Configure through yaml file
|
23
|
+
def self.configure_with(path_to_yaml_file)
|
24
|
+
begin
|
25
|
+
config = YAML.safe_load(IO.read(path_to_yaml_file))
|
26
|
+
rescue Errno::ENOENT
|
27
|
+
log(:warning, "YAML configuration file couldn't be found. Using defaults."); return
|
28
|
+
rescue Psych::SyntaxError
|
29
|
+
log(:warning, 'YAML configuration file contains invalid syntax. Using defaults.'); return
|
30
|
+
end
|
31
|
+
|
32
|
+
configure(config)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.config
|
36
|
+
@config
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module AjaxCanvasField #:nodoc:
|
2
|
+
module Rails #:nodoc:
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
initializer 'ajax_canvas_field.assets.precompile' do |app|
|
5
|
+
%w(stylesheets javascripts images).each do |sub|
|
6
|
+
app.config.assets.paths << root.join('app/assets', sub).to_s
|
7
|
+
end
|
8
|
+
app.config.assets.precompile += %w( mouse_left.png mouse_right.png mouse_middle.png )
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
class AjaxCanvasFieldGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../templates", __FILE__)
|
5
|
+
|
6
|
+
desc "Copy the initializer for AjaxCanvasField"
|
7
|
+
def copy_initializer_file
|
8
|
+
copy_file "initializer.rb", "config/initializers/ajax_canvas_field.rb"
|
9
|
+
|
10
|
+
inject_into_file 'app/assets/javascripts/application.js', "//= require ajax_canvas_field\n", before: "//= require_tree ." rescue nil
|
11
|
+
inject_into_file 'app/assets/stylesheets/application.scss', " *= require ajax_canvas_field\n", before: " *= require_tree ." rescue nil
|
12
|
+
inject_into_file 'app/assets/stylesheets/application.scss.erb', " *= require ajax_canvas_field\n", before: " *= require_tree ." rescue nil
|
13
|
+
inject_into_file 'app/assets/stylesheets/application.css.scss', " *= require ajax_canvas_field\n", before: " *= require_tree ." rescue nil
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
%table
|
2
|
+
- unless no_header
|
3
|
+
%thead
|
4
|
+
%tr
|
5
|
+
%th.canvas_legend_sub Linke Maustaste
|
6
|
+
%th.canvas_legend_sub Mittlere Maustaste
|
7
|
+
%th.canvas_legend_sub Rechte Maustaste
|
8
|
+
%tbody
|
9
|
+
- unless no_icon
|
10
|
+
%tr
|
11
|
+
%td.canvas_legend_sub= image_tag('mouse_left.png', size: '50x50')
|
12
|
+
%td.canvas_legend_sub= image_tag('mouse_middle.png', size: '50x50')
|
13
|
+
%td.canvas_legend_sub= image_tag('mouse_right.png', size: '50x50')
|
14
|
+
%tr
|
15
|
+
%td.canvas_legend_sub= left_text
|
16
|
+
%td.canvas_legend_sub= middle_text
|
17
|
+
%td.canvas_legend_sub= right_text
|
18
|
+
%tr
|
19
|
+
%td.canvas_legend_sub{ style: "background-color: #{left_color}" }
|
20
|
+
%td.canvas_legend_sub{ style: "background-color: #{middle_color}" }
|
21
|
+
%td.canvas_legend_sub{ style: "background-color: #{right_color}" }
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ajax_canvas_field
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- datyv
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-10-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.15'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.15'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Add a CanvasField to point out errors in three different colors
|
42
|
+
email:
|
43
|
+
- yvesgoizet@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- Gemfile
|
49
|
+
- README.md
|
50
|
+
- Rakefile
|
51
|
+
- ajax_canvas_field.gemspec
|
52
|
+
- app/assets/images/mouse_left.png
|
53
|
+
- app/assets/images/mouse_middle.png
|
54
|
+
- app/assets/images/mouse_right.png
|
55
|
+
- app/assets/javascripts/ajax_canvas_field.js
|
56
|
+
- app/assets/javascripts/ro_canvas_field.js
|
57
|
+
- app/assets/stylesheets/ajax_canvas_field.css
|
58
|
+
- app/helpers/canvas_field_helper.rb
|
59
|
+
- app/views/ajax_canvas_field/_canvas_legend.html.haml
|
60
|
+
- assets/images/mouse_left.png
|
61
|
+
- assets/images/mouse_middle.png
|
62
|
+
- assets/images/mouse_right.png
|
63
|
+
- assets/javascripts/ajax_canvas_field.js
|
64
|
+
- assets/javascripts/ro_canvas_field.js
|
65
|
+
- assets/stylesheets/ajax_canvas_field.css
|
66
|
+
- helpers/canvas_field_helper.rb
|
67
|
+
- lib/ajax_canvas_field.rb
|
68
|
+
- lib/ajax_canvas_field/config.rb
|
69
|
+
- lib/ajax_canvas_field/rails.rb
|
70
|
+
- lib/ajax_canvas_field/rails/engine.rb
|
71
|
+
- lib/ajax_canvas_field/rails/version.rb
|
72
|
+
- lib/generators/ajax_canvas_field/ajax_canvas_field_generator.rb
|
73
|
+
- lib/generators/ajax_canvas_field/templates/initializer.rb
|
74
|
+
- views/ajax_canvas_field/_canvas_legend.html.haml
|
75
|
+
homepage: https://github.com/Datyv/ajax_canvas_field
|
76
|
+
licenses:
|
77
|
+
- MIT
|
78
|
+
metadata:
|
79
|
+
allowed_push_host: https://rubygems.org
|
80
|
+
post_install_message:
|
81
|
+
rdoc_options: []
|
82
|
+
require_paths:
|
83
|
+
- app
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.5.2
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: HTML5 CanvasField Support
|
101
|
+
test_files: []
|