Skip to content

Commit 4b74d5e

Browse files
committed
New API: scratchClass
1 parent e8fa05e commit 4b74d5e

File tree

18 files changed

+130
-51
lines changed

18 files changed

+130
-51
lines changed

api/main.js

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,24 @@ ScratchTools.Storage = {};
7474
ScratchTools.Resources = {};
7575
ste.console.log("ScratchTools API Created", "ste-main");
7676

77+
ScratchTools.cssFiles = [];
78+
async function updateCSSFiles() {
79+
let activeCSSFiles = Array.from(document.styleSheets)
80+
.filter((sheet) => sheet.href)
81+
.map((sheet) => sheet.href)
82+
.filter((el) => new URL(el).host === "scratch.mit.edu");
83+
activeCSSFiles = activeCSSFiles.filter(
84+
(el) => !ScratchTools.cssFiles.find((e) => e.url === el)
85+
);
86+
87+
for (var i in activeCSSFiles) {
88+
ScratchTools.cssFiles.push({
89+
url: activeCSSFiles[i],
90+
data: await (await fetch(activeCSSFiles[i])).text(),
91+
});
92+
}
93+
}
94+
7795
if (
7896
window.location.href.startsWith("https://scratch.mit.edu/projects/") &&
7997
window.location.href.includes("/editor")
@@ -159,6 +177,7 @@ function enableScratchToolsSelectorsMutationObserver() {
159177
enableScratchToolsSelectorsMutationObserver();
160178

161179
function returnScratchToolsSelectorsMutationObserverCallbacks() {
180+
updateCSSFiles()
162181
Object.keys(allWaitInstances).forEach(function (key) {
163182
var waitInstance = allWaitInstances[key];
164183
if (!waitInstance.removed) {
@@ -340,6 +359,39 @@ ScratchTools.styles = {
340359
},
341360
};
342361

362+
function scratchClass(name) {
363+
let element = document.querySelector(`[class*='${name}']`);
364+
if (element) {
365+
let classes = [...element.classList];
366+
return classes.find((el) => el.includes(name));
367+
} else {
368+
let text = []
369+
370+
for (var i in ScratchTools.cssFiles) {
371+
text.push(ScratchTools.cssFiles[i].data)
372+
}
373+
374+
text = text.join("\n\n")
375+
let classes = getClassNamesFromCSSText(text)
376+
377+
let relClass = classes.find((el) => el.includes(name))
378+
return relClass
379+
}
380+
}
381+
382+
ScratchTools.getClassNamesFromCSSText = function(cssText) {
383+
const classNames = new Set();
384+
385+
const classRegex = /\.([a-zA-Z0-9_-]+)\b/g;
386+
387+
let match;
388+
while ((match = classRegex.exec(cssText)) !== null) {
389+
classNames.add(match[1]);
390+
}
391+
392+
return Array.from(classNames);
393+
}
394+
343395
ScratchTools.waitForElements(
344396
"ul[class*='menu_menu_'][class*='menu_right_']",
345397
function (ul) {
@@ -351,7 +403,10 @@ ScratchTools.waitForElements(
351403
if (!ul.querySelector(".ste-menu-full-settings")) {
352404
var li = document.createElement("li");
353405
li.className =
354-
"ste-menu-full-settings menu_menu-item_3EwYA menu_hoverable_3u9dt";
406+
"ste-menu-full-settings " +
407+
scratchClass("menu_menu-item_") +
408+
" " +
409+
scratchClass("menu_hoverable_");
355410

356411
var div = document.createElement("div");
357412
div.className = "settings-menu_option_3rMur";
@@ -391,6 +446,8 @@ async function blockliveDetection() {
391446
Object.keys(app).find((key) => key.startsWith("__reactContainer"))
392447
].child.stateNode.store.getState()?.scratchGui;
393448
if (!gui?.projectState) return;
394-
let detectBlocklive = await import("./blocklive-detection/blocklive-detect.js");
449+
let detectBlocklive = await import(
450+
"./blocklive-detection/blocklive-detect.js"
451+
);
395452
detectBlocklive.default();
396-
}
453+
}

api/module.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,26 @@
11
let allFeatures = []
22
let alreadyInjected = [];
33

4+
function scratchClass(name) {
5+
let element = document.querySelector(`[class*='${name}']`);
6+
if (element) {
7+
let classes = [...element.classList];
8+
return classes.find((el) => el.includes(name));
9+
} else {
10+
let text = []
11+
12+
for (var i in ScratchTools.cssFiles) {
13+
text.push(ScratchTools.cssFiles[i].data)
14+
}
15+
16+
text = text.join("\n\n")
17+
let classes = getClassNamesFromCSSText(text)
18+
19+
let relClass = classes.find((el) => el.includes(name))
20+
return relClass
21+
}
22+
}
23+
424
ScratchTools.modules.forEach(async function (script) {
525
var feature = await import(ScratchTools.dir + "/api/feature/index.js");
626
var shouldBeRun = true;
@@ -20,6 +40,7 @@ ScratchTools.modules.forEach(async function (script) {
2040
allFeatures.push(featureGenerated)
2141
fun.default({
2242
feature: featureGenerated,
43+
scratchClass,
2344
console: {
2445
log: function (content) {
2546
ste.console.log(content, script.feature.id);
@@ -56,6 +77,7 @@ ScratchTools.injectModule = async function (script) {
5677
allFeatures.push(featureGenerated)
5778
fun.default({
5879
feature: featureGenerated,
80+
scratchClass,
5981
console: {
6082
log: function (content) {
6183
ste.console.log(content, script.feature.id);

features/dark-paint-editor/script.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default async function ({ feature, console }) {
1+
export default async function ({ feature, console, scratchClass }) {
22
let isDark;
33

44
const BACKGROUND_LIGHT = "#FFFFFF";
@@ -18,10 +18,10 @@ export default async function ({ feature, console }) {
1818
if (document.querySelector(".ste-dark-paint-btn")) return;
1919

2020
let button = document.createElement("div")
21-
button.className = "button-group_button-group_2_h4y ste-dark-paint-btn"
21+
button.className = `${scratchClass("button-group_button-group_2_")} ste-dark-paint-btn`
2222

2323
let span = document.createElement("span")
24-
span.className = "button_button_u6SE2 paint-editor_button-group-button_1I1tm"
24+
span.className = `${scratchClass("button_button_")} ${scratchClass("paint-editor_button-group-button_")}`
2525
span.role = "button"
2626
button.appendChild(span)
2727

features/delete-all.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ function checkForContextMenu() {
77
) {
88
var div = document.createElement("div");
99
div.className =
10-
"react-contextmenu-item context-menu_menu-item_3cioN context-menu_menu-item-bordered_29CJG context-menu_menu-item-danger_1tJg0 scratchtools deleteall";
10+
`react-contextmenu-item ${scratchClass("context-menu_menu-item_")} ${scratchClass("context-menu_menu-item-bordered_")} ${scratchClass("context-menu_menu-item-danger_")} scratchtools deleteall`;
1111
div.role = "menuitem";
1212
div.tabindex = "-1";
1313
div.arialDisabled = "false";

features/echo-effect/script.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
export default function ({ feature, console }) {
1+
export default function ({ feature, console, scratchClass }) {
22
ScratchTools.waitForElements(
33
"div[class^='sound-editor_row_'][class*='sound-editor_row-reverse_']",
44
function (container) {
55
if (container.querySelector(".ste-echo")) return;
66
let button = document.createElement("div");
77
button.className =
8-
"icon-button_container_278u5 sound-editor_effect-button_2zuzT ste-echo";
8+
`${scratchClass("icon-button_container_")} ${scratchClass("sound-editor_effect-button_")} ste-echo`;
99
button.role = "button";
1010

1111
feature.self.hideOnDisable(button)
@@ -20,7 +20,7 @@ export default function ({ feature, console }) {
2020
button.appendChild(img);
2121

2222
let title = document.createElement("div");
23-
title.className = "icon-button_title_36ChS";
23+
title.className = scratchClass("icon-button_title_");
2424
title.textContent = feature.msg("echo");
2525
button.appendChild(title);
2626

features/go-to-parent/script.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ if (
5454
if (data.remix !== undefined) {
5555
if (data.remix.parent !== null) {
5656
var div = document.createElement("div");
57-
div.className = "menu-bar_menu-bar-item_oLDa- scratchtools remix";
57+
div.className = `${scratchClass("menu-bar_menu-bar-item_")} scratchtools remix`;
5858
div.innerHTML = `<a href="https://scratch.mit.edu/projects/${data.remix.parent}/editor" style="color: white;"><span class="button_outlined-button_1bS__ menu-bar_menu-bar-button_3IDN0 community-button_community-button_2Lo_g" role="button"><div class="button_content_3jdgj"><span>Go to Parent</span></div></span></a>`;
5959
document.querySelectorAll("div").forEach(function (el) {
6060
if (el.className.includes("menu-bar_main-menu_")) {

features/last-key-pressed.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ function addKeyPressed() {
1515

1616
function addKeyPressedEditor() {
1717
var div = document.createElement("div");
18-
div.className = "menu-bar_file-group_1_CHX scratchtools navlastkey";
18+
div.className = `${scratchClass("menu-bar_file-group_1_")} scratchtools navlastkey`;
1919
div.innerHTML = `
2020
<span>No Key Pressed</span>
2121
`;

features/more-block-themes/script.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default async function ({ feature, console }) {
1+
export default async function ({ feature, console, scratchClass }) {
22
let CIRCLE = await (await fetch(feature.self.getResource("circle"))).text();
33

44
let COLORS = document.createElement("link")
@@ -118,18 +118,18 @@ export default async function ({ feature, console }) {
118118

119119
let li = document.createElement("li");
120120
li.dataset.id = THEMES[i].id;
121-
li.className = "menu_menu-item_3EwYA menu_hoverable_3u9dt ste-custom";
121+
li.className = `${scratchClass("menu_menu-item_")} ${scratchClass("menu_hoverable_")} ste-custom`;
122122

123123
let div = document.createElement("div");
124-
div.className = "settings-menu_option_3rMur";
124+
div.className = scratchClass("settings-menu_option_");
125125

126126
let check = document.createElement("img");
127-
check.className = "settings-menu_check_3ssaq";
127+
check.className = scratchClass("settings-menu_check_");
128128
check.src = feature.self.getResource("check");
129129

130130
let img = document.createElement("span");
131131
img.innerHTML = CIRCLE.replaceAll("-fill", "-circle-fill" + THEMES[i].id).replaceAll("-stroke", "-circle-stroke-" + THEMES[i].id);
132-
img.className = "settings-menu_icon_3QaRk";
132+
img.className = scratchClass("settings-menu_icon_");
133133

134134
let circleCSS = document.createElement("style");
135135
circleCSS.textContent = css.replaceAll("-fill", "-circle-fill" + THEMES[i].id).replaceAll("-stroke", "-circle-stroke-" + THEMES[i].id)

features/more-editor-fonts/script.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default async function ({ feature, console }) {
1+
export default async function ({ feature, console, scratchClass }) {
22
let { default: openTypeDefault } = await import(
33
"../../libraries/opentype.js"
44
);
@@ -26,20 +26,20 @@ export default async function ({ feature, console }) {
2626
button.currentitem = false;
2727
button.ariaLabel = "Add Font";
2828
button.className =
29-
"action-menu_button_1qbot action-menu_more-button_1fMGZ ste-more-fonts-btn";
29+
`${scratchClass("action-menu_button_")} ${scratchClass("action-menu_more-button_")} ste-more-fonts-btn`;
3030
div.appendChild(button);
3131

3232
let img = Object.assign(document.createElement("img"), {
3333
src: feature.self.getResource("more-text-icon"),
3434
draggable: false,
35-
className: "action-menu_more-icon_TJUQ7",
35+
className: scratchClass("action-menu_more-icon_"),
3636
width: 10,
3737
});
3838
button.appendChild(img);
3939

4040
let tooltip = Object.assign(document.createElement("div"), {
4141
className:
42-
"__react_component_tooltip place-right type-dark action-menu_tooltip_3Bkh5",
42+
`__react_component_tooltip place-right type-dark ${scratchClass("action-menu_tooltip_")}`,
4343
id: `ste-${id}-Add Font`,
4444
textContent: "Add Font",
4545
});

features/more-paint-functions/script.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export default async function ({ feature, console }) {
1+
export default async function ({ feature, console, scratchClass }) {
22
function unite() {
33
let paper = feature.traps.getPaper();
44
let items = paper.project.selectedItems;
@@ -133,20 +133,20 @@ export default async function ({ feature, console }) {
133133
function makeButton({ name, icon, callback }) {
134134
let span = document.createElement("span");
135135
span.className =
136-
"button_button_u6SE2 labeled-icon-button_mod-edit-field_1bXYC ste-more-functions";
136+
`${scratchClass("button_button_")} ${scratchClass("labeled-icon-button_mod-edit-field_")} ste-more-functions`;
137137
span.role = "button";
138138

139139
let img = document.createElement("img");
140140
img.src = feature.self.getResource(icon);
141-
img.className = "labeled-icon-button_edit-field-icon_3j-Pf";
141+
img.className = scratchClass("labeled-icon-button_edit-field-icon_");
142142
img.alt = name;
143143
img.title = name;
144144
img.draggable = false;
145145
span.appendChild(img);
146146

147147
let label = document.createElement("span");
148148
label.textContent = name;
149-
label.className = "labeled-icon-button_edit-field-title_1ZoEV";
149+
label.className = scratchClass("labeled-icon-button_edit-field-title_");
150150
span.appendChild(label);
151151

152152
span.addEventListener("click", function (e) {

0 commit comments

Comments
 (0)