jcontroller 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/.travis.yml +13 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +29 -0
  7. data/Rakefile +1 -0
  8. data/app/assets/javascripts/jcontroller.js +82 -0
  9. data/app/views/jcontroller/_execute_jaction.html.erb +1 -0
  10. data/app/views/jcontroller/_execute_jaction.js.erb +1 -0
  11. data/gemfiles/Gemfile-rails.4.0.x +9 -0
  12. data/gemfiles/Gemfile-rails.4.1.x +9 -0
  13. data/jcontroller.gemspec +32 -0
  14. data/lib/jcontroller/controller_helpers.rb +62 -0
  15. data/lib/jcontroller/engine.rb +16 -0
  16. data/lib/jcontroller/filter.rb +39 -0
  17. data/lib/jcontroller/jaction.rb +91 -0
  18. data/lib/jcontroller/version.rb +3 -0
  19. data/lib/jcontroller/view_helpers.rb +4 -0
  20. data/lib/jcontroller.rb +12 -0
  21. data/spec/fake_app/app/assets/javascripts/application.js +32 -0
  22. data/spec/fake_app/app/assets/javascripts/jcontrollers/admin/admins_jcontroller.js +1 -0
  23. data/spec/fake_app/app/assets/javascripts/jcontrollers/application_jcontroller.js +1 -0
  24. data/spec/fake_app/app/assets/javascripts/jcontrollers/superusers_jcontroller.js +1 -0
  25. data/spec/fake_app/app/assets/javascripts/jcontrollers/users_jcontroller.js +1 -0
  26. data/spec/fake_app/app/controllers.rb +46 -0
  27. data/spec/fake_app/app/helpers.rb +1 -0
  28. data/spec/fake_app/app/views/admin/users/index.html.erb +0 -0
  29. data/spec/fake_app/app/views/layouts/application.html.erb +10 -0
  30. data/spec/fake_app/app/views/superusers/index.html.erb +0 -0
  31. data/spec/fake_app/app/views/users/action_and_parameters.html.erb +0 -0
  32. data/spec/fake_app/app/views/users/different_action.html.erb +0 -0
  33. data/spec/fake_app/app/views/users/index.html.erb +0 -0
  34. data/spec/fake_app/app/views/users/index.js.jbuilder +1 -0
  35. data/spec/fake_app/app/views/users/manual_parameters.html.erb +0 -0
  36. data/spec/fake_app/app/views/users/manually_execute.html.erb +1 -0
  37. data/spec/fake_app/app/views/users/no_action.html.erb +0 -0
  38. data/spec/fake_app/app/views/users/parameters_template.html.erb +0 -0
  39. data/spec/fake_app/app/views/users/parameters_template_params.js.jbuilder +1 -0
  40. data/spec/fake_app/app/views/users/redirect_params.js.jbuilder +1 -0
  41. data/spec/fake_app/app/views/users/state.html.erb +0 -0
  42. data/spec/fake_app/app/views/users/stopped.html.erb +1 -0
  43. data/spec/fake_app/fake_app.rb +29 -0
  44. data/spec/fake_app/routes.rb +20 -0
  45. data/spec/features/jcontroller/action_spec.rb +60 -0
  46. data/spec/features/jcontroller_spec.rb +112 -0
  47. data/spec/spec_helper.rb +10 -0
  48. data/spec/support/wait_for_ajax.rb +15 -0
  49. metadata +245 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 7bfcee10ac94a9114e9d0ece81aa09c870564af1
4
+ data.tar.gz: 504a7afa731f155ac463574b2f9d56b832115e7c
5
+ SHA512:
6
+ metadata.gz: aec42bf2c4cab2d34187deac8853fabc2515b746fc61fd72d520b24f2b103636b3f7266e9feeaa30f7e51718cdf0b1756eb2d9061bf1c8441f2c07261b98af48
7
+ data.tar.gz: 9707c39a865653f525571dffd36ca34ea5ba3715add9f5d8704311a342fd50a35e33596bf365c9a5aaf33958814f8c4b9664d91d55f4fa45484f8af0900ef1ec
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+
19
+ .idea/*
20
+ spec/fake_app/log/*
data/.travis.yml ADDED
@@ -0,0 +1,13 @@
1
+ language: ruby
2
+ script: rspec
3
+ rvm:
4
+ - 1.9.3
5
+ - 2.0.0
6
+ - 2.1.0
7
+ - ruby-head
8
+ gemfile:
9
+ - gemfiles/Gemfile-rails.4.0.x
10
+ - gemfiles/Gemfile-rails.4.1.x
11
+ matrix:
12
+ allow_failures:
13
+ - rvm: ruby-head
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in jcontroller.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Steve Chung
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Jcontroller
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'jcontroller'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install jcontroller
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/jcontroller/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,82 @@
1
+ var Jcontroller = {
2
+ controllers_path: 'Jcontroller/controllers/',
3
+ application_controller_path: "application",
4
+ create: function(controller_path, definition) {
5
+ Jcontroller.define_namespace(Jcontroller.controllers_path + controller_path,
6
+ $.extend({
7
+ parent_path: controller_path === this.application_controller_path ? undefined : "application",
8
+ parent: function() {
9
+ if (Jcontroller.blank(this.parent_cache)) {
10
+ this.parent_cache = Jcontroller.find(this.parent_path);
11
+ }
12
+ return this.parent_cache;
13
+ },
14
+
15
+ dup: function(state, params) {
16
+ var dup = $.extend({}, this, state.jaction);
17
+ dup.state = state;
18
+ dup.params = params;
19
+ if (Jcontroller.present(dup.parent())) dup.parent_cache = dup.parent().dup(state, params);
20
+ return dup;
21
+ },
22
+
23
+ execute_action: function() {
24
+ if ($.isPlainObject(this.html)) {
25
+ this.execute_post_order_filter('before');
26
+ this.execute_post_order_filter(this.action_name);
27
+ this.execute_pre_order_filter('after');
28
+ }
29
+ },
30
+ execute_post_order_filter: function(filter) {
31
+ if (Jcontroller.present(this.parent())) this.parent().execute_post_order_filter(filter);
32
+ this.execute_filter(this[this.format][filter]);
33
+ },
34
+ execute_pre_order_filter: function(filter) {
35
+ this.execute_filter(this[this.format][filter]);
36
+ if (Jcontroller.present(this.parent())) this.parent().execute_pre_order_filter(filter);
37
+ },
38
+ execute_filter: function(filter) {
39
+ if ($.isFunction(filter)) $.proxy(filter, this)();
40
+ }
41
+ },
42
+ definition
43
+ )
44
+ );
45
+ },
46
+ execute_jaction: function(state, params) {
47
+ var controller = this.find(state.jaction.controller_path);
48
+ if (this.present(controller)) {
49
+ controller.dup(state, params).execute_action();
50
+ }
51
+ },
52
+
53
+ blank: function(o) { return typeof o === "undefined" || o === null; },
54
+ present: function(o) { return !this.blank(o); },
55
+
56
+ define_namespace: function(namespace_string, definition) {
57
+ return $.extend(this.get_or_create(namespace_string), definition);
58
+ },
59
+ get_or_create: function(namespace_string) {
60
+ var current_namepace = window;
61
+ $.each(namespace_string.split('/'), function(index, level) {
62
+ if (Jcontroller.blank(current_namepace[level])) current_namepace[level] = {};
63
+ current_namepace = current_namepace[level];
64
+ });
65
+
66
+ return current_namepace;
67
+ },
68
+ find: function(controller_path) {
69
+ if (this.blank(controller_path)) return undefined;
70
+ var namespace_string = this.controllers_path + controller_path;
71
+
72
+ var current_namepace = window;
73
+ $.each(namespace_string.split('/'), function(index, level) {
74
+ if (Jcontroller.blank(current_namepace[level])) {
75
+ current_namepace = undefined;
76
+ return false;
77
+ }
78
+ current_namepace = current_namepace[level];
79
+ });
80
+ return current_namepace;
81
+ }
82
+ };
@@ -0,0 +1 @@
1
+ <script>Jcontroller.page_jaction=function(){Jcontroller.execute_jaction(<%= raw jaction.to_params %>);}; Jcontroller.page_jaction();</script>
@@ -0,0 +1 @@
1
+ (function(){Jcontroller.execute_jaction(<%= raw jaction.to_params %>);})();
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'jcontroller', :path => '..'
4
+
5
+ gem 'rails', '~> 4.0.0'
6
+ gem 'rspec-rails'
7
+ gem 'poltergeist'
8
+ gem 'jbuilder'
9
+ gem 'jquery-rails'
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'jcontroller', :path => '..'
4
+
5
+ gem 'rails', '~> 4.1.0'
6
+ gem 'rspec-rails'
7
+ gem 'poltergeist'
8
+ gem 'jbuilder'
9
+ gem 'jquery-rails'
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'jcontroller/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "jcontroller"
8
+ spec.version = Jcontroller::VERSION
9
+ spec.authors = ["Steve Chung"]
10
+ spec.email = ["steve.chung7@gmail.com"]
11
+ spec.summary = %q{ Controller based javascript outside of your view files. }
12
+ spec.description = %q{ DOM-based Routing for Rails controller based javascript. }
13
+ spec.homepage = "https://github.com/s12chung/jcontroller"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency 'rails', '>= 3.2'
22
+ spec.add_dependency 'request_store'
23
+
24
+ spec.add_development_dependency "bundler"
25
+ spec.add_development_dependency "rake"
26
+
27
+ spec.add_development_dependency "rspec-rails"
28
+ spec.add_development_dependency "poltergeist"
29
+ spec.add_development_dependency "launchy"
30
+ spec.add_development_dependency "jbuilder"
31
+ spec.add_development_dependency "jquery-rails"
32
+ end
@@ -0,0 +1,62 @@
1
+ module Jcontroller
2
+ module ControllerHelpers
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ helper_method :execute_jaction
7
+ end
8
+
9
+ protected
10
+ def js(jaction, options={})
11
+ if jaction == false
12
+ @stop_jaction = true
13
+ else
14
+ self.jaction.parse(jaction)
15
+ if jaction.class.ancestors.include? Hash; options = jaction end
16
+ if options[:params]; self.jaction.parse options end
17
+ if options[:redirect]; flash[:jaction] = self.jaction.to_s end
18
+ end
19
+ end
20
+
21
+ def execute_flash_jaction
22
+ flash[:jaction] ? execute_jaction(flash[:jaction]) : "".html_safe
23
+ end
24
+ def execute_jaction(jaction=self.jaction, options={})
25
+ jaction = Jaction.new(jaction)
26
+ if options.has_key? :params; jaction.parse options end
27
+ view_context.render(
28
+ :partial => 'jcontroller/execute_jaction',
29
+ :locals => {
30
+ jaction: jaction
31
+ }
32
+ )
33
+ end
34
+
35
+ #http://stackoverflow.com/questions/339130/how-do-i-render-a-partial-of-a-different-format-in-rails
36
+ def with_format(format, &block)
37
+ old_formats = formats
38
+ self.formats = [format]
39
+ result = block.call
40
+ self.formats = old_formats
41
+ result
42
+ end
43
+
44
+ def jcontroller_state
45
+ {
46
+ controller_path: controller_path,
47
+ action_name: action_name,
48
+ method: request.method,
49
+ path: request.env['PATH_INFO'],
50
+ format: formats.first
51
+ }
52
+ end
53
+
54
+ def jcontroller_params(action)
55
+ with_format :js do
56
+ if lookup_context.template_exists? action.params_template_path
57
+ view_context.render(:template => action.params_template_path)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,16 @@
1
+ module Jcontroller
2
+ if defined?(Rails) && defined?(Rails::Engine)
3
+ class Engine < Rails::Engine
4
+ initializer "jcontroller.view_helpers" do
5
+ ActionView::Base.send :include, ViewHelpers
6
+ end
7
+
8
+ initializer 'jcontroller.controller' do
9
+ ActiveSupport.on_load(:action_controller) do
10
+ ActionController::Base.send :include, ControllerHelpers
11
+ ActionController::Base.send :include, Filter
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,39 @@
1
+ module Jcontroller
2
+ module Filter
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ append_before_filter :set_jaction_controller
7
+ append_before_filter :set_jaction
8
+ append_after_filter :append_execute_jaction, unless: :redirect?
9
+
10
+ helper_method :jaction
11
+ end
12
+
13
+ protected
14
+ def jaction; @jaction end
15
+ def set_jaction; @jaction = Jcontroller::Jaction.new end
16
+
17
+ def set_jaction_controller; Jcontroller::Jaction.controller = self end
18
+
19
+ def redirect?; self.status == 302 end
20
+ def append_execute_jaction
21
+ unless @stop_jaction
22
+ if formats.first == :html
23
+ jactions = execute_flash_jaction + execute_jaction
24
+ partition_index = response_body[0].rindex('</body>')
25
+
26
+ if partition_index
27
+ head = response_body[0][0, partition_index].html_safe
28
+ rail = response_body[0][partition_index..-1].html_safe
29
+ response.body = head + jactions + rail
30
+ else
31
+ response.body += jactions
32
+ end
33
+ else
34
+ response.body = execute_jaction({ :params => response.body })
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,91 @@
1
+ module Jcontroller
2
+ class Jaction
3
+ ATTRIBUTES = %w[controller_path action_name format params]
4
+ attr_accessor *ATTRIBUTES
5
+
6
+ def initialize(jaction=nil)
7
+ if self.class.controller
8
+ self.controller_path = self.class.controller.controller_path
9
+ self.action_name = self.class.controller.action_name
10
+ self.format = self.class.controller.formats.first
11
+ end
12
+ self.params = {}
13
+
14
+ if jaction
15
+ parse(jaction)
16
+ end
17
+ end
18
+
19
+ def parse(jaction)
20
+ if jaction.class == Jaction
21
+ ATTRIBUTES.each do |attribute|
22
+ self.send(attribute + "=", jaction.send(attribute))
23
+ end
24
+ elsif jaction.class.ancestors.include? Hash
25
+ hash = HashWithIndifferentAccess.new(jaction)
26
+ ATTRIBUTES.each do |attribute|
27
+ if hash[attribute]; self.send(attribute + "=", hash[attribute]) end
28
+ end
29
+ else
30
+ match = jaction.match /(.+(?=\/|#))(?:[\/#](.+?(?=\.|\?|\z))(?:\.(.+?)(?=\?|\z)(?:\?(.+(?=\z)))?)?)?/
31
+ if match
32
+ %w[controller_path action_name format].zip((1..3)).each do |attribute, match_index|
33
+ value = match[match_index]
34
+ if value; send(attribute + "=", value) end
35
+ end
36
+ self.params = Rack::Utils.parse_nested_query(match[4])
37
+ if params[:jaction_params]; self.params = params[:jaction_params] end
38
+ else
39
+ self.action_name = jaction
40
+ end
41
+ end
42
+ end
43
+
44
+ def to_params
45
+ [state.to_json, string_params].join(",")
46
+ end
47
+
48
+ def state
49
+ self.class.controller.send(:jcontroller_state).merge({
50
+ jaction: {
51
+ controller_path: controller_path,
52
+ action_name: action_name,
53
+ format: format
54
+ }
55
+ })
56
+ end
57
+
58
+ def params_template_path
59
+ "#{controller_path}/#{action_name}_params"
60
+ end
61
+
62
+ def format=(format)
63
+ @format = format.to_sym
64
+ end
65
+ def params=(params)
66
+ @params = params.class == String ? params : HashWithIndifferentAccess.new(params)
67
+ end
68
+
69
+ def to_s
70
+ s = "#{controller_path}/#{action_name}"
71
+ if format; s += ".#{format}" end
72
+ unless params.blank?; s += "?#{ (params.class == String ? { :jaction_params => params } : params).to_query }" end
73
+ s
74
+ end
75
+
76
+ protected
77
+ def string_params
78
+ self.class.controller.send(:jcontroller_params, self) || (params.class == String ? params : params.to_json)
79
+ end
80
+
81
+ class << self
82
+ def controller
83
+ RequestStore.store[:jaction_controller]
84
+ end
85
+
86
+ def controller=(controller)
87
+ RequestStore.store[:jaction_controller] = controller
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,3 @@
1
+ module Jcontroller
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,4 @@
1
+ module Jcontroller
2
+ module ViewHelpers
3
+ end
4
+ end
@@ -0,0 +1,12 @@
1
+ require 'request_store'
2
+
3
+ require "jcontroller/version"
4
+
5
+ require 'jcontroller/jaction'
6
+ require 'jcontroller/controller_helpers'
7
+ require 'jcontroller/filter'
8
+ require 'jcontroller/view_helpers'
9
+ require 'jcontroller/engine'
10
+
11
+ module Jcontroller
12
+ end
@@ -0,0 +1,32 @@
1
+ //= require jquery_ujs
2
+ //= require jcontroller
3
+ //= require_self
4
+ //= require_tree .
5
+
6
+ test_append_selector = '#test_append';
7
+ test_append = function(controller_namespace, filter, params) {
8
+ var $div = $(document.createElement('div'));
9
+ $div.attr("filter", controller_namespace + "/" + 'html' + "/" + filter);
10
+ $div.append(params.s);
11
+ $(test_append_selector).append($div);
12
+ };
13
+
14
+ create_routes = function(controller_path, extend) {
15
+ var set_basic_filters = function(format, filters) {
16
+ $.each(filters, function(index, filter) {
17
+ hash[format][filter] = function() {
18
+ test_append(controller_path, filter, this.params);
19
+ }
20
+ });
21
+ };
22
+
23
+ var hash = { html: {}, js: {} };
24
+ hash.html.state = function() {
25
+ $(test_append_selector).html(JSON.stringify(this.state));
26
+ };
27
+ set_basic_filters('html', ["before", "after", "index", "redirect", "redirect_simple",
28
+ "manually_execute", "manual_parameters", "parameters_template"]);
29
+ set_basic_filters('js', ["before", "after", "index"]);
30
+ if (Jcontroller.present(extend)) $.extend(hash, extend);
31
+ Jcontroller.create(controller_path, hash);
32
+ };
@@ -0,0 +1 @@
1
+ create_routes('admin/users');
@@ -0,0 +1 @@
1
+ create_routes('application');
@@ -0,0 +1 @@
1
+ create_routes('superusers', { parent_path: "users" });
@@ -0,0 +1 @@
1
+ create_routes('users');
@@ -0,0 +1,46 @@
1
+ class ApplicationController < ActionController::Base
2
+ self.append_view_path File.join(File.dirname(__FILE__), "views")
3
+ end
4
+
5
+ class UsersController < ApplicationController
6
+ DEFAULT_ACTIONS = %w[state no_action manually_execute parameters_template]
7
+ (%w[index] + DEFAULT_ACTIONS).each do |action|
8
+ class_eval <<-END
9
+ def #{action};end
10
+ END
11
+ end
12
+
13
+ def stopped
14
+ js false
15
+ end
16
+ def redirect
17
+ js({ :redirect => true })
18
+ redirect_to users_path
19
+ end
20
+ def redirect_simple
21
+ js({ :redirect => true, :params => { s: "redirect parameters" } })
22
+ redirect_to users_path
23
+ end
24
+ def different_action
25
+ js "users#index"
26
+ end
27
+
28
+ def manual_parameters
29
+ js :params => { :s => "manual parameters" }
30
+ end
31
+ def action_and_parameters
32
+ js "users/index", { :params => { :s => "action and manual parameters" } }
33
+ end
34
+ end
35
+
36
+ class SuperusersController < UsersController
37
+ def index
38
+ end
39
+ end
40
+
41
+ module Admin
42
+ class UsersController < ApplicationController
43
+ def index
44
+ end
45
+ end
46
+ end
@@ -0,0 +1 @@
1
+ module ApplicationHelper end
@@ -0,0 +1,10 @@
1
+ <html>
2
+ <head>
3
+ <%= javascript_include_tag "//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" %>
4
+ <%= javascript_include_tag "application" %>
5
+ </head>
6
+ <body>
7
+ <div id="test_append"></div>
8
+ <%= yield %>
9
+ </body>
10
+ </html>
File without changes
File without changes
@@ -0,0 +1 @@
1
+ json.s "ajax parameter"
@@ -0,0 +1 @@
1
+ <%= execute_jaction "users#index" %>
File without changes
@@ -0,0 +1 @@
1
+ json.s "parameter template"
@@ -0,0 +1 @@
1
+ json.s "redirect template"
File without changes
@@ -0,0 +1 @@
1
+ <%= link_to "ajax link", users_path, remote: true %>
@@ -0,0 +1,29 @@
1
+ require 'rails'
2
+ require 'action_controller/railtie'
3
+ require 'action_view/railtie'
4
+ require "sprockets/railtie"
5
+
6
+ require 'jbuilder'
7
+ require 'jquery-rails'
8
+ require 'jcontroller'
9
+
10
+ module FakeApp
11
+ class Application < Rails::Application
12
+ config.secret_token = 'Listen to your heart. Be brave. Do what you gotta do.'
13
+ config.session_store :cookie_store, :key => 'session_store'
14
+ config.active_support.deprecation = :log
15
+ config.eager_load = false
16
+
17
+ config.root = File.dirname(__FILE__)
18
+ end
19
+ end
20
+ FakeApp::Application.initialize!
21
+
22
+ %w[controllers helpers].each do |file|
23
+ require "fake_app/app/#{file}"
24
+ end
25
+
26
+ %w[routes].each do |file|
27
+ require "fake_app/#{file}"
28
+ end
29
+ ActionView::Base.send :include, ApplicationHelper
@@ -0,0 +1,20 @@
1
+ FakeApp::Application.routes.draw do
2
+ resources :users, :only => %w[index] do
3
+ collection do
4
+ UsersController::DEFAULT_ACTIONS.each do |action|
5
+ get action
6
+ end
7
+ get :stopped
8
+ get :redirect
9
+ get :redirect_simple
10
+ get :different_action
11
+ get :manual_parameters
12
+ get :action_and_parameters
13
+ end
14
+ end
15
+ resources :superusers, :only => %w[index]
16
+
17
+ namespace :admin do
18
+ resources :users, :only => %w[index]
19
+ end
20
+ end
@@ -0,0 +1,60 @@
1
+ require 'spec_helper'
2
+
3
+ describe Jcontroller::Jaction do
4
+ describe '#parse' do
5
+ before :each do
6
+ @target_jaction = Jcontroller::Jaction.new
7
+ @jaction = Jcontroller::Jaction.new
8
+ end
9
+
10
+ it "should start with empty attributes if there is no controller" do
11
+ Jcontroller::Jaction::ATTRIBUTES.each do |attribute|
12
+ @target_jaction.send(attribute).should == (attribute == "params" ? {} : nil)
13
+ end
14
+ end
15
+
16
+ def test_values(controller_path=nil, action_name=nil)
17
+ if controller_path || action_name
18
+ @target_jaction.controller_path.should == controller_path
19
+ @target_jaction.action_name.should == action_name
20
+ else
21
+ @target_jaction.controller_path.should == 0
22
+ @target_jaction.action_name.should == 1
23
+ @target_jaction.format.should == :js
24
+ @target_jaction.params.should == {}
25
+ end
26
+ end
27
+
28
+ it "should take the passed Action's attributes" do
29
+ @jaction.controller_path = 0
30
+ @jaction.action_name = 1
31
+ @jaction.format = :js
32
+ @jaction.params = {}
33
+ @target_jaction.parse(@jaction)
34
+ test_values
35
+ end
36
+
37
+ it "should take a hash" do
38
+ @target_jaction.parse(:controller_path => 0, :action_name => 1, :format => :js, :params => {})
39
+ test_values
40
+ end
41
+
42
+ it "should take just an action" do
43
+ @target_jaction.parse("index")
44
+ test_values nil, "index"
45
+ end
46
+
47
+ it "should take a # string" do
48
+ @target_jaction.parse("users#index")
49
+ test_values "users", "index"
50
+ end
51
+
52
+ it "should take a namespaced / string with a format and parameters" do
53
+ @target_jaction.parse("admin/users/index.js?blah=meh&waka=baka")
54
+ test_values "admin/users", "index"
55
+ @target_jaction.format.should == :js
56
+ @target_jaction.params[:blah].should == "meh"
57
+ @target_jaction.params[:waka].should == "baka"
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,112 @@
1
+ require 'spec_helper'
2
+
3
+ feature 'invoke correct filter', :js => true do
4
+ before :all do
5
+ @test_append_selector = '#test_append'
6
+ end
7
+
8
+ def filter_namespace(controller_namespace, filter, format="html")
9
+ "#{controller_namespace}/#{format}/#{filter}"
10
+ end
11
+
12
+ def filters(controller_namespace, action, parent_namespaces=%w[application])
13
+ controller_namespaces = parent_namespaces + [controller_namespace]
14
+ filters = []
15
+ filters += controller_namespaces.map {|controller_namespace| filter_namespace(controller_namespace, "before") }
16
+ filters += controller_namespaces.map {|controller_namespace| filter_namespace(controller_namespace, action) }
17
+ filters + controller_namespaces.map {|controller_namespace| filter_namespace(controller_namespace, "after") }.reverse
18
+ end
19
+
20
+ def test_elements(filters, parameters="")
21
+ if parameters.class == String; parameters = [parameters] * filters.size end
22
+ within @test_append_selector do
23
+ (0..filters.size-1).zip(all('div')).each do |index, div|
24
+ div[:filter].should == filters[index]
25
+ div.text.should == parameters[index]
26
+ end
27
+ end
28
+ end
29
+
30
+ it "should pass the state of the request" do
31
+ visit state_users_path
32
+ find(@test_append_selector).text.should == {
33
+ controller_path: "users",
34
+ action_name: "state",
35
+ method: "GET",
36
+ path: "/users/state",
37
+ format: "html",
38
+ jaction: {
39
+ controller_path: "users",
40
+ action_name: "state",
41
+ format: "html"
42
+ }
43
+ }.to_json
44
+ end
45
+
46
+ scenario 'with basic controller' do
47
+ visit users_path
48
+ test_elements filters('users', "index")
49
+ end
50
+ scenario 'with namespaced controller' do
51
+ visit admin_users_path
52
+ test_elements filters('admin/users', "index")
53
+ end
54
+ scenario 'with superclassed controller' do
55
+ visit superusers_path
56
+ test_elements filters('superusers', "index", %w[application users])
57
+ end
58
+
59
+ scenario 'with no action defined' do
60
+ visit no_action_users_path
61
+ test_elements filters('users', "no_action").delete_if {|namespace| namespace.rindex "no_action" }
62
+ end
63
+
64
+ scenario "with manual execution" do
65
+ visit manually_execute_users_path
66
+ test_elements (filters('users', "index") + filters('users', 'manually_execute'))
67
+ end
68
+
69
+ scenario "when stopped" do
70
+ visit stopped_users_path
71
+ within @test_append_selector do
72
+ all('div').size.should == 0
73
+ end
74
+ end
75
+ scenario "when redirected" do
76
+ visit redirect_users_path
77
+ redirect_filters = filters('users', "redirect")
78
+ index_filters = filters('users', "index")
79
+ test_elements redirect_filters + index_filters, ["redirect template"] * redirect_filters.size + [""] * redirect_filters.size
80
+ end
81
+ scenario "when redirected with parameters template" do
82
+ visit redirect_simple_users_path
83
+ redirect_filters = filters('users', "redirect_simple")
84
+ index_filters = filters('users', "index")
85
+ test_elements redirect_filters + index_filters, ["redirect parameters"] * redirect_filters.size + [""] * redirect_filters.size
86
+ end
87
+ scenario "with different action" do
88
+ visit different_action_users_path
89
+ test_elements filters('users', "index")
90
+ end
91
+ scenario 'with parameters' do
92
+ visit manual_parameters_users_path
93
+ test_elements filters('users', "manual_parameters"), "manual parameters"
94
+ end
95
+ scenario "with different action and parameters" do
96
+ visit action_and_parameters_users_path
97
+ test_elements filters('users', "index"), "action and manual parameters"
98
+ end
99
+ scenario 'with parameters template' do
100
+ visit parameters_template_users_path
101
+ test_elements filters('users', "parameters_template"), "parameter template"
102
+ end
103
+
104
+ context "with ajax" do
105
+ scenario "basic controller" do
106
+ visit stopped_users_path
107
+ click_link "ajax link"
108
+ wait_for_ajax
109
+ test_elements filters('users', "index"), "ajax parameter"
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,10 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+
4
+ Dir[File.join(File.dirname(__FILE__), "support/**/*.rb")].each {|f| require f}
5
+
6
+ require 'fake_app/fake_app'
7
+ require 'rspec/rails'
8
+
9
+ require 'capybara/poltergeist'
10
+ Capybara.javascript_driver = :poltergeist
@@ -0,0 +1,15 @@
1
+ module WaitForAjax
2
+ def wait_for_ajax
3
+ Timeout.timeout(Capybara.default_wait_time) do
4
+ loop until finished_all_ajax_requests?
5
+ end
6
+ end
7
+
8
+ def finished_all_ajax_requests?
9
+ page.evaluate_script('jQuery.active').zero?
10
+ end
11
+ end
12
+
13
+ RSpec.configure do |config|
14
+ config.include WaitForAjax, type: :feature
15
+ end
metadata ADDED
@@ -0,0 +1,245 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jcontroller
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Steve Chung
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-06-15 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: request_store
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-rails
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: poltergeist
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: launchy
99
+ requirement: !ruby/object:Gem::Requirement
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
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: jbuilder
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: jquery-rails
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ description: " DOM-based Routing for Rails controller based javascript. "
140
+ email:
141
+ - steve.chung7@gmail.com
142
+ executables: []
143
+ extensions: []
144
+ extra_rdoc_files: []
145
+ files:
146
+ - ".gitignore"
147
+ - ".travis.yml"
148
+ - Gemfile
149
+ - LICENSE.txt
150
+ - README.md
151
+ - Rakefile
152
+ - app/assets/javascripts/jcontroller.js
153
+ - app/views/jcontroller/_execute_jaction.html.erb
154
+ - app/views/jcontroller/_execute_jaction.js.erb
155
+ - gemfiles/Gemfile-rails.4.0.x
156
+ - gemfiles/Gemfile-rails.4.1.x
157
+ - jcontroller.gemspec
158
+ - lib/jcontroller.rb
159
+ - lib/jcontroller/controller_helpers.rb
160
+ - lib/jcontroller/engine.rb
161
+ - lib/jcontroller/filter.rb
162
+ - lib/jcontroller/jaction.rb
163
+ - lib/jcontroller/version.rb
164
+ - lib/jcontroller/view_helpers.rb
165
+ - spec/fake_app/app/assets/javascripts/application.js
166
+ - spec/fake_app/app/assets/javascripts/jcontrollers/admin/admins_jcontroller.js
167
+ - spec/fake_app/app/assets/javascripts/jcontrollers/application_jcontroller.js
168
+ - spec/fake_app/app/assets/javascripts/jcontrollers/superusers_jcontroller.js
169
+ - spec/fake_app/app/assets/javascripts/jcontrollers/users_jcontroller.js
170
+ - spec/fake_app/app/controllers.rb
171
+ - spec/fake_app/app/helpers.rb
172
+ - spec/fake_app/app/views/admin/users/index.html.erb
173
+ - spec/fake_app/app/views/layouts/application.html.erb
174
+ - spec/fake_app/app/views/superusers/index.html.erb
175
+ - spec/fake_app/app/views/users/action_and_parameters.html.erb
176
+ - spec/fake_app/app/views/users/different_action.html.erb
177
+ - spec/fake_app/app/views/users/index.html.erb
178
+ - spec/fake_app/app/views/users/index.js.jbuilder
179
+ - spec/fake_app/app/views/users/manual_parameters.html.erb
180
+ - spec/fake_app/app/views/users/manually_execute.html.erb
181
+ - spec/fake_app/app/views/users/no_action.html.erb
182
+ - spec/fake_app/app/views/users/parameters_template.html.erb
183
+ - spec/fake_app/app/views/users/parameters_template_params.js.jbuilder
184
+ - spec/fake_app/app/views/users/redirect_params.js.jbuilder
185
+ - spec/fake_app/app/views/users/state.html.erb
186
+ - spec/fake_app/app/views/users/stopped.html.erb
187
+ - spec/fake_app/fake_app.rb
188
+ - spec/fake_app/routes.rb
189
+ - spec/features/jcontroller/action_spec.rb
190
+ - spec/features/jcontroller_spec.rb
191
+ - spec/spec_helper.rb
192
+ - spec/support/wait_for_ajax.rb
193
+ homepage: https://github.com/s12chung/jcontroller
194
+ licenses:
195
+ - MIT
196
+ metadata: {}
197
+ post_install_message:
198
+ rdoc_options: []
199
+ require_paths:
200
+ - lib
201
+ required_ruby_version: !ruby/object:Gem::Requirement
202
+ requirements:
203
+ - - ">="
204
+ - !ruby/object:Gem::Version
205
+ version: '0'
206
+ required_rubygems_version: !ruby/object:Gem::Requirement
207
+ requirements:
208
+ - - ">="
209
+ - !ruby/object:Gem::Version
210
+ version: '0'
211
+ requirements: []
212
+ rubyforge_project:
213
+ rubygems_version: 2.2.2
214
+ signing_key:
215
+ specification_version: 4
216
+ summary: Controller based javascript outside of your view files.
217
+ test_files:
218
+ - spec/fake_app/app/assets/javascripts/application.js
219
+ - spec/fake_app/app/assets/javascripts/jcontrollers/admin/admins_jcontroller.js
220
+ - spec/fake_app/app/assets/javascripts/jcontrollers/application_jcontroller.js
221
+ - spec/fake_app/app/assets/javascripts/jcontrollers/superusers_jcontroller.js
222
+ - spec/fake_app/app/assets/javascripts/jcontrollers/users_jcontroller.js
223
+ - spec/fake_app/app/controllers.rb
224
+ - spec/fake_app/app/helpers.rb
225
+ - spec/fake_app/app/views/admin/users/index.html.erb
226
+ - spec/fake_app/app/views/layouts/application.html.erb
227
+ - spec/fake_app/app/views/superusers/index.html.erb
228
+ - spec/fake_app/app/views/users/action_and_parameters.html.erb
229
+ - spec/fake_app/app/views/users/different_action.html.erb
230
+ - spec/fake_app/app/views/users/index.html.erb
231
+ - spec/fake_app/app/views/users/index.js.jbuilder
232
+ - spec/fake_app/app/views/users/manual_parameters.html.erb
233
+ - spec/fake_app/app/views/users/manually_execute.html.erb
234
+ - spec/fake_app/app/views/users/no_action.html.erb
235
+ - spec/fake_app/app/views/users/parameters_template.html.erb
236
+ - spec/fake_app/app/views/users/parameters_template_params.js.jbuilder
237
+ - spec/fake_app/app/views/users/redirect_params.js.jbuilder
238
+ - spec/fake_app/app/views/users/state.html.erb
239
+ - spec/fake_app/app/views/users/stopped.html.erb
240
+ - spec/fake_app/fake_app.rb
241
+ - spec/fake_app/routes.rb
242
+ - spec/features/jcontroller/action_spec.rb
243
+ - spec/features/jcontroller_spec.rb
244
+ - spec/spec_helper.rb
245
+ - spec/support/wait_for_ajax.rb