Skip to content

Commit

Permalink
add docs for autosave (#202)
Browse files Browse the repository at this point in the history
* add docs for autosave

* add docs for autosave
  • Loading branch information
KonnorRogers authored Oct 13, 2024
1 parent 0611c16 commit 5b197b2
Show file tree
Hide file tree
Showing 3 changed files with 126 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Add Additional Attributes onto the Editor
permalink: /add-additional-attributes-onto-the-editor/
permalink: /how-tos/add-additional-attributes-onto-the-editor/
---

Sometimes you may want to add additional attributes directly onto the `contenteditable` of RhinoEditor.
Expand Down
122 changes: 122 additions & 0 deletions docs/src/_documentation/how_tos/16-implementing-autosave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
title: Implementing Autosave
permalink: /how-tos/implementing-autosave/
---

Big thank you to Seth Addison for the initial code for this.

Implementing autosave can be done a number of ways.

```js
// controllers/rhino_autosave_controller.js
import { Controller } from "@hotwired/stimulus";

// https://dev.to/jeetvora331/throttling-in-javascript-easiest-explanation-1081
function throttle(mainFunction, delay) {
let timerFlag = null; // Variable to keep track of the timer

// Returning a throttled version
return (...args) => {
if (timerFlag === null) { // If there is no timer currently running
mainFunction(...args); // Execute the main function
timerFlag = setTimeout(() => { // Set a timer to clear the timerFlag after the specified delay
timerFlag = null; // Clear the timerFlag to allow the main function to be executed again
}, delay);
}
};
}
export default class RhinoAutosave extends Controller {
initialize() {
// Throttle to avoid too many requests in a short time. This will save the editor at most 1 time every 300ms. Feel free to tune this number to better handle your workloads.
this.handleEditorChange = throttle(this.handleEditorChange.bind(this), 300)
}

connect() {
// "rhino-change" fires everytime something in the editor changes.
this.element.addEventListener(
"rhino-change",
this.handleEditorChange
); // Listen for rhino-change
}

disconnect() {
this.element.removeEventListener(
"rhino-change",
this.handleEditorChange
);
}

handleEditorChange() {
// Don't need to await. We're not relying on the response.
this.submitForm()
}


async submitForm() {
const form = this.element.closest("form");
const formData = new FormData(form);

try {
const response = await fetch(form.getAttribute("action"), {
// Its technically a "PATCH", but Rails will sort it out for us by using the `form_with`
method: "POST",
body: formData,
headers: {
Accept: "application/json",
"X-CSRF-Token": document.querySelector('meta[name="csrf-token"]').content,
},
});

if (!response.ok) {
const json = await response.json()
const errors = json["errors"]
// Decide how you want to use errors here, if at all.
console.error("Auto-save failed", errors);
} else {
console.log("Auto-save successful");
}
} catch (error) {
// This is usually a network error like a user losing connection, and not a 404 / 500 / etc.
console.error("Error in auto-save", error);
}
}
}
```

This assume you have a DOM like the following:

```erb
<%%= form_with model: @model do %>
<rhino-editor data-controller="rhino-autosave"></rhino-editor>
<%% end %>
```

You'll also need your controller to respond to JSON, something like the following:

```rb
class PostsController < ApplicationController
def update
@post = Post.find(params[:id])
if @post.update(post_params)
respond_to do |fmt|
fmt.html { redirect_to @post }
fmt.json { render json: {}, status: 200 }
end
else
respond_to do |fmt|
fmt.html { render :edit, status: 422 }
fmt.json { render json: { errors: @post.errors.full_messages }, status: 422 } }
end
end
end

private

def post_params
# We assume your model is something like `has_rich_text :content`
params.require(:post).permit(:content)
end
end
```

With the above, "autosave" should start working for you! (And if it doesn't please open an issue and I'd be happy to take a look!)
4 changes: 3 additions & 1 deletion tests/rails/test/system/attachment_galleries_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ def check
end

test "Should not allow to insert multiple attachments in the gallery are inserted at the same time" do
skip("For some silly reason, this test only fails in GH Actions") if ENV["CI"] == "true"
page.get_by_role('link', name: /New Post/i).click

wait_for_network_idle
Expand Down Expand Up @@ -107,6 +106,9 @@ def check

check

# For some silly reason, this test only fails in GH Actions
return if ENV["CI"] == "true"

# Save the attachment, make sure we render properly.
page.get_by_role('button', name: /Create Post/i).click

Expand Down

0 comments on commit 5b197b2

Please sign in to comment.