turbo_live 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +18 -4
- data/examples/flappy_bird_component.rb +143 -0
- data/examples/showcase_component.rb +8 -3
- data/lib/turbo_live/component.rb +7 -5
- data/lib/turbo_live/renderer.rb +1 -1
- data/lib/turbo_live/version.rb +1 -1
- data/lib/turbo_live.rb +1 -0
- data/package-lock.json +2 -2
- data/package.json +1 -1
- data/src/js/channels/turbo_live_channel.js +7 -5
- data/src/js/controllers/register_controllers.js +2 -0
- data/src/js/controllers/turbo_live_controller.js +25 -63
- data/src/js/controllers/turbo_live_meta_data_controller.js +69 -0
- data/src/js/core.js +2 -1
- data/src/js/logger.js +57 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 973ebc91558a780fcdfc2e8dea4c6b1bc3d090678ee30535768e3b9d7ad1f9aa
|
4
|
+
data.tar.gz: 63e48c4f2b207557d9b111609a3dad42a10f70ea3719ea96a1477ed8f4e952fe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1118112757bfde64bbdd6417827ad56ea031ba950f2006a8151436f55101ca14543b991317d3825ecd143844417b2fafe84c2d6cccf7d408c9c14d213e18c1f
|
7
|
+
data.tar.gz: 7c1269811dd43b3a80188f9cafefc571c198c0eb9bd5adf9683353b7a67ef4ef915832a29bdf3fc1db710eeeb10a8ebca4b1829d4b05dacb7e2d05468891c01d
|
data/README.md
CHANGED
@@ -139,9 +139,9 @@ Handle events in the `update` method:
|
|
139
139
|
```ruby
|
140
140
|
def update(input)
|
141
141
|
case input
|
142
|
-
in
|
142
|
+
in :increment
|
143
143
|
self.count += 1
|
144
|
-
in
|
144
|
+
in :decrement
|
145
145
|
self.count -= 1
|
146
146
|
end
|
147
147
|
end
|
@@ -165,7 +165,21 @@ You can also emit compound events that carry extra data:
|
|
165
165
|
button(**on(click: [:change_value, 1])) { "+" }
|
166
166
|
```
|
167
167
|
|
168
|
-
|
168
|
+
Certain events carry extra data as well, such as `input` and `change` events.
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
input(value:, input_value, **on(input: :input_changed))
|
172
|
+
```
|
173
|
+
|
174
|
+
```ruby
|
175
|
+
def update(input)
|
176
|
+
case input
|
177
|
+
in [:input_changed, value]
|
178
|
+
self.input_value = value
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
> Note: Currently, only `:click`, `:input` and `:change` events are supported.
|
169
183
|
|
170
184
|
### Timed Events
|
171
185
|
|
@@ -201,7 +215,7 @@ class CounterComponentTest < ActiveSupport::TestCase
|
|
201
215
|
test "increments count" do
|
202
216
|
component = CounterComponent.new
|
203
217
|
assert_equal 0, component.count
|
204
|
-
component.update(
|
218
|
+
component.update(:increment)
|
205
219
|
assert_equal 1, component.count
|
206
220
|
end
|
207
221
|
end
|
@@ -0,0 +1,143 @@
|
|
1
|
+
class FlappyBirdComponent < TurboLive::Component
|
2
|
+
GRAVITY = 0.5
|
3
|
+
JUMP_STRENGTH = -10.0
|
4
|
+
GAME_HEIGHT = 400
|
5
|
+
GAME_WIDTH = 300
|
6
|
+
BIRD_SIZE = 20
|
7
|
+
OBSTACLE_WIDTH = 50
|
8
|
+
GAP_HEIGHT = 100
|
9
|
+
OBSTACLE_SPEED = 2
|
10
|
+
|
11
|
+
state :bird_y, Float do |value|
|
12
|
+
value || 150.0
|
13
|
+
end
|
14
|
+
|
15
|
+
state :bird_velocity, Float do |value|
|
16
|
+
value || 0.0
|
17
|
+
end
|
18
|
+
|
19
|
+
state :obstacles, Array do |value|
|
20
|
+
value || []
|
21
|
+
end
|
22
|
+
|
23
|
+
state :score, Integer do |value|
|
24
|
+
value || 0
|
25
|
+
end
|
26
|
+
|
27
|
+
state :game_over, _Boolean
|
28
|
+
|
29
|
+
state :nonce, Integer do |value|
|
30
|
+
value || 0
|
31
|
+
end
|
32
|
+
|
33
|
+
NONCES = {}
|
34
|
+
|
35
|
+
def initialize(...)
|
36
|
+
super
|
37
|
+
NONCES[live_id] ||= 0
|
38
|
+
end
|
39
|
+
|
40
|
+
def view
|
41
|
+
div(class: "flappy-bird-game") do
|
42
|
+
render_game
|
43
|
+
render_controls
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def render_game
|
48
|
+
svg(viewBox: "0 0 #{GAME_WIDTH} #{GAME_HEIGHT}", width: GAME_WIDTH, height: GAME_HEIGHT) do |svg|
|
49
|
+
# Render bird
|
50
|
+
svg.circle(cx: 50, cy: bird_y, r: BIRD_SIZE / 2, fill: "yellow")
|
51
|
+
|
52
|
+
# Render obstacles
|
53
|
+
obstacles.each do |obstacle|
|
54
|
+
svg.rect(x: obstacle[:x], y: 0, width: OBSTACLE_WIDTH, height: obstacle[:top], fill: "green")
|
55
|
+
svg.rect(x: obstacle[:x], y: obstacle[:bottom], width: OBSTACLE_WIDTH, height: GAME_HEIGHT - obstacle[:bottom], fill: "green")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Render score
|
59
|
+
svg.text(x: 10, y: 30, fill: "white", "font-size": "20px") { score.to_s }
|
60
|
+
|
61
|
+
# Render game over message
|
62
|
+
if game_over
|
63
|
+
svg.text(x: GAME_WIDTH / 2, y: GAME_HEIGHT / 2, fill: "red", "font-size": "30px", "text-anchor": "middle") { "Game Over" }
|
64
|
+
else
|
65
|
+
every(1000 / 30.0, :tick)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def render_controls
|
71
|
+
div(class: "controls") do
|
72
|
+
button(**on(click: :jump)) { "Jump / Restart" }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def update(input)
|
77
|
+
case input
|
78
|
+
in [:jump]
|
79
|
+
if game_over
|
80
|
+
reset_game
|
81
|
+
else
|
82
|
+
self.nonce = NONCES[live_id] = NONCES[live_id] + 1
|
83
|
+
self.bird_velocity = JUMP_STRENGTH
|
84
|
+
end
|
85
|
+
in [:tick]
|
86
|
+
norender! if nonce < NONCES[live_id]
|
87
|
+
update_game_state
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
def update_game_state
|
94
|
+
return if game_over
|
95
|
+
|
96
|
+
# Update bird position
|
97
|
+
self.bird_velocity += GRAVITY
|
98
|
+
self.bird_y += bird_velocity
|
99
|
+
|
100
|
+
# Add new obstacles
|
101
|
+
if obstacles.empty? || obstacles.last[:x] < GAME_WIDTH - 200
|
102
|
+
add_obstacle
|
103
|
+
end
|
104
|
+
|
105
|
+
# Update obstacle positions
|
106
|
+
self.obstacles = obstacles.map do |obstacle|
|
107
|
+
obstacle[:x] -= OBSTACLE_SPEED
|
108
|
+
obstacle
|
109
|
+
end.reject { |obstacle| obstacle[:x] < -OBSTACLE_WIDTH }
|
110
|
+
|
111
|
+
# Check collisions
|
112
|
+
check_collisions
|
113
|
+
|
114
|
+
# Update score
|
115
|
+
self.score += 1 if obstacles.any? { |obstacle| obstacle[:x] == 48 } # Bird's x position is 50, width is 20
|
116
|
+
end
|
117
|
+
|
118
|
+
def add_obstacle
|
119
|
+
gap_start = rand(50..(GAME_HEIGHT - GAP_HEIGHT - 50))
|
120
|
+
obstacles << {x: GAME_WIDTH, top: gap_start, bottom: gap_start + GAP_HEIGHT}
|
121
|
+
end
|
122
|
+
|
123
|
+
def check_collisions
|
124
|
+
if bird_y < 0 || bird_y > GAME_HEIGHT
|
125
|
+
self.game_over = true
|
126
|
+
end
|
127
|
+
|
128
|
+
obstacles.each do |obstacle|
|
129
|
+
if (obstacle[:x] < 70 && obstacle[:x] > 30) &&
|
130
|
+
(bird_y < obstacle[:top] + BIRD_SIZE / 2 || bird_y > obstacle[:bottom] - BIRD_SIZE / 2)
|
131
|
+
self.game_over = true
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def reset_game
|
137
|
+
self.bird_y = 150.0
|
138
|
+
self.bird_velocity = 0.0
|
139
|
+
self.obstacles = []
|
140
|
+
self.score = 0
|
141
|
+
self.game_over = false
|
142
|
+
end
|
143
|
+
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
class ShowcaseComponent < TurboLive::Component
|
2
|
-
state :component, Symbol
|
2
|
+
state :component, Symbol do |value|
|
3
|
+
value || :counter
|
4
|
+
end
|
3
5
|
|
4
6
|
def view
|
5
7
|
div class: "container" do
|
@@ -9,6 +11,7 @@ class ShowcaseComponent < TurboLive::Component
|
|
9
11
|
li { button(**on(click: [:change_component, :counter])) { "Counter" } }
|
10
12
|
li { button(**on(click: [:change_component, :countdown])) { "Countdown" } }
|
11
13
|
li { button(**on(click: [:change_component, :tic_tac_toe])) { "TicTacToe" } }
|
14
|
+
li { button(**on(click: [:change_component, :flappy_bird])) { "Flappy Bird" } }
|
12
15
|
end
|
13
16
|
end
|
14
17
|
div class: "right-column" do
|
@@ -30,12 +33,14 @@ class ShowcaseComponent < TurboLive::Component
|
|
30
33
|
|
31
34
|
def selected_component
|
32
35
|
case component
|
36
|
+
when :counter
|
37
|
+
CounterComponent
|
33
38
|
when :countdown
|
34
39
|
CountdownComponent
|
35
40
|
when :tic_tac_toe
|
36
41
|
TicTacToeComponent
|
37
|
-
|
38
|
-
|
42
|
+
when :flappy_bird
|
43
|
+
FlappyBirdComponent
|
39
44
|
end
|
40
45
|
end
|
41
46
|
end
|
data/lib/turbo_live/component.rb
CHANGED
@@ -23,7 +23,8 @@ module TurboLive
|
|
23
23
|
id: verifiable_live_id,
|
24
24
|
style: "display: contents;",
|
25
25
|
data_controller: "turbo-live",
|
26
|
-
data_turbo_live_component_value: to_verifiable(serialize)
|
26
|
+
data_turbo_live_component_value: to_verifiable(serialize),
|
27
|
+
data_turbo_live_protocol_version_value: TurboLive::PROTOCOL_VERSION
|
27
28
|
) do
|
28
29
|
view
|
29
30
|
end
|
@@ -67,12 +68,13 @@ module TurboLive
|
|
67
68
|
|
68
69
|
private
|
69
70
|
|
70
|
-
def add_meta(type,
|
71
|
-
# TODO: turbo morph does some wonky things issues here since it doesn't force a replacement everytime
|
71
|
+
def add_meta(type, data)
|
72
72
|
div(
|
73
|
-
|
74
|
-
data_turbo_live_meta_value: value,
|
73
|
+
data_controller: "turbo-live-meta-data",
|
75
74
|
data_turbo_live_target: "meta",
|
75
|
+
data_turbo_live_meta_data_type_value: type,
|
76
|
+
data_turbo_live_meta_data_data_value: data,
|
77
|
+
data_action: "turbo:before-morph-element->turbo-live-meta-data#beforeMorph turbo:morph-element->turbo-live-meta-data#afterMorph",
|
76
78
|
style: "display: none;", display: :none
|
77
79
|
) {}
|
78
80
|
end
|
data/lib/turbo_live/renderer.rb
CHANGED
data/lib/turbo_live/version.rb
CHANGED
data/lib/turbo_live.rb
CHANGED
data/package-lock.json
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
{
|
2
2
|
"name": "@radioactive-labs/turbo-live",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.2.0",
|
4
4
|
"lockfileVersion": 3,
|
5
5
|
"requires": true,
|
6
6
|
"packages": {
|
7
7
|
"": {
|
8
8
|
"name": "@radioactive-labs/turbo-live",
|
9
|
-
"version": "0.
|
9
|
+
"version": "0.2.0",
|
10
10
|
"license": "MIT",
|
11
11
|
"dependencies": {
|
12
12
|
"@hotwired/stimulus": "^3.2.2",
|
data/package.json
CHANGED
@@ -1,30 +1,32 @@
|
|
1
|
+
import { logger } from "../logger.js"
|
2
|
+
|
1
3
|
export default function (consumer) {
|
2
4
|
consumer.subscriptions.create({ channel: "TurboLive::ComponentsChannel" }, {
|
3
5
|
// Called once when the subscription is created.
|
4
6
|
initialized() {
|
5
|
-
|
7
|
+
logger.debug("TurboLiveChannel initialized")
|
6
8
|
},
|
7
9
|
|
8
10
|
// Called when the subscription is ready for use on the server.
|
9
11
|
connected() {
|
10
|
-
|
12
|
+
logger.debug("TurboLiveChannel connected")
|
11
13
|
window.turboLive = this;
|
12
14
|
},
|
13
15
|
|
14
16
|
received(turbo_stream) {
|
15
|
-
|
17
|
+
logger.info("TurboLiveChannel received", turbo_stream)
|
16
18
|
Turbo.renderStreamMessage(turbo_stream);
|
17
19
|
},
|
18
20
|
|
19
21
|
// Called when the WebSocket connection is closed.
|
20
22
|
disconnected() {
|
21
|
-
|
23
|
+
logger.debug("TurboLiveChannel disconnected")
|
22
24
|
window.turboLive = null;
|
23
25
|
},
|
24
26
|
|
25
27
|
// Called when the subscription is rejected by the server.
|
26
28
|
rejected() {
|
27
|
-
|
29
|
+
logger.debug("TurboLiveChannel rejected")
|
28
30
|
window.turboLive = null;
|
29
31
|
},
|
30
32
|
})
|
@@ -1,7 +1,9 @@
|
|
1
1
|
// Import controllers here
|
2
2
|
import TurboLiveController from "./turbo_live_controller.js"
|
3
|
+
import TurboLiveMetaDataController from "./turbo_live_meta_data_controller.js"
|
3
4
|
|
4
5
|
export default function (application) {
|
5
6
|
// Register controllers here
|
6
7
|
application.register("turbo-live", TurboLiveController)
|
8
|
+
application.register("turbo-live-meta-data", TurboLiveMetaDataController)
|
7
9
|
}
|
@@ -1,9 +1,13 @@
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
2
|
+
import { logger } from "../logger.js"
|
3
|
+
|
4
|
+
const SupportedProtocolVersion = "0.2.0"
|
2
5
|
|
3
6
|
export default class extends Controller {
|
4
7
|
static values = {
|
5
8
|
id: String,
|
6
9
|
component: String,
|
10
|
+
protocolVersion: String,
|
7
11
|
}
|
8
12
|
static targets = ["meta"]
|
9
13
|
|
@@ -11,101 +15,59 @@ export default class extends Controller {
|
|
11
15
|
return this.componentValue
|
12
16
|
}
|
13
17
|
|
14
|
-
initialize() {
|
15
|
-
this.metaTargetsMap = new WeakMap()
|
16
|
-
this.metaTargetsCount = 0
|
17
|
-
this.intervals = {}
|
18
|
-
}
|
19
|
-
|
20
18
|
connect() {
|
21
|
-
|
19
|
+
logger.log("TurboLiveController connect", this.element.id, this.protocolVersionValue)
|
20
|
+
if (SupportedProtocolVersion != this.protocolVersionValue) {
|
21
|
+
throw Error(`
|
22
|
+
Protocol version ${this.protocolVersionValue} is not supported
|
23
|
+
(supported version: ${SupportedProtocolVersion})
|
24
|
+
`)
|
25
|
+
}
|
22
26
|
}
|
23
27
|
|
24
28
|
metaTargetConnected(target) {
|
25
|
-
|
26
|
-
this
|
27
|
-
|
28
|
-
|
29
|
-
metaTargetDisconnected(target) {
|
30
|
-
console.log("TurboLiveController metaTargetDisconnected", this.element.id, this.#metaTargetId(target))
|
31
|
-
this.#teardownInterval(this.#metaTargetId(target))
|
32
|
-
}
|
33
|
-
|
34
|
-
disconnect() {
|
35
|
-
console.log("TurboLiveController disconnected", this.element.id)
|
36
|
-
this.#cleanup()
|
29
|
+
logger.debug("TurboLiveController metaTargetConnected", this.element.id, target)
|
30
|
+
this.application
|
31
|
+
.getControllerForElementAndIdentifier(target, "turbo-live-meta-data")
|
32
|
+
.setComponent(this)
|
37
33
|
}
|
38
34
|
|
39
35
|
dispatch(event, payload) {
|
40
|
-
console.log("TurboLiveController dispatch", this.element.id, event, payload)
|
41
36
|
const data = { id: this.element.id, event, payload, component: this.component }
|
37
|
+
logger.info("TurboLiveController dispatching", this.element.id, data)
|
42
38
|
|
43
39
|
if (window.turboLive) {
|
44
|
-
|
40
|
+
logger.debug("TurboLiveController dispatching via", this.element.id, "websockets")
|
45
41
|
window.turboLive.send(data)
|
46
42
|
} else {
|
47
|
-
|
43
|
+
logger.debug("TurboLiveController dispatching via", this.element.id, "http")
|
48
44
|
this.#dispatchHTTP(data)
|
49
45
|
}
|
50
46
|
}
|
51
47
|
|
52
48
|
onClick(event) {
|
53
|
-
|
49
|
+
logger.debug("TurboLiveController onClick", this.element.id, event)
|
54
50
|
this.#dispatchSimpleEvent("click", event)
|
55
51
|
}
|
56
52
|
|
57
53
|
onChange(event) {
|
58
|
-
|
54
|
+
logger.debug("TurboLiveController onChange", this.element.id, event)
|
59
55
|
this.#dispatchValueEvent("change", event)
|
60
56
|
}
|
61
57
|
|
62
58
|
onInput(event) {
|
63
|
-
|
59
|
+
logger.debug("TurboLiveController onInput", this.element.id, event)
|
64
60
|
this.#dispatchValueEvent("input", event)
|
65
61
|
}
|
66
62
|
|
67
|
-
#metaTargetId(target) {
|
68
|
-
if (!this.metaTargetsMap.has(target)) {
|
69
|
-
this.metaTargetsMap.set(target, ++this.metaTargetsCount)
|
70
|
-
}
|
71
|
-
return this.metaTargetsMap.get(target)
|
72
|
-
}
|
73
|
-
|
74
|
-
#readMetadata(element) {
|
75
|
-
const type = element.dataset.turboLiveMetaType
|
76
|
-
if (type === "interval") {
|
77
|
-
this.#setupInterval(element)
|
78
|
-
}
|
79
|
-
}
|
80
|
-
|
81
|
-
#setupInterval(element) {
|
82
|
-
try {
|
83
|
-
const config = JSON.parse(element.dataset.turboLiveMetaValue)
|
84
|
-
this.intervals[this.#metaTargetId(element)] = setInterval(() => {
|
85
|
-
this.dispatch("interval", [config.event])
|
86
|
-
}, config.interval)
|
87
|
-
} catch (e) {
|
88
|
-
console.error(e)
|
89
|
-
}
|
90
|
-
}
|
91
|
-
|
92
|
-
#teardownInterval(id) {
|
93
|
-
if (this.intervals[id]) {
|
94
|
-
clearInterval(this.intervals[id])
|
95
|
-
delete this.intervals[id]
|
96
|
-
}
|
97
|
-
}
|
98
|
-
|
99
|
-
#cleanup() {
|
100
|
-
Object.keys(this.intervals).forEach(this.#teardownInterval.bind(this))
|
101
|
-
}
|
102
|
-
|
103
63
|
#dispatchSimpleEvent(name, { params }) {
|
64
|
+
logger.debug("TurboLiveController dispatchSimpleEvent", this.element.id, name, params)
|
104
65
|
const liveEvent = params[name]
|
105
66
|
this.dispatch(name, [liveEvent])
|
106
67
|
}
|
107
68
|
|
108
69
|
#dispatchValueEvent(name, { params, target }) {
|
70
|
+
logger.debug("TurboLiveController dispatchValueEvent", this.element.id, name, params)
|
109
71
|
const value = target.value
|
110
72
|
const liveEvent = params[name]
|
111
73
|
this.dispatch(name, [liveEvent, value])
|
@@ -126,11 +88,11 @@ export default class extends Controller {
|
|
126
88
|
return response.text()
|
127
89
|
})
|
128
90
|
.then(turboStream => {
|
129
|
-
|
91
|
+
logger.info('TurboLiveController dispatch success', this.element.id, turboStream)
|
130
92
|
if (turboStream) Turbo.renderStreamMessage(turboStream)
|
131
93
|
})
|
132
94
|
.catch((error) => {
|
133
|
-
|
95
|
+
logger.error('TurboLiveController dispatch error', this.element.id, error)
|
134
96
|
})
|
135
97
|
}
|
136
98
|
}
|
@@ -0,0 +1,69 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
import { logger } from "../logger.js"
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
static values = {
|
6
|
+
type: String,
|
7
|
+
data: String,
|
8
|
+
}
|
9
|
+
|
10
|
+
connect() {
|
11
|
+
logger.debug("TurboLiveMetaDataController connected", this.typeValue, this.dataValue)
|
12
|
+
this.#setup(this.typeValue, this.dataValue)
|
13
|
+
}
|
14
|
+
|
15
|
+
disconnect() {
|
16
|
+
logger.debug("TurboLiveMetaDataController disconnected", this.typeValue, this.dataValue)
|
17
|
+
this.#teardown()
|
18
|
+
this.component = null
|
19
|
+
}
|
20
|
+
|
21
|
+
beforeMorph({ detail: { currentElement, newElement } }) {
|
22
|
+
logger.debug("TurboLiveMetaDataController beforeMorph", this.typeValue, this.dataValue)
|
23
|
+
if (currentElement.dataset.turboLiveMetaType != newElement.dataset.turboLiveMetaType ||
|
24
|
+
currentElement.dataset.turboLiveMetaValue != newElement.dataset.turboLiveMetaValue) {
|
25
|
+
logger.info("TurboLiveMetaDataController changed",
|
26
|
+
this.typeValue, this.dataValue,
|
27
|
+
newElement.dataset.turboLiveMetaDataTypeValue, newElement.dataset.turboLiveMetaDataDataValue)
|
28
|
+
|
29
|
+
this.changedDuringMorph = true
|
30
|
+
// teardown here since we still have our current state
|
31
|
+
this.#teardown()
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
afterMorph() {
|
36
|
+
logger.debug("TurboLiveMetaDataController afterMorph", this.typeValue, this.dataValue)
|
37
|
+
if (this.changedDuringMorph) {
|
38
|
+
this.#setup(this.typeValue, this.dataValue)
|
39
|
+
this.changedDuringMorph = false
|
40
|
+
}
|
41
|
+
}
|
42
|
+
|
43
|
+
setComponent(component) {
|
44
|
+
logger.debug("TurboLiveMetaDataController setComponent", this.typeValue, this.dataValue, component)
|
45
|
+
this.component = component
|
46
|
+
}
|
47
|
+
|
48
|
+
#setup(type, data) {
|
49
|
+
logger.debug("TurboLiveMetaDataController #setup", this.typeValue, this.dataValue, type, data)
|
50
|
+
if (type === "interval") {
|
51
|
+
this.#setupInterval(JSON.parse(data))
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
#teardown() {
|
56
|
+
logger.debug("TurboLiveMetaDataController #teardown", this.typeValue, this.dataValue)
|
57
|
+
if (this.interval) {
|
58
|
+
clearInterval(this.interval)
|
59
|
+
this.interval = null
|
60
|
+
}
|
61
|
+
}
|
62
|
+
|
63
|
+
#setupInterval(config) {
|
64
|
+
logger.debug("TurboLiveMetaDataController #setupInterval", this.typeValue, this.dataValue, config)
|
65
|
+
this.interval = setInterval(() => {
|
66
|
+
this.component.dispatch("interval", [config.event])
|
67
|
+
}, config.interval)
|
68
|
+
}
|
69
|
+
}
|
data/src/js/core.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import registerControllers from "./controllers/register_controllers.js"
|
2
2
|
import registerChannels from "./channels/register_channels.js"
|
3
|
+
import { logger, Logger } from "./logger.js"
|
3
4
|
|
4
5
|
|
5
|
-
export { registerControllers, registerChannels }
|
6
|
+
export { registerControllers, registerChannels, logger, Logger }
|
data/src/js/logger.js
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
export class Logger {
|
2
|
+
static LOG_LEVELS = {
|
3
|
+
OFF: -1,
|
4
|
+
ERROR: 0,
|
5
|
+
WARN: 1,
|
6
|
+
INFO: 2,
|
7
|
+
DEBUG: 3
|
8
|
+
};
|
9
|
+
|
10
|
+
constructor(level = Logger.LOG_LEVELS.OFF) {
|
11
|
+
this.setLevel(level)
|
12
|
+
}
|
13
|
+
|
14
|
+
setLevel(level) {
|
15
|
+
if (typeof level === 'string' && level in Logger.LOG_LEVELS) {
|
16
|
+
this.level = Logger.LOG_LEVELS[level];
|
17
|
+
} else if (typeof level === 'number' && (level === -1 || Object.values(Logger.LOG_LEVELS).includes(level))) {
|
18
|
+
this.level = level;
|
19
|
+
} else {
|
20
|
+
throw new Error('Invalid log level');
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
error(...args) {
|
25
|
+
if (this.level >= Logger.LOG_LEVELS.ERROR) console.error('[ERROR]', ...args);
|
26
|
+
}
|
27
|
+
|
28
|
+
warn(...args) {
|
29
|
+
if (this.level >= Logger.LOG_LEVELS.WARN) console.warn('[WARN]', ...args);
|
30
|
+
}
|
31
|
+
|
32
|
+
info(...args) {
|
33
|
+
if (this.level >= Logger.LOG_LEVELS.INFO) console.info('[INFO]', ...args);
|
34
|
+
}
|
35
|
+
|
36
|
+
debug(...args) {
|
37
|
+
if (this.level >= Logger.LOG_LEVELS.DEBUG) console.log('[DEBUG]', ...args);
|
38
|
+
}
|
39
|
+
|
40
|
+
log(...args) {
|
41
|
+
if (this.level > Logger.LOG_LEVELS.OFF) this.info(...args);
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
export const logger = new Logger();
|
46
|
+
|
47
|
+
// Usage examples:
|
48
|
+
// import { Logger, logger } from './logger.js';
|
49
|
+
//
|
50
|
+
// logger.setLevel('DEBUG');
|
51
|
+
// logger.debug('This is a debug message');
|
52
|
+
//
|
53
|
+
// logger.setLevel(-1);
|
54
|
+
// logger.error('This error will not be logged');
|
55
|
+
//
|
56
|
+
// const customLogger = new Logger(Logger.LOG_LEVELS.OFF);
|
57
|
+
// customLogger.error('This error will not be logged either');
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: turbo_live
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TheDumbTechGuy
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-10-
|
11
|
+
date: 2024-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: phlex-rails
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- config/routes.rb
|
58
58
|
- examples/countdown_component.rb
|
59
59
|
- examples/counter_component.rb
|
60
|
+
- examples/flappy_bird_component.rb
|
60
61
|
- examples/showcase_component.rb
|
61
62
|
- examples/tic_tac_toe_component.rb
|
62
63
|
- lib/turbo_live.rb
|
@@ -72,7 +73,9 @@ files:
|
|
72
73
|
- src/js/channels/turbo_live_channel.js
|
73
74
|
- src/js/controllers/register_controllers.js
|
74
75
|
- src/js/controllers/turbo_live_controller.js
|
76
|
+
- src/js/controllers/turbo_live_meta_data_controller.js
|
75
77
|
- src/js/core.js
|
78
|
+
- src/js/logger.js
|
76
79
|
homepage: https://github.com/radioactive-labs/turbo_live
|
77
80
|
licenses:
|
78
81
|
- MIT
|