Skip to content

Instantly share code, notes, and snippets.

@kachar
Created February 13, 2021 11:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kachar/b04e2b13b1419a0e6cc6fa0fda69f50d to your computer and use it in GitHub Desktop.
Save kachar/b04e2b13b1419a0e6cc6fa0fda69f50d to your computer and use it in GitHub Desktop.
cross-domain-local-storage ES6
/**
* Created by dagan on 07/04/2014.
* https://github.com/ofirdagan/cross-domain-local-storage
*/
const MESSAGE_NAMESPACE = "cross-domain-local-message";
/* global console */
export const xdLocalStorage = () => {
const requests = {};
let options = {
iframeId: "cross-domain-iframe",
iframeUrl: undefined,
initCallback: () => {},
};
let requestId = -1;
let iframe;
let wasInit = false;
let iframeReady = true;
const applyCallback = (data) => {
if (requests[data.id]) {
requests[data.id](data);
delete requests[data.id];
}
};
const receiveMessage = (event) => {
const { data, origin } = event;
if (origin !== window.origin) {
return;
}
console.debug("XD: receiveMessage1", event, origin);
if (data && data.namespace === MESSAGE_NAMESPACE) {
if (data.id === "iframe-ready") {
iframeReady = true;
options.initCallback();
} else {
applyCallback(data);
}
}
};
const buildMessage = (action, key, value, callback) => {
console.debug("XD: buildMessage", action, key, value, callback);
requestId++;
requests[requestId] = callback;
const data = {
namespace: MESSAGE_NAMESPACE,
id: requestId,
action,
key,
value,
};
iframe.contentWindow.postMessage(data, "*");
};
const init = (customOptions) => {
options = { ...options, ...customOptions };
if (window.addEventListener) {
window.addEventListener("message", receiveMessage, false);
} else {
window.attachEvent("onmessage", receiveMessage);
}
const temp = document.createElement("div");
temp.innerHTML = `<iframe id="${options.iframeId}" src="${options.iframeUrl}" style="display: none;"></iframe>`;
document.body.appendChild(temp);
iframe = document.getElementById(options.iframeId);
};
const isApiReady = () => {
if (!wasInit) {
console.log("You must call xdLocalStorage.init() before using it.");
return false;
}
if (!iframeReady) {
console.log(
"You must wait for iframe ready message before using the api."
);
return false;
}
return true;
};
const isDomReady = () => document.readyState === "complete";
return {
//callback is optional for cases you use the api before window load.
init: (customOptions) => {
if (!customOptions.iframeUrl) {
throw new Error("You must specify iframeUrl");
}
if (wasInit) {
console.log("xdLocalStorage was already initialized!");
return;
}
wasInit = true;
if (isDomReady()) {
init(customOptions);
} else {
if (document.addEventListener) {
// All browsers expect IE < 9
document.addEventListener("readystatechange", () => {
if (isDomReady()) {
init(customOptions);
}
});
} else {
// IE < 9
document.attachEvent("readystatechange", () => {
if (isDomReady()) {
init(customOptions);
}
});
}
}
},
setItem: (key, value, callback) => {
if (!isApiReady()) {
return;
}
buildMessage("set", key, value, callback);
},
getItem: (key, callback) => {
if (!isApiReady()) {
return;
}
buildMessage("get", key, null, callback);
},
removeItem: (key, callback) => {
if (!isApiReady()) {
return;
}
buildMessage("remove", key, null, callback);
},
key: (index, callback) => {
if (!isApiReady()) {
return;
}
buildMessage("key", index, null, callback);
},
getSize: (callback) => {
if (!isApiReady()) {
return;
}
buildMessage("size", null, null, callback);
},
getLength: (callback) => {
if (!isApiReady()) {
return;
}
buildMessage("length", null, null, callback);
},
clear: (callback) => {
if (!isApiReady()) {
return;
}
buildMessage("clear", null, null, callback);
},
wasInit: () => wasInit,
};
};
export default xdLocalStorage;
export const xdLocalStoragePostMessageApi = () => {
const defaultData = { namespace: MESSAGE_NAMESPACE };
const postData = (id, data) => {
const mergedData = { ...defaultData, id, ...data };
window.parent.postMessage(mergedData, "*");
};
const getData = (id, key) => {
const value = localStorage.getItem(key);
postData(id, { key, value });
};
const setData = (id, key, value) => {
localStorage.setItem(key, value);
const checkGet = localStorage.getItem(key);
postData(id, { success: checkGet === value });
};
const removeData = (id, key) => {
localStorage.removeItem(key);
postData(id, {});
};
const getKey = (id, index) => {
const key = localStorage.key(index);
postData(id, { key });
};
const getSize = (id) => {
const size = JSON.stringify(localStorage).length;
postData(id, { size });
};
const getLength = (id) => {
const length = localStorage.length;
postData(id, { length });
};
const clear = (id) => {
localStorage.clear();
postData(id, {});
};
const receiveMessage = (event) => {
const { data } = event;
console.debug("XD: receiveMessage20", event);
if (data && data.namespace === MESSAGE_NAMESPACE) {
if (data.action === "set") {
setData(data.id, data.key, data.value);
} else if (data.action === "get") {
getData(data.id, data.key);
} else if (data.action === "remove") {
removeData(data.id, data.key);
} else if (data.action === "key") {
getKey(data.id, data.key);
} else if (data.action === "size") {
getSize(data.id);
} else if (data.action === "length") {
getLength(data.id);
} else if (data.action === "clear") {
clear(data.id);
}
}
};
if (window.addEventListener) {
window.addEventListener("message", receiveMessage, false);
} else {
window.attachEvent("onmessage", receiveMessage);
}
const sendOnLoad = () => {
console.debug("XD: sendOnLoad");
const data = {
namespace: MESSAGE_NAMESPACE,
id: "iframe-ready",
};
window.parent.postMessage(data, "*");
};
//on creation
sendOnLoad();
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment