headshot 0.1.4

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.
Files changed (122) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.md +37 -0
  3. data/Rakefile +38 -0
  4. data/app/middlewares/flash_session_cookie_middleware.rb +18 -0
  5. data/lib/app/controllers/headshot_controller.rb +59 -0
  6. data/lib/app/helpers/headshot_helper.rb +63 -0
  7. data/lib/app/lib/headshot_support.rb +30 -0
  8. data/lib/app/models/headshot_photo.rb +7 -0
  9. data/lib/assets/audio/shutter.mp3 +0 -0
  10. data/lib/assets/javascripts/headshot.js +206 -0
  11. data/lib/assets/javascripts/headshot_support.js +27 -0
  12. data/lib/assets/swfs/headshot.swf +0 -0
  13. data/lib/db/migrate/create_headshot_photos.rb +13 -0
  14. data/lib/generators/headshot/config/config_generator.rb +45 -0
  15. data/lib/generators/headshot/generate/generate_generator.rb +26 -0
  16. data/lib/generators/headshot/install/install_generator.rb +37 -0
  17. data/lib/headshot/version.rb +3 -0
  18. data/lib/headshot.rb +11 -0
  19. data/lib/initializers/session_store.rb +1 -0
  20. data/lib/middlewares/flash_session_cookie_middleware.rb +18 -0
  21. data/lib/tasks/headshot_tasks.rake +4 -0
  22. data/test/app/controller/headshot_controller_test.rb +38 -0
  23. data/test/app/helpers/headshot_helper_test.rb +68 -0
  24. data/test/dummy/README.rdoc +261 -0
  25. data/test/dummy/Rakefile +7 -0
  26. data/test/dummy/app/assets/javascripts/application.js +15 -0
  27. data/test/dummy/app/assets/javascripts/headshot.js +206 -0
  28. data/test/dummy/app/assets/javascripts/headshot_support.js +27 -0
  29. data/test/dummy/app/assets/stylesheets/application.css +13 -0
  30. data/test/dummy/app/controllers/application_controller.rb +3 -0
  31. data/test/dummy/app/helpers/application_helper.rb +2 -0
  32. data/test/dummy/app/middlewares/flash_session_cookie_middleware.rb +18 -0
  33. data/test/dummy/app/models/headshot_photo.rb +7 -0
  34. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  35. data/test/dummy/config/application.rb +59 -0
  36. data/test/dummy/config/boot.rb +10 -0
  37. data/test/dummy/config/database.yml +25 -0
  38. data/test/dummy/config/environment.rb +5 -0
  39. data/test/dummy/config/environments/development.rb +37 -0
  40. data/test/dummy/config/environments/production.rb +67 -0
  41. data/test/dummy/config/environments/test.rb +37 -0
  42. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  43. data/test/dummy/config/initializers/inflections.rb +15 -0
  44. data/test/dummy/config/initializers/mime_types.rb +5 -0
  45. data/test/dummy/config/initializers/secret_token.rb +7 -0
  46. data/test/dummy/config/initializers/session_store.rb +10 -0
  47. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  48. data/test/dummy/config/locales/en.yml +5 -0
  49. data/test/dummy/config/routes.rb +60 -0
  50. data/test/dummy/config.ru +4 -0
  51. data/test/dummy/db/development.sqlite3 +0 -0
  52. data/test/dummy/db/migrate/20130111074937_create_headshot_photos.rb +13 -0
  53. data/test/dummy/db/schema.rb +28 -0
  54. data/test/dummy/db/test.sqlite3 +0 -0
  55. data/test/dummy/log/development.log +32 -0
  56. data/test/dummy/log/test.log +871 -0
  57. data/test/dummy/public/404.html +26 -0
  58. data/test/dummy/public/422.html +26 -0
  59. data/test/dummy/public/500.html +25 -0
  60. data/test/dummy/public/audio/shutter.mp3 +0 -0
  61. data/test/dummy/public/favicon.ico +0 -0
  62. data/test/dummy/public/headshots/empty_file +0 -0
  63. data/test/dummy/public/headshots/headshot_capture_123_1357896182.jpg +0 -0
  64. data/test/dummy/public/headshots/headshot_capture_1383_1357927406.jpg +0 -0
  65. data/test/dummy/public/headshots/headshot_capture_1714_1357928157.jpg +0 -0
  66. data/test/dummy/public/headshots/headshot_capture_1922_1357933499.jpg +0 -0
  67. data/test/dummy/public/headshots/headshot_capture_2223_1357895537.jpg +0 -0
  68. data/test/dummy/public/headshots/headshot_capture_2236_1357927697.jpg +0 -0
  69. data/test/dummy/public/headshots/headshot_capture_2492_1357927181.jpg +0 -0
  70. data/test/dummy/public/headshots/headshot_capture_2517_1357925235.jpg +0 -0
  71. data/test/dummy/public/headshots/headshot_capture_2741_1357933673.jpg +0 -0
  72. data/test/dummy/public/headshots/headshot_capture_2855_1357897722.jpg +0 -0
  73. data/test/dummy/public/headshots/headshot_capture_3004_1357929483.jpg +0 -0
  74. data/test/dummy/public/headshots/headshot_capture_3192_1357895507.jpg +0 -0
  75. data/test/dummy/public/headshots/headshot_capture_3474_1357899111.jpg +0 -0
  76. data/test/dummy/public/headshots/headshot_capture_4030_1357890605.jpg +0 -0
  77. data/test/dummy/public/headshots/headshot_capture_4132_1357925086.jpg +0 -0
  78. data/test/dummy/public/headshots/headshot_capture_4302_1357898574.jpg +0 -0
  79. data/test/dummy/public/headshots/headshot_capture_4439_1357926710.jpg +0 -0
  80. data/test/dummy/public/headshots/headshot_capture_4480_1357897965.jpg +0 -0
  81. data/test/dummy/public/headshots/headshot_capture_4563_1357930722.jpg +0 -0
  82. data/test/dummy/public/headshots/headshot_capture_4779_1357896101.jpg +0 -0
  83. data/test/dummy/public/headshots/headshot_capture_4801_1357927203.jpg +0 -0
  84. data/test/dummy/public/headshots/headshot_capture_4915_1357927616.jpg +0 -0
  85. data/test/dummy/public/headshots/headshot_capture_5027_1357927988.jpg +0 -0
  86. data/test/dummy/public/headshots/headshot_capture_5120_1357896023.jpg +0 -0
  87. data/test/dummy/public/headshots/headshot_capture_5148_1357928143.jpg +0 -0
  88. data/test/dummy/public/headshots/headshot_capture_5319_1357927441.jpg +0 -0
  89. data/test/dummy/public/headshots/headshot_capture_5493_1357985442.jpg +0 -0
  90. data/test/dummy/public/headshots/headshot_capture_5551_1357895850.jpg +0 -0
  91. data/test/dummy/public/headshots/headshot_capture_562_1357899111.jpg +0 -0
  92. data/test/dummy/public/headshots/headshot_capture_5902_1357926881.jpg +0 -0
  93. data/test/dummy/public/headshots/headshot_capture_5992_1357899281.jpg +0 -0
  94. data/test/dummy/public/headshots/headshot_capture_6245_1357896342.jpg +0 -0
  95. data/test/dummy/public/headshots/headshot_capture_6272_1357897339.jpg +0 -0
  96. data/test/dummy/public/headshots/headshot_capture_6444_1357927728.jpg +0 -0
  97. data/test/dummy/public/headshots/headshot_capture_6593_1357926833.jpg +0 -0
  98. data/test/dummy/public/headshots/headshot_capture_6857_1357897385.jpg +0 -0
  99. data/test/dummy/public/headshots/headshot_capture_7017_1357930283.jpg +0 -0
  100. data/test/dummy/public/headshots/headshot_capture_726_1357897738.jpg +0 -0
  101. data/test/dummy/public/headshots/headshot_capture_7481_1357929409.jpg +0 -0
  102. data/test/dummy/public/headshots/headshot_capture_7655_1357897700.jpg +0 -0
  103. data/test/dummy/public/headshots/headshot_capture_7750_1357927107.jpg +0 -0
  104. data/test/dummy/public/headshots/headshot_capture_7955_1357928167.jpg +0 -0
  105. data/test/dummy/public/headshots/headshot_capture_8080_1357927550.jpg +0 -0
  106. data/test/dummy/public/headshots/headshot_capture_8157_1357895552.jpg +0 -0
  107. data/test/dummy/public/headshots/headshot_capture_8240_1357930057.jpg +0 -0
  108. data/test/dummy/public/headshots/headshot_capture_8406_1357927135.jpg +0 -0
  109. data/test/dummy/public/headshots/headshot_capture_8671_1357927946.jpg +0 -0
  110. data/test/dummy/public/headshots/headshot_capture_8714_1357897752.jpg +0 -0
  111. data/test/dummy/public/headshots/headshot_capture_8940_1357933209.jpg +0 -0
  112. data/test/dummy/public/headshots/headshot_capture_9252_1357896077.jpg +0 -0
  113. data/test/dummy/public/headshots/headshot_capture_9642_1357899155.jpg +0 -0
  114. data/test/dummy/public/headshots/headshot_capture_989_1357926734.jpg +0 -0
  115. data/test/dummy/public/headshots/headshot_capture_9975_1357926892.jpg +0 -0
  116. data/test/dummy/public/swfs/headshot.swf +0 -0
  117. data/test/dummy/script/rails +6 -0
  118. data/test/dummy/tmp/headshot_capture_12345_1357840944.jpg +1 -0
  119. data/test/headshot_test.rb +7 -0
  120. data/test/lib/headshot_support_test.rb +38 -0
  121. data/test/test_helper.rb +17 -0
  122. metadata +283 -0
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2012 Diwa del Mundo (diwadm@gmail.com)
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ Headshot
2
+ ========
3
+
4
+ Headshot is a gem that provides a quick and easy way for Ruby on Rails applications to capture users' photos via a web camera without touching ActionScript or JavaScript code. It works by embedding a Flash component in your page's view to access the user's camera and capture the user's photo. Headshot takes care of the configuration and initialization of the Flash component and other support code in your Rails application simplifying the web cam integration process.
5
+
6
+ Sample Code
7
+ ========
8
+
9
+ Below is some sample code to setup Headshot:
10
+
11
+ <b>Controller</b>
12
+
13
+ `class HeadshotDemoController < ApplicationController`
14
+
15
+ `helper :headshot`
16
+
17
+ `end`
18
+
19
+
20
+ <b>View</b>
21
+
22
+ `<%= headshot_default_config(Rails.application.config.session_options[:key], headshot_capture_path) %>`
23
+
24
+ `<%= headshot_camera %>`
25
+
26
+ `<%= headshot_snap_button('Shoot') %>`
27
+
28
+ Demo
29
+ ========
30
+
31
+ Demo and complete documentation are available here:
32
+
33
+ [http://headshot.hypermediasoft.com](http://headshot.hypermediasoft.com)
34
+
35
+ Copyright and Author
36
+ =======
37
+ Copyright (c) 2013 Diwa del Mundo (diwadm@gmail.com), released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,38 @@
1
+ #!/usr/bin/env rake
2
+ begin
3
+ require 'bundler/setup'
4
+ rescue LoadError
5
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ end
7
+ begin
8
+ require 'rdoc/task'
9
+ rescue LoadError
10
+ require 'rdoc/rdoc'
11
+ require 'rake/rdoctask'
12
+ RDoc::Task = Rake::RDocTask
13
+ end
14
+
15
+ RDoc::Task.new(:rdoc) do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Headshot'
18
+ rdoc.options << '--line-numbers'
19
+ rdoc.rdoc_files.include('README.rdoc')
20
+ rdoc.rdoc_files.include('lib/**/*.rb')
21
+ end
22
+
23
+
24
+
25
+
26
+ Bundler::GemHelper.install_tasks
27
+
28
+ require 'rake/testtask'
29
+
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = false
35
+ end
36
+
37
+
38
+ task :default => :test
@@ -0,0 +1,18 @@
1
+ require 'rack/utils'
2
+
3
+ class FlashSessionCookieMiddleware
4
+ def initialize(app, session_key = '_session_id')
5
+ @app = app
6
+ @session_key = session_key
7
+ end
8
+
9
+ def call(env)
10
+ if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/
11
+ req = Rack::Request.new(env)
12
+ env['HTTP_COOKIE'] = [ @session_key, ::Rack::Utils.escape(req.params[@session_key]) ].join('=').freeze unless req.params[@session_key].nil?
13
+ env['HTTP_ACCEPT'] = "#{req.params['_http_accept']}".freeze unless req.params['_http_accept'].nil?
14
+ end
15
+
16
+ @app.call(env)
17
+ end
18
+ end
@@ -0,0 +1,59 @@
1
+ class HeadshotController < ApplicationController
2
+ include HeadshotSupport
3
+ def capture
4
+ file_path = ''
5
+ begin
6
+ file_path = method(:headshot_custom_file_path).call
7
+ rescue
8
+ file_path = headshot_file_path
9
+ end
10
+
11
+ # Pre save hook.
12
+ begin
13
+ method(:headshot_pre_save).call(file_path)
14
+ rescue
15
+ # No pre save hook.
16
+ end
17
+
18
+ # Method for saving the JPEG file.
19
+ begin
20
+ method(:headshot_custom_save_image).call(file_path, request.raw_post)
21
+
22
+ # Only catch the error if method is undefined.
23
+ rescue NameError => e
24
+ saving_result = headshot_save_image(file_path, request.raw_post)
25
+
26
+ unless saving_result
27
+ render :json => {
28
+ :status => 'Error',
29
+ :message => 'Saving of headshot failed.'
30
+ }
31
+ return
32
+ end
33
+ end
34
+
35
+ # Post save hook.
36
+ begin
37
+ method(:headshot_post_save).call(file_path)
38
+ rescue
39
+ @headshot_photo = HeadshotPhoto.create(
40
+ :image_file_name => File.basename(file_path),
41
+ :image_content_type => 'image/jpeg',
42
+ :image_updated_at => Time.now
43
+ )
44
+ end
45
+
46
+ headshot_url = ""
47
+ begin
48
+ headshot_url = method(:headshot_custom_image_url).call(File.basename(file_path))
49
+ rescue
50
+ headshot_url = "#{headshot_image_url(File.basename(file_path))}"
51
+ end
52
+
53
+ render :json => {
54
+ :status => 'Success',
55
+ :message => 'Headshot saved.',
56
+ :url => headshot_url
57
+ }
58
+ end
59
+ end
@@ -0,0 +1,63 @@
1
+ module HeadshotHelper
2
+ def headshot_snap_button(label = 'Snap', options = {})
3
+ options.reverse_merge!({
4
+ :onclick => 'headshotHandlers.snap()'
5
+ })
6
+
7
+ button_tag(label, options)
8
+ end
9
+
10
+ def headshot_config_button(label = 'Configure', options = {})
11
+ options.reverse_merge!({
12
+ :onclick => 'headshot.configure()'
13
+ })
14
+
15
+ button_tag(label, options)
16
+ end
17
+
18
+ def headshot_camera(width = 400, height = 300)
19
+ raw(%{
20
+ <script language="JavaScript">
21
+ headshotInitializer.setup(#{width}, #{height}, params);
22
+ </script>
23
+ })
24
+ end
25
+
26
+ def headshot_default_config(session_key, capture_path, options = {})
27
+ options.reverse_merge!(headshot_default_options)
28
+ session_value = u(cookies[session_key])
29
+ raw(%{
30
+ <script language="JavaScript">
31
+ var params = {
32
+ session_key_name: encodeURIComponent('#{session_value}'),
33
+ csrf_token: encodeURI(encodeURI(headshotUtils.getPageMetaValue('csrf-token')))
34
+ };
35
+
36
+ var headshotHandlers = {
37
+ onComplete: function(msg) {
38
+ headshot.reset();
39
+ },
40
+ snap: function() {
41
+ headshot.snap();
42
+ }
43
+ }
44
+
45
+ headshot.set_swf_url('#{options[:swf_url]}');
46
+ headshot.set_api_url('#{capture_path}');
47
+ headshot.set_quality(#{options[:quality]});
48
+ headshot.set_shutter_sound(#{options[:shutter_sound]}, '#{options[:shutter_sound_url]}');
49
+ headshot.set_hook('onComplete', '#{options[:on_complete]}');
50
+ </script>
51
+ })
52
+ end
53
+
54
+ def headshot_default_options
55
+ {
56
+ :swf_url => '/swfs/headshot.swf',
57
+ :quality => 90,
58
+ :shutter_sound => true,
59
+ :shutter_sound_url => '/audio/shutter.mp3',
60
+ :on_complete => 'headshotHandlers.onComplete'
61
+ }
62
+ end
63
+ end
@@ -0,0 +1,30 @@
1
+ module HeadshotSupport
2
+ def headshot_file_path
3
+ file_name = "headshot_capture_#{headshot_file_timestamp}.jpg"
4
+ File.join(Rails.root, 'public', 'headshots', file_name)
5
+ end
6
+
7
+ def headshot_image_url(file_name)
8
+ 'http://' + request.host_with_port + '/headshots/' + file_name
9
+ end
10
+
11
+ def headshot_save_image(file_path, raw_jpeg_data)
12
+ if raw_jpeg_data
13
+ begin
14
+ File.open(file_path, 'wb') do |file|
15
+ file.write raw_jpeg_data
16
+ end
17
+ rescue
18
+ raise "Headshot: cannot save headshot on #{file_path}. Please check file permissions."
19
+ end
20
+ else
21
+ return nil
22
+ end
23
+
24
+ true
25
+ end
26
+
27
+ def headshot_file_timestamp
28
+ "#{rand(10000)}_#{Time.now.to_i}"
29
+ end
30
+ end
@@ -0,0 +1,7 @@
1
+ class HeadshotPhoto < ActiveRecord::Base
2
+ attr_accessible :description, :image_content_type, :image_file_name, :image_file_size, :image_updated_at
3
+
4
+ belongs_to :capturable, :polymorphic => true
5
+
6
+ #has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" }
7
+ end
Binary file
@@ -0,0 +1,206 @@
1
+ /* headshot */
2
+ /* Easily capture webcam images on Rails applications. */
3
+ /* Initially based on JPEGCam v1.0.9 by Joseph Huckaby. */
4
+ /* Copyright 2012 - Diwa del Mundo <diwadm@gmail.com> */
5
+ /* Licensed under the GNU Lesser Public License */
6
+ /* http://www.gnu.org/licenses/lgpl.html */
7
+
8
+ /* Usage:
9
+ <script language="JavaScript">
10
+ document.write( headshot.get_html(320, 240) );
11
+ headshot.set_api_url( 'test.php' );
12
+ headshot.set_hook( 'onComplete', 'my_callback_function' );
13
+ function my_callback_function(response) {
14
+ console.log("Server responded: " + response);
15
+ }
16
+ </script>
17
+ <a href="javascript:void(headshot.snap())">Take Snapshot</a>
18
+ */
19
+
20
+ window.headshot = {
21
+ version: '0.1.0',
22
+
23
+ // globals
24
+ ie: !!navigator.userAgent.match(/MSIE/),
25
+ protocol: location.protocol.match(/https/i) ? 'https' : 'http',
26
+ callback: null, // user callback for completed uploads
27
+ swf_url: 'headshot.swf', // URI to headshot.swf movie (defaults to cwd)
28
+ shutter_url: 'shutter.mp3', // URI to shutter.mp3 sound
29
+ api_url: '', // URL to upload script
30
+ loaded: false, // true when headshot movie finishes loading
31
+ quality: 90, // JPEG quality (1 - 100)
32
+ shutter_sound: true, // shutter sound effect on/off
33
+ stealth: false, // stealth mode (do not freeze image upon capture)
34
+ hooks: {
35
+ onLoad: null,
36
+ onComplete: null,
37
+ onError: null
38
+ }, // callback hook functions
39
+
40
+ set_hook: function(name, callback) {
41
+ // set callback hook
42
+ // supported hooks: onLoad, onComplete, onError
43
+ if (typeof(this.hooks[name]) == 'undefined')
44
+ return alert("Hook type not supported: " + name);
45
+
46
+ this.hooks[name] = callback;
47
+ },
48
+
49
+ fire_hook: function(name, value) {
50
+ // fire hook callback, passing optional value to it
51
+ if (this.hooks[name]) {
52
+ if (typeof(this.hooks[name]) == 'function') {
53
+ // callback is function reference, call directly
54
+ this.hooks[name](value);
55
+ }
56
+ else if (typeof(this.hooks[name]) == 'array') {
57
+ // callback is PHP-style object instance method
58
+ this.hooks[name][0][this.hooks[name][1]](value);
59
+ }
60
+ else if (window[this.hooks[name]]) {
61
+ // callback is global function name
62
+ window[ this.hooks[name] ](value);
63
+ }
64
+ else if (typeof(this.hooks[name]) == 'string') {
65
+ // callback is a function but has a namespace
66
+ var funcName = this.hooks[name] + "('" + value + "')";
67
+ eval(funcName);
68
+ }
69
+ return true;
70
+ }
71
+ return false; // no hook defined
72
+ },
73
+
74
+ set_api_url: function(url) {
75
+ // set location of upload API script
76
+ this.api_url = url;
77
+ },
78
+
79
+ set_swf_url: function(url) {
80
+ // set location of SWF movie (defaults to headshot.swf in cwd)
81
+ this.swf_url = url;
82
+ },
83
+
84
+ get_html: function(width, height, params) {
85
+ // Return HTML for embedding headshot capture movie
86
+ // Specify pixel width and height (640x480, 320x240, etc.)
87
+ // Server width and height are optional, and default to movie width/height
88
+ server_width = params.server_width ? params.server_width : width;
89
+ server_height = params.server_height ? params.server_height : height;
90
+ session_key_name = params.session_key_name ? params.session_key_name : '';
91
+ csrf_token = params.csrf_token ? params.csrf_token : '';
92
+
93
+ var html = '';
94
+ var flashvars = 'shutter_enabled=' + (this.shutter_sound ? 1 : 0) +
95
+ '&shutter_url=' + escape(this.shutter_url) +
96
+ '&width=' + width +
97
+ '&height=' + height +
98
+ '&server_width=' + server_width +
99
+ '&server_height=' + server_height +
100
+ '&session_key_name=' + session_key_name +
101
+ '&csrf_token=' + csrf_token;
102
+
103
+ if (this.ie) {
104
+ html += '<object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="'+this.protocol+'://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0" width="'+width+'" height="'+height+'" id="headshot_movie" align="middle"><param name="allowScriptAccess" value="always" /><param name="allowFullScreen" value="false" /><param name="movie" value="'+this.swf_url+'" /><param name="loop" value="false" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="bgcolor" value="#ffffff" /><param name="flashvars" value="'+flashvars+'"/></object>';
105
+ }
106
+ else {
107
+ html += '<embed id="headshot_movie" src="'+this.swf_url+'" loop="false" menu="false" quality="best" bgcolor="#ffffff" width="'+width+'" height="'+height+'" name="headshot_movie" align="middle" allowScriptAccess="always" allowFullScreen="false" type="application/x-shockwave-flash" pluginspage="http://www.macromedia.com/go/getflashplayer" flashvars="'+flashvars+'" />';
108
+ }
109
+
110
+ this.loaded = false;
111
+ return html;
112
+ },
113
+
114
+ get_movie: function() {
115
+ // get reference to movie object/embed in DOM
116
+ if (!this.loaded) return alert("ERROR: Movie is not loaded yet");
117
+ var movie = document.getElementById('headshot_movie');
118
+ if (!movie) alert("ERROR: Cannot locate movie 'headshot_movie' in DOM");
119
+ return movie;
120
+ },
121
+
122
+ set_stealth: function(stealth) {
123
+ // set or disable stealth mode
124
+ this.stealth = stealth;
125
+ },
126
+
127
+ snap: function(url, callback, stealth) {
128
+ // take snapshot and send to server
129
+ // specify fully-qualified URL to server API script
130
+ // and callback function (string or function object)
131
+ if (callback) this.set_hook('onComplete', callback);
132
+ if (url) this.set_api_url(url);
133
+ if (typeof(stealth) != 'undefined') this.set_stealth( stealth );
134
+
135
+ this.get_movie()._snap( this.api_url, this.quality, this.shutter_sound ? 1 : 0, this.stealth ? 1 : 0 );
136
+ },
137
+
138
+ freeze: function() {
139
+ // freeze headshot image (capture but do not upload)
140
+ this.get_movie()._snap('', this.quality, this.shutter_sound ? 1 : 0, 0 );
141
+ },
142
+
143
+ upload: function(url, callback) {
144
+ // upload image to server after taking snapshot
145
+ // specify fully-qualified URL to server API script
146
+ // and callback function (string or function object)
147
+ if (callback) this.set_hook('onComplete', callback);
148
+ if (url) this.set_api_url(url);
149
+
150
+ this.get_movie()._upload( this.api_url );
151
+ },
152
+
153
+ reset: function() {
154
+ // reset movie after taking snapshot
155
+ this.get_movie()._reset();
156
+ },
157
+
158
+ configure: function(panel) {
159
+ // open flash configuration panel -- specify tab name:
160
+ // "camera", "privacy", "default", "localStorage", "microphone", "settingsManager"
161
+ if (!panel) panel = "camera";
162
+ this.get_movie()._configure(panel);
163
+ },
164
+
165
+ set_quality: function(new_quality) {
166
+ // set the JPEG quality (1 - 100)
167
+ // default is 90
168
+ this.quality = new_quality;
169
+ },
170
+
171
+ set_shutter_sound: function(enabled, url) {
172
+ // enable or disable the shutter sound effect
173
+ // defaults to enabled
174
+ this.shutter_sound = enabled;
175
+ this.shutter_url = url ? url : 'shutter.mp3';
176
+ },
177
+
178
+ flash_notify: function(type, msg) {
179
+ // receive notification from flash about event
180
+ switch (type) {
181
+ case 'flashLoadComplete':
182
+ // movie loaded successfully
183
+ this.loaded = true;
184
+ this.fire_hook('onLoad');
185
+ break;
186
+
187
+ case 'error':
188
+ // HTTP POST error most likely
189
+ if (!this.fire_hook('onError', msg)) {
190
+ alert("Flash Error: " + msg);
191
+ }
192
+ break;
193
+
194
+ case 'success':
195
+ // upload complete, execute user callback function
196
+ // and pass raw API script results to function
197
+ this.fire_hook('onComplete', msg.toString());
198
+ break;
199
+
200
+ default:
201
+ // catch-all, just in case
202
+ alert("flash_notify: " + type + ": " + msg);
203
+ break;
204
+ }
205
+ }
206
+ };
@@ -0,0 +1,27 @@
1
+ var headshotUtils = {
2
+ getPageMetaTags:function () {
3
+ return document.getElementsByTagName('meta');
4
+ },
5
+ getPageMetaValue:function (metaName) {
6
+ var metaValue = '';
7
+ var pageMetaTags = headshotUtils.getPageMetaTags();
8
+ if (pageMetaTags.length > 0) {
9
+ for (var i = 0; i < pageMetaTags.length; i++) {
10
+ if (pageMetaTags[i]['name'] == metaName) {
11
+ metaValue = pageMetaTags[i]['content'];
12
+ }
13
+ }
14
+ }
15
+
16
+ return metaValue;
17
+ }
18
+ };
19
+
20
+ var headshotInitializer = {
21
+ setup: function(width, height, railsTokens) {
22
+ document.write(headshot.get_html(width, height, railsTokens));
23
+ },
24
+ setupHTML: function(width, height, railsTokens) {
25
+ return headshot.get_html(width, height, railsTokens);
26
+ }
27
+ };
Binary file
@@ -0,0 +1,13 @@
1
+ class CreateHeadshotPhotos < ActiveRecord::Migration
2
+ def change
3
+ create_table :headshot_photos do |t|
4
+ t.string :description
5
+ t.string :image_file_name
6
+ t.string :image_content_type
7
+ t.integer :image_file_size
8
+ t.references :capturable, :polymorphic => true
9
+ t.datetime :image_updated_at
10
+ t.timestamps
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,45 @@
1
+ require 'rails'
2
+
3
+ module Headshot
4
+ module Generators
5
+ class ConfigGenerator < ::Rails::Generators::Base
6
+ desc "This generator configures the application so it would be able to communicate with the Headshot Flash binary."
7
+ source_root File.expand_path('../../../../../lib/assets', __FILE__)
8
+
9
+ def copy_flash_middleware
10
+ say_status('copying', 'Copying Flash session cookie middleware ...')
11
+ copy_file('../middlewares/flash_session_cookie_middleware.rb', 'app/middlewares/flash_session_cookie_middleware.rb')
12
+ end
13
+
14
+ def load_middlewares_in_application_rb
15
+ application_rb_path = "config/application.rb"
16
+ code_marker = "class Application < Rails::Application"
17
+ loading_code = 'config.autoload_paths += %W(#{config.root}/app/middlewares)'
18
+ say_status('checking', 'Checking if application.rb contains the loading code for the middleware.')
19
+
20
+ inject_into_file application_rb_path, :after => "#{code_marker}\n" do
21
+ "\t\t#{loading_code}\n"
22
+ end
23
+ end
24
+
25
+ def initialize_session_store
26
+ session_store_rb_path = "config/initializers/session_store.rb"
27
+ loading_code = 'config.autoload_paths += %W(#{config.root}/app/middlewares)'
28
+ say_status('checking', 'Checking if session_store.rb contains the code for initializing for the middleware.')
29
+ initializer_code = "\n"
30
+
31
+ inside(source_paths[0] + '/../initializers', :verbose => true) do
32
+ initializer_code_lines = IO.readlines('session_store.rb')
33
+ initializer_code += initializer_code_lines.join('')
34
+ end
35
+
36
+ append_file(session_store_rb_path, initializer_code)
37
+ end
38
+
39
+ def create_default_directories
40
+ say_status('creating', 'Creating default headshots directory public/headshots.')
41
+ create_file('public/headshots/empty_file', '')
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,26 @@
1
+ require 'rails'
2
+ require 'rails/generators/migration'
3
+
4
+ module Headshot
5
+ module Generators
6
+ class GenerateGenerator < ::Rails::Generators::Base
7
+ include Rails::Generators::Migration
8
+ desc "This generator creates the template controllers, models, helpers, routes, and migrations."
9
+ source_root File.expand_path('../../../../../', __FILE__)
10
+
11
+ # Copied migration template generator from http://stackoverflow.com/questions/4141739/generators-and-migrations-in-plugins-rails-3
12
+ def self.next_migration_number(path)
13
+ Time.now.utc.strftime("%Y%m%d%H%M%S")
14
+ end
15
+
16
+ def add_headshot_routes
17
+ route %{post "headshot/capture" => 'headshot#capture', :as => :headshot_capture}
18
+ end
19
+
20
+ def create_model_file
21
+ template "lib/app/models/headshot_photo.rb", "app/models/headshot_photo.rb"
22
+ migration_template "lib/db/migrate/create_headshot_photos.rb", "db/migrate/create_headshot_photos.rb"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,37 @@
1
+ require 'rails'
2
+
3
+ #if ::Rails.version < '3.1' || !::Rails.application.config.assets.enabled
4
+
5
+ module Headshot
6
+ module Generators
7
+ class InstallGenerator < ::Rails::Generators::Base
8
+ desc "This generator install the Headshot assets (JavaScript, Audio, and Flash application files)."
9
+ source_root File.expand_path('../../../../../lib/assets', __FILE__)
10
+
11
+ def copy_javascripts
12
+ say_status('copying', 'Copying Javascripts ...')
13
+ copy_file('javascripts/headshot.js', 'app/assets/javascripts/headshot.js')
14
+ copy_file('javascripts/headshot_support.js', 'app/assets/javascripts/headshot_support.js')
15
+ end
16
+
17
+ def copy_audio_files
18
+ say_status('copying', 'Copying Audio files ...')
19
+ copy_file('audio/shutter.mp3', 'public/audio/shutter.mp3')
20
+ end
21
+
22
+ def copy_flash_app_files
23
+ say_status('copying', 'Copying Flash application files ...')
24
+ copy_file('swfs/headshot.swf', 'public/swfs/headshot.swf')
25
+ end
26
+
27
+ def run_other_generators
28
+ generate("headshot:config")
29
+ generate("headshot:generate")
30
+ end
31
+ end
32
+ end
33
+ end
34
+
35
+ # else
36
+ # TODO: what do we do when app is asset-pipelined?
37
+ # end
@@ -0,0 +1,3 @@
1
+ module Headshot
2
+ VERSION = "0.1.4"
3
+ end
data/lib/headshot.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'active_support/dependencies'
2
+
3
+ %w{controllers helpers lib}.each do |dir|
4
+ path = File.join(File.dirname(__FILE__), 'app', dir)
5
+ $LOAD_PATH << path
6
+ ActiveSupport::Dependencies.autoload_paths << path
7
+ ActionController::Base.helper Headshot
8
+ end
9
+
10
+ module Headshot
11
+ end
@@ -0,0 +1 @@
1
+ Rails.application.config.middleware.insert_before(Rails.application.config.session_store, FlashSessionCookieMiddleware, Rails.application.config.session_options[:key])