stimulus_reflex 3.5.0.pre9 → 3.5.0.pre10
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 +4 -4
- data/Gemfile +0 -1
- data/Gemfile.lock +122 -127
- data/README.md +10 -16
- data/app/assets/javascripts/stimulus_reflex.js +710 -505
- data/app/assets/javascripts/stimulus_reflex.min.js +1 -1
- data/app/assets/javascripts/stimulus_reflex.min.js.map +1 -1
- data/app/assets/javascripts/stimulus_reflex.umd.js +660 -500
- data/app/assets/javascripts/stimulus_reflex.umd.min.js +660 -500
- data/app/assets/javascripts/stimulus_reflex.umd.min.js.map +1 -1
- data/app/channels/stimulus_reflex/channel.rb +9 -7
- data/bin/console +0 -2
- data/bin/standardize +2 -1
- data/lib/generators/stimulus_reflex/stimulus_reflex_generator.rb +72 -7
- data/lib/generators/stimulus_reflex/templates/app/controllers/examples_controller.rb.tt +9 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/channels/consumer.js.tt +6 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/channels/index.js.esbuild.tt +4 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/channels/index.js.importmap.tt +2 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/channels/index.js.shakapacker.tt +5 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/channels/index.js.vite.tt +1 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/channels/index.js.webpacker.tt +5 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/config/cable_ready.js.tt +4 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/config/index.js.tt +2 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/config/mrujs.js.tt +9 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/config/stimulus_reflex.js.tt +5 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/%file_name%_controller.js.tt +141 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/application.js.tt +11 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/application_controller.js.tt +74 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/index.js.esbuild.tt +7 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/index.js.importmap.tt +5 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/index.js.shakapacker.tt +5 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/index.js.vite.tt +5 -0
- data/lib/generators/stimulus_reflex/templates/app/javascript/controllers/index.js.webpacker.tt +5 -0
- data/{test/tmp/app/reflexes/user_reflex.rb → lib/generators/stimulus_reflex/templates/app/reflexes/%file_name%_reflex.rb.tt} +38 -9
- data/lib/generators/stimulus_reflex/templates/app/reflexes/application_reflex.rb.tt +27 -0
- data/lib/generators/stimulus_reflex/templates/app/views/examples/show.html.erb.tt +207 -0
- data/lib/generators/stimulus_reflex/templates/config/initializers/cable_ready.rb +22 -0
- data/lib/generators/stimulus_reflex/templates/config/initializers/stimulus_reflex.rb +18 -13
- data/lib/generators/stimulus_reflex/templates/esbuild.config.mjs.tt +94 -0
- data/lib/install/action_cable.rb +155 -0
- data/lib/install/broadcaster.rb +90 -0
- data/lib/install/bundle.rb +56 -0
- data/lib/install/compression.rb +41 -0
- data/lib/install/config.rb +87 -0
- data/lib/install/development.rb +110 -0
- data/lib/install/esbuild.rb +114 -0
- data/lib/install/example.rb +22 -0
- data/lib/install/importmap.rb +133 -0
- data/lib/install/initializers.rb +25 -0
- data/lib/install/mrujs.rb +133 -0
- data/lib/install/npm_packages.rb +25 -0
- data/lib/install/reflexes.rb +25 -0
- data/lib/install/shakapacker.rb +64 -0
- data/lib/install/spring.rb +54 -0
- data/lib/install/updatable.rb +34 -0
- data/lib/install/vite.rb +64 -0
- data/lib/install/webpacker.rb +90 -0
- data/lib/install/yarn.rb +55 -0
- data/lib/stimulus_reflex/broadcasters/broadcaster.rb +15 -8
- data/lib/stimulus_reflex/broadcasters/page_broadcaster.rb +7 -8
- data/lib/stimulus_reflex/broadcasters/selector_broadcaster.rb +10 -10
- data/lib/stimulus_reflex/broadcasters/update.rb +3 -0
- data/lib/stimulus_reflex/cable_readiness.rb +29 -0
- data/lib/stimulus_reflex/cable_ready_channels.rb +5 -5
- data/lib/stimulus_reflex/callbacks.rb +17 -1
- data/lib/stimulus_reflex/concern_enhancer.rb +6 -4
- data/lib/stimulus_reflex/configuration.rb +12 -2
- data/lib/stimulus_reflex/dataset.rb +11 -1
- data/lib/stimulus_reflex/engine.rb +20 -9
- data/lib/stimulus_reflex/html/document.rb +59 -0
- data/lib/stimulus_reflex/html/document_fragment.rb +13 -0
- data/lib/stimulus_reflex/importmap.rb +3 -0
- data/lib/stimulus_reflex/installer.rb +274 -0
- data/lib/stimulus_reflex/open_struct_fix.rb +2 -0
- data/lib/stimulus_reflex/reflex.rb +25 -25
- data/lib/stimulus_reflex/reflex_data.rb +15 -3
- data/lib/stimulus_reflex/reflex_factory.rb +4 -2
- data/lib/stimulus_reflex/request_parameters.rb +2 -0
- data/lib/stimulus_reflex/utils/logger.rb +10 -0
- data/lib/stimulus_reflex/utils/sanity_checker.rb +8 -48
- data/lib/stimulus_reflex/version.rb +1 -1
- data/lib/stimulus_reflex.rb +2 -0
- data/lib/tasks/stimulus_reflex/stimulus_reflex.rake +252 -0
- data/package.json +34 -28
- data/{rollup.config.js → rollup.config.mjs} +8 -7
- data/stimulus_reflex.gemspec +16 -19
- data/yarn.lock +1320 -742
- metadata +124 -77
- data/LATEST +0 -1
- data/lib/generators/stimulus_reflex/initializer_generator.rb +0 -14
- data/test/broadcasters/broadcaster_test.rb +0 -11
- data/test/broadcasters/broadcaster_test_case.rb +0 -39
- data/test/broadcasters/nothing_broadcaster_test.rb +0 -31
- data/test/broadcasters/page_broadcaster_test.rb +0 -79
- data/test/broadcasters/selector_broadcaster_test.rb +0 -173
- data/test/callbacks_test.rb +0 -652
- data/test/concern_enhancer_test.rb +0 -54
- data/test/element_test.rb +0 -254
- data/test/generators/stimulus_reflex_generator_test.rb +0 -58
- data/test/reflex_test.rb +0 -43
- data/test/test_helper.rb +0 -71
- data/test/tmp/app/reflexes/application_reflex.rb +0 -12
- data/yarn-error.log +0 -4964
@@ -0,0 +1 @@
|
|
1
|
+
const channels = import.meta.globEager('./**/*_channel.js')
|
@@ -0,0 +1,141 @@
|
|
1
|
+
import ApplicationController from './application_controller'
|
2
|
+
|
3
|
+
<%- if class_name == "Example" -%>
|
4
|
+
//
|
5
|
+
// This is the Stimulus controller for the Example Reflex.
|
6
|
+
//
|
7
|
+
// It corresponds to the server-side Reflex class located at /app/reflexes/example.rb
|
8
|
+
//
|
9
|
+
// Learn more at: https://docs.stimulusreflex.com/guide/reflexes
|
10
|
+
//
|
11
|
+
|
12
|
+
<%- end -%>
|
13
|
+
export default class extends ApplicationController {
|
14
|
+
connect () {
|
15
|
+
<%- if class_name == "Example" -%>
|
16
|
+
//
|
17
|
+
// StimulusReflex overrides the Stimulus `connect` method. Make sure to call
|
18
|
+
// `super.connect()` so that any code in your superclass `connect` is run.
|
19
|
+
//
|
20
|
+
<%- end -%>
|
21
|
+
super.connect()
|
22
|
+
}
|
23
|
+
<%- if class_name == "Example" -%>
|
24
|
+
|
25
|
+
// With StimulusReflex active in your project, it will continuously scan your DOM for
|
26
|
+
// `data-reflex` attributes on your elements, even if they are dynamically created.
|
27
|
+
//
|
28
|
+
// <a href="#" data-reflex="click->Example#dance">Dance!</a>
|
29
|
+
//
|
30
|
+
// We call this a "declared" Reflex, because it doesn't require any JS to run.
|
31
|
+
//
|
32
|
+
// When your user clicks this link, a Reflex is launched and it calls the `dance` method
|
33
|
+
// on your Example Reflex class. You don't have to do anything else!
|
34
|
+
//
|
35
|
+
// This Stimulus controller doesn't even need to exist for StimulusReflex to work its magic.
|
36
|
+
// https://docs.stimulusreflex.com/guide/reflexes#declaring-a-reflex-in-html-with-data-attributes
|
37
|
+
//
|
38
|
+
// However...
|
39
|
+
//
|
40
|
+
// If we do create an `example` Stimulus controller that extends `ApplicationController`,
|
41
|
+
// we can unlock several additional capabilities, including creating Reflexes with code.
|
42
|
+
//
|
43
|
+
// <a href="#" data-controller="example" data-action="example#dance">Dance!</a>
|
44
|
+
//
|
45
|
+
// StimulusReflex gives our controller a new method, `stimulate`:
|
46
|
+
//
|
47
|
+
// dance() {
|
48
|
+
// this.stimulate('Example#dance')
|
49
|
+
// }
|
50
|
+
//
|
51
|
+
// The `stimulate` method is very flexible, and it gives you the opportunity to pass
|
52
|
+
// parameter options that will be passed to the `dance` method on the server.
|
53
|
+
// https://docs.stimulusreflex.com/guide/reflexes#calling-a-reflex-in-a-stimulus-controller
|
54
|
+
//
|
55
|
+
// Reflex lifecycle methods
|
56
|
+
//
|
57
|
+
// For every method defined in your Reflex class, a matching set of optional
|
58
|
+
// lifecycle callback methods become available in this javascript controller.
|
59
|
+
// https://docs.stimulusreflex.com/guide/lifecycle#client-side-reflex-callbacks
|
60
|
+
//
|
61
|
+
// <a href="#" data-reflex="click->Example#dance" data-controller="example">Dance!</a>
|
62
|
+
//
|
63
|
+
// StimulusReflex will check for the presence of several methods:
|
64
|
+
//
|
65
|
+
// afterReflex(element, reflex, noop, id) {
|
66
|
+
// // fires after every Example Reflex action
|
67
|
+
// }
|
68
|
+
//
|
69
|
+
// afterDance(element, reflex, noop, id) {
|
70
|
+
// // fires after Example Reflexes calling the dance action
|
71
|
+
// }
|
72
|
+
//
|
73
|
+
// Arguments:
|
74
|
+
//
|
75
|
+
// element - the element that triggered the reflex
|
76
|
+
// may be different than the Stimulus controller's this.element
|
77
|
+
//
|
78
|
+
// reflex - the name of the reflex e.g. "Example#dance"
|
79
|
+
//
|
80
|
+
// error/noop - the error message (for reflexError), otherwise null
|
81
|
+
//
|
82
|
+
// id - a UUID4 or developer-provided unique identifier for each Reflex
|
83
|
+
//
|
84
|
+
// Access to the client-side Reflex objects created by this controller
|
85
|
+
//
|
86
|
+
// Every Reflex you create is represented by an object in the global Reflexes collection.
|
87
|
+
// You can access the Example Reflexes created by this controller via the `reflexes` proxy.
|
88
|
+
//
|
89
|
+
// this.reflexes.last
|
90
|
+
// this.reflexes.all
|
91
|
+
// this.reflexes.all[id]
|
92
|
+
// this.reflexes.error
|
93
|
+
//
|
94
|
+
// The proxy allows you to access the most recent Reflex, an array of all Reflexes, a specific
|
95
|
+
// Reflex specified by its `id` and an array of all Reflexes in a given lifecycle stage.
|
96
|
+
//
|
97
|
+
// If you explore the Reflex object, you'll see all relevant details,
|
98
|
+
// including the `data` that is being delivered to the server.
|
99
|
+
//
|
100
|
+
// Pretty cool, right?
|
101
|
+
//
|
102
|
+
<%- end -%>
|
103
|
+
<%- actions.each do |action| -%>
|
104
|
+
|
105
|
+
// <%= "before_#{action}".camelize(:lower) %>(element, reflex, noop, id) {
|
106
|
+
// console.log("before <%= action %>", element, reflex, id)
|
107
|
+
// }
|
108
|
+
|
109
|
+
// <%= "#{action}_queued".camelize(:lower) %>(element, reflex, noop, id) {
|
110
|
+
// console.log("<%= action %> enqueued for delivery upon connection", element, reflex, id)
|
111
|
+
// }
|
112
|
+
|
113
|
+
// <%= "#{action}_delivered".camelize(:lower) %>(element, reflex, noop, id) {
|
114
|
+
// console.log("<%= action %> delivered to the server", element, reflex, id)
|
115
|
+
// }
|
116
|
+
|
117
|
+
// <%= "#{action}_success".camelize(:lower) %>(element, reflex, noop, id) {
|
118
|
+
// console.log("<%= action %> successfully executed", element, reflex, id)
|
119
|
+
// }
|
120
|
+
|
121
|
+
// <%= "#{action}_error".camelize(:lower) %>(element, reflex, error, id) {
|
122
|
+
// console.error("<%= action %> server-side error", element, reflex, error, id)
|
123
|
+
// }
|
124
|
+
|
125
|
+
// <%= "#{action}_halted".camelize(:lower) %>(element, reflex, noop, id) {
|
126
|
+
// console.warn("<%= action %> halted before execution", element, reflex, id)
|
127
|
+
// }
|
128
|
+
|
129
|
+
// <%= "#{action}_forbidden".camelize(:lower) %>(element, reflex, noop, id) {
|
130
|
+
// console.warn("<%= action %> forbidden from executing", element, reflex, id)
|
131
|
+
// }
|
132
|
+
|
133
|
+
// <%= "after_#{action}".camelize(:lower) %>(element, reflex, noop, id) {
|
134
|
+
// console.log("<%= action %> has been executed by the server", element, reflex, id)
|
135
|
+
// }
|
136
|
+
|
137
|
+
// <%= "finalize_#{action}".camelize(:lower) %>(element, reflex, noop, id) {
|
138
|
+
// console.log("<%= action %> changes have been applied", element, reflex, id)
|
139
|
+
// }
|
140
|
+
<%- end -%>
|
141
|
+
}
|
@@ -0,0 +1,11 @@
|
|
1
|
+
import { Application } from "@hotwired/stimulus"
|
2
|
+
import consumer from "../channels/consumer"
|
3
|
+
|
4
|
+
const application = Application.start()
|
5
|
+
|
6
|
+
// Configure Stimulus development experience
|
7
|
+
application.debug = false
|
8
|
+
application.consumer = consumer
|
9
|
+
window.Stimulus = application
|
10
|
+
|
11
|
+
export { application }
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import { Controller } from '@hotwired/stimulus'
|
2
|
+
import StimulusReflex from 'stimulus_reflex'
|
3
|
+
|
4
|
+
// This is the Stimulus ApplicationController.
|
5
|
+
// All StimulusReflex controllers should inherit from this class.
|
6
|
+
//
|
7
|
+
// Example:
|
8
|
+
//
|
9
|
+
// import ApplicationController from './application_controller'
|
10
|
+
//
|
11
|
+
// export default class extends ApplicationController { ... }
|
12
|
+
//
|
13
|
+
// Learn more at: https://docs.stimulusreflex.com
|
14
|
+
//
|
15
|
+
|
16
|
+
export default class extends Controller {
|
17
|
+
connect () {
|
18
|
+
StimulusReflex.register(this)
|
19
|
+
}
|
20
|
+
|
21
|
+
// Application-wide lifecycle methods
|
22
|
+
//
|
23
|
+
// Use these methods to handle lifecycle callbacks for all controllers.
|
24
|
+
// Using lifecycle methods is optional, so feel free to delete these if you don't need them.
|
25
|
+
//
|
26
|
+
// Arguments:
|
27
|
+
//
|
28
|
+
// element - the element that triggered the reflex
|
29
|
+
// may be different than the Stimulus controller's this.element
|
30
|
+
//
|
31
|
+
// reflex - the name of the reflex e.g. "Example#demo"
|
32
|
+
//
|
33
|
+
// error/noop - the error message (for reflexError), otherwise null
|
34
|
+
//
|
35
|
+
// id - a UUID4 or developer-provided unique identifier for each Reflex
|
36
|
+
//
|
37
|
+
|
38
|
+
beforeReflex (element, reflex, noop, id) {
|
39
|
+
// document.body.classList.add('wait')
|
40
|
+
}
|
41
|
+
|
42
|
+
reflexQueued (element, reflex, noop, id) {
|
43
|
+
// Reflex will be delivered to server upon reconnection
|
44
|
+
}
|
45
|
+
|
46
|
+
reflexDelivered (element, reflex, noop, id) {
|
47
|
+
// Reflex has been delivered to the server
|
48
|
+
}
|
49
|
+
|
50
|
+
reflexSuccess (element, reflex, noop, id) {
|
51
|
+
// show success message
|
52
|
+
}
|
53
|
+
|
54
|
+
reflexError (element, reflex, error, id) {
|
55
|
+
// show error message
|
56
|
+
}
|
57
|
+
|
58
|
+
reflexForbidden (element, reflex, noop, id) {
|
59
|
+
// Reflex action did not have permission to run
|
60
|
+
// window.location = '/'
|
61
|
+
}
|
62
|
+
|
63
|
+
reflexHalted (element, reflex, noop, id) {
|
64
|
+
// handle aborted Reflex action
|
65
|
+
}
|
66
|
+
|
67
|
+
afterReflex (element, reflex, noop, id) {
|
68
|
+
// document.body.classList.remove('wait')
|
69
|
+
}
|
70
|
+
|
71
|
+
finalizeReflex (element, reflex, noop, id) {
|
72
|
+
// all operations have completed, animation etc is now safe
|
73
|
+
}
|
74
|
+
}
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
class
|
3
|
+
class <%= class_name %>Reflex < ApplicationReflex
|
4
|
+
<%- if class_name == "Example" -%>
|
4
5
|
# Add Reflex methods in this file.
|
5
6
|
#
|
6
7
|
# All Reflex instances include CableReady::Broadcaster and expose the following properties:
|
@@ -16,28 +17,56 @@ class UserReflex < ApplicationReflex
|
|
16
17
|
# - signed - use a signed Global ID to map dataset attribute to a model eg. element.signed[:foo]
|
17
18
|
# - unsigned - use an unsigned Global ID to map dataset attribute to a model eg. element.unsigned[:foo]
|
18
19
|
# - cable_ready - a special cable_ready that can broadcast to the current visitor (no brackets needed)
|
19
|
-
# -
|
20
|
+
# - id - a UUIDv4 that uniquely identifies each Reflex
|
21
|
+
# - tab_id - a UUIDv4 that uniquely identifies the browser tab
|
20
22
|
#
|
21
23
|
# Example:
|
22
24
|
#
|
23
25
|
# before_reflex do
|
24
26
|
# # throw :abort # this will prevent the Reflex from continuing
|
25
|
-
# # learn more about callbacks at https://docs.stimulusreflex.com/
|
27
|
+
# # learn more about callbacks at https://docs.stimulusreflex.com/guide/lifecycle
|
26
28
|
# end
|
27
29
|
#
|
28
30
|
# def example(argument=true)
|
29
|
-
# # Your logic here...
|
31
|
+
# # Your logic here! Update models, launch jobs, poll Redis...
|
32
|
+
#
|
33
|
+
# # By default, Reflexes call the controller action for the current page and render the view.
|
30
34
|
# # Any declared instance variables will be made available to the Rails controller and view.
|
35
|
+
#
|
36
|
+
# # You can also use the `morph` method to mark a Reflex as Selector or Nothing.
|
37
|
+
# # https://docs.stimulusreflex.com/guide/morph-modes#introducing-morphs
|
31
38
|
# end
|
32
39
|
#
|
33
|
-
# Learn more at: https://docs.stimulusreflex.com/
|
40
|
+
# Learn more at: https://docs.stimulusreflex.com/guide/reflex-classes
|
34
41
|
|
35
|
-
|
36
|
-
|
42
|
+
<%- end -%>
|
43
|
+
<%- if class_name == "Example" -%>
|
44
|
+
def increment
|
45
|
+
count = session[:count] || 0
|
46
|
+
session[:count] = count + 1
|
47
|
+
|
48
|
+
morph "#time", Time.now
|
49
|
+
morph "#count", session[:count]
|
37
50
|
|
38
|
-
|
51
|
+
cable_ready.set_value(selector: "progress", value: session[:count])
|
52
|
+
|
53
|
+
if session[:count] == 5
|
54
|
+
cable_ready.text_content(selector: "#reload", text: "Try reloading your browser window. The count is persisted in the session!")
|
55
|
+
end
|
56
|
+
|
57
|
+
if session[:count] >= 10
|
58
|
+
cable_ready.dispatch_event(name: "fireworks")
|
59
|
+
end
|
39
60
|
end
|
40
61
|
|
41
|
-
def
|
62
|
+
def reset
|
63
|
+
session[:count] = 0
|
64
|
+
end
|
65
|
+
<%- else -%>
|
66
|
+
<%- actions.each do |action| -%>
|
67
|
+
def <%= action %>
|
42
68
|
end
|
69
|
+
<%= "\n" unless action == actions.last -%>
|
70
|
+
<%- end -%>
|
71
|
+
<%- end -%>
|
43
72
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ApplicationReflex < StimulusReflex::Reflex
|
4
|
+
# Put application-wide Reflex behavior and callbacks in this file.
|
5
|
+
#
|
6
|
+
# Learn more at: https://docs.stimulusreflex.com/guide/reflex-classes
|
7
|
+
#
|
8
|
+
# If your ActionCable connection is: `identified_by :current_user`
|
9
|
+
# delegate :current_user, to: :connection
|
10
|
+
#
|
11
|
+
# current_user delegation alloqs you to use the Current pattern, too:
|
12
|
+
# before_reflex do
|
13
|
+
# Current.user = current_user
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
# To access view helpers inside Reflexes:
|
17
|
+
# delegate :helpers, to: :ApplicationController
|
18
|
+
#
|
19
|
+
# If you need to localize your Reflexes, you can set the I18n locale here:
|
20
|
+
#
|
21
|
+
# before_reflex do
|
22
|
+
# I18n.locale = :fr
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# For code examples, considerations and caveats, see:
|
26
|
+
# https://docs.stimulusreflex.com/guide/patterns#internationalization
|
27
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html lang="en">
|
3
|
+
<head>
|
4
|
+
<title>StimulusReflex Demo</title>
|
5
|
+
<meta charset="utf-8">
|
6
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
7
|
+
<%%= csrf_meta_tags %>
|
8
|
+
<%%= csp_meta_tag %>
|
9
|
+
|
10
|
+
<%% unless Rails.root.join("config/importmap.rb").exist? %>
|
11
|
+
<script type="importmap">
|
12
|
+
{
|
13
|
+
"imports": {
|
14
|
+
"fireworks-js": "https://ga.jspm.io/npm:fireworks-js@2.10.0/dist/index.es.js"
|
15
|
+
}
|
16
|
+
}
|
17
|
+
</script>
|
18
|
+
<%% end %>
|
19
|
+
|
20
|
+
<%% if respond_to?(:vite_javascript_tag) %>
|
21
|
+
<%%= vite_client_tag %>
|
22
|
+
<%%= vite_javascript_tag "application", defer: true %>
|
23
|
+
<%% elsif respond_to?(:javascript_pack_tag) %>
|
24
|
+
<%%= javascript_pack_tag "application", defer: true %>
|
25
|
+
<%% elsif respond_to?(:javascript_importmap_tags) %>
|
26
|
+
<%%= javascript_importmap_tags %>
|
27
|
+
<%% elsif respond_to?(:javascript_include_tag) %>
|
28
|
+
<%%= javascript_include_tag "application", defer: true %>
|
29
|
+
<%% end %>
|
30
|
+
|
31
|
+
<script async src="https://ga.jspm.io/npm:es-module-shims@1.5.1/dist/es-module-shims.js" crossorigin="anonymous"></script>
|
32
|
+
<script type="module">
|
33
|
+
import { Fireworks } from 'fireworks-js'
|
34
|
+
|
35
|
+
const fireworks = new Fireworks(document.querySelector('.fireworks'))
|
36
|
+
document.addEventListener('fireworks', () => fireworks.launch(12))
|
37
|
+
</script>
|
38
|
+
|
39
|
+
<link rel="stylesheet" href="https://unpkg.com/@picocss/pico@latest/css/pico.min.css">
|
40
|
+
</head>
|
41
|
+
|
42
|
+
<body style="cursor: auto;">
|
43
|
+
<main class="container">
|
44
|
+
<h1>StimulusReflex</h1>
|
45
|
+
|
46
|
+
<p>Actual demonstrations will show up in this space, soon. In the meantime, verify that your installation was successful:</p>
|
47
|
+
|
48
|
+
<button data-reflex="click->Example#increment">Increment</button>
|
49
|
+
<button data-reflex="click->Example#reset">Reset</button>
|
50
|
+
|
51
|
+
<br />
|
52
|
+
|
53
|
+
<div>
|
54
|
+
Last Refresh:
|
55
|
+
<b><mark id="time"><%%= Time.now %></mark></b>
|
56
|
+
</div>
|
57
|
+
|
58
|
+
<div>
|
59
|
+
Clicked
|
60
|
+
<b><mark id="count"><%%= session[:count] || 0 %></mark></b>
|
61
|
+
times
|
62
|
+
</div>
|
63
|
+
|
64
|
+
<br/>
|
65
|
+
|
66
|
+
<progress value="<%%= session[:count] %>" max="10"></progress>
|
67
|
+
|
68
|
+
<div id="reload"></div>
|
69
|
+
|
70
|
+
<h1>CableReady</h1>
|
71
|
+
|
72
|
+
<p>CableReady lets you control one or many clients from the server in real-time.</p>
|
73
|
+
|
74
|
+
<p>Everything in CableReady revolves around its <a href="https://cableready.stimulusreflex.com/reference/operations" target="_blank">38+</a> <b>operations</b>, which are commands that can update content, raise events, write cookies and even play audio. A group of one or more operations is called a <b>broadcast</b>. Broadcasts follow a <a href="https://dev.to/leastbad/the-cableready-language-implementation-project-4hjd">simple JSON format</a>.</p>
|
75
|
+
|
76
|
+
<p>We're going to go through the main ways developers use CableReady with some live demonstrations and code samples. We recommend that you open the controller class and ERB template for this page to follow along.</p>
|
77
|
+
|
78
|
+
<article>
|
79
|
+
<h3>Subscribe to a channel to receive broadcasts</h3>
|
80
|
+
|
81
|
+
WebSockets is the primary way most Rails developers use CableReady, via the <ins>cable_ready</ins> method.
|
82
|
+
|
83
|
+
<p>Use the <ins>cable_ready_stream_from</ins> helper to create a secure Action Cable subscription:</p>
|
84
|
+
|
85
|
+
<kbd>cable_ready_stream_from :example_page</kbd>
|
86
|
+
|
87
|
+
<%%= cable_ready_stream_from :example_page %>
|
88
|
+
|
89
|
+
<p style="margin-top: 1rem;">Every user looking at a page subscribed to the <ins>:example_page</ins> channel will receive the same broadcasts.</p>
|
90
|
+
|
91
|
+
<p>You can call <ins>cable_ready</ins> <a href="https://cableready.stimulusreflex.com/guide/cableready-everywhere" target="_blank">pretty much anywhere</a> in your application. Try it in your <kbd>rails console</kbd> now:</p>
|
92
|
+
|
93
|
+
<kbd>include CableReady::Broadcaster<br>cable_ready[:example_page].text_content("#cable_ready_stream_from_output", text: "Hello from the console!").broadcast</kbd>
|
94
|
+
|
95
|
+
<p style="margin-top: 1rem;">Any message you send will appear in the <ins>#cable_ready_stream_from_output</ins> DIV below — even if you <i>open multiple tabs</i>.</p>
|
96
|
+
|
97
|
+
<div id="cable_ready_stream_from_output" style="height: 2rem; font-weight: bolder; border: coral 2px dashed; padding: 0.15rem 0.4rem;"></div>
|
98
|
+
|
99
|
+
<p style="margin-top: 1rem;">While it's easy to <a href="https://cableready.stimulusreflex.com/guide/broadcasting-to-resources" target="_blank">create your own custom Action Cable channels</a>, <ins>cable_ready_stream_from</ins> will be the first tool you reach for, because it doesn't require any additional code.</p>
|
100
|
+
|
101
|
+
<p>Specify Active Record models or compound qualifiers to go full-ninja: 🥷</p>
|
102
|
+
|
103
|
+
<kbd>cable_ready_stream_from current_user</kbd><br>
|
104
|
+
|
105
|
+
<kbd style="margin-top: 0.3rem;">cable_ready_stream_from @post, :comments</kbd>
|
106
|
+
|
107
|
+
<p style="margin-top: 1rem;">These examples barely scrape the surface of what's possible. Be sure to check out the <a href="https://cableready.stimulusreflex.com/guide/identifiers" target="_blank">Stream Identifiers</a> chapter.</p>
|
108
|
+
</article>
|
109
|
+
|
110
|
+
<article>
|
111
|
+
<h3>Updatable: magically update the DOM when server-side data changes</h3>
|
112
|
+
|
113
|
+
<p>The <ins>updates_for</ins> helper allow you to designate sections of your page that will <a href="https://cableready.stimulusreflex.com/guide/updatable" target="_blank">update automatically</a> with new content when an Active Record model changes. 🤯</p>
|
114
|
+
|
115
|
+
<small>It's difficult to demonstrate this feature without creating a temporary model and a migration; a road to hell, paved with good intentions. However, you likely have these models (or similar) in your application. Uncomment, tweak if necessary and follow along!</small>
|
116
|
+
|
117
|
+
<p style="margin-top: 1rem;">First, call <ins>enable_updates</ins> in your model. You can use it on associations, too.</p>
|
118
|
+
|
119
|
+
<kbd> class User < ApplicationRecord<br>
|
120
|
+
enable_updates<br>
|
121
|
+
has_many :posts, enable_updates: true<br>
|
122
|
+
end<br>
|
123
|
+
<br>
|
124
|
+
class Post < ApplicationRecord<br>
|
125
|
+
belongs_to :user<br>
|
126
|
+
end
|
127
|
+
</kbd>
|
128
|
+
|
129
|
+
<p style="margin-top: 1rem;">By default, updates will be broadcast when any CRUD action is performed on the model. You can customize this behavior by passing options such as <ins>on: [:create, :update]</ins> or <ins>if: -> { id.even? }</ins>.</p>
|
130
|
+
|
131
|
+
<p>Next, use the <ins>updates_for</ins> helper to create one or more containers that will receive content updates.</p>
|
132
|
+
|
133
|
+
<kbd> <%= cable_ready_updates_for current_user do %><br>
|
134
|
+
<%= current_user.name %><br>
|
135
|
+
<% end %>
|
136
|
+
</kbd>
|
137
|
+
|
138
|
+
<!--
|
139
|
+
<%%#= cable_ready_updates_for current_user do %>
|
140
|
+
<p style="margin-top: 1rem;"><%%#= current_user.name %></p>
|
141
|
+
<%%# end %>
|
142
|
+
-->
|
143
|
+
|
144
|
+
<p style="margin-top: 1rem;">Update the current user in Rails console, and your page instantly reflects the new name. 🪄</p>
|
145
|
+
|
146
|
+
<p>Specify the class constant to get updates when records are created or deleted:</p>
|
147
|
+
|
148
|
+
<kbd> <%= cable_ready_updates_for User do %><br>
|
149
|
+
<ul><br>
|
150
|
+
<% @users.each do |user| %><br>
|
151
|
+
<li><%= user.name %></li><br>
|
152
|
+
<% end %><br>
|
153
|
+
</ul><br>
|
154
|
+
<% end %>
|
155
|
+
</kbd>
|
156
|
+
|
157
|
+
<!--
|
158
|
+
<%%#= cable_ready_updates_for User do %>
|
159
|
+
<ul style="margin-top: 1rem;">
|
160
|
+
<%%# @users.each do |user| %>
|
161
|
+
<li><%%#= user.name %></li>
|
162
|
+
<%%# end %>
|
163
|
+
</ul>
|
164
|
+
<%%# end %>
|
165
|
+
-->
|
166
|
+
|
167
|
+
<p style="margin-top: 1rem;">Update when new posts are created by the current user:</p>
|
168
|
+
|
169
|
+
<kbd> <%= cable_ready_updates_for current_user, :posts do %><br>
|
170
|
+
<ul><br>
|
171
|
+
<% @posts.each do |post| %><br>
|
172
|
+
<li><%= post.title %></li><br>
|
173
|
+
<% end %><br>
|
174
|
+
</ul><br>
|
175
|
+
<% end %>
|
176
|
+
</kbd>
|
177
|
+
|
178
|
+
<!--
|
179
|
+
<%%#= cable_ready_updates_for current_user, :posts do %>
|
180
|
+
<ul style="margin-top: 1rem;">
|
181
|
+
<%%# @posts.each do |post| %>
|
182
|
+
<li><%%#= post.title %></li>
|
183
|
+
<%%# end %>
|
184
|
+
</ul>
|
185
|
+
<%%# end %>
|
186
|
+
-->
|
187
|
+
|
188
|
+
<p style="margin-top: 1rem;">One major advantage of the Updatable approach is that each visitor sees <b>personalized content</b>. This is difficult with a WebSockets broadcast, where every subscriber receives the same data.</p>
|
189
|
+
|
190
|
+
<p>Instead, Updatable notifies all subscribers that an update is available, prompting each client to make a fetch request and refresh sections of the page.</p>
|
191
|
+
|
192
|
+
<p>There's more to <a href="https://cableready.stimulusreflex.com/guide/updatable" target="_blank">Updatable</a> than what's covered here... <i>but, not much more</i>. It really is that simple.</p>
|
193
|
+
</article>
|
194
|
+
|
195
|
+
<article>
|
196
|
+
<p>If you're finished with this example page and resource controller, you can destroy them:</p>
|
197
|
+
|
198
|
+
<kbd>rails destroy stimulus_reflex example</kbd>
|
199
|
+
</article>
|
200
|
+
|
201
|
+
<p>As always, please drop by the <a href="https://discord.gg/stimulus-reflex" target="_blank">StimulusReflex Discord server</a> if you have any questions or need support of any kind. We're incredibly proud of the community that has formed around these libraries, and we discuss everything from JavaScript/Ruby/CSS to View Component/Phlex to databases and CRDTs. <b>We'd love to hear what you're building with StimulusReflex and CableReady.</b></p>
|
202
|
+
|
203
|
+
<p>You can find the documentation for StimulusReflex <a href="https://docs.stimulusreflex.com" target="_blank">here</a> and CableReady <a href="https://cableready.stimulusreflex.com" target="_blank">here</a>.</p>
|
204
|
+
</main>
|
205
|
+
<div class="fireworks" style="position: fixed; bottom: 0; width: 100vw; height: 100vh; pointer-events: none;"></div>
|
206
|
+
</body>
|
207
|
+
</html>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
CableReady.configure do |config|
|
4
|
+
# Enable/disable exiting / warning when the sanity checks fail options:
|
5
|
+
# `:exit` or `:warn` or `:ignore`
|
6
|
+
#
|
7
|
+
# config.on_failed_sanity_checks = :exit
|
8
|
+
|
9
|
+
# Enable/disable assets compilation
|
10
|
+
# `true` or `false`
|
11
|
+
#
|
12
|
+
# config.precompile_assets = true
|
13
|
+
|
14
|
+
# Define your own custom operations
|
15
|
+
# https://cableready.stimulusreflex.com/customization#custom-operations
|
16
|
+
#
|
17
|
+
# config.add_operation_name :jazz_hands
|
18
|
+
|
19
|
+
# Change the default Active Job queue used for broadcast_later and broadcast_later_to
|
20
|
+
#
|
21
|
+
# config.broadcast_job_queue = :default
|
22
|
+
end
|