lexxy-realtime 0.8.0 → 0.9.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 +13 -8
- data/app/assets/javascript/lexxy_realtime/yrby-client.js +13 -0
- data/app/assets/javascript/lexxy_realtime/yrby-client.js.map +1 -1
- data/app/assets/javascript/lexxy_realtime/yrby-client.min.js +1 -1
- data/app/channels/lexxy_realtime/document_channel.rb +1 -1
- data/lib/lexxy_realtime/attribute.rb +73 -0
- data/lib/lexxy_realtime/collaborative.rb +17 -45
- data/lib/lexxy_realtime/engine.rb +4 -0
- data/lib/lexxy_realtime/form_builder.rb +4 -3
- data/lib/lexxy_realtime/version.rb +1 -1
- data/lib/lexxy_realtime.rb +5 -0
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 444a86a830537d630ccb1247fc6a601b84e30498c5e38d8ca5ce789e095117a6
|
|
4
|
+
data.tar.gz: 4373eae50d13855bf9895cc505ab323e2949bb73a90aa80d50888e9df4d14be2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 23d8d6e07ccd5af9548f0bab391f4b91b1673fabc4a6e5f51d9ce9b4a7777f3abde513e01ebce95afab2b1c2c3b941fe9b9c3a140086f9f99648253f26c00d86
|
|
7
|
+
data.tar.gz: c782da01923dbd52a49016f4971d3f6309c3bd0074705b461c8c6cf028d6a7216a2316bc63dfb6b9e621f5b75f5cfaaf5a4e64a3e0c74e127cc03680164b70d7
|
data/README.md
CHANGED
|
@@ -110,9 +110,11 @@ turn the setting off again. The gem doesn't include a task for this.
|
|
|
110
110
|
|
|
111
111
|
The channel saves each CRDT update, renders the full document with
|
|
112
112
|
`Y::Lexxy`, and saves the HTML through the Action Text writer. This
|
|
113
|
-
happens in `
|
|
114
|
-
for each update. There's no background job, so
|
|
115
|
-
soon as the channel finishes handling the
|
|
113
|
+
happens in `post.collaborative_document(:body).refresh`, inside the
|
|
114
|
+
channel's handler for each update. There's no background job, so
|
|
115
|
+
`post.body` is up to date as soon as the channel finishes handling the
|
|
116
|
+
update. An edit from Ruby, `post.collaborative_document(:body).edit`,
|
|
117
|
+
renders the body the same way.
|
|
116
118
|
|
|
117
119
|
If rendering fails, the channel logs the error and keeps the update. The
|
|
118
120
|
next update renders the full document again. Until then, `post.body`
|
|
@@ -166,14 +168,17 @@ subscription is rejected:
|
|
|
166
168
|
# app/controllers/posts_controller.rb
|
|
167
169
|
def grant
|
|
168
170
|
@post = current_user.posts.find(params[:id]) # your own authorization, again
|
|
169
|
-
render json: { grant: @post.
|
|
171
|
+
render json: { grant: @post.collaborative_document(:body).grant(expires_in: 10.minutes) }
|
|
170
172
|
end
|
|
171
173
|
```
|
|
172
174
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
For a field declared with `has_collaborative_rich_text`,
|
|
176
|
+
`collaborative_document(:body)` returns this gem's document. Its `grant` is
|
|
177
|
+
the one the form helper renders, its `channel` is
|
|
178
|
+
`LexxyRealtime::DocumentChannel`, `edit` changes the document from Ruby and
|
|
179
|
+
renders the body, and `refresh` renders the body on demand. Code that takes
|
|
180
|
+
a yrby-rails document, such as `collaborative_document_tag`, gets this
|
|
181
|
+
gem's grant and channel for the field.
|
|
177
182
|
|
|
178
183
|
That action grants write access, so its check must be at least as strict
|
|
179
184
|
as the page that renders the form. If it skips authorization, anyone who
|
|
@@ -1317,6 +1317,12 @@ var ActionCableProvider = class {
|
|
|
1317
1317
|
#resolveSynced;
|
|
1318
1318
|
#onDocUpdate = () => this.#refreshStatus();
|
|
1319
1319
|
#page = null;
|
|
1320
|
+
#presence = null;
|
|
1321
|
+
#onAwarenessUpdate = ({ added, updated, removed }) => {
|
|
1322
|
+
if (this.#state.phase !== "disconnected") return;
|
|
1323
|
+
const id = this.awareness.clientID;
|
|
1324
|
+
if (added.includes(id) || updated.includes(id) || removed.includes(id)) this.#presence = null;
|
|
1325
|
+
};
|
|
1320
1326
|
/**
|
|
1321
1327
|
* Resolves once the document has first caught up with the server. Most
|
|
1322
1328
|
* editor bindings seed an empty document when they mount, so binding
|
|
@@ -1349,6 +1355,7 @@ var ActionCableProvider = class {
|
|
|
1349
1355
|
}
|
|
1350
1356
|
};
|
|
1351
1357
|
this.awareness = new ProviderAwareness(doc, this.#onError);
|
|
1358
|
+
this.awareness.on("update", this.#onAwarenessUpdate);
|
|
1352
1359
|
this.session = new YProtocolSession(doc, {
|
|
1353
1360
|
awareness: this.awareness,
|
|
1354
1361
|
resendInterval: opts.resendInterval,
|
|
@@ -1397,6 +1404,10 @@ var ActionCableProvider = class {
|
|
|
1397
1404
|
phase: "subscribing",
|
|
1398
1405
|
attempt
|
|
1399
1406
|
};
|
|
1407
|
+
const presence = this.#presence;
|
|
1408
|
+
this.#presence = null;
|
|
1409
|
+
if (presence) this.awareness.setLocalState(presence);
|
|
1410
|
+
if (!this.#subscribing(attempt)) return;
|
|
1400
1411
|
const on = (callback) => (...args) => {
|
|
1401
1412
|
const run = () => {
|
|
1402
1413
|
if (this.#active(attempt)) callback(...args);
|
|
@@ -1499,6 +1510,7 @@ var ActionCableProvider = class {
|
|
|
1499
1510
|
};
|
|
1500
1511
|
this.#state = stopping;
|
|
1501
1512
|
this.#unwatchPage();
|
|
1513
|
+
this.#presence = this.awareness.getLocalState();
|
|
1502
1514
|
this.session.removeLocalAwareness();
|
|
1503
1515
|
this.session.pause();
|
|
1504
1516
|
this.#unsubscribe(state.subscription);
|
|
@@ -1514,6 +1526,7 @@ var ActionCableProvider = class {
|
|
|
1514
1526
|
}
|
|
1515
1527
|
#destroyOwned() {
|
|
1516
1528
|
this.session.destroy();
|
|
1529
|
+
this.awareness.off("update", this.#onAwarenessUpdate);
|
|
1517
1530
|
this.awareness.destroy();
|
|
1518
1531
|
this.doc.off("update", this.#onDocUpdate);
|
|
1519
1532
|
}
|