Spaces:
Runtime error
Runtime error
| // This file is imported from | |
| // https://github.com/ScratchAddons/ScratchAddons/blob/master/addon-api/content-script/contextmenu.js | |
| /* eslint-disable */ | |
| let initialized = false; | |
| let hasDynamicContextMenu = false; | |
| let contextMenus = []; | |
| const onReactContextMenu = function (e) { | |
| if (!e.target) return; | |
| const ctxTarget = e.target.closest(".react-contextmenu-wrapper"); | |
| if (!ctxTarget) return; | |
| let ctxMenu = ctxTarget.querySelector("nav.react-contextmenu"); | |
| let type; | |
| const extra = {}; | |
| if (false && !ctxMenu && ctxTarget.closest(".monitor-overlay")) { | |
| // Monitors are rendered on document.body. | |
| // This is internal id which is different from the actual monitor ID. | |
| // Optional chain just to prevent crashes when they change the internal stuff. | |
| const mInternalId = ctxTarget[this.traps.getInternalKey(ctxTarget)]?.return?.stateNode?.props?.id; | |
| if (!mInternalId) return; | |
| ctxMenu = Array.prototype.find.call( | |
| document.querySelectorAll("body > nav.react-contextmenu"), | |
| (candidate) => candidate[this.traps.getInternalKey(candidate)]?.return?.stateNode?.props?.id === mInternalId | |
| ); | |
| if (!ctxMenu) return; | |
| const props = ctxTarget[this.traps.getInternalKey(ctxTarget)]?.return?.return?.return?.stateNode?.props; | |
| if (!props) return; | |
| extra.monitorParams = props.params; | |
| extra.opcode = props.opcode; | |
| extra.itemId = props.id; | |
| extra.targetId = props.targetId; | |
| type = `monitor_${props.mode}`; | |
| } else if (ctxTarget[this.traps.getInternalKey(ctxTarget)]?.return?.return?.return?.stateNode?.props?.dragType) { | |
| // SpriteSelectorItem which despite its name is used for costumes, sounds, backpacked script etc | |
| const props = ctxTarget[this.traps.getInternalKey(ctxTarget)].return.return.return.stateNode.props; | |
| type = props.dragType.toLowerCase(); | |
| extra.name = props.name; | |
| extra.itemId = props.id; | |
| extra.index = props.index; | |
| } else { | |
| return; | |
| } | |
| const ctx = { | |
| menuItem: ctxMenu, | |
| target: ctxTarget, | |
| type, | |
| ...extra, | |
| }; | |
| Array.from(ctxMenu.children).forEach((existing) => { | |
| if (existing.classList.contains("sa-ctx-menu")) existing.remove(); | |
| }); | |
| for (const item of hasDynamicContextMenu | |
| ? contextMenus.flatMap((menu) => (typeof menu === "function" ? menu(type, ctx) : menu)) | |
| : contextMenus) { | |
| if (!item) continue; | |
| if (item.types && !item.types.some((itemType) => type === itemType)) continue; | |
| if (item.condition && !item.condition(ctx)) continue; | |
| const itemElem = document.createElement("div"); | |
| const classes = ["context-menu_menu-item"]; | |
| if (item.border) classes.push("context-menu_menu-item-bordered"); | |
| if (item.dangerous) classes.push("context-menu_menu-item-danger"); | |
| itemElem.className = this.scratchClass(...classes, { | |
| others: ["react-contextmenu-item", "sa-ctx-menu", item.className || ""], | |
| }); | |
| const label = document.createElement("span"); | |
| label.textContent = item.label; | |
| itemElem.append(label); | |
| this.displayNoneWhileDisabled(itemElem, { | |
| display: "block", | |
| }); | |
| itemElem.addEventListener("click", (e) => { | |
| e.stopPropagation(); | |
| window.dispatchEvent( | |
| new CustomEvent("REACT_CONTEXTMENU_HIDE", { | |
| detail: { | |
| action: "REACT_CONTEXTMENU_HIDE", | |
| }, | |
| }) | |
| ); | |
| item.callback(ctx); | |
| }); | |
| this.appendToSharedSpace({ | |
| space: item.position, | |
| order: item.order, | |
| scope: ctxMenu, | |
| element: itemElem, | |
| }); | |
| } | |
| return; | |
| }; | |
| const initialize = (tab) => { | |
| if (initialized) return; | |
| initialized = true; | |
| document.body.addEventListener("contextmenu", (e) => onReactContextMenu.call(tab, e), { capture: true }); | |
| }; | |
| export const addContextMenu = (tab, callback, opts) => { | |
| if (typeof opts === "undefined") { | |
| contextMenus.push(callback); | |
| hasDynamicContextMenu = true; | |
| } else { | |
| contextMenus.push({ | |
| ...opts, | |
| callback, | |
| }); | |
| } | |
| initialize(tab); | |
| }; | |