soiz1's picture
Upload 2891 files
6bcb42f verified
raw
history blame
3.74 kB
// A file to split Editor Devtools by features.
// Unlike userscript.js, this file mainly interacts with VM.
export default class ShowBroadcast {
constructor(addon) {
this.addon = addon;
this.vm = this.addon.tab.traps.vm;
this.highlights = {
timeoutId: 0,
callback: () => {},
};
}
showSenders(broadcastId) {
this.highlightTargets(this.getTargetsWithSenders(broadcastId));
}
getTargetsWithSenders(broadcastId) {
const targetWithSenders = [];
for (const target of this.vm.runtime.targets) {
if (!target.isOriginal) return;
for (const blockId of Object.keys(target.blocks._blocks)) {
const block = target.blocks.getBlock(blockId);
if (block.inputs.BROADCAST_INPUT) {
const input = block.inputs.BROADCAST_INPUT;
// For results, blocks must NOT be inserted, for convenience.
if (
input.block === input.shadow &&
target.blocks.getBlock(input.shadow).fields.BROADCAST_OPTION.id === broadcastId
) {
targetWithSenders.push(target);
break;
}
}
}
}
return targetWithSenders;
}
showReceivers(broadcastId) {
this.highlightTargets(this.getTargetsWithReceivers(broadcastId));
}
getTargetsWithReceivers(broadcastId) {
const targetWithReceivers = [];
for (const target of this.vm.runtime.targets) {
if (!target.isOriginal) return;
for (const blockId of Object.keys(target.blocks._blocks)) {
const block = target.blocks.getBlock(blockId);
if (block.opcode === "event_whenbroadcastreceived" && block.fields.BROADCAST_OPTION.id === broadcastId) {
targetWithReceivers.push(target);
break;
}
}
}
return targetWithReceivers;
}
highlightTargets(targets) {
if (this.highlights.timeoutId) {
this.highlights.callback();
clearTimeout(this.highlights.timeoutId);
this.highlights = {
timeoutId: 0,
callback: () => {},
};
}
const elemPendingToRemoveHighlights = [];
for (const target of targets) {
let elem = null;
if (target.isStage) {
elem = document.querySelector('div[class*="stage-selector_header"]');
} else if (target.isOriginal) {
// This is one of the most ridiculous code I've ever written.
// This essentially compares sprite names to textContent so that we can add CSS.
const possibleElements = document.querySelectorAll('div[class*="sprite-selector-item_sprite-name"]');
const spriteNameElem = Array.prototype.find.call(
possibleElements,
(elem) => elem.textContent === target.getName()
);
if (!spriteNameElem) continue;
elem = spriteNameElem.parentElement;
}
elem.dataset.highlighted = "true";
elemPendingToRemoveHighlights.push(elem);
}
const callbackFactory = (elemToRemoveHighlights) => () => {
for (const removingElem of elemToRemoveHighlights) {
if (!removingElem.isConnected) continue;
removingElem.dataset.highlighted = "false";
}
};
const callback = callbackFactory(elemPendingToRemoveHighlights);
this.highlights = {
callback,
timeoutId: setTimeout(callback, 2000),
};
}
getAssociatedBroadcastId(blockId) {
const editingTarget = this.vm.editingTarget;
const block = editingTarget.blocks.getBlock(blockId);
if (block.opcode === "event_whenbroadcastreceived") {
return block.fields.BROADCAST_OPTION.id;
} else {
const input = block.inputs.BROADCAST_INPUT;
// Allow shadow blocks
return editingTarget.blocks.getBlock(input.shadow).fields.BROADCAST_OPTION.id;
}
}
}