Files
2020-11-14 07:31:27 -05:00

198 lines
5.9 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LocalStorage - Cross-Tab Communication with JavaScript</title>
<link
href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css"
rel="stylesheet"
/>
<link
rel="stylesheet"
href="https://unpkg.com/@tailwindcss/typography@0.2.x/dist/typography.min.css"
/>
<style>
ol li {
padding-left: 0.75rem !important;
}
ol li:before {
content: none !important;
}
</style>
</head>
<body class="prose lg:prose-lg mx-auto mt-8">
<nav class="flex space-x-6 mb-6">
<a href="/">Home</a>
<a href="/localstorage" class="font-bold">LocalStorage</a>
<a href="/sharedworker">SharedWorker</a>
<a href="/broadcastchannel">BroadcastChannel</a>
</nav>
<h1>LocalStorage Cross-Tab Communication</h1>
<form id="sendMessageForm">
<label class="block font-bold">Add A Message</label>
<div class="flex flex-wrap md:flex-no-wrap">
<input
name="message"
class="w-full px-2 py-1 md:rounded-l border border-gray-400 focus:border-gray-600"
/>
<button
type="submit"
class="px-3 py-1 md:rounded-r bg-gray-800 text-gray-100 hover:bg-gray-900"
>
Send
</button>
</div>
</form>
<div class="flex justify-between items-baseline">
<h3>Messages</h3>
<form id="clearMessagesForm">
<button type="submit">Clear Messages</button>
</form>
</div>
<p id="messagesPlaceholder">No messages</p>
<ol id="messages" class="list-none grid"></ol>
<script>
const messagesEl = document.getElementById('messages');
const messagesPlaceholderEl = document.getElementById('messagesPlaceholder');
const messagesKey = 'messages';
const senderIdKey = 'senderId';
const tabSenderId = getSenderId();
/* FUNCTIONALITY CODE */
loadMessages();
document.forms.sendMessageForm.addEventListener('submit', handleSendMessage);
document.forms.clearMessagesForm.addEventListener('submit', handleClearMessages);
window.addEventListener('storage', handleNewMessage);
function handleSendMessage(event) {
event.preventDefault();
const value = event.target.message.value;
const message = makeMessage(value);
const messages = addMessage(message);
handleNewMessage({ key: messagesKey, newValue: messages });
setStringifiedStorageItem(messagesKey, messages);
event.target.reset();
event.target.message.focus();
}
function handleClearMessages(event) {
if (event) event.preventDefault();
setStringifiedStorageItem(messagesKey, []);
messagesEl.innerHTML = '';
showEl(messagesPlaceholderEl);
}
function handleNewMessage({ key, newValue, oldValue = getMessages() }) {
newValue = parseArray(newValue);
oldValue = parseArray(oldValue);
if (!newValue || !newValue.length) {
return handleClearMessages();
}
const newMessages = getArrayDifference(newValue, oldValue, 'id');
displayMessages(newMessages);
hideEl(messagesPlaceholderEl);
}
function addMessage(message) {
let messages = getMessages();
messages.push(message);
return messages;
}
function makeMessage(message) {
return {
id: getUniqueId(),
senderId: tabSenderId,
message,
};
}
function makeMessageEl({ message, id, senderId }) {
const li = document.createElement('li');
const baseClassName = 'px-3 py-1 rounded';
li.id = id;
li.textContent = message;
li.className =
senderId == tabSenderId
? `${baseClassName} bg-blue-600 text-white place-self-end`
: `${baseClassName} bg-gray-700 text-white place-self-start`;
return li;
}
function loadMessages() {
const messages = getMessages();
if (messages.length) {
hideEl(messagesPlaceholderEl);
}
displayMessages(messages);
}
function displayMessages(messages) {
messages.forEach((msg) => messagesEl.appendChild(makeMessageEl(msg)));
}
function getMessages() {
const messages = getParsedStorageItem(messagesKey);
return !Array.isArray(messages) ? [] : messages;
}
/* UTILITIES */
function hideEl(el) {
el.classList.add('hidden');
}
function showEl(el) {
el.classList.remove('hidden');
}
function parseArray(item) {
if (!item || !item.length) return [];
return !Array.isArray(item) ? JSON.parse(item) : item;
}
function getArrayDifference(primary, secondary, key) {
return key
? primary.filter((x) => !secondary.find((y) => x[key] === y[key]))
: primary.filter((item) => !secondary.includes(item));
}
function setStringifiedStorageItem(key, value) {
localStorage.setItem(key, value ? JSON.stringify(value) : value);
}
function getParsedStorageItem(storageKey) {
let stringValue = localStorage.getItem(storageKey);
return stringValue ? JSON.parse(stringValue) : stringValue;
}
function getSenderId() {
let senderId = sessionStorage.getItem(senderIdKey) || getUniqueId();
sessionStorage.setItem(senderIdKey, senderId);
return senderId;
}
function getUniqueId() {
return '_' + Math.random().toString(36).substr(2, 9);
}
</script>
</body>
</html>