stimulus_reflex 2.0.0 → 2.1.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of stimulus_reflex might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8072c82ab1f16ce62c41e6d970952c3762a9e2fe5d87d2036ff2f37af7f3a4fb
4
- data.tar.gz: b3549d33023d9c27e878443f48391e13b82562e4dc9d9cbfb64b9744d8fe0702
3
+ metadata.gz: f261317eba89f3aca406db338af66069b57121ef68188dd32c22a8b263c84c0d
4
+ data.tar.gz: 16ead06810e664961d5d0bea297a82bfd109616c363eecb63e2211efbe0718e0
5
5
  SHA512:
6
- metadata.gz: 5ba2646379f9bbe65485d947c55467640e890d516ad571f704e064f0fb78956b977ba405d5698efdb6fd3b7e87f1075a9948d59c4b6ec2855410d3b290137a31
7
- data.tar.gz: 756a22a1a4cb5f1d4ad985dd1424ed15edc3d2e4d8efcf080d3c3a9a551a170fc1a76d84543fd105acc104b97c07d7f377348a00ec329222fa6341c0e627051c
6
+ metadata.gz: 43c62ef1ddec489d525dd429a78ee0113b215918ac4fa95192cf75fafe356b42705e775b29ccfa2ddf193833b3bc42d5e736828d97234353e2ae06bdd929bd63
7
+ data.tar.gz: 0b5870db51f39af566c2eda1a574783dba205b9f37d1c07083d82a5df6ef6a0a63dde0b43ee0881492155715e945926452f529677b7951d10f27228471a80097
@@ -0,0 +1,76 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, sex characteristics, gender identity and expression,
9
+ level of experience, education, socio-economic status, nationality, personal
10
+ appearance, race, religion, or sexual identity and orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ - Using welcoming and inclusive language
18
+ - Being respectful of differing viewpoints and experiences
19
+ - Gracefully accepting constructive criticism
20
+ - Focusing on what is best for the community
21
+ - Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ - The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ - Trolling, insulting/derogatory comments, and personal or political attacks
28
+ - Public or private harassment
29
+ - Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ - Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at natehop@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72
+
73
+ [homepage]: https://www.contributor-covenant.org
74
+
75
+ For answers to common questions about this code of conduct, see
76
+ https://www.contributor-covenant.org/faq
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- stimulus_reflex (2.0.0)
5
- cable_ready (>= 4.0.3)
4
+ stimulus_reflex (2.1.2)
5
+ cable_ready (>= 4.0.7)
6
6
  nokogiri
7
7
  rack
8
8
  rails (>= 5.2)
@@ -67,18 +67,18 @@ GEM
67
67
  zeitwerk (~> 2.1, >= 2.1.8)
68
68
  ast (2.4.0)
69
69
  builder (3.2.3)
70
- cable_ready (4.0.3)
70
+ cable_ready (4.0.7)
71
71
  rails (>= 5.2)
72
72
  coderay (1.1.2)
73
73
  concurrent-ruby (1.1.5)
74
74
  crass (1.0.4)
75
- erubi (1.8.0)
75
+ erubi (1.9.0)
76
76
  globalid (0.4.2)
77
77
  activesupport (>= 4.2.0)
78
- i18n (1.6.0)
78
+ i18n (1.7.0)
79
79
  concurrent-ruby (~> 1.0)
80
80
  jaro_winkler (1.5.3)
81
- loofah (2.2.3)
81
+ loofah (2.3.0)
82
82
  crass (~> 1.0.2)
83
83
  nokogiri (>= 1.5.9)
84
84
  mail (2.7.1)
@@ -89,12 +89,12 @@ GEM
89
89
  mimemagic (0.3.3)
90
90
  mini_mime (1.0.2)
91
91
  mini_portile2 (2.4.0)
92
- minitest (5.11.3)
93
- nio4r (2.5.1)
92
+ minitest (5.12.2)
93
+ nio4r (2.5.2)
94
94
  nokogiri (1.10.4)
95
95
  mini_portile2 (~> 2.4.0)
96
- parallel (1.17.0)
97
- parser (2.6.4.0)
96
+ parallel (1.18.0)
97
+ parser (2.6.5.0)
98
98
  ast (~> 2.4.0)
99
99
  pry (0.12.2)
100
100
  coderay (~> 1.1.0)
@@ -122,8 +122,8 @@ GEM
122
122
  rails-dom-testing (2.0.3)
123
123
  activesupport (>= 4.2.0)
124
124
  nokogiri (>= 1.6)
125
- rails-html-sanitizer (1.2.0)
126
- loofah (~> 2.2, >= 2.2.2)
125
+ rails-html-sanitizer (1.3.0)
126
+ loofah (~> 2.3)
127
127
  railties (6.0.0)
128
128
  actionpack (= 6.0.0)
129
129
  activesupport (= 6.0.0)
@@ -131,7 +131,7 @@ GEM
131
131
  rake (>= 0.8.7)
132
132
  thor (>= 0.20.3, < 2.0)
133
133
  rainbow (3.0.0)
134
- rake (12.3.3)
134
+ rake (13.0.0)
135
135
  rubocop (0.72.0)
136
136
  jaro_winkler (~> 1.5.1)
137
137
  parallel (~> 1.10)
@@ -142,14 +142,14 @@ GEM
142
142
  rubocop-performance (1.4.1)
143
143
  rubocop (>= 0.71.0)
144
144
  ruby-progressbar (1.10.1)
145
- sprockets (3.7.2)
145
+ sprockets (4.0.0)
146
146
  concurrent-ruby (~> 1.0)
147
147
  rack (> 1, < 3)
148
148
  sprockets-rails (3.2.1)
149
149
  actionpack (>= 4.0)
150
150
  activesupport (>= 4.0)
151
151
  sprockets (>= 3.0.0)
152
- standard (0.1.3)
152
+ standard (0.1.4)
153
153
  rubocop (~> 0.72.0)
154
154
  rubocop-performance (~> 1.4.0)
155
155
  standardrb (1.0.0)
@@ -162,7 +162,7 @@ GEM
162
162
  websocket-driver (0.7.1)
163
163
  websocket-extensions (>= 0.1.0)
164
164
  websocket-extensions (0.1.4)
165
- zeitwerk (2.1.10)
165
+ zeitwerk (2.2.0)
166
166
 
167
167
  PLATFORMS
168
168
  ruby
data/README.md CHANGED
@@ -1,305 +1,45 @@
1
- [![Lines of Code](http://img.shields.io/badge/lines_of_code-218-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
1
+ [![Lines of Code](http://img.shields.io/badge/lines_of_code-465-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
2
2
  [![Maintainability](https://api.codeclimate.com/v1/badges/2b24fdbd1ae37a24bedb/maintainability)](https://codeclimate.com/github/hopsoft/stimulus_reflex/maintainability)
3
- ![Prettier](https://github.com/hopsoft/stimulus_reflex/workflows/Prettier%20Check%20Action/badge.svg)
4
- ![StandardRB](https://github.com/hopsoft/stimulus_reflex/workflows/StandardRB%20Check%20Action/badge.svg)
3
+ ![Prettier-Standard](https://github.com/hopsoft/stimulus_reflex/workflows/Prettier-Standard/badge.svg)
4
+ ![StandardRB](https://github.com/hopsoft/stimulus_reflex/workflows/StandardRB/badge.svg)
5
+ ![Tests](https://github.com/hopsoft/stimulus_reflex/workflows/Tests/badge.svg)
5
6
 
6
7
  # StimulusReflex
7
8
 
8
9
  _reflex_ - an action that is performed as a response to a stimulus
9
10
 
10
- ### Build reactive [Single Page Applications (SPAs)](https://en.wikipedia.org/wiki/Single-page_application) with [Rails](https://rubyonrails.org) and [Stimulus](https://stimulusjs.org)
11
-
12
- This project supports building [reactive applications](https://en.wikipedia.org/wiki/Reactive_programming)
13
- with the Rails tooling you already know and love.
14
- It's designed to work perfectly with [server rendered HTML](https://guides.rubyonrails.org/action_view_overview.html),
15
- [Russian doll caching](https://edgeguides.rubyonrails.org/caching_with_rails.html#russian-doll-caching),
16
- [Stimulus](https://stimulusjs.org), [Turbolinks](https://www.youtube.com/watch?v=SWEts0rlezA), etc...
17
-
18
- __No need for a complex front-end framework. No need to grow your team or duplicate your efforts.__
11
+ **Build reactive applications with the Rails tooling you already know and love.** StimulusReflex is designed to work perfectly with [server rendered HTML](https://guides.rubyonrails.org/action_view_overview.html), [Russian doll caching](https://edgeguides.rubyonrails.org/caching_with_rails.html#russian-doll-caching), [Stimulus](https://stimulusjs.org/), [Turbolinks](https://www.youtube.com/watch?v=SWEts0rlezA), etc... and strives to live up to the vision outlined in [The Rails Doctrine](https://rubyonrails.org/doctrine/).
19
12
 
20
13
  _Inspired by [Phoenix LiveView](https://youtu.be/Z2DU0qLfPIY?t=670)._ 🙌
21
14
 
22
- ## Table of Contents
23
-
24
- <!-- toc -->
25
-
26
- - [Before you Begin](#before-you-begin)
27
- - [How it Works](#how-it-works)
28
- - [Setup](#setup)
29
- * [JavaScript](#javascript)
30
- + [app/javascript/controllers/index.js](#appjavascriptcontrollersindexjs)
31
- * [Gemfile](#gemfile)
32
- - [Usage](#usage)
33
- * [Implicit Declarative Reflexes](#implicit-declarative-reflexes)
34
- + [app/views/pages/example.html.erb](#appviewspagesexamplehtmlerb)
35
- + [app/reflexes/example_reflex.rb](#appreflexesexample_reflexrb)
36
- * [Explicitly Defined Reflexes](#explicitly-defined-reflexes)
37
- + [app/views/pages/example.html.erb](#appviewspagesexamplehtmlerb-1)
38
- + [app/javascript/controllers/example.js](#appjavascriptcontrollersexamplejs)
39
- + [app/reflexes/example_reflex.rb](#appreflexesexample_reflexrb-1)
40
- - [What Just Happened](#what-just-happened)
41
- - [Advanced Usage](#advanced-usage)
42
- * [The Reflex `element` property](#the-reflex-element-property)
43
- * [ActionCable](#actioncable)
44
- + [Performance](#performance)
45
- + [ActionCable Rooms](#actioncable-rooms)
46
- * [Render Delay](#render-delay)
47
- - [Demo Applications](#demo-applications)
48
- - [Contributing](#contributing)
49
- * [Coding Standards](#coding-standards)
50
- * [Releasing](#releasing)
51
-
52
- <!-- tocstop -->
53
-
54
- ## Before you Begin
55
-
56
- StimulusReflex provides functionality similar to what can already be achieved with Rails by combining
57
- [UJS remote elements](https://guides.rubyonrails.org/working_with_javascript_in_rails.html#remote-elements)
58
- , [Stimulus](https://stimulusjs.org), and [Turbolinks](https://github.com/turbolinks/turbolinks).
59
- _Consider building with standard Rails tooling before introducing StimulusReflex._
60
- _Check out the [Stimulus TodoMVC](https://github.com/hopsoft/stimulus_todomvc) example if you are unsure how to accomplish this._
61
-
62
- StimulusReflex offers 3 primary benefits over the traditional Rails HTTP request/response cycle.
63
-
64
- 1. __Communication happens on the ActionCable web socket__ _- saves time by avoiding the overhead of establishishing traditional HTTP connections_
65
- 1. __The controller action is invoked directly__ _- skips framework overhead such as the middleware chain, etc..._
66
- 1. __DOM diffing is used to update the page__ _- provides faster rendering and less jitter_
67
-
68
- ## How it Works
69
-
70
- 1. Render a standard Rails view template
71
- 1. Use [Stimulus](https://stimulusjs.org) and [ActionCable](https://edgeguides.rubyonrails.org/action_cable_overview.html) to invoke a method on the server
72
- 1. Watch the page automatically render updates via fast [DOM diffing](https://github.com/patrick-steele-idem/morphdom)
73
- 1. That's it...
74
-
75
- __Yes, it really is that simple.__
76
- There are no hidden gotchas.
77
-
78
- ![How it Works](https://raw.githubusercontent.com/hopsoft/stimulus_reflex/master/docs/diagram.png)
79
-
80
- ## Setup
81
-
82
- ### JavaScript
83
-
84
- ```
85
- yarn add stimulus_reflex
86
- ```
87
- #### app/javascript/controllers/index.js
88
-
89
- This is the file where Stimulus is initialized in your application.
90
- _Note that your file location may be different._
91
-
92
- ```javascript
93
- import { Application } from 'stimulus';
94
- import { definitionsFromContext } from 'stimulus/webpack-helpers';
95
- import StimulusReflex from 'stimulus_reflex';
96
-
97
- const application = Application.start();
98
- const context = require.context('controllers', true, /_controller\.js$/);
99
- application.load(definitionsFromContext(context));
100
- StimulusReflex.initialize(application);
101
- ```
102
-
103
- ### Gemfile
104
-
105
- ```ruby
106
- gem "stimulus_reflex"
107
- ```
108
-
109
- ## Usage
110
-
111
- ### Implicit Declarative Reflexes
112
-
113
- This example shows how to create a reactive feature without the need to write any JavaScript
114
- other than initializing StimulusReflex itself _([see the setup instructions](#javascript))_. Everything else is managed entirely by HTML and Ruby.
115
-
116
- #### app/views/pages/example.html.erb
117
-
118
- ```erb
119
- <head></head>
120
- <body>
121
- <a href="#" data-reflex="click->ExampleReflex#increment" data-step="1" data-count="<%= @count.to_i %>">
122
- Increment <%= @count.to_i %>
123
- </a>
124
- </body>
125
- </html>
126
- ```
127
-
128
- #### app/reflexes/example_reflex.rb
129
-
130
- ```ruby
131
- class ExampleReflex < StimulusReflex::Reflex
132
- def increment
133
- @count = element.dataset[:count].to_i + element.dataset[:step].to_i
134
- end
135
- end
136
- ```
137
-
138
- The code above will automatically update the relevant DOM nodes with the updated count whenever the anchor is clicked.
139
-
140
- __Note that all concerns from managing state to rendering views are handled server side.__
141
- This technique works regardless of how complex the UI may become.
142
- For example, we could render multiple instances of `@count` in unrelated sections of the page and they will all update.
143
-
144
- ### Explicitly Defined Reflexes
145
-
146
- This example shows how to create a reactive feature by defining an explicit client side
147
- Stimulus controller to handle the DOM event and trigger the server side reflex.
148
-
149
- #### app/views/pages/example.html.erb
150
-
151
- ```erb
152
- <head></head>
153
- <body>
154
- <a href="#" data-controller="example" data-action="click->example#increment">
155
- Increment <%= @count.to_i %>
156
- </a>
157
- </body>
158
- </html>
159
- ```
160
-
161
- #### app/javascript/controllers/example.js
162
-
163
- ```javascript
164
- import { Controller } from "stimulus"
165
- import StimulusReflex from "stimulus_reflex"
15
+ ## Docs
166
16
 
167
- export default class extends Controller {
168
- connect() {
169
- StimulusReflex.register(this);
170
- }
17
+ - [Official Documentation](https://docs.stimulusreflex.com)
18
+ - [Documentation Source Code](https://github.com/hopsoft/stimulus_reflex/tree/master/docs)
171
19
 
172
- increment() {
173
- // trigger a server-side reflex and a client-side page update
174
- this.stimulate('ExampleReflex#increment', 1);
175
- }
176
- }
177
- ```
178
-
179
- #### app/reflexes/example_reflex.rb
180
-
181
- ```ruby
182
- class ExampleReflex < StimulusReflex::Reflex
183
- def increment(step = 1)
184
- @count = @count.to_i + step
185
- end
186
- end
187
- ```
188
-
189
- ## What Just Happened
190
-
191
- The following happens when a `StimulusReflex::Reflex` is invoked.
192
-
193
- 1. The page that triggered the reflex is re-rerendered. _Instance variables created in the reflex are available to both the controller and view templates._
194
- 2. The re-rendered HTML is sent to the client over the ActionCable socket.
195
- 3. The page is updated via fast DOM diffing courtesy of morphdom.
196
-
197
- _NOTE: While future versions of StimulusReflex may support more granular updates, today the entire body is re-rendered and sent over the socket._
198
-
199
- ## Advanced Usage
200
-
201
- ### The Reflex `element` property
202
-
203
- All reflex methods expose an `element` property.
204
- This property holds a Hash like data structure that represents the HTML element that triggered the refelx.
205
- It contains all of the Stimulus controller's
206
- [DOM element attributes](https://developer.mozilla.org/en-US/docs/Web/API/Element/attributes) as well as other properties like `checked` and `value`.
207
- _Most of the values will be strings._
208
-
209
- ```html
210
- <checkbox id="example"
211
- label="Example"
212
- data-controller="checkbox"
213
- data-value="123"
214
- checked />
215
- ```
216
-
217
- ```ruby
218
- class ExampleReflex < StimulusReflex::Reflex
219
- def work()
220
- element[:id] # => the HTML element's id attribute value
221
- element.dataset # => a Hash that represents the HTML element's dataset
222
-
223
- element[:id] # => "example"
224
- element[:checked] # => true
225
- element[:label] # => "Example"
226
- element["data-controller"] # => "checkbox"
227
- element["data-value"] # => "123"
228
- element.dataset[:controller] # => "checkbox"
229
- element.dataset[:value] # => "123"
230
- end
231
- end
232
- ```
233
-
234
- - `element[:checked]` holds a boolean
235
- - `element[:selected]` holds a boolean
236
- - `element[:value]` holds the [DOM element's value](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#value)
237
- - `select` elements assign `element[:value]` to their selected option's value
238
- - `select` elements with _multiselect_ enabled assign `element[:values]` to their selected options values
239
- - All other values exposed in `element` are extracted from the DOM element's attributes
240
-
241
- ### ActionCable
242
-
243
- StimulusReflex will use the ActionCable defaults of `window.App` and `App.cable` if they exist.
244
- If these defaults do not exist, StimulusReflex will establish a new socket connection.
245
-
246
- #### Performance
247
-
248
- ActionCable emits verbose log messages. Disabling ActionCable logs may improve performance.
249
-
250
- ```ruby
251
- # config/application.rb
252
-
253
- ActionCable.server.config.logger = Logger.new(nil)
254
- ```
255
-
256
- #### ActionCable Rooms
257
-
258
- You may find the need to restrict notifications to a specific room.
259
- This can be accomplished by setting the `data-room` attribute on the StimulusController element.
260
-
261
- ```erb
262
- <a href="#" data-controller="example" data-action="click->example#increment" data-room="12345">
263
- ```
264
-
265
- ### Render Delay
266
-
267
- An attempt is made to reduce repaint/reflow jitter when users trigger lots of updates.
268
-
269
- You can control how long to wait _(think debounce)_ prior to updating the page.
270
- Simply set the `renderDelay` _(milliseconds)_ option when registering the controller.
271
-
272
- ```javascript
273
- export default class extends Controller {
274
- connect() {
275
- StimulusReflex.register(this, {renderDelay: 200});
276
- }
277
- }
278
- ```
279
-
280
- The default value is `25`.
281
-
282
- ## Demo Applications
283
-
284
- Building apps with StimulusReflex should evoke your memories of the original [Rails demo video](https://www.youtube.com/watch?v=Gzj723LkRJY).
285
-
286
- > Look at all the things I'm **not** doing. -DHH
20
+ ## Contributing
287
21
 
288
- - [TodoMVC](https://github.com/hopsoft/stimulus_reflex_todomvc)
22
+ ### Code of Conduct
289
23
 
290
- ## Contributing
24
+ Everyone interacting with StimulusReflex is expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md)
291
25
 
292
26
  ### Coding Standards
293
27
 
294
28
  This project uses [Standard](https://github.com/testdouble/standard)
295
- and [Prettier](https://github.com/prettier/prettier) to minimize bike shedding related to code formatting.
29
+ and [Prettier-Standard](https://github.com/sheerun/prettier-standard) to minimize bike shedding related to code formatting.
30
+
296
31
  Please run `./bin/standardize` prior submitting pull requests.
297
32
 
33
+ View the [wiki](https://github.com/hopsoft/stimulus_reflex/wiki/Editor-Configuration) to see recommendations for configuring your editor to work best with the project.
34
+
298
35
  ### Releasing
299
36
 
300
37
  1. Bump version number at `lib/stimulus_reflex/version.rb`
301
38
  1. Run `rake build`
302
39
  1. Run `rake release`
303
40
  1. Change directories `cd ./javascript`
304
- 1. Run `yarn publish --tag GIT_TAG_CREATED_BY_RUBYGEMS`
305
- 1. Assign same version number to the JavaScript package _Might not be required?_
41
+ 1. Run `yarn publish` - NOTE: this will throw a fatal error because the tag already exists but the package will still publish
42
+
43
+ ## License
44
+
45
+ StimulusReflex is released under the [MIT License](LICENSE.txt).
data/Rakefile CHANGED
@@ -1,4 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bundler/gem_tasks"
4
- task default: :spec
4
+
5
+ task default: [:test]
6
+
7
+ task :test do
8
+ exec "cd javascript && yarn run test"
9
+ end
data/bin/loc ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ cloc --exclude-dir=node_modules,test --include-ext=rb,js .
data/bin/standardize CHANGED
@@ -1,4 +1,4 @@
1
- #!/bin/bash
1
+ #!/usr/bin/env bash
2
2
 
3
3
  bundle exec standardrb --fix
4
- cd ./javascript && yarn run prettier --write stimulus_reflex.js
4
+ cd ./javascript && yarn run prettier-standard stimulus_reflex.js test/*.js
@@ -18,6 +18,8 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
18
18
 
19
19
  def receive(data)
20
20
  url = data["url"].to_s
21
+ selectors = (data["selectors"] || []).select(&:present?)
22
+ selectors = ["body"] if selectors.blank?
21
23
  target = data["target"].to_s
22
24
  reflex_name, method_name = target.split("#")
23
25
  reflex_name = reflex_name.classify
@@ -25,21 +27,27 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
25
27
  element = StimulusReflex::Element.new(data["attrs"])
26
28
 
27
29
  begin
28
- reflex = reflex_name.constantize.new(self, url: url, element: element)
30
+ reflex_class = reflex_name.constantize
31
+ raise ArgumentError.new("#{reflex_name} is not a StimulusReflex::Reflex") unless is_reflex?(reflex_class)
32
+ reflex = reflex_class.new(self, url: url, element: element, selectors: selectors)
29
33
  delegate_call_to_reflex reflex, method_name, arguments
30
34
  rescue => invoke_error
31
- logger.error "\e[31mStimulusReflex::Channel Failed to invoke #{target}! #{url} #{invoke_error}\e[0m"
35
+ return broadcast_error("StimulusReflex::Channel Failed to invoke #{target}! #{url} #{invoke_error}", data)
32
36
  end
33
37
 
34
38
  begin
35
- render_page_and_broadcast_morph url, reflex
39
+ render_page_and_broadcast_morph url, reflex, selectors, data
36
40
  rescue => render_error
37
- logger.error "\e[31mStimulusReflex::Channel Failed to rerender #{url} #{render_error}\e[0m"
41
+ broadcast_error "StimulusReflex::Channel Failed to re-render #{url} #{render_error}", data
38
42
  end
39
43
  end
40
44
 
41
45
  private
42
46
 
47
+ def is_reflex?(reflex_class)
48
+ reflex_class.ancestors.include? StimulusReflex::Reflex
49
+ end
50
+
43
51
  def delegate_call_to_reflex(reflex, method_name, arguments = [])
44
52
  method = reflex.method(method_name)
45
53
  required_params = method.parameters.select { |(kind, _)| kind == :req }
@@ -54,9 +62,9 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
54
62
  end
55
63
  end
56
64
 
57
- def render_page_and_broadcast_morph(url, reflex)
65
+ def render_page_and_broadcast_morph(url, reflex, selectors, data = {})
58
66
  html = render_page(url, reflex)
59
- broadcast_morph url, html if html.present?
67
+ broadcast_morphs selectors, data, html if html.present?
60
68
  end
61
69
 
62
70
  def render_page(url, reflex)
@@ -90,14 +98,28 @@ class StimulusReflex::Channel < ActionCable::Channel::Base
90
98
  controller.response.body
91
99
  end
92
100
 
93
- def broadcast_morph(url, html)
94
- html = extract_body_html(html)
95
- cable_ready[stream_name].morph selector: "body", html: html, children_only: true
101
+ def broadcast_morphs(selectors, data, html)
102
+ document = Nokogiri::HTML(html)
103
+ selectors.each do |selector|
104
+ match = document.css(selector)
105
+ next if match.blank?
106
+ cable_ready[stream_name].morph(
107
+ selector: selector,
108
+ html: match.inner_html,
109
+ children_only: true,
110
+ permanent_attribute_name: "data-reflex-permanent",
111
+ stimulus_reflex: data
112
+ )
113
+ end
96
114
  cable_ready.broadcast
97
115
  end
98
116
 
99
- def extract_body_html(html)
100
- doc = Nokogiri::HTML(html)
101
- doc.css("body").to_s
117
+ def broadcast_error(message, data = {})
118
+ logger.error "\e[31m#{message}\e[0m"
119
+ cable_ready[stream_name].dispatch_event(
120
+ name: "stimulus-reflex:500",
121
+ detail: {stimulus_reflex: data.merge(error: message)}
122
+ )
123
+ cable_ready.broadcast
102
124
  end
103
125
  end
@@ -1,15 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class StimulusReflex::Reflex
4
- attr_reader :channel, :url, :element
4
+ attr_reader :channel, :url, :element, :selectors
5
5
 
6
6
  delegate :connection, to: :channel
7
7
  delegate :session, to: :request
8
8
 
9
- def initialize(channel, url: nil, element: nil)
9
+ def initialize(channel, url: nil, element: nil, selectors: [])
10
10
  @channel = channel
11
11
  @url = url
12
12
  @element = element
13
+ @selectors = selectors
13
14
  end
14
15
 
15
16
  def request
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module StimulusReflex
4
- VERSION = "2.0.0"
4
+ VERSION = "2.1.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stimulus_reflex
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Hopkins
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-09-11 00:00:00.000000000 Z
12
+ date: 2019-10-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: 4.0.3
62
+ version: 4.0.7
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: 4.0.3
69
+ version: 4.0.7
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: bundler
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -145,13 +145,14 @@ executables: []
145
145
  extensions: []
146
146
  extra_rdoc_files: []
147
147
  files:
148
+ - CODE_OF_CONDUCT.md
148
149
  - Gemfile
149
150
  - Gemfile.lock
150
151
  - LICENSE.txt
151
152
  - README.md
152
- - README.md.orig
153
153
  - Rakefile
154
154
  - bin/console
155
+ - bin/loc
155
156
  - bin/setup
156
157
  - bin/standardize
157
158
  - lib/stimulus_reflex.rb
data/README.md.orig DELETED
@@ -1,159 +0,0 @@
1
- [![Lines of Code](http://img.shields.io/badge/lines_of_code-159-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
2
- [![Maintainability](https://api.codeclimate.com/v1/badges/2b24fdbd1ae37a24bedb/maintainability)](https://codeclimate.com/github/hopsoft/stimulus_reflex/maintainability)
3
-
4
- # StimulusReflex
5
-
6
- ### Build reactive [Single Page Applications (SPAs)](https://en.wikipedia.org/wiki/Single-page_application) with [Rails](https://rubyonrails.org) and [Stimulus](https://stimulusjs.org)
7
-
8
- This project supports building [reactive applications](https://en.wikipedia.org/wiki/Reactive_programming)
9
- with the Rails tooling you already know and love.
10
- It's designed to work perfectly with [server rendered HTML](https://guides.rubyonrails.org/action_view_overview.html),
11
- [Russian doll caching](https://edgeguides.rubyonrails.org/caching_with_rails.html#russian-doll-caching),
12
- [Stimulus](https://stimulusjs.org), [Turbolinks](https://www.youtube.com/watch?v=SWEts0rlezA), etc...
13
-
14
-
15
- __No need for a complex front-end framework. No need to grow your team or duplicate your efforts.__
16
-
17
- ---
18
-
19
- > The lifecycle of a "modern" SPA app is so convoluted, it requires a team to build and support.
20
- > The wire size and computation demands of these heavy client sites frequently run slower than the server-rendered pages that they replaced.
21
- > With Stimulus Reflex, a Rails developer can build Single Page Applications without the need for client rendering or heavy JS frameworks.
22
-
23
- ---
24
-
25
- _Inspired by [Phoenix LiveView](https://youtu.be/Z2DU0qLfPIY?t=670)._ 🙌
26
-
27
- ## How it Works
28
-
29
- 1. Render a standard Rails view template
30
- 1. Use [Stimulus](https://stimulusjs.org) and [ActionCable](https://edgeguides.rubyonrails.org/action_cable_overview.html) to invoke a method on the server
31
- 1. Watch the page automatically render updates via fast [DOM diffing](https://github.com/patrick-steele-idem/morphdom)
32
- 1. That's it...
33
-
34
- __Yes, it really is that simple.__
35
- There are no hidden gotchas.
36
-
37
- ![How it Works](https://raw.githubusercontent.com/hopsoft/stimulus_reflex/master/docs/diagram.png)
38
-
39
- ## Setup
40
-
41
- ### JavaScript
42
-
43
- ```
44
- yarn add stimulus_reflex
45
- ```
46
-
47
- ### Gemfile
48
-
49
- ```ruby
50
- gem "stimulus_reflex"
51
- ```
52
-
53
- ## Basic Usage
54
-
55
- ### app/views/pages/example.html.erb
56
-
57
- ```erb
58
- <head></head>
59
- <body>
60
- <a href="#" data-controller="example" data-action="click->example#increment">
61
- Increment <%= @count.to_i %>
62
- </a>
63
- </body>
64
- </html>
65
- ```
66
-
67
- ### app/javascript/controllers/example.js
68
-
69
- ```javascript
70
- import { Controller } from "stimulus"
71
- import StimulusReflex from "stimulus_reflex"
72
-
73
- export default class extends Controller {
74
- connect() {
75
- StimulusReflex.register(this);
76
- }
77
-
78
- increment() {
79
- // trigger a server-side reflex and a client-side page update
80
- this.stimulate('ExampleReflex#increment', 1);
81
- }
82
- }
83
- ```
84
-
85
- ### app/reflexes/example_reflex.rb
86
-
87
- ```ruby
88
- class ExampleReflex < StimulusReflex::Reflex
89
- def increment(step = 1)
90
- @count = @count.to_i + step
91
- end
92
- end
93
- ```
94
-
95
- The following happens after the `StimulusReflex::Reflex` method call finishes.
96
-
97
- 1. The page that triggered the reflex is re-rerendered. _Instance variables created in the reflex are available to both the controller and view templates._
98
- 2. The re-rendered HTML is sent to the client over the ActionCable socket.
99
- 3. The page is updated via fast DOM diffing courtesy of morphdom. _While future versions of StimulusReflex might support more granular updates, today the entire body is re-rendered and sent over the socket._
100
-
101
- ## Advanced Usage
102
-
103
- ### ActionCable
104
-
105
- StimulusReflex will use the ActionCable defaults of `window.App` and `App.cable` if they exist.
106
- If these defaults do not exist, StimulusReflex will establish a new socket connection.
107
-
108
- ### Performance
109
-
110
- ActionCable emits verbose log messages. Disabling ActionCable logs may improve performance.
111
-
112
- ```ruby
113
- # config/application.rb
114
-
115
- ActionCable.server.config.logger = Logger.new(nil)
116
- ```
117
-
118
- ### ActionCable Rooms
119
-
120
- You may find the need to restrict notifications to a specific room.
121
- This can be accomplished by setting the `data-room` attribute on the StimulusController element.
122
-
123
- ```erb
124
- <a href="#" data-controller="example" data-action="click->example#increment" data-room="12345">
125
- ```
126
-
127
- ### Render Delay
128
-
129
- An attempt is made to reduce repaint/reflow jitter when users trigger lots of updates.
130
-
131
- You can control how long to wait _(think debounce)_ prior to updating the page.
132
- Simply set the `renderDelay` _(milliseconds)_ option when registering the controller.
133
-
134
- ```javascript
135
- export default class extends Controller {
136
- connect() {
137
- StimulusReflex.register(this, {renderDelay: 200});
138
- }
139
- }
140
- ```
141
-
142
- The default value is `25`.
143
-
144
- ## Demo Applications
145
-
146
- Building apps with StimulusReflex should evoke your memories of the original [Rails demo video](https://www.youtube.com/watch?v=Gzj723LkRJY).
147
-
148
- > Look at all the things I'm **not** doing. -DHH
149
-
150
- - [TodoMVC](https://github.com/hopsoft/stimulus_reflex_todomvc)
151
-
152
- <<<<<<< HEAD
153
- ## Contributing
154
-
155
- This project uses [Standard](https://github.com/testdouble/standard)
156
- and [Prettier](https://github.com/prettier/prettier) to minimize bike shedding related to code formatting.
157
- Please run `./bin/standardize` prior submitting pull requests.
158
- =======
159
- >>>>>>> master