Skip to content

Commit

Permalink
Basic extension example
Browse files Browse the repository at this point in the history
  • Loading branch information
getvictor committed May 12, 2024
0 parents commit d301346
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.idea/
1 change: 1 addition & 0 deletions 1-basic-extension/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Full article coming soon to [Victor on Software](https://victoronsoftware.com)
16 changes: 16 additions & 0 deletions 1-basic-extension/src/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use strict"

function setBadgeText(enabled) {
const text = enabled ? "ON" : "OFF"
void chrome.action.setBadgeText({text: text})
}

function startUp() {
chrome.storage.sync.get("enabled", (data) => {
setBadgeText(!!data.enabled)
})
}

// Ensure the background script always runs.
chrome.runtime.onStartup.addListener(startUp)
chrome.runtime.onInstalled.addListener(startUp)
61 changes: 61 additions & 0 deletions 1-basic-extension/src/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"use strict"

const blurFilter = "blur(6px)"
let textToBlur = ""

// Search this DOM node for text to blur and blur the parent element if found.
function processNode(node) {
if (node.childNodes.length > 0) {
Array.from(node.childNodes).forEach(processNode)
}
if (node.nodeType === Node.TEXT_NODE && node.textContent !== null && node.textContent.trim().length > 0) {
const parent = node.parentElement
if (parent !== null && (parent.tagName === 'SCRIPT' || parent.style.filter === blurFilter)) {
// Already blurred
return
}
if (node.textContent.includes(textToBlur)) {
blurElement(parent)
}
}
}

function blurElement(elem) {
elem.style.filter = blurFilter
console.debug("blurred id:" + elem.id + " class:" + elem.className + " tag:" + elem.tagName + " text:" + elem.textContent)
}

// Create a MutationObserver to watch for changes to the DOM.
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.addedNodes.length > 0) {
mutation.addedNodes.forEach(processNode)
} else {
processNode(mutation.target)
}
})
})

// Enable the content script by default.
let enabled = true
const keys = ["enabled", "item"]

chrome.storage.sync.get(keys, (data) => {
if (data.enabled === false) {
enabled = false
}
if (data.item) {
textToBlur = data.item
}
// Only start observing the DOM if the extension is enabled and there is text to blur.
if (enabled && textToBlur.trim().length > 0) {
observer.observe(document, {
attributes: false,
characterData: true,
childList: true,
subtree: true,
})
// Loop through all elements on the page for initial processing.
processNode(document)
}
})
21 changes: 21 additions & 0 deletions 1-basic-extension/src/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"manifest_version": 3,
"name": "My Chrome Extension",
"version": "0.1.0",
"description": "My first Chrome extension.",
"action": {
"default_popup": "popup.html"
},
"permissions": [
"storage"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
}
}
57 changes: 57 additions & 0 deletions 1-basic-extension/src/popup.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/* The switch - the box around the slider */
.switch {
margin-left: 30%; /* Center the switch */
position: relative;
display: inline-block;
width: 60px;
height: 34px;
}

/* Hide default HTML checkbox */
.switch input {
opacity: 0;
width: 0;
height: 0;
}

/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
}

.slider::before {
position: absolute;
content: "";
height: 26px;
width: 26px;
left: 4px;
bottom: 4px;
background-color: white;
}

input:checked + .slider {
background-color: #2196F3;
}

input:checked + .slider:before {
transform: translateX(26px); /* Move the slider to the right when checked */
}

/* Rounded sliders */
.slider.round {
border-radius: 34px;
}

.slider.round::before {
border-radius: 50%;
}

.secret {
margin: 5px;
}
14 changes: 14 additions & 0 deletions 1-basic-extension/src/popup.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html lang="en">
<head>
<title>My popup</title>
<link rel="stylesheet" type="text/css" href="popup.css">
</head>
<body>
<label class="switch">
<input id="enabled" type="checkbox">
<span class="slider round"></span>
</label>
<input class="secret" id="item" type="text">
<script src="popup.js"></script>
</body>
</html>
32 changes: 32 additions & 0 deletions 1-basic-extension/src/popup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"use strict";

console.log("Hello, world from popup!")

function setBadgeText(enabled) {
const text = enabled ? "ON" : "OFF"
void chrome.action.setBadgeText({text: text})
}

// Handle the ON/OFF switch
const checkbox = document.getElementById("enabled")
chrome.storage.sync.get("enabled", (data) => {
checkbox.checked = !!data.enabled
void setBadgeText(data.enabled)
})
checkbox.addEventListener("change", (event) => {
if (event.target instanceof HTMLInputElement) {
void chrome.storage.sync.set({"enabled": event.target.checked})
void setBadgeText(event.target.checked)
}
})

// Handle the input field
const input = document.getElementById("item")
chrome.storage.sync.get("item", (data) => {
input.value = data.item || ""
});
input.addEventListener("change", (event) => {
if (event.target instanceof HTMLInputElement) {
void chrome.storage.sync.set({"item": event.target.value})
}
})
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Code examples for [Chrome extension software development articles from Victor on Software](https://victoronsoftware.com)

0 comments on commit d301346

Please sign in to comment.