Skip to content

Commit 47c9363

Browse files
feat: add checkboxes in the interface and highlight Bootstrap 5 deprecated classes (#8)
Co-authored-by: Christian Oliff <[email protected]>
1 parent 89b69ce commit 47c9363

6 files changed

Lines changed: 244 additions & 23 deletions

File tree

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ For Microsoft Edge:
4141

4242
## Data
4343

44-
Data are generated by running `npm run generate:data` and are stored in the `data` folder:
44+
Data is generated by running `npm run generate:data` and is stored in the `data` folder:
4545
* `bootstrap-{$version}-deprecated-classes` contains the list of deprecated classes for the given Bootstrap version which is compared to the latest Bootstrap version.
4646
* `bootstrap-{$version}.json` contains the list of classes for the given Bootstrap version.
4747

48+
Please note that the data for the current Bootstrap version is generated manually. The deprecated classes can't be automatically detected.
49+
4850
## Sponsors
4951

5052
<p align="center">
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"deprecated":[".btn-close-white",".carousel-dark",".dropdown-menu-dark",".navbar-dark",".navbar-light",".text-black-50",".text-muted",".text-white-50"]}

popup/choose_bootstrap_version.html

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,18 @@
66
</head>
77
<body>
88
<div id="popup-content">
9-
<button id="bs3">Bootstrap 3</button>
10-
<button id="bs4">Bootstrap 4</button>
9+
<div>
10+
<input type="checkbox" id="bs3" name="bs3" />
11+
<label for="bs3">Bootstrap 3</label>
12+
</div>
13+
<div>
14+
<input type="checkbox" id="bs4" name="bs4" />
15+
<label for="bs4">Bootstrap 4</label>
16+
</div>
17+
<div>
18+
<input type="checkbox" id="bs5" name="bs5" />
19+
<label for="bs5">Bootstrap 5<br>(removed in Bootstrap 6)</label>
20+
</div>
1121
<button type="reset">Reset</button>
1222
</div>
1323
<div id="error-content" class="hidden">

popup/choose_bootstrap_version.js

Lines changed: 74 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,64 @@
1-
document.querySelectorAll("button").forEach((button) => {
2-
button.addEventListener("click", switchFunction);
1+
// Extension Initialization
2+
// This script runs when the popup is opened. Since the checkbox states are not persistent,
3+
// we need to retrieve the current state of the checkboxes and update them to reflect the
4+
// current content on the page of the active tab.
5+
// Note: The checkbox states reset to default when the page reloads, which means this
6+
// behavior works more reliably with single-page applications (SPAs) than with traditional websites.
7+
chrome.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
8+
for (const tab of tabs) {
9+
try {
10+
chrome.scripting.executeScript({
11+
target: {
12+
tabId: tab.id,
13+
allFrames: true,
14+
},
15+
func: () => {
16+
const state = {
17+
bs3: document.body.classList.contains('bootstrap-browser-extension-bs-3'),
18+
bs4: document.body.classList.contains('bootstrap-browser-extension-bs-4'),
19+
bs5: document.body.classList.contains('bootstrap-browser-extension-bs-5')
20+
};
21+
return state;
22+
},
23+
}, (results) => {
24+
if (chrome.runtime.lastError) {
25+
console.error(`Script injection failed: ${chrome.runtime.lastError.message}`);
26+
} else {
27+
const state = results[0].result;
28+
document.getElementById('bs3').checked = state.bs3;
29+
document.getElementById('bs4').checked = state.bs4;
30+
document.getElementById('bs5').checked = state.bs5;
31+
}
32+
});
33+
} catch (err) {
34+
console.error(`Failed to execute script: ${err}`);
35+
}
36+
}
37+
});
38+
39+
document.querySelectorAll('button[type="reset"]').forEach((button) => {
40+
button.addEventListener("click", reset);
341
});
442

43+
document.querySelectorAll('input[type="checkbox"]').forEach((checkbox) => {
44+
checkbox.addEventListener("change", switchFunction);
45+
});
46+
47+
function reset() {
48+
document.querySelectorAll('input[type="checkbox"]').forEach((checkbox) => {
49+
checkbox.checked = false;
50+
const event = new Event('change');
51+
checkbox.dispatchEvent(event);
52+
});
53+
}
54+
555
function switchFunction() {
656
chrome.tabs.query({ active: true, currentWindow: true }).then((tabs) => {
7-
highlightDeprecatedClasses(tabs, this.id);
57+
highlightDeprecatedClasses(tabs, this.id, this.checked);
858
});
959
}
1060

11-
async function highlightDeprecatedClasses(tabs, param) {
61+
async function highlightDeprecatedClasses(tabs, paramRef, paramChecked) {
1262
for (const tab of tabs) {
1363
try {
1464
await chrome.scripting.insertCSS({
@@ -24,24 +74,32 @@ async function highlightDeprecatedClasses(tabs, param) {
2474
tabId: tab.id,
2575
allFrames: true,
2676
},
27-
func: async (param) => {
28-
const extensionAvailableClasses = [
29-
"bootstrap-browser-extension-bs-4",
30-
"bootstrap-browser-extension-bs-3",
31-
];
32-
33-
document.body.classList.remove(...extensionAvailableClasses);
34-
35-
switch(param) {
77+
func: async (paramRef, paramChecked) => {
78+
switch(paramRef) {
3679
case "bs3":
37-
document.body.classList.add("bootstrap-browser-extension-bs-3");
80+
if (paramChecked) {
81+
document.body.classList.add("bootstrap-browser-extension-bs-3");
82+
} else {
83+
document.body.classList.remove("bootstrap-browser-extension-bs-3");
84+
}
3885
break;
3986
case "bs4":
40-
document.body.classList.add("bootstrap-browser-extension-bs-4");
87+
if (paramChecked) {
88+
document.body.classList.add("bootstrap-browser-extension-bs-4");
89+
} else {
90+
document.body.classList.remove("bootstrap-browser-extension-bs-4");
91+
}
92+
break;
93+
case "bs5":
94+
if (paramChecked) {
95+
document.body.classList.add("bootstrap-browser-extension-bs-5");
96+
} else {
97+
document.body.classList.remove("bootstrap-browser-extension-bs-5");
98+
}
4199
break;
42100
}
43101
},
44-
args: [param],
102+
args: [paramRef, paramChecked],
45103
});
46104
} catch (err) {
47105
console.error(`Failed to execute script: ${err}`);

script/build.mjs

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as fs from 'fs/promises';
22
import * as diff from 'fast-array-diff';
33
import { getCSSClasses } from './getCSSClasses.mjs';
4+
import { outputFile, remove } from 'fs-extra';
45

56
const minimumBootstrapVersion = 3
67
const maximumBootstrapVersion = 5
@@ -32,18 +33,33 @@ for (const version of bootstrapVersions.slice(0, -1)) {
3233
await fs.writeFile(outputFilePath, JSON.stringify(outputJSONContent))
3334
}
3435

36+
// Generate ./data/bootstrap-${version}-deprecated-classes.json` manually for the latest version
37+
const latestVersionOutputFilePath = `./data/bootstrap-${maximumBootstrapVersion}-deprecated-classes.json`
38+
await fs.writeFile(latestVersionOutputFilePath, JSON.stringify({
39+
deprecated: [
40+
".btn-close-white",
41+
".carousel-dark",
42+
".dropdown-menu-dark",
43+
".navbar-dark",
44+
".navbar-light",
45+
".text-black-50",
46+
".text-muted",
47+
".text-white-50",
48+
]
49+
}))
50+
3551
// Generate CSS file from `data/bootstrap-${version}-deprecated-classes.json` files
3652
const generatedCSSFile = "./styles.css"
3753
console.log(`Generating ${generatedCSSFile}...`)
3854
await fs.writeFile(generatedCSSFile, "")
39-
for (const version of bootstrapVersions.slice(0, -1)) {
55+
for (const version of bootstrapVersions) {
4056
await fs.appendFile(generatedCSSFile, `.bootstrap-browser-extension-bs-${version} {`)
4157

42-
const deprecatedClasses = JSON.parse(await fs.readFile(`data/bootstrap-${version}-deprecated-classes.json`)).removed
43-
for (const deprecatedClass of deprecatedClasses) {
58+
const removedClasses = JSON.parse(await fs.readFile(`data/bootstrap-${version}-deprecated-classes.json`)).removed ?? []
59+
for (const removedClass of removedClasses) {
4460
await fs.appendFile(generatedCSSFile,
4561
`
46-
${deprecatedClass} {
62+
${removedClass} {
4763
border: 5px solid red;
4864
border-radius: 0;
4965
@@ -53,6 +69,27 @@ for (const version of bootstrapVersions.slice(0, -1)) {
5369
padding: 2px;
5470
border: 2px solid black;
5571
z-index: 10000;
72+
content: '${removedClass}'
73+
}
74+
}
75+
`
76+
)
77+
}
78+
79+
const deprecatedClasses = JSON.parse(await fs.readFile(`data/bootstrap-${version}-deprecated-classes.json`)).deprecated ?? []
80+
for (const deprecatedClass of deprecatedClasses) {
81+
await fs.appendFile(generatedCSSFile,
82+
`
83+
${deprecatedClass} {
84+
border: 5px solid yellow;
85+
border-radius: 0;
86+
87+
&::before {
88+
color: #000;
89+
background-color: rgb(214, 202, 71);
90+
padding: 2px;
91+
border: 2px solid black;
92+
z-index: 10000;
5693
content: '${deprecatedClass}'
5794
}
5895
}

styles.css

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14756,3 +14756,116 @@
1475614756
}
1475714757
}
1475814758
}
14759+
.bootstrap-browser-extension-bs-5 {
14760+
.btn-close-white {
14761+
border: 5px solid yellow;
14762+
border-radius: 0;
14763+
14764+
&::before {
14765+
color: #000;
14766+
background-color: rgb(214, 202, 71);
14767+
padding: 2px;
14768+
border: 2px solid black;
14769+
z-index: 10000;
14770+
content: '.btn-close-white'
14771+
}
14772+
}
14773+
14774+
.carousel-dark {
14775+
border: 5px solid yellow;
14776+
border-radius: 0;
14777+
14778+
&::before {
14779+
color: #000;
14780+
background-color: rgb(214, 202, 71);
14781+
padding: 2px;
14782+
border: 2px solid black;
14783+
z-index: 10000;
14784+
content: '.carousel-dark'
14785+
}
14786+
}
14787+
14788+
.dropdown-menu-dark {
14789+
border: 5px solid yellow;
14790+
border-radius: 0;
14791+
14792+
&::before {
14793+
color: #000;
14794+
background-color: rgb(214, 202, 71);
14795+
padding: 2px;
14796+
border: 2px solid black;
14797+
z-index: 10000;
14798+
content: '.dropdown-menu-dark'
14799+
}
14800+
}
14801+
14802+
.navbar-dark {
14803+
border: 5px solid yellow;
14804+
border-radius: 0;
14805+
14806+
&::before {
14807+
color: #000;
14808+
background-color: rgb(214, 202, 71);
14809+
padding: 2px;
14810+
border: 2px solid black;
14811+
z-index: 10000;
14812+
content: '.navbar-dark'
14813+
}
14814+
}
14815+
14816+
.navbar-light {
14817+
border: 5px solid yellow;
14818+
border-radius: 0;
14819+
14820+
&::before {
14821+
color: #000;
14822+
background-color: rgb(214, 202, 71);
14823+
padding: 2px;
14824+
border: 2px solid black;
14825+
z-index: 10000;
14826+
content: '.navbar-light'
14827+
}
14828+
}
14829+
14830+
.text-black-50 {
14831+
border: 5px solid yellow;
14832+
border-radius: 0;
14833+
14834+
&::before {
14835+
color: #000;
14836+
background-color: rgb(214, 202, 71);
14837+
padding: 2px;
14838+
border: 2px solid black;
14839+
z-index: 10000;
14840+
content: '.text-black-50'
14841+
}
14842+
}
14843+
14844+
.text-muted {
14845+
border: 5px solid yellow;
14846+
border-radius: 0;
14847+
14848+
&::before {
14849+
color: #000;
14850+
background-color: rgb(214, 202, 71);
14851+
padding: 2px;
14852+
border: 2px solid black;
14853+
z-index: 10000;
14854+
content: '.text-muted'
14855+
}
14856+
}
14857+
14858+
.text-white-50 {
14859+
border: 5px solid yellow;
14860+
border-radius: 0;
14861+
14862+
&::before {
14863+
color: #000;
14864+
background-color: rgb(214, 202, 71);
14865+
padding: 2px;
14866+
border: 2px solid black;
14867+
z-index: 10000;
14868+
content: '.text-white-50'
14869+
}
14870+
}
14871+
}

0 commit comments

Comments
 (0)