Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions api/content/redux.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Thank you to WorldLanguages, ErrorGamer2000, and apple502j

function injectRedux() {
window.__steRedux = {};

class ReDucks {
static compose(...composeArgs) {
if (composeArgs.length === 0) return (...args) => args;
return (...args) => {
const composeArgsReverse = composeArgs.slice(0).reverse();
let result = composeArgsReverse.shift()(...args);
for (const fn of composeArgsReverse) {
result = fn(result);
}
return result;
};
}

static applyMiddleware(...middlewares) {
return (createStore) =>
(...createStoreArgs) => {
const store = createStore(...createStoreArgs);
let { dispatch } = store;
const api = {
getState: store.getState,
dispatch: (action) => dispatch(action),
};
const initialized = middlewares.map((middleware) => middleware(api));
dispatch = ReDucks.compose(...initialized)(store.dispatch);
return Object.assign({}, store, { dispatch });
};
}
}

let newerCompose = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
function compose(...args) {
const steRedux = window.__steRedux;
const reduxTarget = (steRedux.target = new EventTarget());
steRedux.state = {};
steRedux.dispatch = () => {};

function middleware({ getState, dispatch }) {
steRedux.dispatch = dispatch;
steRedux.state = getState();
return (next) => (action) => {
const nextReturn = next(action);
const ev = new CustomEvent("statechanged", {
detail: {
prev: steRedux.state,
next: (steRedux.state = getState()),
action,
},
});
reduxTarget.dispatchEvent(ev);
return nextReturn;
};
}
args.splice(1, 0, ReDucks.applyMiddleware(middleware));
return newerCompose
? newerCompose.apply(this, args)
: ReDucks.compose.apply(this, args);
}

try {
Object.defineProperty(window, "__REDUX_DEVTOOLS_EXTENSION_COMPOSE__", {
get: () => compose,
set: (v) => {
newerCompose = v;
},
});
} catch (err) {
window.__steRedux = __scratchAddonsRedux;
}
}

if (!(document.documentElement instanceof SVGElement)) {
immediatelyRunFunctionInMainWorld(injectRedux);
}
32 changes: 32 additions & 0 deletions api/content/vm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Thank you to mxmou, WorldLanguages, ErrorGamer2000, apple502j, TheColaber, and towerofnix

function immediatelyRunFunctionInMainWorld(fn) {
if (typeof fn !== "function") throw "Expected function";
const div = document.createElement("div");
div.setAttribute("onclick", "(" + fn + ")()");
document.documentElement.appendChild(div);
div.click();
div.remove();
}

immediatelyRunFunctionInMainWorld(() => {
const oldBind = Function.prototype.bind;
window.__steTraps = new EventTarget()
const onceMap = (__steTraps._onceMap = Object.create(null));

Function.prototype.bind = function (...args) {
if (Function.prototype.bind === oldBind) {
return oldBind.apply(this, args);
} else if (
args[0] &&
Object.prototype.hasOwnProperty.call(args[0], "editingTarget") &&
Object.prototype.hasOwnProperty.call(args[0], "runtime")
) {
onceMap.vm = args[0];
Function.prototype.bind = oldBind;
return oldBind.apply(this, args);
} else {
return oldBind.apply(this, args);
}
};
});
4 changes: 1 addition & 3 deletions api/feature.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,7 @@ class Feature {
this.getInternalKey = function(element) {
return Object.keys(element).find((key) => key.startsWith("__reactInternalInstance")) || null
}
this.redux = document.querySelector("#app")?.[
Object.keys(app).find((key) => key.startsWith("__reactContainer"))
].child.stateNode.store
this.redux = window.__steRedux
if (finalFeature.version !== 2) {
console.warn(
`'${finalFeature.file}' does not use Feature v2. It is recommended that you use the newest version.`
Expand Down
79 changes: 35 additions & 44 deletions api/vm.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,7 @@ ScratchTools.Scratch = {
blockly: null,
};
try {
ScratchTools.Scratch.vm =
window.vm ||
(() => {
const app = document.querySelector("#app");
return app[
Object.keys(app).find((key) => key.startsWith("__reactContainer"))
].child.stateNode.store.getState().scratchGui.vm;
})();
ScratchTools.Scratch.vm = window.vm || window.__steTraps._onceMap.vm;
ste.console.log("Able to load Virtual Machine.", "ste-traps");
} catch (err) {
ste.console.warn("Unable to load Virtual Machine.", "ste-traps");
Expand All @@ -28,22 +21,24 @@ try {

ScratchTools.Scratch.scratchSound = function () {
try {
return document.querySelector("div.sound-editor_editor-container_iUSW-")[
let rI = document.querySelector("[class^=sound-editor_editor-container]")[
Object.keys(
document.querySelector("div.sound-editor_editor-container_iUSW-")
).find((key) => key.startsWith("__reactInternalInstance"))
].return.return.return.stateNode;
document.querySelector("[class^=sound-editor_editor-container]")
).find((key) => key.startsWith("__reactFiber"))
];

while (!rI.stateNode?.audioBufferPlayer) {
rI = rI.return;
}
return rI.stateNode;
} catch (err) {
return null;
}
};

ScratchTools.Scratch.scratchGui = function () {
try {
const app = document.querySelector("#app");
return app[
Object.keys(app).find((key) => key.startsWith("__reactContainer"))
].child.stateNode.store.getState().scratchGui;
return window.__steRedux.state.scratchGui;
} catch (err) {
return null;
}
Expand Down Expand Up @@ -176,46 +171,42 @@ ScratchTools.Scratch.waitForContextMenu = function (info) {
};

ScratchTools.Scratch.scratchPaint = function () {
var app = document.querySelector(".paint-editor_mode-selector_28iiQ")||document.querySelector(".paint-editor_mode-selector_O2uhP")||document.querySelector("[class*='paint-editor_mode-selector_']");
if (app !== null) {
return (
app[
Object.keys(app).find((key) =>
key.startsWith("__reactInternalInstance")
)
].child.stateNode.store?.getState()?.scratchPaint || null
);
} else {
try {
return __steRedux.state.scratchPaint;
} catch (err) {
return null;
}
};

ScratchTools.Scratch.getPaper = function () {
let paintElement = document.querySelector(
"[class*='paint-editor_mode-selector']"
);
let paintState =
paintElement[
Object.keys(paintElement).find((key) =>
key.startsWith("__reactInternalInstance")
)
].child;
window.__paperCache = null

async function getPaper() {
const modeSelector = document.querySelector("[class*='paint-editor_mode-selector']");
const internalState = modeSelector[Object.keys(modeSelector).find((el) => el.startsWith("__reactFiber"))].child;
let toolState = internalState;
let tool;
while (paintState) {
let paintIn = paintState.child?.stateNode;
if (paintIn?.tool) {
tool = paintIn.tool;
while (toolState) {
const toolInstance = toolState.child.child.stateNode;
if (toolInstance.tool) {
tool = toolInstance.tool;
break;
}
if (paintIn?.blob && paintIn?.blob.tool) {
tool = paintIn.blob.tool;
if (toolInstance.blob && toolInstance.blob.tool) {
tool = toolInstance.blob.tool;
break;
}
paintState = paintState.sibling;
toolState = toolState.sibling;
}
if (tool) {
return tool._scope;
const paperScope = tool._scope;
window.__paperCache = paperScope
return paperScope;
}
return null
}

ScratchTools.Scratch.getPaper = async function () {
return await getPaper()
};

async function alertForUpdates() {
Expand Down
4 changes: 2 additions & 2 deletions features/dark-paint-editor/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ export default async function ({ feature, console, scratchClass }) {
}
);

function updateTheme(isDark) {
let paper = feature.traps.getPaper();
async function updateTheme(isDark) {
let paper = await feature.traps.getPaper();

let backgroundLayer = paper.project.layers.find(
(el) => el.data?.["isBackgroundGuideLayer"]
Expand Down
48 changes: 25 additions & 23 deletions features/more-paint-functions/script.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default async function ({ feature, console, scratchClass }) {
function unite() {
let paper = feature.traps.getPaper();
async function unite() {
let paper = await feature.traps.getPaper();
let items = paper.project.selectedItems;

if (items.length !== 2) return;
Expand All @@ -18,8 +18,8 @@ export default async function ({ feature, console, scratchClass }) {
paper.tool.onUpdateImage();
}

function subtract() {
let paper = feature.traps.getPaper();
async function subtract() {
let paper = await feature.traps.getPaper();
let items = paper.project.selectedItems;

if (items.length !== 2) return;
Expand All @@ -37,8 +37,8 @@ export default async function ({ feature, console, scratchClass }) {
paper.tool.onUpdateImage();
}

function exclude() {
let paper = feature.traps.getPaper();
async function exclude() {
let paper = await feature.traps.getPaper();
let items = paper.project.selectedItems;

if (items.length !== 2) return;
Expand All @@ -56,8 +56,8 @@ export default async function ({ feature, console, scratchClass }) {
paper.tool.onUpdateImage();
}

function intersect() {
let paper = feature.traps.getPaper();
async function intersect() {
let paper = await feature.traps.getPaper();
let items = paper.project.selectedItems;

if (items.length !== 2) return;
Expand Down Expand Up @@ -112,23 +112,25 @@ export default async function ({ feature, console, scratchClass }) {
}
);

feature.redux.subscribe(function () {
if (document.querySelector(".ste-more-functions")) {
let span = document.querySelector(".ste-more-functions");
if (
feature.traps.paint().format === "BITMAP" ||
feature.traps.paint().selectedItems?.length < 2
) {
document.querySelectorAll(".ste-more-functions").forEach(function (el) {
el.classList.add("button_mod-disabled_1rf31");
});
} else {
document.querySelectorAll(".ste-more-functions").forEach(function (el) {
el.classList.remove("button_mod-disabled_1rf31");
});
feature.redux.target.addEventListener("statechanged", function(e) {
if (e.detail.action.type.startsWith("scratch-paint/")) {
if (document.querySelector(".ste-more-functions")) {
let span = document.querySelector(".ste-more-functions");
if (
feature.traps.paint().format === "BITMAP" ||
feature.traps.paint().selectedItems?.length < 2
) {
document.querySelectorAll(".ste-more-functions").forEach(function (el) {
el.classList.add("button_mod-disabled_1rf31");
});
} else {
document.querySelectorAll(".ste-more-functions").forEach(function (el) {
el.classList.remove("button_mod-disabled_1rf31");
});
}
}
}
});
})

function makeButton({ name, icon, callback }) {
let span = document.createElement("span");
Expand Down
4 changes: 3 additions & 1 deletion features/opacity-slider/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,16 @@ export default function ({ feature, console, scratchClass }) {

let lastColor;

feature.redux.subscribe(function () {
feature.redux.target.addEventListener("statechanged", function(e) {
if (e.detail.action.type.startsWith("scratch-paint/")) {
let slider = document.querySelector(".ste-opacity-background");
let newColor =
feature.traps.paint?.()?.selectedItems[0]?.fillColor?._canvasStyle;
if (!slider) return;
if (newColor === lastColor) return;
lastColor = newColor;
slider.style.background = `linear-gradient(270deg, ${lastColor} 0%, rgba(0, 0, 0, 0) 100%)`;
}
});

function handleSlider(handle, value) {
Expand Down
12 changes: 6 additions & 6 deletions features/outline-shape-options/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ export default async function ({ feature, console }) {
Join: ["miter", "round", "bevel", "arcs", "miter-clip"],
};

function createSection(type) {
const selectedItems = feature.traps.getPaper().project.selectedItems;
async function createSection(type) {
const selectedItems = (await feature.traps.getPaper()).project.selectedItems;
const result = document.createElement("div");
let strokeValue = undefined;

Expand Down Expand Up @@ -64,13 +64,13 @@ export default async function ({ feature, console }) {

ScratchTools.waitForElements(
"div[class*='color-picker_swatch-row_']",
function (element) {
async function (element) {
if (feature.traps.paint().modals.fillColor) return;
if (feature.traps.getPaper().project.selectedItems.length < 1) return;
if ((await feature.traps.getPaper())?.project.selectedItems.length < 1) return;
const dividerLine = document.createElement("div");
dividerLine.classList.add("color-picker_divider_3a3qR");
const sectionCap = createSection("Cap");
const sectionJoin = createSection("Join");
const sectionCap = await createSection("Cap");
const sectionJoin = await createSection("Join");

element.insertAdjacentElement("afterend", sectionJoin);
element.insertAdjacentElement("afterend", sectionCap);
Expand Down
Loading