jskit_rails 2.0.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: bcd9fbda4dcb8214247e55f4b44a5cc97e9b5d83
4
- data.tar.gz: 645875d832923ce32348206255e18f544df2f486
3
+ metadata.gz: c91237c5bcdcaf3e07c63d3ea1d8fdf695f3d8cc
4
+ data.tar.gz: a97db69c109e60868568b1c96f700f1ceddbe860
5
5
  SHA512:
6
- metadata.gz: 0f0ce3d5b2cf5f534c142a53db851957cd1f7025853106e4266e854d026cb89f993df5097c13b6512601dc901e56cc1d7d697e83ec30c6dbcfac8b7285892d17
7
- data.tar.gz: 00f8b09e5ec97a0ebe0f40406be07e20a33969cd4dfd81366586b9aa8eca0d3a0f7d5c1267b2f90c7b0976920b7eceeb010f28d5a55100a4d99ddd6445f29243
6
+ metadata.gz: cd161b20e817067d9aba06c9237685fe769eb525b6f1291435e1cfbce738cb7f4619fa8d2356ee8de88d1db6af713e4cf50838f57669103db1c4d87c8152717e
7
+ data.tar.gz: 0db0caed9c124a807fb1409987c6cc03f342d6f53cea306a0fe7100fb2c1cecc3a48ae4846594639a3e05164dd3c5655722090568a2cd955a2c14ac2c7625b61
data/README.md CHANGED
@@ -18,6 +18,9 @@ Bundle it up:
18
18
  bundle install
19
19
  ```
20
20
 
21
+ Usage
22
+ -----
23
+
21
24
  Add the `jskit` helper to your layout (i.e. `app/views/layouts/application.html.erb`):
22
25
 
23
26
  ```html
@@ -30,26 +33,169 @@ Add the jskit javascript (i.e. `app/assets/javascripts/application.js`):
30
33
  //= require jskit_rails
31
34
  ```
32
35
 
33
- That's it, now all controller actions will be triggered on the `JSKit` dispatcher. For example, assume you have a `PagesController` with an `index` action. When we visit the `pages#index` page the `jskit` helper will trigger the appropriate event:
36
+ That's it, now all controller actions will be triggered on the `JSKit` dispatcher.
37
+
38
+ ### Controllers
39
+
40
+ JSKit offers controllers as a basic building block for JavaScript functionality. Making a folder inside `app/assets/javascripts` named `controllers` is a great place to put these:
41
+
42
+ ```sh
43
+ mkdir app/assets/javascripts/controllers
44
+ ```
45
+
46
+ Now simply require that entire directory in your `application.js` file:
34
47
 
35
48
  ```js
49
+ //= require_tree ./controllers
50
+ ```
51
+
52
+ #### Events
53
+
54
+ There are three events triggered on every page rendered: an application controller global event, a controller global event and a controller action event. Given a `Posts` controller, when rendering the `index` action, you will notice the three events triggered where the `<%= jskit %>` snippet was placed:
55
+
56
+ ```js
57
+ App.Dispatcher.trigger("controller:application:all");
58
+ App.Dispatcher.trigger("controller:pages:all");
36
59
  App.Dispatcher.trigger("controller:pages:index");
37
60
  ```
38
61
 
39
- If you wish to pass data to the event handler, simply set the payload from the controller:
62
+ This allows you to integrate your JavaScript at key points in your rails application with minimal coupling. An event triggered with no corresponding `JSKit` controller or action defined has no effect.
63
+
64
+ #### Application Controller
65
+
66
+ It's common to have some JavaScript that runs on every page of your application. In the past, you may have slapped random bits of code inside a jQuery `$(document).ready` block but not with JSKit. JSKit makes an explicit yet minimally coupled connection between your Rails app and your client-side code. To define application-wide behavior, define an application controller in `app/assets/controller/application_controller.js`:
67
+
68
+ ```js
69
+ App.createController("Application", {
70
+ all: function() {
71
+ // This handler will be triggered on all pages
72
+ }
73
+ });
74
+ ```
75
+
76
+ The `all` method is automatically wired to the `controller:application:all` event, which is automatically triggered on each page via the `<%= jskit %>` snippet. You now have a simple, testable controller to define behavior in your application.
77
+
78
+ All other controllers are defined in the same way, the only difference is that your other controllers will have actions defined. Assuming you have a `Posts` controller in ruby, whose index action needs a bit of JavaScript to spice up the template. You would simply create a corresponding `Posts` controller in `app/assets/javascripts/posts_controller.js`:
79
+
80
+ ```js
81
+ App.createController("Posts", {
82
+ actions: ["index"],
83
+
84
+ index: function() {
85
+ // do stuff on the index page
86
+ }
87
+ });
88
+ ```
89
+
90
+ Here you can see that the `actions` array tells JSKit to wire up the `index` method to the `controller:posts:index` event. This event is automatically fired by the `<%= jskit %>` snippet.
91
+
92
+ #### Mapped Events
93
+
94
+ Sometimes you may want to map and action to a method with a different name, or you may want to map multiple actions to the same method. This is accomplished using mapped actions. Instead of using a string in the actions array, use an object to map the action name to the controller's method:
95
+
96
+ ```js
97
+ App.createController("Posts", {
98
+ actions: [
99
+ "index",
100
+ { new: "setupForm" },
101
+ { edit: "setupForm" },
102
+ { create: "setupForm" }
103
+ ],
104
+
105
+ index: function() {
106
+ // do stuff on the index page
107
+ },
108
+
109
+ setupForm: function() {
110
+ // setup the posts form
111
+ }
112
+ });
113
+ ```
114
+
115
+ Here you can see that the `new`, `edit`, and `create` actions are all being wired up to the same method `setupForm`. This allows you to reuse common behavior that is needed accross multiple actions.
116
+
117
+ Finally, you may wish to have some functionality that runs on every action of a controller, to do this, simply define an all method. The `all` method is automatically wired to the `controller:<controller name>:all` event:
118
+
119
+ ```js
120
+ App.createController("Posts", {
121
+ ...
122
+
123
+ all: function() {
124
+ // do something on every action of the controller
125
+ },
126
+
127
+ ...
128
+ });
129
+ ```
130
+
131
+ This event structure is a simple and powerful way to coordinate your Rails application with the client-side code.
132
+
133
+ ### Event Payloads
134
+
135
+ In addition to simply triggering events, you may optionally pass data to these events. You can pass arbitrary data to any of the three events triggered on page render. To pass data to the application controller's `all` event:
136
+
40
137
 
41
138
  ```rb
42
- class PagesController < ApplicationController
43
- def index
44
- set_jskit_payload("foo", [1, 2, 3], { some: "object" })
139
+ class ApplicationController < ApplicationController
140
+ before_action :set_jskit_payload
141
+
142
+ ...
143
+
144
+ private
145
+
146
+ def set_jskit_payload
147
+ set_app_payload(current_user)
45
148
  end
46
149
  end
47
150
  ```
48
151
 
49
- Everything passed to `set_payload` will be converted to json for you (via `to_json`) and passed to the dispatcher:
152
+ This will pass the current user object to the `Application` controller. You can set the payload as an array if you wish to pass multiple values:
153
+
154
+ ```rb
155
+ class ApplicationController < ApplicationController
156
+ before_action :set_jskit_payload
157
+
158
+ ...
159
+
160
+ private
161
+
162
+ def set_jskit_payload
163
+ set_app_payload(current_user, [1, 2, 3], { some: "hash" })
164
+ end
165
+ end
166
+ ```
167
+
168
+ This will pass each item in the array as an argument to the event handler on the controller. Note that each item will have `to_json` called on it automatically, so there is no need to do it yourself. The above example will produce the following triggered event:
50
169
 
51
170
  ```js
52
- App.Dispatcher.trigger("controller:pages:index", "foo", [1, 2, 3], { "some": "object" });
171
+ ...
172
+ App.Dispatcher.trigger("controller:application:all", { first_name: "John", last_name: "Doe" }, [1, 2, 3], { "some": "hash" });
173
+ ...
53
174
  ```
54
175
 
55
- Here is an example application using `jskit_rails`: [jskit_rails-example](https://github.com/daytonn/jskit_rails-example)
176
+ This allows you to share data from your Rails app without explicit knowldge of how your client-side code will consume it. You may also set the controller and action event payloads in the same way:
177
+
178
+ ```rb
179
+ class PostsController < ApplicationController
180
+ before_action :set_jskit_payload
181
+
182
+ def index
183
+ set_action_payload("PostsController#index")
184
+ end
185
+
186
+ private
187
+
188
+ def set_jskit_payload
189
+ set_controller_payload("PostsController")
190
+ end
191
+ end
192
+ ```
193
+
194
+ This should be everything you need to design and test basic client-side interactions with JSKit. If you'd like to see a working example check out [this repo](https://github.com/daytonn/jskit_rails-example).
195
+
196
+ Traceur Compiler
197
+ ----------------
198
+
199
+ The [jskit](https://github.com/daytonn/jskit) library is written with JavaScript [ES6 features](https://github.com/google/traceur-compiler/wiki/LanguageFeatures) using the [Traceur compiler](https://github.com/google/traceur-compiler). The [traceur runtime](https://github.com/google/traceur-compiler/wiki/Building-custom-Traceur-runtimes) is included in jskit to provide these features.
200
+
201
+ _Note: While the traceur-runtime is included with jskit, if you wish to write your own code with ES6 features, you will need a separate traceur-compiler for use with the asset pipeline. Something like: [sprockets-traceur](https://github.com/gunpowderlabs/sprockets-traceur) or [traceur-rails](https://github.com/aackerman/traceur-rails). You would not need to include the `traceur-runtime` from these tools since it is included in the jskit library itself. All of your es6 scripts would need to be loaded after jskit to take advantage of it's included runtime._
@@ -1,68 +1,59 @@
1
1
  ApplicationController.class_eval do
2
2
  helper_method :jskit
3
3
 
4
- module JSKit
5
- mattr_reader :action_payload, :app_payload, :controller_payload
6
- mattr_accessor :event_namespace, :controller_name, :action_name
7
-
8
- def action_payload=(payload)
9
- @@action_payload = payload_js([*payload])
10
- end
11
-
12
- def controller_payload=(payload)
13
- @@controller_payload = payload_js([*payload])
14
- end
4
+ def jskit(config = { namespace: nil })
5
+ events = [
6
+ application_event(config),
7
+ controller_event(config),
8
+ action_event(config)
9
+ ].join("\n")
15
10
 
16
- def app_payload=(payload)
17
- @@app_payload = payload_js([*payload])
18
- end
11
+ view_context.javascript_tag(events)
12
+ end
19
13
 
20
- private
14
+ def set_action_payload(*args)
15
+ @action_payload = payload_js(args)
16
+ end
21
17
 
22
- def action_event
23
- [
24
- JskitRails.configuration.app_namespace,
25
- "Dispatcher",
26
- %Q(trigger("#{[event_namespace, "controller", controller_name, action_name].compact.join(":")}"#{JSKit.action_payload});)
27
- ].join(".")
28
- end
18
+ def set_controller_payload(*args)
19
+ @controller_payload = payload_js(args)
20
+ end
29
21
 
30
- def controller_event
31
- [
32
- JskitRails.configuration.app_namespace,
33
- "Dispatcher",
34
- %Q(trigger("#{[event_namespace, "controller", controller_name, "all"].compact.join(":")}"#{JSKit.controller_payload});)
35
- ].join(".")
36
- end
22
+ def set_app_payload(*args)
23
+ @app_payload = payload_js(args)
24
+ end
37
25
 
26
+ private
38
27
 
39
- def application_event
40
- [
41
- JskitRails.configuration.app_namespace,
42
- "Dispatcher",
43
- %Q(trigger("#{[event_namespace, "controller", "application", "all"].compact.join(":")}"#{JSKit.app_payload});)
44
- ].join(".")
45
- end
28
+ def payload_js(payload)
29
+ comma = ", "
30
+ comma + payload.map(&:to_json).join(comma)
31
+ end
46
32
 
47
- def payload_js(payload)
48
- payload.empty? ? "" : ", #{payload.map(&:to_json).join(', ')}"
49
- end
33
+ def action_event(config)
34
+ build_event_trigger(config, controller_name, action_name, @action_payload)
35
+ end
50
36
 
51
- module_function(
52
- :action_payload=,
53
- :app_payload=,
54
- :controller_payload=,
55
- :payload_js,
56
- :application_event,
57
- :action_event,
58
- :controller_event)
37
+ def controller_event(config)
38
+ build_event_trigger(config, controller_name, "all", @controller_payload)
59
39
  end
60
40
 
61
- def jskit(config = { namespace: nil })
62
- JSKit.event_namespace = config[:namespace]
63
- JSKit.controller_name = controller_name
64
- JSKit.action_name = action_name
41
+ def application_event(config)
42
+ build_event_trigger(config, "application", "all", @app_payload)
43
+ end
65
44
 
66
- view_context.javascript_tag [JSKit.application_event, JSKit.controller_event, JSKit.action_event].join("\n")
45
+ def build_event_trigger(config, middle_namespace, final_namespace, payload)
46
+ event = [
47
+ config[:namespace],
48
+ "controller",
49
+ middle_namespace,
50
+ final_namespace
51
+ ].compact.join(":")
52
+
53
+ [
54
+ JskitRails.configuration.app_namespace,
55
+ "Dispatcher",
56
+ %Q(trigger("#{event}"#{payload});)
57
+ ].join(".")
67
58
  end
68
59
  end
@@ -1,43 +1,59 @@
1
1
  require "rails_helper"
2
2
 
3
- describe ApplicationController, type: :controller do
4
- describe "#action_payload" do
5
- it "sets the action_payload to an array of the arguments passed" do
6
- ApplicationController::JSKit.action_payload = "foo"
7
- expect(ApplicationController::JSKit.action_payload).to eq(', "foo"')
8
- ApplicationController::JSKit.action_payload = ["foo", "bar", "baz"]
9
- expect(ApplicationController::JSKit.action_payload).to eq(', "foo", "bar", "baz"')
10
- end
11
- end
3
+ class OrdersController < ApplicationController
4
+ end
12
5
 
13
- describe "#controller_payload" do
14
- it "sets the controller_payload to an array of the arguments passed" do
15
- ApplicationController::JSKit.controller_payload = "foo"
16
- expect(ApplicationController::JSKit.controller_payload).to eq(', "foo"')
17
- ApplicationController::JSKit.controller_payload = ["foo", "bar", "baz"]
18
- expect(ApplicationController::JSKit.controller_payload).to eq(', "foo", "bar", "baz"')
19
- end
20
- end
6
+ describe OrdersController, type: :controller do
7
+ shared_examples "a payload setter" do |payload_type|
8
+ describe "#set_#{payload_type}_payload" do
9
+ it "sets the #{payload_type}_payload to an array of the passed arguments" do
10
+ controller.send("set_#{payload_type}_payload", "foo")
11
+ expect(assigns("#{payload_type}_payload")).to eq(', "foo"')
21
12
 
22
- describe "#app_payload" do
23
- it "sets the app_payload to an array of the arguments passed" do
24
- ApplicationController::JSKit.app_payload = "foo"
25
- expect(ApplicationController::JSKit.app_payload).to eq(', "foo"')
26
- ApplicationController::JSKit.app_payload = ["foo", "bar", "baz"]
27
- expect(ApplicationController::JSKit.app_payload).to eq(', "foo", "bar", "baz"')
13
+ controller.send("set_#{payload_type}_payload", "foo", "bar", "baz")
14
+ expect(assigns("#{payload_type}_payload")).to eq(', "foo", "bar", "baz"')
15
+
16
+ controller.send("set_#{payload_type}_payload", ["foo", "bar", "baz"])
17
+ expect(assigns("#{payload_type}_payload")).to eq(', ["foo","bar","baz"]')
18
+ end
28
19
  end
29
20
  end
30
21
 
22
+ it_behaves_like "a payload setter", :action
23
+ it_behaves_like "a payload setter", :controller
24
+ it_behaves_like "a payload setter", :app
25
+
31
26
  describe "#jskit" do
27
+ let(:view_context) { controller.view_context }
28
+
29
+ before do
30
+ controller.action_name = "action"
31
+ end
32
+
32
33
  it "returns a script tag with the global event and the controller event" do
33
- subject = ApplicationController.new
34
- allow(ApplicationController::JSKit).to receive(:controller_name) { "test_controller" }
35
- allow(ApplicationController::JSKit).to receive(:action_name) { "test_action" }
36
- application_event = ApplicationController::JSKit.send(:application_event)
37
- controller_event = ApplicationController::JSKit.send(:controller_event)
38
- action_event = ApplicationController::JSKit.send(:action_event)
39
-
40
- expect(subject.jskit).to eq(subject.view_context.javascript_tag([application_event, controller_event, action_event].join("\n")))
34
+ app_event = "App.Dispatcher.trigger(\"controller:application:all\", \"baz\");"
35
+ controller_event = "App.Dispatcher.trigger(\"controller:orders:all\", \"bar\");"
36
+ action_event = "App.Dispatcher.trigger(\"controller:orders:action\", \"foo\");"
37
+ expected_js = view_context.javascript_tag([app_event, controller_event, action_event].join("\n"))
38
+
39
+ controller.set_action_payload("foo")
40
+ controller.set_controller_payload("bar")
41
+ controller.set_app_payload("baz")
42
+
43
+ expect(controller.jskit).to eq(expected_js)
44
+ end
45
+
46
+ it "is exposed as a helper method" do
47
+ expect(controller.view_context.jskit).to eq(controller.jskit)
48
+ end
49
+
50
+ it "namespaces events based on the config" do
51
+ app_event = "App.Dispatcher.trigger(\"some_namespace:controller:application:all\");"
52
+ controller_event = "App.Dispatcher.trigger(\"some_namespace:controller:orders:all\");"
53
+ action_event = "App.Dispatcher.trigger(\"some_namespace:controller:orders:action\");"
54
+ expected_js = view_context.javascript_tag([app_event, controller_event, action_event].join("\n"))
55
+
56
+ expect(controller.jskit(namespace: "some_namespace")).to eq(expected_js)
41
57
  end
42
58
  end
43
59
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jskit_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dayton Nolan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-11-03 00:00:00.000000000 Z
11
+ date: 2014-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails