~callum/beavers-dam

4021a627384f766145d027f283f58d828d1b0512 — Callum Brown 1 year, 29 days ago 4c27bd7
declarativeNetRequest refactor
6 files changed, 133 insertions(+), 135 deletions(-)

D content/content.css
D content/content.js
A dam/dam.html
A dam/dam.js
M manifest.json
M popup/popup.js
D content/content.css => content/content.css +0 -9
@@ 1,9 0,0 @@
#beavers-dam {
	height: 100%;
	width: 100%;
	position: fixed;
	top: 0;
	left: 0;
	background-color: lightblue;
	z-index: 999999999;
}

D content/content.js => content/content.js +0 -86
@@ 1,86 0,0 @@
const save = (text) => {
	chrome.storage.local.get(
		{ entries: [] }
	).then((items) => {
		// Can't store a Map, use an Object instead
		const entry = {
			"date": Date(),
			"hostname": location.hostname,
			"text": text,
		};
		items.entries.push(entry);
		chrome.storage.local.set(
			{ entries: items.entries }
		);
	});
};


const undam = (hostname) => {
	chrome.storage.sync.get(
			{ dammed: [] },
	).then((items) => {
		const index = items.dammed.indexOf(hostname);
		if (index !== -1) {
			items.dammed.splice(index, 1);
			chrome.storage.sync.set(
				{ dammed: items.dammed }
			);
		}
	});
};


const buildDam = () => {
	const dam = document.createElement("div");
	dam.id = "beavers-dam";
	document.body.append(dam);

	const textarea = document.createElement("textarea");
	dam.append(textarea);

	dam.append(document.createElement("br"));

	const saveAndViewJournal = document.createElement("button");
	saveAndViewJournal.textContent = "Save & View Journal";
	saveAndViewJournal.addEventListener("click", () => {
		if (textarea.value.length > 0) {
			save(textarea.value);
		}
		window.open(chrome.runtime.getURL("journal/journal.html"), "_self");
	});
	dam.append(saveAndViewJournal)

	const saveAndContinue = document.createElement("button");
	saveAndContinue.textContent = `Save & Continue to ${location.hostname}`;
	saveAndContinue.addEventListener("click", () => {
		chrome.storage.sync.get(
			{ minWords: 0 }
		).then((items) => {
			const numWords = textarea.value.trim().split(" ").length;
			if (numWords >= items.minWords) {
				save(textarea.value);
				dam.remove();
				// Check if this host should be undammed (see popup.js)
				chrome.storage.local.get(["undam"]).then((items) => {
					if (items.undam === location.hostname) {
						undam(location.hostname);
						chrome.storage.local.set({ undam: null });
					}
				});
			} else {
				window.alert(`Please write at least ${items.minWords} words.`);
			}
		});
	});
	dam.append(saveAndContinue)
};


chrome.storage.sync.get(
	{ dammed: [] },
).then((items) => {
	if (items.dammed.includes(location.hostname)) {
		buildDam();
	}
});

A dam/dam.html => dam/dam.html +19 -0
@@ 0,0 1,19 @@
<!DOCTYPE html>
<html>
	<head>
		<title>Beaver's Dam</title>
		<script src="dam.js" defer></script>
	</head>
	<body>
		<h1>Beaver's Dam</h1>
		<textarea id="entry"></textarea>
		<br>
		<button id="save-and-view-journal">Save &amp; View Journal</button>
		<br>
		<label for="domain">Domain to continue to</label>
		<br>
		<input id="domain"></input>
		<br>
		<button id="save-and-continue">Save &amp; Continue</button>
	</body>
</html>

A dam/dam.js => dam/dam.js +47 -0
@@ 0,0 1,47 @@
async function save(text) {
	let items = await chrome.storage.local.get({ entries: [] });
	// Can't store a Map, use an Object instead
	const entry = {
		"date": Date(),
		"hostname": location.hostname,
		"text": text,
	};
	items.entries.push(entry);
	await chrome.storage.local.set({ entries: items.entries });
}


async function saveAndViewJournal() {
	const text = document.getElementById("entry").value;
	if (text.length > 0) {
		await save(text);
	}
	window.open(chrome.runtime.getURL("journal/journal.html"), "_self");
}


async function saveAndContinue() {
	// XXX: Does not validate domain input
	const domain = document.getElementById("domain").value;
	const destination = new URL(`https://${domain}`);
	const text = document.getElementById("entry").value;
	const numWords = text.trim().split(" ").length;
	const items = await chrome.storage.sync.get({ minWords: 1 });
	if (text.length > 0 && numWords >= items.minWords) {
		await save(text);
		window.open(destination, "_self");
	} else {
		window.alert(`Please write at least ${items.minWords} words.`);
	}
}


document.getElementById("save-and-view-journal").addEventListener(
	"click",
	saveAndViewJournal,
);

document.getElementById("save-and-continue").addEventListener(
	"click",
	saveAndContinue,
);

M manifest.json => manifest.json +12 -9
@@ 3,21 3,24 @@
	"name": "Beaver's Dam",
	"description": "Base Level Extension",
	"version": "0.4",
	"permissions": ["storage", "tabs"],
	"permissions": [
		"storage",
		"tabs",
		"declarativeNetRequestWithHostAccess"
	],
	"host_permissions": [
		"<all_urls>"
	],
	"action": {
		"default_popup": "popup/popup.html"
	},
	"options_page": "options/options.html",
	"content_scripts": [
		{
			"js": ["content/content.js"],
			"css": ["content/content.css"],
			"matches": ["*://*/*"]
		}
	],
	"web_accessible_resources": [
		{
			"resources": [ "journal/journal.html" ],
			"resources": [
				"dam/dam.html",
				"journal/journal.html"
			],
			"matches": [ "*://*/*" ]
		}
	]

M popup/popup.js => popup/popup.js +55 -31
@@ 1,3 1,57 @@
async function updateRules(domains) {
	await chrome.declarativeNetRequest.updateDynamicRules({
		addRules: [{
			id: 1,
			action: {
				type: "redirect",
				redirect: {extensionPath: "/dam/dam.html"},
			},
			condition: {
				requestDomains: domains,
				resourceTypes: ["main_frame"],
				excludedInitiatorDomains: [
					new URL(chrome.runtime.getURL("dam/dam.html")).hostname
				],
			},
		}],
		removeRuleIds: [1],
	});
}


async function setToggleDammedBehaviour() {
	const toggleDammedButton= document.getElementById("toggle-dammed");
	const [tab] = await chrome.tabs.query({ active: true});
	const domain = new URL(tab.url).hostname;

	const [rule] = await chrome.declarativeNetRequest.getDynamicRules(
		{ ruleIds: [1] }
	);

	let dammed;
	if (rule === undefined) {
		// No rules set yet
		dammed = [];
	} else {
		dammed = rule.condition.requestDomains;
	}

	if (dammed.includes(domain)) {
		toggleDammedButton.textContent = `Undam ${domain}`;
		const index = dammed.indexOf(domain);
		dammed.splice(index, 1);
	} else {
		toggleDammedButton.textContent = `Dam ${domain}`;
		dammed.push(domain);
	}

	toggleDammedButton.addEventListener("click", async () => {
		await updateRules(dammed);
		chrome.tabs.reload(tab.id).then(window.close);
	});
}


document.getElementById("open-journal").addEventListener(
	"click",
	() => window.open(chrome.runtime.getURL("journal/journal.html")),


@@ 16,34 70,4 @@ document.getElementById("clear").addEventListener(
	},
);

chrome.tabs.query({ active: true}).then(([tab]) => {
	const hostname = new URL(tab.url).hostname;
	const toggleDammedButton= document.getElementById("toggle-dammed");
	chrome.storage.sync.get(
		{ dammed: [] },
	).then((items) => {
		let toggleDammed;
		if (items.dammed.includes(hostname)) {
			toggleDammedButton.textContent = `Undam ${hostname}`;
			toggleDammed = () => {
				// Set hostname to be undammed in content.js
				chrome.storage.local.set({ undam: hostname }).then(() => {
					chrome.tabs.reload(tab.id).then(window.close);
				});
			};
		} else {
			toggleDammedButton.textContent = `Dam ${hostname}`;
			toggleDammed = () => {
				// Dam hostname
				items.dammed.push(hostname);
				console.log(items.dammed);
				chrome.storage.sync.set(
					{ dammed: items.dammed }
				).then(() => {
					chrome.tabs.reload(tab.id).then(window.close);
				});
			};
		}
		toggleDammedButton.addEventListener("click", toggleDammed);
	});
});
setToggleDammedBehaviour();