198 lines
5.9 KiB
HTML
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>
|