paloma 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +148 -0
- data/License +22 -0
- data/README.md +240 -0
- data/Rakefile +16 -0
- data/app/views/paloma/_callback_hook.html.erb +33 -0
- data/lib/paloma.rb +14 -0
- data/lib/paloma/action_controller_extension.rb +52 -0
- data/lib/paloma/action_controller_filters.rb +53 -0
- data/lib/paloma/paloma_generator.rb +94 -0
- data/lib/paloma/templates/_callbacks.js +2 -0
- data/lib/paloma/templates/_local.js +20 -0
- data/lib/paloma/templates/action.js +5 -0
- data/lib/paloma/templates/index.js +1 -0
- data/lib/paloma/templates/paloma.js +22 -0
- data/paloma.gemspec +23 -0
- data/spec/callback_spec.rb +65 -0
- data/spec/sample_app/app/assets/javascripts/application.js +4 -0
- data/spec/sample_app/app/assets/javascripts/paloma/articles/callbacks.js +1 -0
- data/spec/sample_app/app/assets/javascripts/paloma/articles/create.js +3 -0
- data/spec/sample_app/app/assets/javascripts/paloma/articles/edit.js +3 -0
- data/spec/sample_app/app/assets/javascripts/paloma/articles/index.js +3 -0
- data/spec/sample_app/app/assets/javascripts/paloma/articles/new.js +3 -0
- data/spec/sample_app/app/assets/javascripts/paloma/articles/show.js +3 -0
- data/spec/sample_app/app/assets/javascripts/paloma/articles/update.js +3 -0
- data/spec/sample_app/app/assets/javascripts/paloma/index.js +2 -0
- data/spec/sample_app/app/assets/javascripts/paloma/paloma.js +1 -0
- data/spec/sample_app/app/views/articles/index.html.erb +5 -0
- data/spec/sample_app/app/views/articles/new.html.erb +9 -0
- data/spec/sample_app/app/views/articles/show.html.erb +2 -0
- data/spec/sample_app/app/views/layouts/application.html.erb +12 -0
- data/spec/sample_app/controllers.rb +54 -0
- data/spec/sample_app/init.rb +33 -0
- data/spec/sample_app/model.rb +28 -0
- data/spec/sample_app/paloma_test +0 -0
- data/spec/spec_helper.rb +21 -0
- metadata +215 -39
@@ -0,0 +1,33 @@
|
|
1
|
+
<% callback_details_id = "#{Time.now.to_i}#{(rand * 1000).ceil}" %>
|
2
|
+
|
3
|
+
<div class="callback-details" id="callback-details-<%= callback_details_id %>">
|
4
|
+
<script type="text/javascript">
|
5
|
+
var id = "callback-details-<%= callback_details_id %>",
|
6
|
+
callbacks = [];
|
7
|
+
|
8
|
+
// Remove any callback details if any
|
9
|
+
$('.callback-details[id!=" + id + "]').remove();
|
10
|
+
|
11
|
+
|
12
|
+
// Convert callbacks to javascript variable
|
13
|
+
<% callbacks.each do |callback| %>
|
14
|
+
callbacks.push({
|
15
|
+
name: '<%= callback[:name] %>',
|
16
|
+
params: eval($('<div/>').html("(<%= callback[:params].to_json %>)").text())
|
17
|
+
});
|
18
|
+
<% end %>
|
19
|
+
|
20
|
+
|
21
|
+
// Run Callbacks
|
22
|
+
for (var i = 0, len = callbacks.length; i < len; i++){
|
23
|
+
var callback = callbacks[i],
|
24
|
+
callbackFunction = Paloma.callbacks[callback.name];
|
25
|
+
|
26
|
+
console.log("Paloma: Fetching [" + callback.name + "]");
|
27
|
+
if (callback != undefined){
|
28
|
+
console.log("Paloma: Calling [" + callback.name + "]");
|
29
|
+
callbackFunction(callback.params);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
</script>
|
33
|
+
</div>
|
data/lib/paloma.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
module Paloma
|
2
|
+
def self.root
|
3
|
+
@paloma_root ||= File.dirname(__FILE__) + '/../'
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'action_controller/railtie'
|
8
|
+
require 'rails/generators'
|
9
|
+
|
10
|
+
# TODO: Rails version checking
|
11
|
+
|
12
|
+
require 'paloma/paloma_generator'
|
13
|
+
require 'paloma/action_controller_filters'
|
14
|
+
require 'paloma/action_controller_extension'
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Paloma
|
2
|
+
|
3
|
+
# TODO explain!
|
4
|
+
module ::ActionController::Redirecting
|
5
|
+
alias_method :original_redirect_to, :redirect_to
|
6
|
+
end
|
7
|
+
|
8
|
+
|
9
|
+
|
10
|
+
module ActionControllerExtension
|
11
|
+
def redirect_js_hook options = {}, response_status = {}
|
12
|
+
add_to_callbacks @__callback__, @__js_params__
|
13
|
+
original_redirect_to options, response_status
|
14
|
+
end
|
15
|
+
alias_method :redirect_to, :redirect_js_hook
|
16
|
+
|
17
|
+
|
18
|
+
#
|
19
|
+
# js_callback false
|
20
|
+
# js_callback :new, :params => {}
|
21
|
+
# js_callback :controller => '', :action => '', :params => {}
|
22
|
+
# js_callback :params => {}
|
23
|
+
#
|
24
|
+
def js_callback options = {}, extras = {}
|
25
|
+
default_callback = "#{controller_name}/#{action_name}"
|
26
|
+
params = {}
|
27
|
+
|
28
|
+
if options.is_a? Hash
|
29
|
+
params = options[:params]
|
30
|
+
callback = options[:controller].present? && options[:action].present? ?
|
31
|
+
"#{options[:controller]}/#{options[:action]}" :
|
32
|
+
default_callback
|
33
|
+
|
34
|
+
elsif options.is_a? Symbol
|
35
|
+
params = extras[:params]
|
36
|
+
callback = "#{controller_name}/#{options}"
|
37
|
+
|
38
|
+
elsif options.nil? || options.is_a?(TrueClass)
|
39
|
+
callback = default_callback
|
40
|
+
|
41
|
+
else # false
|
42
|
+
callback = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
@__callback__ = callback
|
46
|
+
@__js_params__ = params
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
::ActionController::Base.send :include, ActionControllerExtension
|
52
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Paloma
|
2
|
+
module ActionControllerFilters
|
3
|
+
|
4
|
+
def self.included base
|
5
|
+
base.module_eval do
|
6
|
+
prepend_view_path "#{Paloma.root}/app/views/"
|
7
|
+
before_filter :js_callback
|
8
|
+
after_filter :update_callback, :if => :html_response_from_render?
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def html_response_from_render?
|
16
|
+
[nil, 'text/html'].include?(response.content_type) && self.status != 302
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def update_callback
|
21
|
+
add_to_callbacks @__callback__, @__js_params__
|
22
|
+
|
23
|
+
response_body[0] += view_context.render(
|
24
|
+
:partial => "paloma/callback_hook",
|
25
|
+
:locals => {:callbacks => session[:callbacks]})
|
26
|
+
|
27
|
+
response.body = response_body[0]
|
28
|
+
clear_callbacks
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def add_to_callbacks name, params
|
33
|
+
return true if name.nil?
|
34
|
+
session[:callbacks] ||= []
|
35
|
+
session[:callbacks].push({:name => name, :params => params})
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def get_callbacks
|
40
|
+
session[:callbacks]
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
def clear_callbacks
|
45
|
+
session[:callbacks] = []
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
::ActionController::Base.send :include, ActionControllerFilters
|
51
|
+
end
|
52
|
+
|
53
|
+
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module Paloma
|
2
|
+
#
|
3
|
+
# Setup:
|
4
|
+
# rails g paloma:setup
|
5
|
+
# - Generates the following:
|
6
|
+
# - 'paloma' folder under app/assets/javascripts/paloma
|
7
|
+
# - index.js and paloma.js under the 'paloma' folder
|
8
|
+
#
|
9
|
+
#
|
10
|
+
# Usage:
|
11
|
+
# rails g paloma:add <controller_name>
|
12
|
+
# - Generates the following:
|
13
|
+
# - a folder under app/assets/javascripts/paloma named as <controller_name>
|
14
|
+
# - callbacks.js inside the folder just made
|
15
|
+
# - Updates index.js under the 'paloma' folder
|
16
|
+
# - adds a line in order to require the callbacks to be made under the recently made folder
|
17
|
+
#
|
18
|
+
#
|
19
|
+
# rails g paloma:add <controller_name>/<action_name>
|
20
|
+
# - Generates the following:
|
21
|
+
# - <action_name>.js file inside the <controller_name> folder
|
22
|
+
#
|
23
|
+
#
|
24
|
+
# Generated Files:
|
25
|
+
# index.js
|
26
|
+
# - contains code for requiring all callbacks of all folders
|
27
|
+
# - always updated when new folders and callback.js files are created
|
28
|
+
#
|
29
|
+
# paloma.js
|
30
|
+
# - declaration of namespace used in all callbacks
|
31
|
+
#
|
32
|
+
# <controller_name>/callbacks.js
|
33
|
+
# - contains code for requiring all callbacks under the same folder <controller_name>
|
34
|
+
#
|
35
|
+
# <controller_name>/<action_name>.js
|
36
|
+
# - actual code to be executed when callback is called
|
37
|
+
#
|
38
|
+
|
39
|
+
PARENT = 'app/assets/javascripts/paloma/'
|
40
|
+
INDEX = PARENT + 'index.js'
|
41
|
+
PALOMA = PARENT + 'paloma.js'
|
42
|
+
|
43
|
+
class SetupGenerator < ::Rails::Generators::Base
|
44
|
+
source_root File.expand_path('../templates', __FILE__)
|
45
|
+
|
46
|
+
def setup_paloma
|
47
|
+
#index.js on callbacks folder
|
48
|
+
has_index = File.exists? INDEX
|
49
|
+
copy_file 'index.js', INDEX unless has_index
|
50
|
+
|
51
|
+
has_paloma = File.exists? PALOMA
|
52
|
+
copy_file 'paloma.js', PALOMA unless has_paloma
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
class AddGenerator < ::Rails::Generators::NamedBase
|
59
|
+
source_root File.expand_path('../templates', __FILE__)
|
60
|
+
|
61
|
+
def create_callback_file
|
62
|
+
file = file_path.split('/')
|
63
|
+
controller = file[0]
|
64
|
+
action = file[1]
|
65
|
+
|
66
|
+
callbacks = PARENT + "#{controller}/_callbacks.js"
|
67
|
+
templates = "#{Paloma.root}/lib/paloma/templates/"
|
68
|
+
local = PARENT + "#{controller}/_local.js"
|
69
|
+
action_file = PARENT + "#{controller}/#{action}.js"
|
70
|
+
|
71
|
+
#_callbacks.js per folder(controller)
|
72
|
+
has_callbacks = File.exists? callbacks
|
73
|
+
unless has_callbacks
|
74
|
+
content = File.read(templates + '_callbacks.js').gsub('controller', "#{controller}")
|
75
|
+
File.open(callbacks, 'w'){ |f| f.write(content) }
|
76
|
+
File.open(INDEX, 'a+'){|f| f << "\n//= require ./" + controller + '/_callbacks' }
|
77
|
+
end
|
78
|
+
|
79
|
+
#_local.js per folder(controller)
|
80
|
+
has_local =File.exists? local
|
81
|
+
unless has_local
|
82
|
+
content = File.read(templates + '_local.js').gsub('controller', "#{controller}")
|
83
|
+
File.open(local, 'w'){ |f| f.write(content) }
|
84
|
+
end
|
85
|
+
|
86
|
+
#<action>.js on folder(controller) - code for callback
|
87
|
+
has_action = File.exists? action_file
|
88
|
+
unless (action.nil? || has_action)
|
89
|
+
content = File.read(templates + 'action.js').gsub('controller/action', "#{controller}/#{action}")
|
90
|
+
File.open(action_file, 'w'){ |f| f.write(content) }
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Paloma.controller = {
|
2
|
+
|
3
|
+
/*
|
4
|
+
Put here code which can be used by all callbacks
|
5
|
+
under the controller folder.
|
6
|
+
|
7
|
+
Example:
|
8
|
+
|
9
|
+
variableName: value;
|
10
|
+
|
11
|
+
functionName: function(params){
|
12
|
+
alert('Paloma');
|
13
|
+
};
|
14
|
+
|
15
|
+
To use the variable and function:
|
16
|
+
Paloma.controller.variableName
|
17
|
+
Paloma.controller.functionName(params);
|
18
|
+
*/
|
19
|
+
|
20
|
+
};
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require ./paloma
|
@@ -0,0 +1,22 @@
|
|
1
|
+
window.Paloma = {callbacks:{}};
|
2
|
+
|
3
|
+
Paloma.g = {
|
4
|
+
|
5
|
+
/*
|
6
|
+
Put here global code that can be used by all callbacks,
|
7
|
+
regardless which folder they're from.
|
8
|
+
|
9
|
+
Example:
|
10
|
+
|
11
|
+
variableName: value;
|
12
|
+
|
13
|
+
functionName: function(params){
|
14
|
+
alert('Paloma');
|
15
|
+
};
|
16
|
+
|
17
|
+
To use the variable and function:
|
18
|
+
Paloma.g.variableName
|
19
|
+
Paloma.g.functionName(params);
|
20
|
+
*/
|
21
|
+
|
22
|
+
};
|
data/paloma.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'paloma'
|
3
|
+
s.version = '0.0.2'
|
4
|
+
s.date = '2012-12-17'
|
5
|
+
s.summary = "Javascript Callback Manager for Rails"
|
6
|
+
s.description = "Javascript Callback Manager for Rails"
|
7
|
+
s.authors = ["Karl Paragua", "Bia Esmero"]
|
8
|
+
s.email = 'kb.paragua@gmail.com'
|
9
|
+
s.files = `git ls-files`.split("\n")
|
10
|
+
s.homepage = 'https://github.com/kbparagua/paloma'
|
11
|
+
|
12
|
+
s.add_dependency 'jquery-rails'
|
13
|
+
|
14
|
+
s.add_development_dependency 'rails', ['>= 3.1.0']
|
15
|
+
s.add_development_dependency 'bundler', ['>= 1.0.0']
|
16
|
+
s.add_development_dependency 'rake', ['>= 0']
|
17
|
+
s.add_development_dependency 'sqlite3', ['>= 0']
|
18
|
+
s.add_development_dependency 'rspec', ['>= 0']
|
19
|
+
s.add_development_dependency 'rspec-rails', ['~> 2.0']
|
20
|
+
s.add_development_dependency 'capybara', ['>= 1.0']
|
21
|
+
s.add_development_dependency 'database_cleaner', ['>= 0']
|
22
|
+
s.add_development_dependency 'launchy', ['>= 0']
|
23
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
feature 'Callbacks' do
|
4
|
+
|
5
|
+
it 'should execute articles/new callback', :js => true do
|
6
|
+
visit new_article_path
|
7
|
+
page.has_selector?('#from-articles-new-callback').should == true
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
it 'should execute callbacks for articles/create and articles/show', :js => true do
|
12
|
+
visit new_article_path
|
13
|
+
|
14
|
+
fill_in 'article[title]', :with => 'sexy paloma'
|
15
|
+
fill_in 'article[body]', :with => 'sexy paloma body'
|
16
|
+
click_button 'Save'
|
17
|
+
|
18
|
+
page.has_selector?('#from-articles-create-callback').should == true
|
19
|
+
page.has_selector?('#from-articles-show-callback').should == true
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
it 'should execute "new" callback instead of "create" after failed save', :js => true do
|
24
|
+
visit new_article_path
|
25
|
+
|
26
|
+
fill_in 'article[body]', :with => 'sexy paloma body'
|
27
|
+
click_button 'Save'
|
28
|
+
|
29
|
+
page.has_selector?('#from-articles-create-callback').should == false
|
30
|
+
page.has_selector?('#from-articles-new-callback').should == true
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
it 'should have an access on the passed parameters on js_callback', :js => true do
|
35
|
+
1.upto(30) do |i|
|
36
|
+
Article.create :title => "Sexy Paloma #{i}", :body => "Sexy Body"
|
37
|
+
end
|
38
|
+
|
39
|
+
visit articles_path
|
40
|
+
page.has_selector?('#article-count-30').should == true
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
it 'should not execute articles/update callback', :js => true do
|
45
|
+
article = Article.create :title => "Sexy Paloma Baby!", :body => "OMG"
|
46
|
+
|
47
|
+
visit edit_article_path(article)
|
48
|
+
fill_in 'article[body]', :with => 'Updated Body'
|
49
|
+
click_button 'Save'
|
50
|
+
|
51
|
+
page.has_selector?('#from-articles-update-callback').should == false
|
52
|
+
page.has_selector?('#from-articles-show-callback').should == true
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
it 'should execute articles/edit callback after failed update', :js => true do
|
57
|
+
article = Article.create :title => 'Sexy Paloma Baby!', :body => 'Yeah'
|
58
|
+
|
59
|
+
visit edit_article_path(article)
|
60
|
+
fill_in 'article[title]', :with => ''
|
61
|
+
click_button 'Save'
|
62
|
+
|
63
|
+
page.has_selector?('#from-articles-edit-callback').should == true
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
//= require_tree .
|