Skip to content

Instantly share code, notes, and snippets.

@generalmimon
Last active January 17, 2021 23:23
Show Gist options
  • Save generalmimon/0a7cdb1c112885025d4d84b5412bedab to your computer and use it in GitHub Desktop.
Save generalmimon/0a7cdb1c112885025d4d84b5412bedab to your computer and use it in GitHub Desktop.
User JS to automatically save <textarea> contents into browser localStorage (intended for GitHub)
// Not working version right now, grab an older one from Revisions
(function(storageKey) {
'use strict';
const IDLE_DELAY = 10 * 1000; // in miliseconds
let timeout;
let currentPageKey = null;
class UrlSync {
constructor() {
}
getPageKey(url) {
const urlObj = new URL(url);
urlObj.hash = '';
return urlObj.toString();
}
// should be called ASAP to ensure that no call escapes
observeHistoryManipulation(history) {
history.replaceState = function(...args) {
History.prototype.replaceState.call(this, ...args);
console.log('replaceState', args);
};
history.pushState = function(...args) {
History.prototype.pushState.call(this, ...args);
console.log('pushState', args);
};
}
}
function getPageKey() {
const url = new URL(location.href);
url.hash = '';
return url.toString();
}
function loadStorage(storageKey) {
const savedData = localStorage.getItem(storageKey);
if (savedData) {
try {
return JSON.parse(savedData);
} catch (e) {}
}
return {};
}
function getConflictText(editedText, savedText) {
return (
`<<<<<< Edited text
${editedText}
=======
${savedText}
>>>>>>> Saved draft in localStorage`
);
}
function restoreSession(data) {
for (let id in data) {
if (!data.hasOwnProperty(id)) continue;
const el = document.getElementById(id);
if (!el) continue;
if (!el.tagName || el.tagName.toLowerCase() !== 'textarea') {
console.warn(el, 'with id =', id, 'is not <textarea>, skipping');
continue;
}
if (el.value === data[id]) continue;
el.value = el.value ? getConflictText(el.value, data[id]) : data[id];
}
}
function initSession(storage, pageKey) {
const data = storage[pageKey];
if (!data) {
storage[pageKey] = {};
return;
}
restoreSession(data);
}
const {saveDraft, syncPageKey} = (function(storageKey) {
const storage = loadStorage(storageKey);
let isAlarm = false;
function saveDraft(id, content, el, pageKey) {
storage[pageKey][id] = content;
localStorage.setItem(storageKey, JSON.stringify(storage));
el.style.transition = 'background-color .5s';
el.style.backgroundColor = '#01ff707f';
setTimeout(() => {
el.style.backgroundColor = '';
}, 500);
}
function syncPageKey() {
const pageKey = getPageKey();
if (pageKey !== currentPageKey) {
initSession(storage, currentPageKey);
}
}
return {saveDraft, syncPageKey};
})(storageKey);
const {addSaveTask, resolveTasks} = (function(saveDraft) {
let todoTasks = {};
function addSaveTask(args, id) {
todoTasks[id] = args;
}
function resolveTasks() {
for (let id in todoTasks) {
saveDraft.apply(null, todoTasks[id]);
}
todoTasks = {};
}
return {addSaveTask, resolveTasks};
})(saveDraft);
document.addEventListener('input', (e) => {
const el = e.target;
if (!el.tagName || el.tagName.toLowerCase() !== 'textarea') return true;
addSaveTask([el.id, el.value, el], el.id);
if (timeout) clearTimeout(timeout);
timeout = setTimeout(resolveTasks, IDLE_DELAY);
});
window.addEventListener('load', onPageLoad);
})('textareaDrafts');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment