websocket-rails 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.
Files changed (53) hide show
  1. data/.gitignore +6 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +103 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +79 -0
  6. data/Rakefile +37 -0
  7. data/config/routes.rb +3 -0
  8. data/lib/websocket-rails.rb +18 -0
  9. data/lib/websocket_rails/base_controller.rb +29 -0
  10. data/lib/websocket_rails/connection_manager.rb +38 -0
  11. data/lib/websocket_rails/data_store.rb +49 -0
  12. data/lib/websocket_rails/dispatcher.rb +71 -0
  13. data/lib/websocket_rails/engine.rb +15 -0
  14. data/lib/websocket_rails/extensions/common.rb +11 -0
  15. data/lib/websocket_rails/extensions/websocket_rack.rb +55 -0
  16. data/lib/websocket_rails/version.rb +3 -0
  17. data/test/dummy/Rakefile +7 -0
  18. data/test/dummy/app/controllers/application_controller.rb +3 -0
  19. data/test/dummy/app/helpers/application_helper.rb +2 -0
  20. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  21. data/test/dummy/config.ru +4 -0
  22. data/test/dummy/config/application.rb +45 -0
  23. data/test/dummy/config/boot.rb +10 -0
  24. data/test/dummy/config/database.yml +22 -0
  25. data/test/dummy/config/environment.rb +5 -0
  26. data/test/dummy/config/environments/development.rb +26 -0
  27. data/test/dummy/config/environments/production.rb +49 -0
  28. data/test/dummy/config/environments/test.rb +35 -0
  29. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  30. data/test/dummy/config/initializers/inflections.rb +10 -0
  31. data/test/dummy/config/initializers/mime_types.rb +5 -0
  32. data/test/dummy/config/initializers/secret_token.rb +7 -0
  33. data/test/dummy/config/initializers/session_store.rb +8 -0
  34. data/test/dummy/config/locales/en.yml +5 -0
  35. data/test/dummy/config/routes.rb +58 -0
  36. data/test/dummy/public/404.html +26 -0
  37. data/test/dummy/public/422.html +26 -0
  38. data/test/dummy/public/500.html +26 -0
  39. data/test/dummy/public/favicon.ico +0 -0
  40. data/test/dummy/public/javascripts/application.js +2 -0
  41. data/test/dummy/public/javascripts/controls.js +965 -0
  42. data/test/dummy/public/javascripts/dragdrop.js +974 -0
  43. data/test/dummy/public/javascripts/effects.js +1123 -0
  44. data/test/dummy/public/javascripts/prototype.js +6001 -0
  45. data/test/dummy/public/javascripts/rails.js +202 -0
  46. data/test/dummy/public/stylesheets/.gitkeep +0 -0
  47. data/test/dummy/script/rails +6 -0
  48. data/test/integration/navigation_test.rb +7 -0
  49. data/test/support/integration_case.rb +5 -0
  50. data/test/test_helper.rb +22 -0
  51. data/test/websocket_rails_test.rb +7 -0
  52. data/websocket-rails.gemspec +26 -0
  53. metadata +218 -0
@@ -0,0 +1,202 @@
1
+ (function() {
2
+ Ajax.Responders.register({
3
+ onCreate: function(request) {
4
+ var token = $$('meta[name=csrf-token]')[0];
5
+ if (token) {
6
+ if (!request.options.requestHeaders) request.options.requestHeaders = {};
7
+ request.options.requestHeaders['X-CSRF-Token'] = token.readAttribute('content');
8
+ }
9
+ }
10
+ });
11
+
12
+ // Technique from Juriy Zaytsev
13
+ // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
14
+ function isEventSupported(eventName) {
15
+ var el = document.createElement('div');
16
+ eventName = 'on' + eventName;
17
+ var isSupported = (eventName in el);
18
+ if (!isSupported) {
19
+ el.setAttribute(eventName, 'return;');
20
+ isSupported = typeof el[eventName] == 'function';
21
+ }
22
+ el = null;
23
+ return isSupported;
24
+ }
25
+
26
+ function isForm(element) {
27
+ return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM';
28
+ }
29
+
30
+ function isInput(element) {
31
+ if (Object.isElement(element)) {
32
+ var name = element.nodeName.toUpperCase();
33
+ return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA';
34
+ }
35
+ else return false;
36
+ }
37
+
38
+ var submitBubbles = isEventSupported('submit'),
39
+ changeBubbles = isEventSupported('change');
40
+
41
+ if (!submitBubbles || !changeBubbles) {
42
+ // augment the Event.Handler class to observe custom events when needed
43
+ Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
44
+ function(init, element, eventName, selector, callback) {
45
+ init(element, eventName, selector, callback);
46
+ // is the handler being attached to an element that doesn't support this event?
47
+ if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
48
+ (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
49
+ // "submit" => "emulated:submit"
50
+ this.eventName = 'emulated:' + this.eventName;
51
+ }
52
+ }
53
+ );
54
+ }
55
+
56
+ if (!submitBubbles) {
57
+ // discover forms on the page by observing focus events which always bubble
58
+ document.on('focusin', 'form', function(focusEvent, form) {
59
+ // special handler for the real "submit" event (one-time operation)
60
+ if (!form.retrieve('emulated:submit')) {
61
+ form.on('submit', function(submitEvent) {
62
+ var emulated = form.fire('emulated:submit', submitEvent, true);
63
+ // if custom event received preventDefault, cancel the real one too
64
+ if (emulated.returnValue === false) submitEvent.preventDefault();
65
+ });
66
+ form.store('emulated:submit', true);
67
+ }
68
+ });
69
+ }
70
+
71
+ if (!changeBubbles) {
72
+ // discover form inputs on the page
73
+ document.on('focusin', 'input, select, textarea', function(focusEvent, input) {
74
+ // special handler for real "change" events
75
+ if (!input.retrieve('emulated:change')) {
76
+ input.on('change', function(changeEvent) {
77
+ input.fire('emulated:change', changeEvent, true);
78
+ });
79
+ input.store('emulated:change', true);
80
+ }
81
+ });
82
+ }
83
+
84
+ function handleRemote(element) {
85
+ var method, url, params;
86
+
87
+ var event = element.fire("ajax:before");
88
+ if (event.stopped) return false;
89
+
90
+ if (element.tagName.toLowerCase() === 'form') {
91
+ method = element.readAttribute('method') || 'post';
92
+ url = element.readAttribute('action');
93
+ // serialize the form with respect to the submit button that was pressed
94
+ params = element.serialize({ submit: element.retrieve('rails:submit-button') });
95
+ // clear the pressed submit button information
96
+ element.store('rails:submit-button', null);
97
+ } else {
98
+ method = element.readAttribute('data-method') || 'get';
99
+ url = element.readAttribute('href');
100
+ params = {};
101
+ }
102
+
103
+ new Ajax.Request(url, {
104
+ method: method,
105
+ parameters: params,
106
+ evalScripts: true,
107
+
108
+ onCreate: function(response) { element.fire("ajax:create", response); },
109
+ onComplete: function(response) { element.fire("ajax:complete", response); },
110
+ onSuccess: function(response) { element.fire("ajax:success", response); },
111
+ onFailure: function(response) { element.fire("ajax:failure", response); }
112
+ });
113
+
114
+ element.fire("ajax:after");
115
+ }
116
+
117
+ function insertHiddenField(form, name, value) {
118
+ form.insert(new Element('input', { type: 'hidden', name: name, value: value }));
119
+ }
120
+
121
+ function handleMethod(element) {
122
+ var method = element.readAttribute('data-method'),
123
+ url = element.readAttribute('href'),
124
+ csrf_param = $$('meta[name=csrf-param]')[0],
125
+ csrf_token = $$('meta[name=csrf-token]')[0];
126
+
127
+ var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
128
+ $(element.parentNode).insert(form);
129
+
130
+ if (method !== 'post') {
131
+ insertHiddenField(form, '_method', method);
132
+ }
133
+
134
+ if (csrf_param) {
135
+ insertHiddenField(form, csrf_param.readAttribute('content'), csrf_token.readAttribute('content'));
136
+ }
137
+
138
+ form.submit();
139
+ }
140
+
141
+ function disableFormElements(form) {
142
+ form.select('input[type=submit][data-disable-with]').each(function(input) {
143
+ input.store('rails:original-value', input.getValue());
144
+ input.setValue(input.readAttribute('data-disable-with')).disable();
145
+ });
146
+ }
147
+
148
+ function enableFormElements(form) {
149
+ form.select('input[type=submit][data-disable-with]').each(function(input) {
150
+ input.setValue(input.retrieve('rails:original-value')).enable();
151
+ });
152
+ }
153
+
154
+ function allowAction(element) {
155
+ var message = element.readAttribute('data-confirm');
156
+ return !message || confirm(message);
157
+ }
158
+
159
+ document.on('click', 'a[data-confirm], a[data-remote], a[data-method]', function(event, link) {
160
+ if (!allowAction(link)) {
161
+ event.stop();
162
+ return false;
163
+ }
164
+
165
+ if (link.readAttribute('data-remote')) {
166
+ handleRemote(link);
167
+ event.stop();
168
+ } else if (link.readAttribute('data-method')) {
169
+ handleMethod(link);
170
+ event.stop();
171
+ }
172
+ });
173
+
174
+ document.on("click", "form input[type=submit], form button[type=submit], form button:not([type])", function(event, button) {
175
+ // register the pressed submit button
176
+ event.findElement('form').store('rails:submit-button', button.name || false);
177
+ });
178
+
179
+ document.on("submit", function(event) {
180
+ var form = event.findElement();
181
+
182
+ if (!allowAction(form)) {
183
+ event.stop();
184
+ return false;
185
+ }
186
+
187
+ if (form.readAttribute('data-remote')) {
188
+ handleRemote(form);
189
+ event.stop();
190
+ } else {
191
+ disableFormElements(form);
192
+ }
193
+ });
194
+
195
+ document.on('ajax:create', 'form', function(event, form) {
196
+ if (form == event.findElement()) disableFormElements(form);
197
+ });
198
+
199
+ document.on('ajax:complete', 'form', function(event, form) {
200
+ if (form == event.findElement()) enableFormElements(form);
201
+ });
202
+ })();
File without changes
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
3
+
4
+ APP_PATH = File.expand_path('../../config/application', __FILE__)
5
+ require File.expand_path('../../config/boot', __FILE__)
6
+ require 'rails/commands'
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class NavigationTest < ActiveSupport::IntegrationCase
4
+ test "truth" do
5
+ assert_kind_of Dummy::Application, Rails.application
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ # Define a bare test case to use with Capybara
2
+ class ActiveSupport::IntegrationCase < ActiveSupport::TestCase
3
+ include Capybara
4
+ include Rails.application.routes.url_helpers
5
+ end
@@ -0,0 +1,22 @@
1
+ # Configure Rails Envinronment
2
+ ENV["RAILS_ENV"] = "test"
3
+
4
+ require File.expand_path("../dummy/config/environment.rb", __FILE__)
5
+ require "rails/test_help"
6
+
7
+ ActionMailer::Base.delivery_method = :test
8
+ ActionMailer::Base.perform_deliveries = true
9
+ ActionMailer::Base.default_url_options[:host] = "test.com"
10
+
11
+ Rails.backtrace_cleaner.remove_silencers!
12
+
13
+ # Configure capybara for integration testing
14
+ require "capybara/rails"
15
+ Capybara.default_driver = :rack_test
16
+ Capybara.default_selector = :css
17
+
18
+ # Run any available migration
19
+ ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
20
+
21
+ # Load support files
22
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
@@ -0,0 +1,7 @@
1
+ require 'test_helper'
2
+
3
+ class Websocket-railsTest < ActiveSupport::TestCase
4
+ test "truth" do
5
+ assert_kind_of Module, Websocket-rails
6
+ end
7
+ end
@@ -0,0 +1,26 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+ require "websocket_rails/version"
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "websocket-rails"
6
+ s.summary = "Plug and play websocket support for ruby on rails. Includes event router for mapping javascript events to controller actions."
7
+ s.description = "Seamless Ruby on Rails websocket integration."
8
+ s.homepage = "https://github.com/DanKnox/websocket-rails"
9
+ s.files = Dir["{lib,config}/**/*"] + ["MIT-LICENSE", "Rakefile", "Gemfile", "README.rdoc"]
10
+ s.version = WebsocketRails::VERSION
11
+ s.platform = Gem::Platform::RUBY
12
+ s.authors = [ "Dan Knox", "Kyle Whalen", "Three Dot Loft LLC" ]
13
+ s.email = [ "dknox@threedotloft.com" ]
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
17
+ s.require_path = 'lib'
18
+
19
+ s.add_dependency "rack"
20
+ s.add_dependency "em-websocket", '~> 0.3.6'
21
+ s.add_dependency "websocket-rack"
22
+ s.add_dependency "thin"
23
+ s.add_development_dependency "rake"
24
+ s.add_development_dependency "rails"
25
+ s.add_development_dependency "sqlite3"
26
+ end
metadata ADDED
@@ -0,0 +1,218 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: websocket-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Dan Knox
9
+ - Kyle Whalen
10
+ - Three Dot Loft LLC
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+ date: 2012-03-26 00:00:00.000000000Z
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rack
18
+ requirement: !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ! '>='
22
+ - !ruby/object:Gem::Version
23
+ version: '0'
24
+ type: :runtime
25
+ prerelease: false
26
+ version_requirements: !ruby/object:Gem::Requirement
27
+ none: false
28
+ requirements:
29
+ - - ! '>='
30
+ - !ruby/object:Gem::Version
31
+ version: '0'
32
+ - !ruby/object:Gem::Dependency
33
+ name: em-websocket
34
+ requirement: !ruby/object:Gem::Requirement
35
+ none: false
36
+ requirements:
37
+ - - ~>
38
+ - !ruby/object:Gem::Version
39
+ version: 0.3.6
40
+ type: :runtime
41
+ prerelease: false
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 0.3.6
48
+ - !ruby/object:Gem::Dependency
49
+ name: websocket-rack
50
+ requirement: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ type: :runtime
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ - !ruby/object:Gem::Dependency
65
+ name: thin
66
+ requirement: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ type: :runtime
73
+ prerelease: false
74
+ version_requirements: !ruby/object:Gem::Requirement
75
+ none: false
76
+ requirements:
77
+ - - ! '>='
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ - !ruby/object:Gem::Dependency
81
+ name: rake
82
+ requirement: !ruby/object:Gem::Requirement
83
+ none: false
84
+ requirements:
85
+ - - ! '>='
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ type: :development
89
+ prerelease: false
90
+ version_requirements: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ - !ruby/object:Gem::Dependency
97
+ name: rails
98
+ requirement: !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ! '>='
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ - !ruby/object:Gem::Dependency
113
+ name: sqlite3
114
+ requirement: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ type: :development
121
+ prerelease: false
122
+ version_requirements: !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ! '>='
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ description: Seamless Ruby on Rails websocket integration.
129
+ email:
130
+ - dknox@threedotloft.com
131
+ executables: []
132
+ extensions: []
133
+ extra_rdoc_files: []
134
+ files:
135
+ - .gitignore
136
+ - Gemfile
137
+ - Gemfile.lock
138
+ - MIT-LICENSE
139
+ - README.md
140
+ - Rakefile
141
+ - config/routes.rb
142
+ - lib/websocket-rails.rb
143
+ - lib/websocket_rails/base_controller.rb
144
+ - lib/websocket_rails/connection_manager.rb
145
+ - lib/websocket_rails/data_store.rb
146
+ - lib/websocket_rails/dispatcher.rb
147
+ - lib/websocket_rails/engine.rb
148
+ - lib/websocket_rails/extensions/common.rb
149
+ - lib/websocket_rails/extensions/websocket_rack.rb
150
+ - lib/websocket_rails/version.rb
151
+ - test/dummy/Rakefile
152
+ - test/dummy/app/controllers/application_controller.rb
153
+ - test/dummy/app/helpers/application_helper.rb
154
+ - test/dummy/app/views/layouts/application.html.erb
155
+ - test/dummy/config.ru
156
+ - test/dummy/config/application.rb
157
+ - test/dummy/config/boot.rb
158
+ - test/dummy/config/database.yml
159
+ - test/dummy/config/environment.rb
160
+ - test/dummy/config/environments/development.rb
161
+ - test/dummy/config/environments/production.rb
162
+ - test/dummy/config/environments/test.rb
163
+ - test/dummy/config/initializers/backtrace_silencers.rb
164
+ - test/dummy/config/initializers/inflections.rb
165
+ - test/dummy/config/initializers/mime_types.rb
166
+ - test/dummy/config/initializers/secret_token.rb
167
+ - test/dummy/config/initializers/session_store.rb
168
+ - test/dummy/config/locales/en.yml
169
+ - test/dummy/config/routes.rb
170
+ - test/dummy/public/404.html
171
+ - test/dummy/public/422.html
172
+ - test/dummy/public/500.html
173
+ - test/dummy/public/favicon.ico
174
+ - test/dummy/public/javascripts/application.js
175
+ - test/dummy/public/javascripts/controls.js
176
+ - test/dummy/public/javascripts/dragdrop.js
177
+ - test/dummy/public/javascripts/effects.js
178
+ - test/dummy/public/javascripts/prototype.js
179
+ - test/dummy/public/javascripts/rails.js
180
+ - test/dummy/public/stylesheets/.gitkeep
181
+ - test/dummy/script/rails
182
+ - test/integration/navigation_test.rb
183
+ - test/support/integration_case.rb
184
+ - test/test_helper.rb
185
+ - test/websocket_rails_test.rb
186
+ - websocket-rails.gemspec
187
+ homepage: https://github.com/DanKnox/websocket-rails
188
+ licenses: []
189
+ post_install_message:
190
+ rdoc_options: []
191
+ require_paths:
192
+ - lib
193
+ required_ruby_version: !ruby/object:Gem::Requirement
194
+ none: false
195
+ requirements:
196
+ - - ! '>='
197
+ - !ruby/object:Gem::Version
198
+ version: '0'
199
+ segments:
200
+ - 0
201
+ hash: -2923788248734806992
202
+ required_rubygems_version: !ruby/object:Gem::Requirement
203
+ none: false
204
+ requirements:
205
+ - - ! '>='
206
+ - !ruby/object:Gem::Version
207
+ version: '0'
208
+ segments:
209
+ - 0
210
+ hash: -2923788248734806992
211
+ requirements: []
212
+ rubyforge_project:
213
+ rubygems_version: 1.8.19
214
+ signing_key:
215
+ specification_version: 3
216
+ summary: Plug and play websocket support for ruby on rails. Includes event router
217
+ for mapping javascript events to controller actions.
218
+ test_files: []