Skip to content

Commit

Permalink
Update cookie class
Browse files Browse the repository at this point in the history
  • Loading branch information
ahosgood committed Nov 16, 2023
1 parent effe15b commit 8b57273
Showing 1 changed file with 124 additions and 50 deletions.
174 changes: 124 additions & 50 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,38 @@ import Prism from "prismjs";

window.TNAFrontend.initAll();

class CookieEventHandler {
events = {};

constructor() {
if (CookieEventHandler._instance) {
return CookieEventHandler._instance;
}
CookieEventHandler._instance = this;
}

/**
* Add an event listener.
* @param {string} event - The event to add a listener for.
* @param {function} callback - The callback function to call when the event is triggered.
*/
on(event, callback) {
if (!Object.prototype.hasOwnProperty.call(this.events, event)) {
this.events[event] = [];
}
this.events[event] = [...this.events[event], callback];
}

/** @protected */
trigger(event, data = {}) {
if (Object.prototype.hasOwnProperty.call(this.events, event)) {
this.events[event].forEach((eventToTrigger) =>
eventToTrigger.call(this, data),
);
}
}
}

/**
* Class to handle cookies.
* @class Cookies
Expand All @@ -10,44 +42,68 @@ window.TNAFrontend.initAll();
*/
class Cookies {
/** @protected */
events = {};
cookiesPolicyKey = "cookies_policy";
extraPolicies = [];
/** @protected */
domain = "";
/** @protected */
secure = true;
/** @protected */
policiesKey = "";

/**
* Create a cookie handler.
* @param {string[]} [extraPolicies=[]] - The extra cookie policies to manage.
* @param {string} [cookiesPolicyKey=cookies_policy] - The name of the cookie.
* @param {string[]} [extraPolicies=[]] - The extra cookie policies to manage in addition to essential, settings and usage.
* @param {string} [options.domain=""] - The domain to register the cookie with.
* @param {string} [options.secure=true] - Only set cookie in HTTPS environments.
* @param {string} [options.policiesKey=cookies_policy] - The name of the cookie.
*/
constructor(extraPolicies = [], cookiesPolicyKey = "cookies_policy") {
constructor(extraPolicies = [], options = {}) {
const {
domain = "",
secure = true,
policiesKey = "cookies_policy",
} = options;
this.extraPolicies = extraPolicies;
this.domain = domain;
this.secure = secure;
this.policiesKey = policiesKey;
this.events = new CookieEventHandler();
this.init();
}

/** @protected */
init() {
this.savePolicies({
...Object.fromEntries(extraPolicies.map((k) => [k.toLowerCase(), false])),
...Object.fromEntries(
this.extraPolicies.map((k) => [k.toLowerCase(), false]),
),
usage: false,
settings: false,
...this.policies,
essential: true,
});
if (
Cookies._instance &&
Cookies._instance.cookiesPolicyKey === cookiesPolicyKey
) {
return Cookies._instance;
}
Cookies._instance = this;
this.cookiesPolicyKey = cookiesPolicyKey;
this.events = {};
}

get all() {
const deserialised = {};
document.cookie.split(";").forEach((cookie) => {
const parts = cookie.trim().split("=");
deserialised[parts[0]] = parts[1];
});
document.cookie
.split("; ")
.filter((x) => x)
.forEach((cookie) => {
const parts = cookie.trim().split("=");
if (parts[0]) {
deserialised[parts[0]] = parts[1];
}
});
return deserialised;
}

get policies() {
return JSON.parse(this.get(this.cookiesPolicyKey) || "{}");
try {
return JSON.parse(this.get(this.policiesKey) || "{}");
} catch (e) {
return {};
}
}

/**
Expand Down Expand Up @@ -86,27 +142,57 @@ class Cookies {
* @param {number} [options.maxAge=31536000] - The maximum age of the cookie in seconds.
* @param {string} [options.path=/] - The path to register the cookie for.
* @param {string} [options.sameSite=Lax] - The sameSite attribute.
* @param {string} [options.domain=this.domain] - The domain to register the cookie with.
* @param {string} [options.secure=this.secure] - Only set cookie in HTTPS environments.
*/
set(key, value, options = {}) {
const {
maxAge = 60 * 60 * 24 * 365,
path = "/",
sameSite = "Lax",
domain = this.domain,
secure = this.secure,
} = options;
document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(
if (!key) {
return;
}
const cookie = `${encodeURIComponent(key)}=${encodeURIComponent(value)};${
domain ? ` domain=${domain}; ` : ""
} samesite=${sameSite}; path=${path}; max-age=${maxAge}${
secure ? "; secure" : ""
}`;
document.cookie = cookie;
this.events.trigger("setCookie", {
key,
value,
)}; SameSite=${sameSite}; path=${path}; max-age=${maxAge}; Secure`;
this.trigger("setCookie", { key, value, maxAge, path, sameSite });
maxAge,
path,
sameSite,
domain,
secure,
cookie,
});
}

/**
* Delete a cookie.
* @param {string} key - The cookie name.
* @param {string} [path=/] - The path to the cookie is registered on.
*/
delete(key, path = "/") {
this.set(key, "", -1, path);
this.trigger("deleteCookie", { key, path });
delete(key, path = "/", domain = null) {
const options = { maxAge: -1, path, domain: domain || undefined };
this.set(key, "", options);
this.events.trigger("deleteCookie", { key, ...options });
}

/**
* Delete all cookies.
*/
deleteAll(path = "/", domain = null) {
Object.keys(this.all).forEach((cookie) => {
this.delete(cookie, path, domain);
});
this.events.trigger("deleteAllCookies", { path, domain });
}

/**
Expand All @@ -115,8 +201,8 @@ class Cookies {
*/
acceptPolicy(policy) {
this.setPolicy(policy, true);
this.trigger("acceptPolicy", policy);
this.trigger("changePolicy", { [policy]: true });
this.events.trigger("acceptPolicy", policy);
this.events.trigger("changePolicy", { [policy]: true });
}

/**
Expand All @@ -125,8 +211,8 @@ class Cookies {
*/
rejectPolicy(policy) {
this.setPolicy(policy, false);
this.trigger("rejectPolicy", policy);
this.trigger("changePolicy", { [policy]: false });
this.events.trigger("rejectPolicy", policy);
this.events.trigger("changePolicy", { [policy]: false });
}

/**
Expand All @@ -143,7 +229,7 @@ class Cookies {
[policy]: accepted,
essential: true,
});
this.trigger("changePolicy", { [policy]: accepted });
this.events.trigger("changePolicy", { [policy]: accepted });
}

/**
Expand All @@ -154,8 +240,8 @@ class Cookies {
Object.keys(this.policies).map((k) => [k.toLowerCase(), true]),
);
this.savePolicies(allPolicies);
this.trigger("acceptAllPolicies");
this.trigger("changePolicy", allPolicies);
this.events.trigger("acceptAllPolicies");
this.events.trigger("changePolicy", allPolicies);
}

/**
Expand All @@ -169,16 +255,16 @@ class Cookies {
essential: true,
};
this.savePolicies(allPolicies);
this.trigger("rejectAllPolicies");
this.trigger("changePolicy", allPolicies);
this.events.trigger("rejectAllPolicies");
this.events.trigger("changePolicy", allPolicies);
}

/**
* Commit policy preferences to the browser.
* @param {object} policies - The policies to commit.
*/
savePolicies(policies) {
this.set(this.cookiesPolicyKey, JSON.stringify(policies));
this.set(this.policiesKey, JSON.stringify(policies));
}

/**
Expand All @@ -193,24 +279,12 @@ class Cookies {
}

/**
* Accept a policy.
* Add an event listener.
* @param {string} event - The event to add a listener for.
* @param {function} callback - The callback function to call when the event is triggered.
*/
on(event, callback) {
if (!Object.prototype.hasOwnProperty.call(this.events, event)) {
this.events[event] = [];
}
this.events[event] = [...this.events[event], callback];
}

/** @protected */
trigger(event, data = {}) {
if (Object.prototype.hasOwnProperty.call(this.events, event)) {
this.events[event].forEach((eventToTrigger) =>
eventToTrigger.call(this, data),
);
}
this.events.on(event, callback);
}
}

Expand Down

0 comments on commit 8b57273

Please sign in to comment.