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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 992aeb83b159a49fae25e6e6897b120e288ad7f497352aa0580cc76d0d548d4e
4
- data.tar.gz: aa54afbad36600e60da26c0db20bd619381bcf8ee499817ef5111dbfa32cfd91
3
+ metadata.gz: 444a86a830537d630ccb1247fc6a601b84e30498c5e38d8ca5ce789e095117a6
4
+ data.tar.gz: 4373eae50d13855bf9895cc505ab323e2949bb73a90aa80d50888e9df4d14be2
5
5
  SHA512:
6
- metadata.gz: 89100b1162553474b8ee6f795d9f782b7ca1623a9ae62d77460b9a1edd1411d8b23fd404a16e114dcbe289b0091153a10f7ccfdc8c66dec089203a283e351dad
7
- data.tar.gz: eb7eed40ea71ebd9fe6b8ce872e8b18373ad3f34a352468a7a9f4fffd06d5cd9cd23d255313a95b2afd74bf3a452b47c13afb49b4ed3a64245fbe04e0a538697
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 `refresh_collaborative_rich_text`, inside the channel's handler
114
- for each update. There's no background job, so `post.body` is up to date as
115
- soon as the channel finishes handling the update.
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.collaborative_rich_text_grant(:body, expires_in: 10.minutes) }
171
+ render json: { grant: @post.collaborative_document(:body).grant(expires_in: 10.minutes) }
170
172
  end
171
173
  ```
172
174
 
173
- `collaborative_rich_text_grant` makes the same grant the form helper
174
- renders, for `LexxyRealtime::DocumentChannel`. A grant from yrby-rails'
175
- `collaborative_sgid` doesn't work here, because the channel checks a
176
- different purpose.
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
  }