active_scaffold_camera 0.1.0 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56d1640c691ca62f6ab79aafee4744747a13df0a0e38fe7b438a38307a231d9b
4
- data.tar.gz: 1541dfdac0a71ac903ddb1bffa802c4d18ee32bb457c72ba8318c02cd6f7390e
3
+ metadata.gz: 6d2dd4e1f852c81a0a90e6b77b0db2fdf259a974843c907e059283bcc0b251be
4
+ data.tar.gz: 01eeb04a95ba9e38326e0038e203019b521342f8b5a1b3803d12f00995e511d6
5
5
  SHA512:
6
- metadata.gz: 543e5399bea1be0b8f5da896077ecc5d2571fbeff60179ab949b7070bbc3fb2dca943255305b1d9528d8047a5dc00094f9a44119be48df8e22ddd0e527bd94f1
7
- data.tar.gz: b60afb1a520108e836fcb17dba4dc9fb47f7f4a1d8509cff886444a148701e9ac58427ca8467b927acbde58de315cbd6a2ab69e76e5a44030b01b03fd4143e9a
6
+ metadata.gz: 320c8a9a6e429e0155a31823db685ef430e4eabe806641ba2f856ed942a06e253cfdd1614a09c2cd0d58b1ba6c413902eb0989123bd8799edf988b31514a6761
7
+ data.tar.gz: 9ad5a523b0f1b902f5d33f35a15e5c5a9cfbb2e18ca9313f5a2ae3d04d655f325f65e471acbd41d585ea1b179a61a7ea8c6da2eb6ecb3fd3541a37e2abe17e29
@@ -1,39 +1,48 @@
1
- h1. Camera for ActiveScaffold
1
+ # Camera for ActiveScaffold
2
2
 
3
3
  Currently, this plugin is compatible with ActiveScaffold >= 3.4 gem.
4
4
 
5
- h2. Overview
5
+ ## Overview
6
6
 
7
- This plugin adds a camera viewer to take a snapshot from camera on ActiveScaffold forms. It uses "SayCheese.js":https://github.com/leemachin/say-cheese
7
+ This plugin adds a camera viewer to take a snapshot from camera on ActiveScaffold forms. It uses [SayCheese.js](https://github.com/leemachin/say-cheese)
8
8
 
9
- h2. Installation
9
+ ### Browser compatibility
10
+
11
+ The plugin uses the modern `navigator.mediaDevices` API when available, including
12
+ [`enumerateDevices()`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices)
13
+ and `deviceId` constraints. The legacy callback-based API, `MediaStreamTrack.getSources`,
14
+ and `sourceId` constraints remain available as a fallback for older browsers.
15
+
16
+ Camera access requires a secure context (HTTPS or localhost) and the user's permission.
17
+
18
+ ## Installation
10
19
 
11
20
  You'll need at least ActiveScaffold 3.4 to use this
12
21
 
13
- <pre>
22
+ ```
14
23
  gem install active_scaffold_camera
15
- </pre>
24
+ ```
16
25
 
17
- h2. Usage
26
+ ## Usage
18
27
 
19
- h4. Step 1
28
+ #### Step 1
20
29
 
21
30
  Set column to use :snapshot form_ui
22
31
 
23
- h4. Step 2
32
+ #### Step 2
24
33
 
25
34
  Setup snapshot using options method on column
26
35
 
27
- <pre>
36
+ ```ruby
28
37
  # app/controllers/visitors_controller.rb
29
38
 
30
39
  class VisitorsController < ApplicationController
31
40
  active_scaffold :visitor do |config|
32
- config.columns[:signature].form_ui = :signaturepad
33
- config.columns[:signature].options = {:source => -1}
41
+ config.columns[:id_card].form_ui = :snapshot
42
+ config.columns[:id_card].options = {:source => -1}
34
43
  end
35
44
  end
36
- </pre>
45
+ ```
37
46
 
38
47
  Available options: video_not_supported, audio_not_supported, media_forbidden, source
39
48
 
@@ -41,20 +50,20 @@ Source can be set to use a specific source instead of displaying source selector
41
50
 
42
51
  If video_not_supported, audio_not_supported or media_forbidden are symbols they will be translated (using as_ method, so it must be on active_scaffold namespace). They have a default translation.
43
52
 
44
- h4. Save image
53
+ #### Save image
45
54
 
46
55
  Snapshot form_ui sends a data url, encoded on base64, of the image, so it should be saved on column of blob type.
47
56
 
48
- h2. Support
57
+ ## Support
49
58
 
50
- If you have issues installing the plugin, search / post to the "Active Scaffold":http://groups.google.com/group/activescaffold forum or "Create an issue":http://github.com/activescaffold/active_scaffold_camera/issues
59
+ If you have issues installing the plugin, search / post to the [Active Scaffold](http://groups.google.com/group/activescaffold) forum or [Create an issue](http://github.com/activescaffold/active_scaffold_camera/issues)
51
60
 
52
- h2. Contributing
61
+ ## Contributing
53
62
 
54
63
  Fork, hack, push, and request a pull:
55
64
 
56
65
  http://github.com/activescaffold/active_scaffold_camera/
57
66
 
58
- h2. License
67
+ ## License
59
68
 
60
69
  Released under the MIT license (included).
@@ -2,12 +2,40 @@
2
2
  //= require_self
3
3
 
4
4
  ActiveScaffold.snapshot = function(selector_or_elements, parent) {
5
+ function modernMediaApi() {
6
+ return navigator.mediaDevices && navigator.mediaDevices.getUserMedia;
7
+ }
8
+
5
9
  function videoConstraint(video) {
6
- return typeof(video) == 'string' ? {optional: [{sourceId: video}]} : video;
10
+ if (typeof(video) != 'string') return video;
11
+ return modernMediaApi() ? {deviceId: {exact: video}} : {optional: [{sourceId: video}]};
7
12
  }
8
13
 
9
14
  function audioConstraint(audio) {
10
- return typeof(audio) == 'string' ? {optional: [{sourceId: audio}]} : audio;
15
+ if (typeof(audio) != 'string') return audio;
16
+ return modernMediaApi() ? {deviceId: {exact: audio}} : {optional: [{sourceId: audio}]};
17
+ }
18
+
19
+ function enumerateVideoSources(callback) {
20
+ if (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) {
21
+ navigator.mediaDevices.enumerateDevices().then(function(devices) {
22
+ callback(devices.filter(function(device) {
23
+ return device.kind == 'videoinput';
24
+ }).map(function(device) {
25
+ return {id: device.deviceId, label: device.label};
26
+ }));
27
+ }).catch(function() {
28
+ callback([]);
29
+ });
30
+ } else if (window.MediaStreamTrack && MediaStreamTrack.getSources) {
31
+ MediaStreamTrack.getSources(function(sourceInfos) {
32
+ callback(sourceInfos.filter(function(source) {
33
+ return source.kind == 'video';
34
+ }));
35
+ });
36
+ } else {
37
+ callback([]);
38
+ }
11
39
  }
12
40
 
13
41
  function startVideo(element, video, audio, video_select) {
@@ -59,22 +87,15 @@ ActiveScaffold.snapshot = function(selector_or_elements, parent) {
59
87
 
60
88
  elements.each(function() {
61
89
  var $element = $(this), selector = '#' + $element.attr('id');
62
- MediaStreamTrack.getSources(function(sourceInfos) {
63
- var sources = [];
64
- for(i in sourceInfos) {
65
- var source = sourceInfos[i];
66
- if (source.kind == 'video') {
67
- sources.push(source);
68
- }
69
- }
90
+ enumerateVideoSources(function(sources) {
70
91
  var video, source, select, index = $element.data('source');
71
92
  if (index != null) {
72
93
  if (index < 0) source = sources[sources.length + index];
73
94
  else source = sources[index];
74
95
  if (source) video = source.id;
75
96
  } else if (sources.length > 1) {
76
- var select = $('<select>');
77
- for (i in sources) {
97
+ select = $('<select>');
98
+ for (var i in sources) {
78
99
  source = sources[i];
79
100
  select.append($('<option>').val(source.id).html(source.label || 'camera ' + (i + 1)));
80
101
  }
@@ -16,7 +16,7 @@ var SayCheese = (function() {
16
16
 
17
17
  var SayCheese;
18
18
 
19
- navigator.getUserMedia = (navigator.getUserMedia ||
19
+ var legacyGetUserMedia = (navigator.getUserMedia ||
20
20
  navigator.webkitGetUserMedia ||
21
21
  navigator.mozGetUserMedia ||
22
22
  navigator.msGetUserMedia ||
@@ -89,6 +89,8 @@ var SayCheese = (function() {
89
89
  streaming = false;
90
90
 
91
91
  this.video = document.createElement('video');
92
+ this.video.autoplay = true;
93
+ this.video.playsInline = true;
92
94
 
93
95
  this.video.addEventListener('canplay', function() {
94
96
  if (!streaming) {
@@ -137,7 +139,7 @@ var SayCheese = (function() {
137
139
  SayCheese.prototype.start = function start() {
138
140
 
139
141
  // fail fast and softly if browser not supported
140
- if (navigator.getUserMedia === false) {
142
+ if ((!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) && legacyGetUserMedia === false) {
141
143
  this.trigger('error', 'NOT_SUPPORTED');
142
144
  return false;
143
145
  }
@@ -146,7 +148,9 @@ var SayCheese = (function() {
146
148
  this.stream = stream;
147
149
  this.createVideo();
148
150
 
149
- if (navigator.mozGetUserMedia) {
151
+ if ('srcObject' in this.video) {
152
+ this.video.srcObject = stream;
153
+ } else if (navigator.mozGetUserMedia) {
150
154
  this.video.mozSrcObject = stream;
151
155
  } else {
152
156
  this.video.src = this.getStreamUrl();
@@ -169,16 +173,36 @@ var SayCheese = (function() {
169
173
  this.trigger('error', error);
170
174
  }.bind(this);
171
175
 
172
- return navigator.getUserMedia({ video: this.options.video, audio: this.options.audio }, success, error);
176
+ var constraints = { video: this.options.video, audio: this.options.audio };
177
+
178
+ if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
179
+ return navigator.mediaDevices.getUserMedia(constraints).then(success).catch(error);
180
+ }
181
+
182
+ return legacyGetUserMedia.call(navigator, constraints, success, error);
173
183
  };
174
184
 
175
185
  SayCheese.prototype.stop = function stop() {
176
- this.stream.stop();
186
+ if (!this.stream) {
187
+ return false;
188
+ }
189
+
190
+ if (this.stream.getTracks) {
191
+ this.stream.getTracks().forEach(function(track) {
192
+ track.stop();
193
+ });
194
+ } else if (this.stream.stop) {
195
+ this.stream.stop();
196
+ }
177
197
 
178
- if (window.URL && window.URL.revokeObjectURL) {
198
+ if (this.video && 'srcObject' in this.video) {
199
+ this.video.srcObject = null;
200
+ } else if (this.video && window.URL && window.URL.revokeObjectURL && this.video.src) {
179
201
  window.URL.revokeObjectURL(this.video.src);
180
202
  }
181
203
 
204
+ this.stream = null;
205
+
182
206
  return this.trigger('stop');
183
207
  };
184
208
 
@@ -1,7 +1,7 @@
1
1
  module ActiveScaffoldCamera
2
2
  module Version
3
3
  MAJOR = 0
4
- MINOR = 1
4
+ MINOR = 2
5
5
  PATCH = 0
6
6
 
7
7
  STRING = [MAJOR, MINOR, PATCH].compact.join('.')
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_scaffold_camera
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergio Cambra
8
8
  - Volker Hochstein
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2024-04-05 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
@@ -46,10 +45,10 @@ executables: []
46
45
  extensions: []
47
46
  extra_rdoc_files:
48
47
  - LICENSE
49
- - README.textile
48
+ - README.md
50
49
  files:
51
50
  - LICENSE
52
- - README.textile
51
+ - README.md
53
52
  - app/assets/javascripts/active_scaffold_camera.js
54
53
  - app/assets/javascripts/say-cheese.js
55
54
  - app/assets/stylesheets/active_scaffold_camera.scss
@@ -63,7 +62,6 @@ homepage: http://github.com/activescaffold/active_scaffold_camera
63
62
  licenses:
64
63
  - MIT
65
64
  metadata: {}
66
- post_install_message:
67
65
  rdoc_options: []
68
66
  require_paths:
69
67
  - lib
@@ -78,8 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
78
76
  - !ruby/object:Gem::Version
79
77
  version: '0'
80
78
  requirements: []
81
- rubygems_version: 3.2.3
82
- signing_key:
79
+ rubygems_version: 3.6.9
83
80
  specification_version: 4
84
81
  summary: Snapshot form_ui using saycheese.js
85
82
  test_files: []