Skip to content

Commit

Permalink
Initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
BernhardBaumrock committed Mar 29, 2024
1 parent 5f58f2d commit b82a439
Show file tree
Hide file tree
Showing 6 changed files with 491 additions and 1 deletion.
58 changes: 58 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Release on Push

on:
push:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: "14"

- name: Install Dependencies
run: npm install

- name: Minify consenty.js
run: npx terser consenty.js -o consenty.min.js -c -m

- name: Commit minified file
run: |
git config --local user.email "[email protected]"
git config --local user.name "GitHub Action"
git add consenty.min.js
git commit -m "Minify consenty.js" -a || echo "No changes to commit"
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
force: true

- name: Create Release
id: create_release
uses: actions/create-release@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
draft: false
prerelease: false

- name: Upload Release Asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: ./consenty.min.js
asset_name: consenty.min.js
asset_content_type: application/javascript
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
# Consenty
Simple vanilla javascript consent management for your website.

Welcome to Consenty, a sleek and straightforward vanilla JavaScript library designed to simplify consent management on your website. Whether you're looking to embed YouTube videos, use cookies, or manage any other type of user consent, Consenty has got you covered.

## Why Consenty?

Ever found yourself thinking, "All I want to do is embed a YouTube video on my site. How hard can it be?" Well, in the EU and many other places, you're required to obtain user consent before loading external assets like YouTube videos. This is where Consenty shines! It offers a lightweight, easy-to-implement solution for managing user consents without the need for bulky consent management platforms or annoying cookie banners.

Building your own consent management tool might seem daunting, but with Consenty, it's a breeze. We handle the nitty-gritty details, such as interfacing with local storage and ensuring users can easily revoke their permissions at any time.

For a deep dive into how to implement and use Consenty, check out our comprehensive documentation at [baumrock.github.io/Consenty](https://baumrock.github.io/Consenty).

And hey, if you find Consenty as useful as we hope you will, why not give us a star on GitHub? It's proven to increase your karma and bring eternal happiness (results may vary).
166 changes: 166 additions & 0 deletions consenty.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
var consenty;
(() => {
class Consenty {
elements = {};

allow(prop) {
this.save(prop, true);
}

getStorage() {
let json = localStorage.getItem("consenty") || "{}";
let storage;
try {
storage = JSON.parse(json);
if (typeof storage !== "object") return {};
if (!storage) return {};
return storage;
} catch (e) {
return {};
}
}

handleChange(e) {
const el = e.target;

// handle checkbox toggle
if (el.type === "checkbox" && el.hasAttribute("consenty-toggle")) {
const prop = el.getAttribute("consenty-toggle");
if (el.checked) this.allow(prop);
else this.revoke(prop);
}
}

handleClick(e) {
let el;
if ((el = e.target.closest("[consenty-allow]"))) {
// clicked on element with allow attribute
const prop = el.getAttribute("consenty-allow");
this.allow(prop);
} else if ((el = e.target.closest("[consenty-revoke]"))) {
// clicked on element with revoke attribute
const prop = el.getAttribute("consenty-revoke");
this.revoke(prop);
}
}

hasConsent(name) {
let storage = this.getStorage();
return storage && name in storage ? !!storage[name] : false;
}

hideElement(id) {
const element = this.elements[id];
if (element.new) {
element.new.remove();
element.new = false;
this.elements[id] = element;
}
}

init() {
this.reload();
document.dispatchEvent(new CustomEvent("consenty:init"));
}

initCheckboxes() {
document.querySelectorAll("[consenty-toggle]").forEach((checkbox) => {
checkbox.checked = this.hasConsent(
checkbox.getAttribute("consenty-toggle")
);
});
}

reload() {
this.toggleIFs();
this.initCheckboxes();
}

revoke(prop) {
this.save(prop, false);
}

save(prop, value) {
let storage = this.getStorage();
const from = this.hasConsent(prop);
if (!value) {
delete storage[prop];
document.dispatchEvent(
new CustomEvent("consenty:revoke", { detail: prop })
);
} else {
storage[prop] = 1;
document.dispatchEvent(
new CustomEvent("consenty:allow", { detail: prop })
);
}
this.saveStorage(storage);
document.dispatchEvent(
new CustomEvent("consenty:change", {
detail: {
name: prop,
from: from,
to: this.hasConsent(prop),
},
})
);
this.toggleIFs();
}

saveStorage(storage) {
localStorage.setItem("consenty", JSON.stringify(storage));
}

toggleIFs() {
document.querySelectorAll("[consenty-if]").forEach((el) => {
// get or set id of this element for later use
let id;
if (!el.hasAttribute("data-consenty-id")) {
id = Object.keys(this.elements).length + 1;
this.elements[id] = { old: el, new: false };
el.setAttribute("data-consenty-id", id);
} else {
id = el.getAttribute("data-consenty-id");
}

// get property name and type
const rawprop = el.getAttribute("consenty-if");
const type = rawprop.startsWith("!") ? "hideif" : "showif";
let prop = type === "showif" ? rawprop : rawprop.substring(1);

// toggle element / code
if (type === "showif") {
if (this.hasConsent(prop)) this.showElement(id);
else this.hideElement(id);
} else {
if (this.hasConsent(prop)) this.hideElement(id);
else this.showElement(id);
}
});
}

showElement(id) {
const element = this.elements[id];
if (!element.new) {
let tagName = element.old.tagName.toLowerCase();
if (tagName === "template") {
let newDiv = document.createElement("div");
let el = element.old;
el.parentNode.insertBefore(newDiv, el.nextSibling);
newDiv.appendChild(document.importNode(el.content, true));
element.new = newDiv;
this.elements[id] = element;
this.reload();
}
}
}
}

// load consenty when dom is ready
document.addEventListener("DOMContentLoaded", function () {
consenty = new Consenty();
consenty.init();
document.addEventListener("click", consenty.handleClick.bind(consenty));
document.addEventListener("change", consenty.handleChange.bind(consenty));
});
})();
Loading

0 comments on commit b82a439

Please sign in to comment.