introducing: preserve unsaved changes on bearblog posts
Is this you: "OH FUCK!!! I just accidentally closed my browser and I forgot to save my Bearblog post. All that progress is lost!!!"
First of all, stop cursing. Children read this site for God's sake. Secondly, I wrote a script to help fix this problem.
Herman wants to keep Bearblog free of JavaScript, which I totally get. It's a noble endeavor, but one of the massive problems with keeping this site JavaScript-free is that you lose out on nice-to-have features that can really only be accomplished via JavaScript.
The good thing is that the users are able to add custom scripts to their dashboards via this page: https://bearblog.dev/dashboard/customise/
Introducing: Preserved Unsaved Changes on Bearblog
This script is intended for people (like me) who write their posts in the Bearblog editor, rather than somewhere else like in the Notes app or elsewhere. This script will save a copy of your draft to your browser storage and restore it back.
🚨 Please keep in mind that this is different from the "Save as Draft" feature that Bearblog offers natively. This is intended purely for those who might forget to press "Save as Draft" at the top of a new post before exiting the page.
Features include:
- Auto-saves a draft when refreshing or closing the browser when editing an existing post
- will not save periodically, only when leaving the page through some mechanism like refreshing or browser close
- Auto-saves a draft when refreshing or closing the browser when creating a new unsaved/unpublished post
- again, will not save periodically, only when leaving the page through some mechanism like refreshing or browser close
- Customize whether you only want to save drafts of new posts, existing posts, or both
- Unique drafts. Editing 2 different posts will produce 2 different drafts, so drafts will not overwrite each other
- Drafts will last for 2 hours then be deleted on next visit (but this duration can be customized to your liking)
- Customize whether you want to be asked first before restoring a draft or if you want it done automatically when the page loads
- This is on by default, but may be super annoying to some people
How to Install
- Go to your Dashboard customize page: https://bearblog.dev/dashboard/customise/
- Paste the script below into the "Dashboard footer content" section
- Set the
SAVE_DRAFT_ON_NEW_POST_PAGE_ENABLED
variable totrue
orfalse
if you want draft saving on new posts - Set the
SAVE_DRAFT_ON_EDIT_EXISTING_POST_PAGE_ENABLED
variable totrue
orfalse
if you want draft saving on existing/saved posts - Set the
ASK_BEFORE_RESTORING_DRAFT
totrue
orfalse
if you want to be asked first before restoring the draft- You might want to set this to
false
since the prompt may get annoying
- You might want to set this to
- Set the
HOW_MANY_HOURS_TO_KEEP_DRAFTS
to a number of hours you want the drafts to remain for. The default is 2 - Hit the "Save" button to save the script
<script type="text/javascript">
(() => {
/*
the following script will save bearblog posts to a browser storage so that
the page can be refreshed and the previously drafted post can persist.
Feel free to change the settings below to your liking
*/
/* START SETTINGS: */
/*
change these to false if you want to turn off saving drafts
on a specific page
*/
const SAVE_DRAFT_ON_NEW_POST_PAGE_ENABLED = true;
const SAVE_DRAFT_ON_EDIT_EXISTING_POST_PAGE_ENABLED = true;
/*
change to false if you want to automatically restore drafts
without asking first
*/
const ASK_BEFORE_RESTORING_DRAFT = true;
/*
change how many hours you want the drafts to persist for
*/
const HOW_MANY_HOURS_TO_KEEP_DRAFTS = 2;
/* END SETTINGS */
const storageKeyNew = 'beardraft_newpost';
const storageKeyEdit = (uuid) => `beardraft_editpost_${uuid}`;
/* whether or not you're on the create new post page */
const isNewPage = !!location.pathname.match(/posts\/new\/*$/);
/*
the bearblog URL split into a list of word groups
(e.g. "posts/fmwyyiAgqWjjBhKzKzaH", "posts/", "fmwyyiAgqWjjBhKzKzaH")
*/
const editPageGroups = location.pathname.match(/(posts\/)(\w*)/);
/* whether or not you're on the editing existing post page */
const isEditPage = !!editPageGroups;
/* the unique ID of your bear post, seen in the URL */
const postUUID = !!editPageGroups ? editPageGroups[2] : '';
/* current date in milliseconds */
const now = Date.now();
const setDraft = (key, value, _now, expiresInHours) => {
const expiresinMS = expiresInHours * 60 * 60 * 1000;
localStorage.setItem(key, `{ "expires": ${_now + expiresinMS}, "post": "${value}" }`);
};
const getDraft = (key) => {
try {
const _value = localStorage.getItem(key);
const valueAsJSON = JSON.parse(_value);
return valueAsJSON?.post;
} catch (e) {
return undefined;
}
};
const expireOldDrafts = (_now) => {
const allLocalStorageValues = { ...localStorage };
(Object.keys(allLocalStorageValues) || []).forEach((eachKey) => {
const isBearDraft = !!eachKey.match(/beardraft/gi);
if (isBearDraft) {
try {
const draftValue = allLocalStorageValues[eachKey];
const valueAsObject = JSON.parse(draftValue);
if (typeof valueAsObject?.expires === 'number' && valueAsObject.expires < _now) {
localStorage.removeItem(eachKey);
}
} catch (e) {}
}
}, []);
};
/* get rid of expired drafts from local storage */
expireOldDrafts(now);
/*
paste the draft to the field if new page
*/
const bodyContent = document.getElementById('body_content');
if (SAVE_DRAFT_ON_NEW_POST_PAGE_ENABLED && isNewPage && !!bodyContent) {
const draftValue = getDraft(storageKeyNew);
if (!!draftValue) {
if (
!ASK_BEFORE_RESTORING_DRAFT ||
(ASK_BEFORE_RESTORING_DRAFT &&
window.confirm(
'You have an unsaved draft saved in your browser storage. Want to restore this post from that draft?'
))
) {
bodyContent.value = decodeURIComponent(draftValue);
}
}
}
/*
paste the draft to the field if edit page
*/
if (SAVE_DRAFT_ON_EDIT_EXISTING_POST_PAGE_ENABLED && isEditPage && !!bodyContent) {
const draftValue = getDraft(storageKeyEdit(postUUID));
if (!!draftValue) {
if (
!ASK_BEFORE_RESTORING_DRAFT ||
(ASK_BEFORE_RESTORING_DRAFT &&
window.confirm(
'You have an unsaved draft saved in your browser storage. Want to restore this post from that draft?'
))
) {
bodyContent.value = decodeURIComponent(draftValue);
}
}
}
window.addEventListener('beforeunload', () => {
/* the actual content of the post */
const postBodyElement = document.getElementById('body_content');
const postBody = !!postBodyElement ? postBodyElement.value : '';
/* only sets the draft if there is any text in the post */
if (!!postBody) {
if (isNewPage) {
if (SAVE_DRAFT_ON_NEW_POST_PAGE_ENABLED && !!postBody) {
/* save a new draft if we're on the "create new post" page */
setDraft(storageKeyNew, encodeURIComponent(postBody), now, HOW_MANY_HOURS_TO_KEEP_DRAFTS);
}
} else if (isEditPage) {
/* save an editing draft if we're on the "editing an existing post" page */
if (SAVE_DRAFT_ON_EDIT_EXISTING_POST_PAGE_ENABLED && !!postBody) {
setDraft(storageKeyEdit(postUUID), encodeURIComponent(postBody), now, HOW_MANY_HOURS_TO_KEEP_DRAFTS);
}
}
}
});
})();
</script>
like this post? discuss it on the forums at basementcommunity.com. Or you can also send me an email!