diff --git "a/js/addon-default-entry.js" "b/js/addon-default-entry.js" new file mode 100644--- /dev/null +++ "b/js/addon-default-entry.js" @@ -0,0 +1,13439 @@ +(window["webpackJsonpGUI"] = window["webpackJsonpGUI"] || []).push([["addon-default-entry"],{ + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/color-picker/style.css": +/*!****************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/color-picker/style.css ***! + \****************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".sa-color-picker {\n display: flex;\n}\n\n.sa-color-picker-code {\n margin: 8px 0;\n}\n\n.sa-color-picker-paint {\n margin-top: 16px;\n margin-bottom: 4px;\n}\n\n.sa-color-picker > .sa-color-picker-color {\n border: none;\n border-top-left-radius: 1rem;\n border-bottom-left-radius: 1rem;\n padding: 0;\n padding-left: 0.6rem;\n padding-right: 0.4rem;\n margin-left: 0.5rem;\n outline: none;\n box-sizing: border-box;\n width: 3rem;\n height: 2rem;\n}\n[theme=\"dark\"] .sa-color-picker > .sa-color-picker-color {\n background: var(--ui-secondary);\n}\n\n.sa-color-picker > .sa-color-picker-text {\n box-sizing: border-box;\n width: calc(150px - 3rem);\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n}\n\n[dir=\"rtl\"] .sa-color-picker > .sa-color-picker-color {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n border-top-right-radius: 1rem;\n border-bottom-right-radius: 1rem;\n margin-left: 0;\n margin-right: 0.5rem;\n}\n\n[dir=\"rtl\"] .sa-color-picker > .sa-color-picker-text {\n border-top-left-radius: 1rem;\n border-bottom-left-radius: 1rem;\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n}\n\nbody.sa-hide-eye-dropper-background div[class*=\"stage_color-picker-background\"] {\n /* Do not show eye dropper background if the color picker is \"fake\" */\n display: none;\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/editor-comment-previews/userstyle.css": +/*!*******************************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/editor-comment-previews/userstyle.css ***! + \*******************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".sa-comment-preview-outer {\n position: fixed;\n top: 0;\n left: 0;\n z-index: 100000000;\n pointer-events: none;\n}\n\n.sa-comment-preview-inner {\n width: calc(200px - 16px);\n max-height: calc(132px - 8px);\n padding: 8px;\n overflow: hidden;\n\n font-size: 12px;\n white-space: pre-wrap;\n pointer-events: none;\n\n color: rgb(87, 94, 117);\n background-color: rgb(255 255 255 / 90%);\n border-style: none;\n border-radius: 8px;\n filter: drop-shadow(0px 5px 5px rgb(0 0 0 / 10%));\n\n transform: perspective(200px);\n}\n\n@supports (backdrop-filter: blur(16px)) {\n .sa-comment-preview-inner {\n background-color: rgb(255 255 255 / 75%);\n backdrop-filter: blur(16px);\n }\n}\n\n.sa-comment-preview-fade {\n transition: opacity 0.1s, filter 0.1s, transform 0.1s linear;\n}\n\n.sa-comment-preview-hidden {\n opacity: 0;\n filter: none;\n transform: perspective(200px) translateZ(-20px);\n}\n\n.sa-comment-preview-reduce-transparency {\n background-color: rgb(255 255 255);\n backdrop-filter: none;\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/editor-searchable-dropdowns/userscript.css": +/*!************************************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/editor-searchable-dropdowns/userscript.css ***! + \************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".u-dropdown-searchbar {\n width: 100%;\n box-sizing: border-box;\n /* based on styles for the title input */\n color: white;\n background-color: hsla(0, 100%, 100%, 0.25);\n border: 1px solid hsla(0, 0%, 0%, 0.15);\n padding: 0.5rem;\n outline: none;\n transition: 0.25s ease-out;\n font-size: 13px;\n font-weight: bold;\n border-radius: 4px;\n}\n.u-dropdown-searchbar:hover {\n background-color: hsla(0, 100%, 100%, 0.5);\n}\n.u-dropdown-searchbar:focus {\n background-color: white;\n color: black;\n}\n.blocklyDropDownDiv .goog-menu {\n overflow-x: hidden;\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/editor-theme3/compatibility.css": +/*!*************************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/editor-theme3/compatibility.css ***! + \*************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, "/* Imported by other addons */\n\n.sa-block-color {\n --sa-block-colored-background: var(--sa-block-background-primary);\n --sa-block-colored-background-secondary: var(--sa-block-field-background);\n --sa-block-bright-background: var(--sa-block-background-primary);\n --sa-block-text: white;\n --sa-block-gray-text: white;\n --sa-block-colored-text: var(--sa-block-background-primary);\n --sa-block-text-on-bright-background: white;\n}\n\n.sa-block-color-motion {\n --sa-block-background-primary: var(--editorTheme3-motion-primary, #4c97ff);\n --sa-block-background-secondary: var(--editorTheme3-motion-secondary, #4280d7);\n --sa-block-background-tertiary: var(--editorTheme3-motion-tertiary, #3373cc);\n --sa-block-field-background: var(--editorTheme3-motion-field, #3373cc);\n}\n\n.sa-block-color-looks {\n --sa-block-background-primary: var(--editorTheme3-looks-primary, #9966ff);\n --sa-block-background-secondary: var(--editorTheme3-looks-secondary, #855cd6);\n --sa-block-background-tertiary: var(--editorTheme3-looks-tertiary, #774dcb);\n --sa-block-field-background: var(--editorTheme3-looks-field, #774dcb);\n}\n\n.sa-block-color-sounds {\n --sa-block-background-primary: var(--editorTheme3-sounds-primary, #cf63cf);\n --sa-block-background-secondary: var(--editorTheme3-sounds-secondary, #c94fc9);\n --sa-block-background-tertiary: var(--editorTheme3-sounds-tertiary, #bd42bd);\n --sa-block-field-background: var(--editorTheme3-sounds-field, #bd42bd);\n}\n\n.sa-block-color-events {\n --sa-block-background-primary: var(--editorTheme3-event-primary, #ffbf00);\n --sa-block-background-secondary: var(--editorTheme3-event-secondary, #e6ac00);\n --sa-block-background-tertiary: var(--editorTheme3-event-tertiary, #cc9900);\n --sa-block-field-background: var(--editorTheme3-event-field, #cc9900);\n}\n\n.sa-block-color-control {\n --sa-block-background-primary: var(--editorTheme3-control-primary, #ffab19);\n --sa-block-background-secondary: var(--editorTheme3-control-secondary, #ec9c13);\n --sa-block-background-tertiary: var(--editorTheme3-control-tertiary, #cf8b17);\n --sa-block-field-background: var(--editorTheme3-control-field, #cf8b17);\n}\n\n.sa-block-color-sensing {\n --sa-block-background-primary: var(--editorTheme3-sensing-primary, #5cb1d6);\n --sa-block-background-secondary: var(--editorTheme3-sensing-secondary, #47a8d1);\n --sa-block-background-tertiary: var(--editorTheme3-sensing-tertiary, #2e8eb8);\n --sa-block-field-background: var(--editorTheme3-sensing-field, #2e8eb8);\n}\n\n.sa-block-color-operators {\n --sa-block-background-primary: var(--editorTheme3-operators-primary, #59c059);\n --sa-block-background-secondary: var(--editorTheme3-operators-secondary, #46b946);\n --sa-block-background-tertiary: var(--editorTheme3-operators-tertiary, #389438);\n --sa-block-field-background: var(--editorTheme3-operators-field, #389438);\n}\n\n.sa-block-color-data {\n --sa-block-background-primary: var(--editorTheme3-data-primary, #ff8c1a);\n --sa-block-background-secondary: var(--editorTheme3-data-secondary, #ff8000);\n --sa-block-background-tertiary: var(--editorTheme3-data-tertiary, #db6e00);\n --sa-block-field-background: var(--editorTheme3-data-field, #db6e00);\n}\n\n.sa-block-color-data-lists,\n.sa-block-color-list {\n --sa-block-background-primary: var(--editorTheme3-data_lists-primary, #ff661a);\n --sa-block-background-secondary: var(--editorTheme3-data_lists-secondary, #ff5500);\n --sa-block-background-tertiary: var(--editorTheme3-data_lists-tertiary, #e64d00);\n --sa-block-field-background: var(--editorTheme3-data_lists-field, #e64d00);\n}\n\n.sa-block-color-more,\n.sa-block-color-null {\n --sa-block-background-primary: var(--editorTheme3-more-primary, #ff6680);\n --sa-block-background-secondary: var(--editorTheme3-more-secondary, #ff4d6a);\n --sa-block-background-tertiary: var(--editorTheme3-more-tertiary, #ff3355);\n --sa-block-field-background: var(--editorTheme3-more-field, #ff3355);\n}\n\n.sa-block-color-pen {\n --sa-block-background-primary: var(--editorTheme3-pen-primary, #0fbd8c);\n --sa-block-background-secondary: var(--editorTheme3-pen-secondary, #0da57a);\n --sa-block-background-tertiary: var(--editorTheme3-pen-tertiary, #0b8e69);\n --sa-block-field-background: var(--editorTheme3-pen-field, #0b8e69);\n}\n\n.sa-block-color-addon-custom-block {\n --sa-block-background-primary: var(--editorTheme3-sa-primary, #29beb8);\n --sa-block-background-secondary: var(--editorTheme3-sa-secondary, #3aa8a4);\n --sa-block-background-tertiary: var(--editorTheme3-sa-tertiary, #3aa8a4);\n --sa-block-field-background: var(--editorTheme3-sa-field, #3aa8a4);\n}\n\n.sa-block-color-TurboWarp {\n --sa-block-background-primary: var(--editorTheme3-tw-primary, #ff4c4c);\n --sa-block-background-secondary: var(--editorTheme3-tw-secondary, #e64444);\n --sa-block-background-tertiary: var(--editorTheme3-tw-tertiary, #e64444);\n --sa-block-field-background: var(--editorTheme3-tw-field, #e64444);\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/find-bar/userstyle.css": +/*!****************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/find-bar/userstyle.css ***! + \****************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports +exports.i(__webpack_require__(/*! -!../../../../node_modules/css-loader!../editor-theme3/compatibility.css */ "./node_modules/css-loader/index.js!./src/addons/addons/editor-theme3/compatibility.css"), ""); + +// module +exports.push([module.i, ".sa-find-bar {\n display: flex;\n align-items: center;\n white-space: nowrap;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n width: 100%;\n height: 100%;\n margin-left: 1em;\n}\n.sa-find-bar[hidden] {\n /* !important to override displayNoneWhileDisabled */\n display: none !important;\n}\n\n.sa-find-wrapper {\n overflow: visible;\n position: relative;\n height: 2rem;\n width: 100%;\n max-width: 16em;\n}\n\n.sa-find-dropdown-out {\n display: block;\n top: -6px;\n z-index: 100;\n width: 100%;\n max-width: 16em;\n position: relative;\n padding: 4px;\n border: none;\n border-radius: 4px;\n margin-top: 6px;\n}\n\n.sa-find-dropdown-out.visible {\n position: absolute;\n width: 16em;\n box-shadow: 0px 0px 8px 1px var(--ui-black-transparent, rgba(0, 0, 0, 0.3));\n background-color: var(--ui-primary, white);\n}\n\n/* We need to modify Scratch styles so that the place where the find bar is injected */\n/* has actually correct size information, which is used to make the find bar not cover up controls */\n[class*=\"gui_tab-list_\"] {\n width: 100%;\n}\n[class*=\"gui_tab_\"] {\n flex-grow: 0;\n}\n\n.sa-find-input {\n width: 100%;\n box-sizing: border-box !important;\n /* !important required for extension, because CSS injection method (and hence order) differs from addon */\n height: 1.5rem;\n\n /* Change Scratch default styles */\n border-radius: 0.25rem;\n font-size: 0.75rem;\n padding-left: 0.4em;\n}\n\n.sa-find-input:focus {\n /* Change Scratch default styles */\n box-shadow: none;\n}\n\n.sa-find-dropdown {\n display: none;\n position: relative;\n padding: 0.2em 0;\n font-size: 0.75rem;\n line-height: 1;\n overflow-y: auto;\n min-height: 128px;\n max-height: 65vh;\n user-select: none;\n max-width: 100%;\n margin-top: 6px;\n border: none;\n}\n\n.sa-find-dropdown-out.visible > .sa-find-dropdown {\n display: block;\n}\n\n.sa-find-dropdown > li {\n display: block;\n padding: 0.5em 0.3em;\n white-space: nowrap;\n margin: 0;\n font-weight: bold;\n text-overflow: ellipsis;\n overflow: hidden;\n}\n\n.sa-find-dropdown > li > b {\n background-color: #aaffaa;\n color: black;\n}\n\n/* Drop down items */\n.sa-find-dropdown > li:hover,\n.sa-find-dropdown > li.sel {\n color: var(--sa-block-text-on-bright-background);\n cursor: pointer;\n}\n\n.sa-find-dropdown > li::before {\n content: \"\\25CF \"; /* ● */\n}\n\n.sa-find-flag {\n color: #4cbf56;\n}\n/* .sa-find-dropdown added for specificity */\n.sa-find-dropdown > .sa-find-flag:hover,\n.sa-find-dropdown > .sa-find-flag.sel {\n background-color: #4cbf56;\n color: white;\n}\n\n.sa-find-dropdown .sa-block-color {\n color: var(--sa-block-colored-text);\n}\n.sa-find-dropdown .sa-block-color:hover,\n.sa-find-dropdown .sa-block-color.sel {\n background-color: var(--sa-block-bright-background);\n}\n\n.sa-find-carousel {\n font-weight: normal;\n position: absolute;\n right: 0;\n white-space: nowrap;\n background-color: inherit;\n z-index: 1;\n padding: 0;\n}\n\n.sa-find-carousel-control {\n padding: 0 6px;\n}\n\n.sa-find-carousel-control:hover {\n color: #ffff80;\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/folders/style.css": +/*!***********************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/folders/style.css ***! + \***********************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".sa-folders-contextmenu-item {\n max-width: 250px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n[sa-folders-context-type=\"folder\"] .react-contextmenu > :not(.sa-ctx-menu) {\n display: none;\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/middle-click-popup/userstyle.css": +/*!**************************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/middle-click-popup/userstyle.css ***! + \**************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports +exports.i(__webpack_require__(/*! -!../../../../node_modules/css-loader!../editor-theme3/compatibility.css */ "./node_modules/css-loader/index.js!./src/addons/addons/editor-theme3/compatibility.css"), ""); + +// module +exports.push([module.i, ".sa-mcp-root {\n display: flex;\n white-space: nowrap;\n font-family: \"Helvetica Neue\", Helvetica, Arial, sans-serif;\n\n position: absolute;\n min-width: 100px;\n background-color: white;\n border-radius: 4px;\n box-shadow:\n rgba(0, 0, 0, 0.3) 0 0 3px,\n rgba(0, 0, 0, 0.2) 0 3px 10px;\n\n z-index: 999;\n}\n\n.sa-mcp-container {\n display: flex;\n flex-flow: column;\n top: -6px;\n z-index: 100;\n position: absolute;\n box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.3);\n background-color: white;\n border: none;\n border-radius: 4px;\n overflow: auto;\n resize: both;\n}\n[theme=\"dark\"] .sa-mcp-container {\n background-color: #222;\n}\n\n.sa-mcp-input-wrapper {\n position: relative;\n margin: 4px;\n /* !important required for extension, because CSS injection method (and hence order) differs from addon */\n box-sizing: border-box !important;\n height: 1.5rem;\n min-height: 1.5rem;\n\n /* Change Scratch default styles */\n border-radius: 0.25rem;\n font-size: 0.75rem;\n padding-left: 0.2rem;\n padding-right: 0.2rem;\n}\n\n.sa-mcp-input-wrapper:focus {\n /* Change Scratch default styles */\n box-shadow: none;\n}\n\n.sa-mcp-input-wrapper[data-error=\"true\"] {\n border-color: red;\n}\n\n.sa-mcp-input-wrapper > input {\n position: absolute;\n border: 0;\n background-color: transparent;\n outline: none;\n width: 100%;\n height: 100%;\n line-height: 100%;\n box-sizing: border-box;\n}\n\n.sa-mcp-input-suggestion {\n color: hsla(225, 15%, 40%, 0.65);\n}\n\n.sa-mcp-preview-container {\n flex: auto;\n overflow-y: scroll;\n scrollbar-width: none;\n}\n\n.sa-mcp-preview-container::-webkit-scrollbar {\n width: 0;\n height: 0;\n}\n\n.sa-mcp-preview-blocks {\n width: 100%;\n min-height: 100%;\n /* https://stackoverflow.com/a/22166728/8448397 */\n float: left;\n}\n\n.sa-mcp-preview-scrollbar {\n position: absolute;\n width: 11px;\n right: 0;\n bottom: 0;\n}\n\n.sa-mcp-preview-block-bg {\n width: 100%;\n fill: transparent;\n cursor: grab;\n}\n\n.sa-mcp-preview-block {\n filter: brightness(95%);\n cursor: grab;\n}\n\n.sa-mcp-preview-block-selection {\n filter: brightness(103%);\n}\n\n.sa-mcp-preview-block-bg-selection {\n fill: #7774;\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/multi-tab-code/userstyle.css": +/*!**********************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/multi-tab-code/userstyle.css ***! + \**********************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".tab-scroller {\n width: max-content;\n display: flex;\n position: absolute;\n}\n.tab-scrollbar {\n position: absolute;\n background-color: black;\n height: 1px;\n width: 20px;\n bottom: 0;\n}\n.tab-scrollbar:hover { height: 3px; }\n.tab-wrapper {\n position: absolute;\n right: 0;\n height: 17px;\n overflow-x: hidden;\n overflow-y: visible;\n scrollbar-width: thin;\n}\n.tab-wrapper.copying {\n height: 29px;\n}\n.tab-adder-button {\n width: 12px;\n height: 12px;\n margin: 1px;\n margin-right: 11px;\n border-radius: 3px;\n border: none;\n}\n[theme=dark] .tab-adder-button {\n filter: invert(1);\n}\n.tab-adder-button:hover {\n background-color: rgba(0 0 0 / 15%);\n}\n.tab-bounds {\n height: 14px;\n display: inline-flex;\n flex-direction: column;\n align-items: flex-start;\n width: max-content;\n}\n.tab-bounds.copying {\n height: 28px;\n}\n.tab {\n border-radius: 3px;\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n padding: 1px 4px;\n min-width: 20px;\n font-size: 10px;\n text-align: center;\n cursor: pointer;\n overflow-y: hidden;\n user-select: none;\n background-color: var(--ui-primary, hsla(215, 100%, 95%, 1));\n border: 1px solid var(--ui-black-transparent, hsla(0, 0%, 0%, 0.15));\n color: var(--text-primary, hsla(225, 15%, 40%, 1));\n border-top: none;\n transition: height 100ms ease-in, color 100ms ease-in;\n}\n.tab.unselected {\n height: 7px;\n color: transparent;\n}\n.tab.hover {\n height: 10px;\n color: #333;\n}\n.tab.selected {\n height: 14px;\n color: var(--text-primary, hsla(225, 15%, 40%, 1));\n}\n.tab.copying {\n height: 28px;\n color: var(--text-primary, hsla(225, 15%, 40%, 1));\n}", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/onion-skinning/style.css": +/*!******************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/onion-skinning/style.css ***! + \******************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".sa-onion-button {\n position: relative;\n}\n.sa-onion-button:focus-within {\n background-color: hsla(194, 100%, 50%, 0.2);\n}\n[theme=\"dark\"] .sa-onion-image {\n filter: brightness(0) invert(0.8);\n}\n.sa-onion-button[data-enabled=\"true\"] .sa-onion-image {\n filter: brightness(0) invert(1);\n}\n.sa-onion-button[data-enabled=\"true\"] {\n background-color: #00c3ff;\n}\n\n.sa-onion-group {\n position: relative;\n flex-direction: row;\n}\n\n.sa-onion-settings-wrapper {\n position: absolute;\n justify-items: center;\n left: 50%;\n width: 1.95rem;\n height: 1.95rem;\n display: grid;\n}\n\n.sa-onion-settings {\n position: absolute;\n bottom: 100%;\n /* based on the styles for the color dropdown */\n padding: 4px;\n border-radius: 4px;\n border: 1px solid var(--paint-ui-pane-border, #ddd);\n box-shadow: 0px 0px 8px 1px rgba(0, 0, 0, 0.3);\n transition-property: bottom, opacity;\n transition-duration: 500ms;\n transition-timing-function: cubic-bezier(0.23, 1, 0.32, 1);\n opacity: 0;\n pointer-events: none;\n background: var(--ui-primary, white);\n min-height: 100%;\n min-width: 100%;\n display: flex;\n flex-direction: column;\n gap: 0.25em;\n}\n.sa-onion-settings[data-visible=\"true\"] {\n bottom: calc(100% + 22px);\n pointer-events: auto;\n opacity: 1;\n}\n\n.sa-onion-settings-line {\n display: flex;\n justify-content: flex-end;\n align-items: baseline;\n gap: 0.25em;\n}\n\n.sa-onion-settings-input {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n text-align: center;\n border: 0;\n background: transparent;\n -moz-appearance: textfield;\n border: 0;\n outline: 0;\n}\n\n.sa-onion-settings-input::-webkit-outer-spin-button,\n.sa-onion-settings-input::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n}\n\n.sa-onion-settings-tip {\n position: absolute;\n bottom: 0;\n transform: translateY(100%);\n right: calc(50% - 7px);\n}\n.sa-onion-settings-polygon {\n fill: var(--ui-primary, white);\n stroke: var(--paint-ui-pane-border, #ddd);\n}\n\n.sa-onion-settings-label {\n white-space: nowrap;\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/pick-colors-from-stage/style.css": +/*!**************************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/pick-colors-from-stage/style.css ***! + \**************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".sa-stage-color-picker-picking [class^=\"stage_color-picker-background_\"] {\n display: none;\n}\n", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/reorder-custom-inputs/arrows.css": +/*!**************************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/reorder-custom-inputs/arrows.css ***! + \**************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, ".blocklyTextShiftArrow {\n position: absolute;\n top: -50px;\n left: 50%;\n margin-left: -12.5px;\n cursor: pointer;\n}", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/toolbox-category-drag/userstyle.css": +/*!*****************************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/toolbox-category-drag/userstyle.css ***! + \*****************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, "div[class=\"scratchCategoryMenuRow\"][data-dragger=\"true\"] > div {\n background: white;\n font-size: 0.65rem;\n}\n\n[theme=\"dark\"] div[class=\"scratchCategoryMenuRow\"][data-dragger=\"true\"] > div {\n background: var(--ui-secondary);\n}", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/css-loader/index.js!./src/addons/addons/toolbox-full-blocks-on-hover/userstyle.css": +/*!************************************************************************************************!*\ + !*** ./node_modules/css-loader!./src/addons/addons/toolbox-full-blocks-on-hover/userstyle.css ***! + \************************************************************************************************/ +/*! no static exports found */ +/***/ (function(module, exports, __webpack_require__) { + +exports = module.exports = __webpack_require__(/*! ../../../../node_modules/css-loader/lib/css-base.js */ "./node_modules/css-loader/lib/css-base.js")(false); +// imports + + +// module +exports.push([module.i, "[class*=\"blocks_blocks_\"] .blocklyFlyout:has(.blocklyDraggable:hover) {\n overflow: visible;\n z-index: 31;\n}\n\n[class*=\"blocks_blocks_\"] .blocklyFlyout:has(.blocklyDraggable:hover) .blocklyWorkspace {\n clip-path: unset !important;\n}", ""]); + +// exports + + +/***/ }), + +/***/ "./node_modules/url-loader/dist/cjs.js!./src/addons/addons/editor-devtools/icon--close.svg": +/*!*************************************************************************************************!*\ + !*** ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/editor-devtools/icon--close.svg ***! + \*************************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = ("data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA3LjQ4IDcuNDgiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDpub25lO3N0cm9rZTojZmZmO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6MnB4O308L3N0eWxlPjwvZGVmcz48dGl0bGU+aWNvbi0tYWRkPC90aXRsZT48bGluZSBjbGFzcz0iY2xzLTEiIHgxPSIzLjc0IiB5MT0iNi40OCIgeDI9IjMuNzQiIHkyPSIxIi8+PGxpbmUgY2xhc3M9ImNscy0xIiB4MT0iMSIgeTE9IjMuNzQiIHgyPSI2LjQ4IiB5Mj0iMy43NCIvPjwvc3ZnPg=="); + +/***/ }), + +/***/ "./node_modules/url-loader/dist/cjs.js!./src/addons/addons/folders/folder.svg": +/*!************************************************************************************!*\ + !*** ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/folders/folder.svg ***! + \************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = ("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPjxwYXRoIGQ9Ik0xMCA0SDRjLTEuMSAwLTEuOTkuOS0xLjk5IDJMMiAxOGMwIDEuMS45IDIgMiAyaDE2YzEuMSAwIDItLjkgMi0yVjhjMC0xLjEtLjktMi0yLTJoLThsLTItMnoiLz48L3N2Zz4="); + +/***/ }), + +/***/ "./node_modules/url-loader/dist/cjs.js!./src/addons/addons/multi-tab-code/add.svg": +/*!****************************************************************************************!*\ + !*** ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/multi-tab-code/add.svg ***! + \****************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = ("data:image/svg+xml;base64,PHN2ZwogICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICAgd2lkdGg9IjE0IgogICAgaGVpZ2h0PSIxNCIKICAgIHZpZXdCb3g9IjAgMCAxMCAxMCIKICAgIHN0cm9rZT0iYmxhY2siCiAgICBzdHJva2UtbGluZWNhcD0icm91bmQiCj4KICAgIDxsaW5lIHgxPSI1IiB5MT0iMS41IiB4Mj0iNSIgeTI9IjguNSI+PC9saW5lPgogICAgPGxpbmUgeDE9IjEuNSIgeTE9IjUiIHgyPSI4LjUiIHkyPSI1Ij48L2xpbmU+Cjwvc3ZnPg=="); + +/***/ }), + +/***/ "./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/decrement.svg": +/*!**********************************************************************************************!*\ + !*** ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/decrement.svg ***! + \**********************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = ("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUgMTEuMzU4aDE3LjUwMXYxLjI4NUgzLjI1eiIvPjwvc3ZnPg=="); + +/***/ }), + +/***/ "./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/increment.svg": +/*!**********************************************************************************************!*\ + !*** ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/increment.svg ***! + \**********************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = ("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHdpZHRoPSIyNCI+PHBhdGggc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUgMTEuMzU4aDE3LjUwMXYxLjI4NUgzLjI1eiIvPjxwYXRoIHRyYW5zZm9ybT0icm90YXRlKDkwKSIgc3R5bGU9ImZpbGw6IzU3NWU3NTtzdHJva2Utd2lkdGg6LjczNDczNiIgZD0iTTMuMjUtMTIuNjQyaDE3LjUwMXYxLjI4NUgzLjI1eiIvPjwvc3ZnPg=="); + +/***/ }), + +/***/ "./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/settings.svg": +/*!*********************************************************************************************!*\ + !*** ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/settings.svg ***! + \*********************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = ("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PHBhdGggc3R5bGU9Im9wYWNpdHk6Ljc1O2ZpbGw6bm9uZTtzdHJva2U6IzAwMDtzdHJva2Utd2lkdGg6NDtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MSIgZD0iTTU2IDE2djk2IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMi4zNzYgLTIuMzc2KSBzY2FsZSguMjI0NjIpIi8+PHBhdGggc3R5bGU9Im9wYWNpdHk6LjU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNNDAgMzJ2NjQiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouMjU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjptaXRlcjtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNMjQgNDh2MzIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouNzU7ZmlsbDpub25lO3N0cm9rZTojMDAwO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eToxIiBkPSJNNzIgMTZ2OTYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48cGF0aCBzdHlsZT0ib3BhY2l0eTouNTtmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Ik04OCAzMnY2NCIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTIuMzc2IC0yLjM3Nikgc2NhbGUoLjIyNDYyKSIvPjxwYXRoIHN0eWxlPSJvcGFjaXR5Oi4yNTtmaWxsOm5vbmU7c3Ryb2tlOiMwMDA7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjEiIGQ9Ik0xMDQgNDh2MzIiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjM3NiAtMi4zNzYpIHNjYWxlKC4yMjQ2MikiLz48L3N2Zz4="); + +/***/ }), + +/***/ "./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/toggle.svg": +/*!*******************************************************************************************!*\ + !*** ./node_modules/url-loader/dist/cjs.js!./src/addons/addons/onion-skinning/toggle.svg ***! + \*******************************************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = ("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCI+PGcgc3Ryb2tlLXdpZHRoPSIxLjIiIHN0cm9rZT0iIzAwMTAyNiI+PGcgc3R5bGU9Im9wYWNpdHk6LjU7c3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lIj48cGF0aCBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2Utd2lkdGg6NDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIgZmlsbD0iI2JmYmZiZiIgZD0iTTY4LjQ1IDMyLjQ1N2MuMy0uMi44LS4xLjkuM2wyLjYgMTAuN3M2LjQgNC43IDguMyA4YzMuMiA1LjUgMy4zIDEwIDMuMyAxMHM3LjEgMi4xIDguMyA3LjhjMS4yIDUuNy0zLjIgMTYuNS0yMiAyMC4yLTE4LjggMy43LTMzLjktMS40LTQxLTEyLjgtNy4xLTExLjQgNC4xLTI1IDMuNS0yNC4ybC0yLjEtMTcuOWMtLjEtLjQuNC0uNy44LS41bDEyLjEgNy45czQuNS0xLjcgOS4yLTEuOWMyLjgtLjIgNS4yIDAgNy41LjR6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtNC42NTIgLTQuNjUpIHNjYWxlKC4yMzI5KSIvPjxwYXRoIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGZpbGw9Im5vbmUiIGQ9Ik0xMDEuNjUgNjIuOTU3Yy00LjcgMy44LTExLjkgMy45LTExLjkgMy45bTEwLjYgNy4zYy02LjMuNS0xMC4yLTEuNC0xMC4yLTEuNG0tNjguOC0xMC4xczguNiAyLjggMTIuMSA1LjltLjMgMy41Yy00LjMgMS43LTExLjcuNi0xMS43LjYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC00LjY1MiAtNC42NSkgc2NhbGUoLjIzMjkpIi8+PC9nPjxnIHN0eWxlPSJvcGFjaXR5Oi43NTtzdHJva2Utd2lkdGg6NDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmUiPjxwYXRoIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowIiBmaWxsPSIjYmZiZmJmIiBkPSJNNjguNDUgMzIuNDU3Yy4zLS4yLjgtLjEuOS4zbDIuNiAxMC43czYuNCA0LjcgOC4zIDhjMy4yIDUuNSAzLjMgMTAgMy4zIDEwczcuMSAyLjEgOC4zIDcuOGMxLjIgNS43LTMuMiAxNi41LTIyIDIwLjItMTguOCAzLjctMzMuOS0xLjQtNDEtMTIuOC03LjEtMTEuNCA0LjEtMjUgMy41LTI0LjJsLTIuMS0xNy45Yy0uMS0uNC40LS43LjgtLjVsMTIuMSA3LjlzNC41LTEuNyA5LjItMS45YzIuOC0uMiA1LjIgMCA3LjUuNHoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjMyMyAtMi4zMjEpIHNjYWxlKC4yMzI5KSIvPjxwYXRoIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTpub3JtYWw7ZmlsbDpub25lO2ZpbGwtcnVsZTpldmVub2RkO3N0cm9rZS13aWR0aDo0O3N0cm9rZS1taXRlcmxpbWl0OjEwO3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2UtZGFzaG9mZnNldDowIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBzdHJva2UtbGluZWNhcD0icm91bmQiIGZpbGw9Im5vbmUiIGQ9Ik0xMDEuNjUgNjIuOTU3Yy00LjcgMy44LTExLjkgMy45LTExLjkgMy45bTEwLjYgNy4zYy02LjMuNS0xMC4yLTEuNC0xMC4yLTEuNG0tNjguOC0xMC4xczguNiAyLjggMTIuMSA1LjltLjMgMy41Yy00LjMgMS43LTExLjcuNi0xMS43LjYiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yLjMyMyAtMi4zMjEpIHNjYWxlKC4yMzI5KSIvPjwvZz48ZyBzdHlsZT0ic3Ryb2tlLXdpZHRoOjQ7c3Ryb2tlLW1pdGVybGltaXQ6MTA7c3Ryb2tlLWRhc2hhcnJheTpub25lIj48cGF0aCBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6I2ZmZjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2Utd2lkdGg6NDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIgZmlsbD0iI2JmYmZiZiIgZD0iTTczLjQ1IDM3LjQ1N2MuMy0uMi44LS4xLjkuM2wyLjYgMTAuN3M2LjQgNC43IDguMyA4YzMuMiA1LjUgMy4zIDEwIDMuMyAxMHM3LjEgMi4xIDguMyA3LjhjMS4yIDUuNy0zLjIgMTYuNS0yMiAyMC4yLTE4LjggMy43LTMzLjktMS40LTQxLTEyLjgtNy4xLTExLjQgNC4xLTI1IDMuNS0yNC4ybC0yLjEtMTcuOWMtLjEtLjQuNC0uNy44LS41bDEyLjEgNy45czQuNS0xLjcgOS4yLTEuOWMyLjgtLjIgNS4yIDAgNy41LjR6IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMS4xNTkgLTEuMTU3KSBzY2FsZSguMjMyOSkiLz48cGF0aCBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6bm9ybWFsO2ZpbGw6bm9uZTtmaWxsLXJ1bGU6ZXZlbm9kZDtzdHJva2Utd2lkdGg6NDtzdHJva2UtbWl0ZXJsaW1pdDoxMDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZzZXQ6MCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBmaWxsPSJub25lIiBkPSJNMTA2LjY1IDY3Ljk1N2MtNC43IDMuOC0xMS45IDMuOS0xMS45IDMuOW0xMC42IDcuM2MtNi4zLjUtMTAuMi0xLjQtMTAuMi0xLjRtLTY4LjgtMTAuMXM4LjYgMi44IDEyLjEgNS45bS4zIDMuNWMtNC4zIDEuNy0xMS43LjYtMTEuNy42IiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgtMS4xNTkgLTEuMTU3KSBzY2FsZSguMjMyOSkiLz48L2c+PC9nPjwvc3ZnPg=="); + +/***/ }), + +/***/ "./src/addons/addons/bitmap-copy/_runtime_entry.js": +/*!*********************************************************!*\ + !*** ./src/addons/addons/bitmap-copy/_runtime_entry.js ***! + \*********************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/bitmap-copy/userscript.js"); +/* generated by pull.js */ + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"] +}; + +/***/ }), + +/***/ "./src/addons/addons/bitmap-copy/userscript.js": +/*!*****************************************************!*\ + !*** ./src/addons/addons/bitmap-copy/userscript.js ***! + \*****************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = (async _ref => { + let { + addon, + console + } = _ref; + if (!addon.tab.redux.state) return console.warn("Redux is not available!"); + addon.tab.redux.initialize(); + addon.tab.redux.addEventListener("statechanged", _ref2 => { + let { + detail + } = _ref2; + if (addon.self.disabled) return; + const e = detail; + if (!e.action || e.action.type !== "scratch-paint/clipboard/SET") return; + const items = e.next.scratchPaint.clipboard.items; + if (items.length !== 1) return; + const firstItem = items[0]; + // TODO vector support + if (!Array.isArray(firstItem) || firstItem[0] !== "Raster") return console.log("copied element is vector"); + const dataURL = firstItem[1].source; + addon.tab.copyImage(dataURL).then(() => console.log("Image successfully copied")).catch(e => console.error("Image could not be copied: ".concat(e))); + }); +}); + +/***/ }), + +/***/ "./src/addons/addons/block-cherry-picking/_runtime_entry.js": +/*!******************************************************************!*\ + !*** ./src/addons/addons/block-cherry-picking/_runtime_entry.js ***! + \******************************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/block-cherry-picking/userscript.js"); +/* generated by pull.js */ + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"] +}; + +/***/ }), + +/***/ "./src/addons/addons/block-cherry-picking/userscript.js": +/*!**************************************************************!*\ + !*** ./src/addons/addons/block-cherry-picking/userscript.js ***! + \**************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _block_duplicate_module_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../block-duplicate/module.js */ "./src/addons/addons/block-duplicate/module.js"); + +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon, + console + } = _ref; + const update = () => { + _block_duplicate_module_js__WEBPACK_IMPORTED_MODULE_0__["setCherryPicking"](!addon.self.disabled, addon.settings.get("invertDrag")); + }; + addon.self.addEventListener("disabled", update); + addon.self.addEventListener("reenabled", update); + addon.settings.addEventListener("change", update); + update(); + _block_duplicate_module_js__WEBPACK_IMPORTED_MODULE_0__["load"](addon); +}); + +/***/ }), + +/***/ "./src/addons/addons/block-duplicate/_runtime_entry.js": +/*!*************************************************************!*\ + !*** ./src/addons/addons/block-duplicate/_runtime_entry.js ***! + \*************************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/block-duplicate/userscript.js"); +/* generated by pull.js */ + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"] +}; + +/***/ }), + +/***/ "./src/addons/addons/block-duplicate/module.js": +/*!*****************************************************!*\ + !*** ./src/addons/addons/block-duplicate/module.js ***! + \*****************************************************/ +/*! exports provided: setCherryPicking, setDuplication, load */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setCherryPicking", function() { return setCherryPicking; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setDuplication", function() { return setDuplication; }); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "load", function() { return load; }); +let enableCherryPicking = false; +let invertCherryPicking = false; +function setCherryPicking(newEnabled, newInverted) { + enableCherryPicking = newEnabled; + // If cherry picking is disabled, also disable invert. Duplicating blocks can still cause + // this setting to be used. + invertCherryPicking = newEnabled && newInverted; +} +let enableDuplication = false; +function setDuplication(newEnabled) { + enableDuplication = newEnabled; +} + +// mostRecentEvent_ is sometimes a fake event, so we can't rely on reading its properties. +let ctrlOrMetaPressed = false; +let altPressed = false; +document.addEventListener("mousedown", function (e) { + ctrlOrMetaPressed = e.ctrlKey || e.metaKey; + altPressed = e.altKey; +}, { + capture: true +}); +let loaded = false; +async function load(addon) { + if (loaded) { + return; + } + loaded = true; + const ScratchBlocks = await addon.tab.traps.getBlockly(); + + // https://github.com/LLK/scratch-blocks/blob/912b8cc728bea8fd91af85078c64fcdbfe21c87a/core/gesture.js#L454 + const originalStartDraggingBlock = ScratchBlocks.Gesture.prototype.startDraggingBlock_; + ScratchBlocks.Gesture.prototype.startDraggingBlock_ = function () { + let block = this.targetBlock_; + + // Scratch uses fake mouse events to implement right click > duplicate + const isRightClickDuplicate = !(this.mostRecentEvent_ instanceof MouseEvent); + const isDuplicating = enableDuplication && altPressed && !isRightClickDuplicate && !this.flyout_ && !this.shouldDuplicateOnDrag_ && (this.targetBlock_.type !== "procedures_definition" || this.targetBlock_.type !== "procedures_definition_return"); + const isCherryPickingInverted = invertCherryPicking && !isRightClickDuplicate && block.getParent(); + const canCherryPick = enableCherryPicking || isDuplicating; + const isCherryPicking = canCherryPick && ctrlOrMetaPressed === !isCherryPickingInverted && !block.isShadow(); + if (isDuplicating || isCherryPicking) { + if (!ScratchBlocks.Events.getGroup()) { + // Scratch will disable grouping on its own later. + ScratchBlocks.Events.setGroup(true); + } + } + if (isDuplicating) { + // Based on https://github.com/LLK/scratch-blocks/blob/feda366947432b9d82a4f212f43ff6d4ab6f252f/core/scratch_blocks_utils.js#L171 + // Setting this.shouldDuplicateOnDrag_ = true does NOT work because it doesn't call changeObscuredShadowIds + this.startWorkspace_.setResizesEnabled(false); + ScratchBlocks.Events.disable(); + let newBlock; + try { + const xmlBlock = ScratchBlocks.Xml.blockToDom(block); + newBlock = ScratchBlocks.Xml.domToBlock(xmlBlock, this.startWorkspace_); + ScratchBlocks.scratchBlocksUtils.changeObscuredShadowIds(newBlock); + const xy = block.getRelativeToSurfaceXY(); + newBlock.moveBy(xy.x, xy.y); + } catch (e) { + console.error(e); + } + ScratchBlocks.Events.enable(); + if (newBlock) { + block = newBlock; + this.targetBlock_ = newBlock; + if (ScratchBlocks.Events.isEnabled()) { + ScratchBlocks.Events.fire(new ScratchBlocks.Events.BlockCreate(newBlock)); + } + } + } + if (isCherryPicking) { + if (isRightClickDuplicate || isDuplicating) { + const nextBlock = block.getNextBlock(); + if (nextBlock) { + nextBlock.dispose(); + } + } + block.unplug(true); + } + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + return originalStartDraggingBlock.call(this, ...args); + }; +} + +/***/ }), + +/***/ "./src/addons/addons/block-duplicate/userscript.js": +/*!*********************************************************!*\ + !*** ./src/addons/addons/block-duplicate/userscript.js ***! + \*********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _module_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./module.js */ "./src/addons/addons/block-duplicate/module.js"); + +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon, + console + } = _ref; + const update = () => { + _module_js__WEBPACK_IMPORTED_MODULE_0__["setDuplication"](!addon.self.disabled); + }; + addon.self.addEventListener("disabled", update); + addon.self.addEventListener("reenabled", update); + update(); + _module_js__WEBPACK_IMPORTED_MODULE_0__["load"](addon); +}); + +/***/ }), + +/***/ "./src/addons/addons/block-switching/_runtime_entry.js": +/*!*************************************************************!*\ + !*** ./src/addons/addons/block-switching/_runtime_entry.js ***! + \*************************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/block-switching/userscript.js"); +/* generated by pull.js */ + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"] +}; + +/***/ }), + +/***/ "./src/addons/addons/block-switching/userscript.js": +/*!*********************************************************!*\ + !*** ./src/addons/addons/block-switching/userscript.js ***! + \*********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* eslint-disable */ + +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon, + console, + msg + } = _ref; + const ScratchBlocks = await addon.tab.traps.getBlockly(); + const vm = addon.tab.traps.vm; + let blockSwitches = {}; + let procedureSwitches = {}; + const noopSwitch = { + isNoop: true + }; + const randomColor = () => { + const num = Math.floor(Math.random() * 256 * 256 * 256); + return "#".concat(num.toString(16).padStart(6, "0")); + }; + const buildSwitches = () => { + blockSwitches = {}; + procedureSwitches = {}; + if (addon.settings.get("motion")) { + blockSwitches["motion_turnright"] = [noopSwitch, { + opcode: "motion_turnleft" + }]; + blockSwitches["motion_turnleft"] = [{ + opcode: "motion_turnright" + }, noopSwitch]; + blockSwitches["motion_gotoxy"] = [noopSwitch, { + opcode: "motion_changebyxy", + remapInputName: { + X: "DX", + Y: "DY" + } + }]; + blockSwitches["motion_changebyxy"] = [{ + opcode: "motion_gotoxy", + remapInputName: { + DX: "X", + DY: "Y" + } + }, noopSwitch]; + blockSwitches["motion_setx"] = [noopSwitch, { + opcode: "motion_changexby", + remapInputName: { + X: "DX" + } + }, { + opcode: "motion_sety", + remapInputName: { + X: "Y" + } + }, { + opcode: "motion_changeyby", + remapInputName: { + X: "DY" + } + }]; + blockSwitches["motion_changexby"] = [{ + opcode: "motion_setx", + remapInputName: { + DX: "X" + } + }, noopSwitch, { + opcode: "motion_sety", + remapInputName: { + DX: "Y" + } + }, { + opcode: "motion_changeyby", + remapInputName: { + DX: "DY" + } + }]; + blockSwitches["motion_sety"] = [{ + opcode: "motion_setx", + remapInputName: { + Y: "X" + } + }, { + opcode: "motion_changexby", + remapInputName: { + Y: "DX" + } + }, noopSwitch, { + opcode: "motion_changeyby", + remapInputName: { + Y: "DY" + } + }]; + blockSwitches["motion_changeyby"] = [{ + opcode: "motion_setx", + remapInputName: { + DY: "X" + } + }, { + opcode: "motion_changexby", + remapInputName: { + DY: "DX" + } + }, { + opcode: "motion_sety", + remapInputName: { + DY: "Y" + } + }, noopSwitch]; + blockSwitches["motion_xposition"] = [noopSwitch, { + opcode: "motion_yposition" + }]; + blockSwitches["motion_yposition"] = [{ + opcode: "motion_xposition" + }, noopSwitch]; + } + if (addon.settings.get("looks")) { + blockSwitches["looks_seteffectto"] = [noopSwitch, { + opcode: "looks_changeeffectby", + remapInputName: { + VALUE: "CHANGE" + } + }]; + blockSwitches["looks_changeeffectby"] = [{ + opcode: "looks_seteffectto", + remapInputName: { + CHANGE: "VALUE" + } + }, noopSwitch]; + blockSwitches["looks_setsizeto"] = [noopSwitch, { + opcode: "looks_changesizeby", + remapInputName: { + SIZE: "CHANGE" + } + }]; + blockSwitches["looks_changesizeby"] = [{ + opcode: "looks_setsizeto", + remapInputName: { + CHANGE: "SIZE" + } + }, noopSwitch]; + blockSwitches["looks_costumenumbername"] = [noopSwitch, { + opcode: "looks_backdropnumbername" + }]; + blockSwitches["looks_backdropnumbername"] = [{ + opcode: "looks_costumenumbername" + }, noopSwitch]; + blockSwitches["looks_show"] = [noopSwitch, { + opcode: "looks_hide" + }]; + blockSwitches["looks_hide"] = [{ + opcode: "looks_show" + }, noopSwitch]; + blockSwitches["looks_setShape"] = [{ + opcode: "looks_setShape" + }, noopSwitch]; + blockSwitches["looks_setColor"] = [{ + opcode: "looks_setColor" + }, noopSwitch]; + blockSwitches["looks_setFont"] = [{ + opcode: "looks_setFont" + }, noopSwitch]; + blockSwitches["looks_nextcostume"] = [noopSwitch, { + opcode: "looks_nextbackdrop" + }]; + blockSwitches["looks_nextbackdrop"] = [{ + opcode: "looks_nextcostume" + }, noopSwitch]; + blockSwitches["looks_say"] = [noopSwitch, { + opcode: "looks_sayforsecs", + createInputs: { + SECS: { + shadowType: "math_number", + value: "2" + } + } + }, { + opcode: "looks_think" + }, { + opcode: "looks_thinkforsecs", + createInputs: { + SECS: { + shadowType: "math_number", + value: "2" + } + } + }]; + blockSwitches["looks_think"] = [{ + opcode: "looks_say" + }, { + opcode: "looks_sayforsecs", + createInputs: { + SECS: { + shadowType: "math_number", + value: "2" + } + } + }, noopSwitch, { + opcode: "looks_thinkforsecs", + createInputs: { + SECS: { + shadowType: "math_number", + value: "2" + } + } + }]; + blockSwitches["looks_sayforsecs"] = [{ + opcode: "looks_say", + splitInputs: ["SECS"] + }, { + opcode: "looks_think", + splitInputs: ["SECS"] + }, noopSwitch, { + opcode: "looks_thinkforsecs" + }]; + blockSwitches["looks_thinkforsecs"] = [{ + opcode: "looks_say", + splitInputs: ["SECS"] + }, { + opcode: "looks_think", + splitInputs: ["SECS"] + }, { + opcode: "looks_sayforsecs" + }, noopSwitch]; + blockSwitches["looks_switchbackdropto"] = [noopSwitch, { + opcode: "looks_switchbackdroptoandwait" + }]; + blockSwitches["looks_switchbackdroptoandwait"] = [{ + opcode: "looks_switchbackdropto" + }, noopSwitch]; + blockSwitches["looks_gotofrontback"] = [noopSwitch, { + opcode: "looks_goforwardbackwardlayers", + remapInputName: { + FRONT_BACK: "FORWARD_BACKWARD" + }, + mapFieldValues: { + FRONT_BACK: { + front: "forward", + back: "backward" + } + }, + createInputs: { + NUM: { + shadowType: "math_integer", + value: "1" + } + } + }]; + blockSwitches["looks_goforwardbackwardlayers"] = [{ + opcode: "looks_gotofrontback", + splitInputs: ["NUM"], + remapInputName: { + FORWARD_BACKWARD: "FRONT_BACK" + }, + mapFieldValues: { + FORWARD_BACKWARD: { + forward: "front", + backward: "back" + } + } + }, noopSwitch]; + } + if (addon.settings.get("sound")) { + blockSwitches["sound_play"] = [noopSwitch, { + opcode: "sound_playuntildone" + }]; + blockSwitches["sound_playuntildone"] = [{ + opcode: "sound_play" + }, noopSwitch]; + blockSwitches["sound_seteffectto"] = [noopSwitch, { + opcode: "sound_changeeffectby" + }]; + blockSwitches["sound_changeeffectby"] = [{ + opcode: "sound_seteffectto" + }, noopSwitch]; + blockSwitches["sound_setvolumeto"] = [noopSwitch, { + opcode: "sound_changevolumeby" + }]; + blockSwitches["sound_changevolumeby"] = [{ + opcode: "sound_setvolumeto" + }, noopSwitch]; + } + if (addon.settings.get("event")) { + blockSwitches["event_broadcast"] = [noopSwitch, { + opcode: "event_broadcastandwait" + }]; + blockSwitches["event_broadcastandwait"] = [{ + opcode: "event_broadcast" + }, noopSwitch]; + } + if (addon.settings.get("control")) { + blockSwitches["control_if"] = [noopSwitch, { + opcode: "control_if_else" + }]; + blockSwitches["control_if_else"] = [{ + opcode: "control_if", + splitInputs: ["SUBSTACK2"] + }, noopSwitch]; + blockSwitches["control_repeat_until"] = [noopSwitch, { + opcode: "control_while" + }, { + opcode: "control_wait_until", + splitInputs: ["SUBSTACK"] + }, { + opcode: "control_forever", + splitInputs: ["CONDITION"] + }]; + blockSwitches["control_forever"] = [{ + opcode: "control_repeat_until" + }, { + opcode: "control_while" + }, noopSwitch]; + blockSwitches["control_wait_until"] = [{ + opcode: "control_repeat_until" + }, noopSwitch]; + blockSwitches["control_while"] = [{ + opcode: "control_repeat_until" + }, noopSwitch, { + opcode: "control_forever", + splitInputs: ["CONDITION"] + }]; + } + if (addon.settings.get("operator")) { + blockSwitches["operator_equals"] = [{ + opcode: "operator_gt" + }, { + opcode: "operator_gtorequal" + }, { + opcode: "operator_lt" + }, { + opcode: "operator_ltorequal" + }, noopSwitch, { + opcode: "operator_notequal" + }]; + blockSwitches["operator_gt"] = [noopSwitch, { + opcode: "operator_gtorequal" + }, { + opcode: "operator_lt" + }, { + opcode: "operator_ltorequal" + }, { + opcode: "operator_equals" + }, { + opcode: "operator_notequal" + }]; + blockSwitches["operator_lt"] = [{ + opcode: "operator_gt" + }, { + opcode: "operator_gtorequal" + }, noopSwitch, { + opcode: "operator_ltorequal" + }, { + opcode: "operator_equals" + }, { + opcode: "operator_notequal" + }]; + blockSwitches["operator_notequal"] = [{ + opcode: "operator_gt" + }, { + opcode: "operator_gtorequal" + }, { + opcode: "operator_lt" + }, { + opcode: "operator_ltorequal" + }, { + opcode: "operator_equals" + }, noopSwitch]; + blockSwitches["operator_gtorequal"] = [{ + opcode: "operator_gt" + }, noopSwitch, { + opcode: "operator_lt" + }, { + opcode: "operator_ltorequal" + }, { + opcode: "operator_equals" + }, { + opcode: "operator_notequal" + }]; + blockSwitches["operator_ltorequal"] = [{ + opcode: "operator_gt" + }, { + opcode: "operator_gtorequal" + }, { + opcode: "operator_lt" + }, noopSwitch, { + opcode: "operator_equals" + }, { + opcode: "operator_notequal" + }]; + blockSwitches["operator_add"] = [noopSwitch, { + opcode: "operator_subtract" + }, { + opcode: "operator_multiply" + }, { + opcode: "operator_divide" + }, { + opcode: "operator_power" + }, { + opcode: "operator_mod" + }]; + blockSwitches["operator_subtract"] = [{ + opcode: "operator_add" + }, noopSwitch, { + opcode: "operator_multiply" + }, { + opcode: "operator_divide" + }, { + opcode: "operator_power" + }, { + opcode: "operator_mod" + }]; + blockSwitches["operator_multiply"] = [{ + opcode: "operator_add" + }, { + opcode: "operator_subtract" + }, noopSwitch, { + opcode: "operator_divide" + }, { + opcode: "operator_power" + }, { + opcode: "operator_mod" + }]; + blockSwitches["operator_divide"] = [{ + opcode: "operator_add" + }, { + opcode: "operator_subtract" + }, { + opcode: "operator_multiply" + }, noopSwitch, { + opcode: "operator_power" + }, { + opcode: "operator_mod" + }]; + blockSwitches["operator_power"] = [{ + opcode: "operator_add" + }, { + opcode: "operator_subtract" + }, { + opcode: "operator_multiply" + }, { + opcode: "operator_divide" + }, noopSwitch, { + opcode: "operator_mod" + }]; + blockSwitches["operator_mod"] = [{ + opcode: "operator_add" + }, { + opcode: "operator_subtract" + }, { + opcode: "operator_multiply" + }, { + opcode: "operator_divide" + }, { + opcode: "operator_power" + }, noopSwitch]; + blockSwitches["operator_and"] = [noopSwitch, { + opcode: "operator_or" + }]; + blockSwitches["operator_or"] = [{ + opcode: "operator_and" + }, noopSwitch]; + blockSwitches["operator_trueBoolean"] = [noopSwitch, { + opcode: "operator_falseBoolean" + }]; + blockSwitches["operator_falseBoolean"] = [{ + opcode: "operator_trueBoolean" + }, noopSwitch]; + } + if (addon.settings.get("sensing")) { + blockSwitches["sensing_mousex"] = [noopSwitch, { + opcode: "sensing_mousey" + }]; + blockSwitches["sensing_mousey"] = [{ + opcode: "sensing_mousex" + }, noopSwitch]; + blockSwitches["sensing_touchingcolor"] = [noopSwitch, { + opcode: "sensing_coloristouchingcolor", + createInputs: { + COLOR2: { + shadowType: "colour_picker", + value: randomColor + } + } + }]; + blockSwitches["sensing_coloristouchingcolor"] = [{ + opcode: "sensing_touchingcolor", + splitInputs: ["COLOR2"] + }, noopSwitch]; + } + if (addon.settings.get("data")) { + blockSwitches["data_setvariableto"] = [noopSwitch, { + opcode: "data_changevariableby", + remapShadowType: { + VALUE: "math_number" + } + }]; + blockSwitches["data_changevariableby"] = [{ + opcode: "data_setvariableto", + remapShadowType: { + VALUE: "text" + } + }, noopSwitch]; + blockSwitches["data_showvariable"] = [noopSwitch, { + opcode: "data_hidevariable" + }]; + blockSwitches["data_hidevariable"] = [{ + opcode: "data_showvariable" + }, noopSwitch]; + blockSwitches["data_showlist"] = [noopSwitch, { + opcode: "data_hidelist" + }]; + blockSwitches["data_hidelist"] = [{ + opcode: "data_showlist" + }, noopSwitch]; + blockSwitches["data_replaceitemoflist"] = [noopSwitch, { + opcode: "data_insertatlist" + }]; + blockSwitches["data_insertatlist"] = [{ + opcode: "data_replaceitemoflist" + }, noopSwitch]; + blockSwitches["data_deleteoflist"] = [noopSwitch, { + opcode: "data_deletealloflist", + splitInputs: ["INDEX"] + }]; + blockSwitches["data_deletealloflist"] = [{ + opcode: "data_deleteoflist", + createInputs: { + INDEX: { + shadowType: "math_integer", + value: "1" + } + } + }, noopSwitch]; + } + if (addon.settings.get("extension")) { + blockSwitches["pen_penDown"] = [noopSwitch, { + opcode: "pen_penUp" + }]; + blockSwitches["pen_penUp"] = [{ + opcode: "pen_penDown" + }, noopSwitch]; + blockSwitches["pen_setPenColorParamTo"] = [noopSwitch, { + opcode: "pen_changePenColorParamBy" + }]; + blockSwitches["pen_changePenColorParamBy"] = [{ + opcode: "pen_setPenColorParamTo" + }, noopSwitch]; + blockSwitches["pen_setPenHueToNumber"] = [noopSwitch, { + opcode: "pen_changePenHueBy" + }]; + blockSwitches["pen_changePenHueBy"] = [{ + opcode: "pen_setPenHueToNumber" + }, noopSwitch]; + blockSwitches["pen_setPenShadeToNumber"] = [noopSwitch, { + opcode: "pen_changePenShadeBy" + }]; + blockSwitches["pen_changePenShadeBy"] = [{ + opcode: "pen_setPenShadeToNumber" + }, noopSwitch]; + blockSwitches["pen_setPenSizeTo"] = [noopSwitch, { + opcode: "pen_changePenSizeBy" + }]; + blockSwitches["pen_changePenSizeBy"] = [{ + opcode: "pen_setPenSizeTo" + }, noopSwitch]; + blockSwitches["music_setTempo"] = [noopSwitch, { + opcode: "music_changeTempo" + }]; + blockSwitches["music_changeTempo"] = [{ + opcode: "music_setTempo" + }, noopSwitch]; + if (vm.extensionManager) { + const switches = vm.extensionManager.getAddonBlockSwitches(); + Object.getOwnPropertyNames(switches).forEach(extID => { + Object.getOwnPropertyNames(switches[extID]).forEach(block => { + blockSwitches["".concat(extID, "_").concat(block)] = switches[extID][block]; + }); + }); + } + vm.runtime.on("EXTENSION_ADDED", () => { + const switches = vm.extensionManager.getAddonBlockSwitches(); + Object.getOwnPropertyNames(switches).forEach(extID => { + Object.getOwnPropertyNames(switches[extID]).forEach(block => { + blockSwitches["".concat(extID, "_").concat(block)] = switches[extID][block]; + }); + }); + }); + } + if (addon.settings.get("sa")) { + const logProc = "\u200B\u200Blog\u200B\u200B %s"; + const warnProc = "\u200B\u200Bwarn\u200B\u200B %s"; + const errorProc = "\u200B\u200Berror\u200B\u200B %s"; + const logMessage = msg("debugger_log"); + const warnMessage = msg("debugger_warn"); + const errorMessage = msg("debugger_error"); + const logSwitch = { + mutate: { + proccode: logProc + }, + msg: logMessage + }; + const warnSwitch = { + mutate: { + proccode: warnProc + }, + msg: warnMessage + }; + const errorSwitch = { + mutate: { + proccode: errorProc + }, + msg: errorMessage + }; + procedureSwitches[logProc] = [{ + msg: logMessage, + isNoop: true + }, warnSwitch, errorSwitch]; + procedureSwitches[warnProc] = [logSwitch, { + msg: warnMessage, + isNoop: true + }, errorSwitch]; + procedureSwitches[errorProc] = [logSwitch, warnSwitch, { + msg: errorMessage, + isNoop: true + }]; + } + + // Switching for these is implemented by Scratch. We only define them here to optionally add a border. + // Because we don't implement the switching ourselves, this is not controlled by the data category option. + blockSwitches["data_variable"] = []; + blockSwitches["data_listcontents"] = []; + }; + buildSwitches(); + addon.settings.addEventListener("change", buildSwitches); + + /** + * @param {*} workspace + * @param {Element} xmlBlock + */ + const pasteBlockXML = (workspace, xmlBlock) => { + // Similar to https://github.com/LLK/scratch-blocks/blob/7575c9a0f2c267676569c4b102b76d77f35d9fd6/core/workspace_svg.js#L1020 + // but without the collision checking. + const block = ScratchBlocks.Xml.domToBlock(xmlBlock, workspace); + const x = +xmlBlock.getAttribute("x"); + const y = +xmlBlock.getAttribute("y"); + // Don't need to handle RTL here + block.moveBy(x, y); + return block; + }; + + /** + * @param {string} shadowType The type of shadow eg. "math_number" + * @returns {string} The name of the shadow's inner field that contains the user-visible value + */ + const getShadowFieldName = shadowType => { + // This is non-comprehensive. + if (shadowType === "text") { + return "TEXT"; + } + if (shadowType === "colour_picker") { + return "COLOUR"; + } + return "NUM"; + }; + + /** + * @template T + * @param {T|()=>T} value + * @returns {T} + */ + const callIfFunction = value => { + if (typeof value === "function") { + return value(); + } + return value; + }; + const menuCallbackFactory = (block, opcodeData) => () => { + if (opcodeData.isNoop) { + return; + } + if (opcodeData.fieldValue) { + block.setFieldValue(opcodeData.fieldValue, "VALUE"); + return; + } + try { + ScratchBlocks.Events.setGroup(true); + const workspace = block.workspace; + const blocksToBringToForeground = []; + // Split inputs before we clone the block. + if (opcodeData.splitInputs) { + for (const inputName of opcodeData.splitInputs) { + const input = block.getInput(inputName); + if (!input) { + continue; + } + const connection = input.connection; + if (!connection) { + continue; + } + if (connection.isConnected()) { + const targetBlock = connection.targetBlock(); + if (targetBlock.isShadow()) { + // Deleting shadows is handled later. + } else { + connection.disconnect(); + blocksToBringToForeground.push(targetBlock); + } + } + } + } + + // Make a copy of the block with the proper type set. + // It doesn't seem to be possible to change a Block's type after it's created, so we'll just make a new block instead. + const xml = ScratchBlocks.Xml.blockToDom(block); + // blockToDomWithXY's handling of RTL is strange, so we encode the position ourselves. + const position = block.getRelativeToSurfaceXY(); + xml.setAttribute("x", position.x); + xml.setAttribute("y", position.y); + if (opcodeData.opcode) { + xml.setAttribute("type", opcodeData.opcode); + } + const parentBlock = block.getParent(); + let parentConnection; + let blockConnectionType; + if (parentBlock) { + // If the block has a parent, find the parent -> child connection that will be reattached later. + const parentConnections = parentBlock.getConnections_(); + parentConnection = parentConnections.find(c => c.targetConnection && c.targetConnection.sourceBlock_ === block); + // There's two types of connections from child -> parent. We need to figure out which one is used. + const blockConnections = block.getConnections_(); + const blockToParentConnection = blockConnections.find(c => c.targetConnection && c.targetConnection.sourceBlock_ === parentBlock); + blockConnectionType = blockToParentConnection.type; + } + + // Array.from creates a clone of the children list. This is important as we may remove + // children as we iterate. + for (const child of Array.from(xml.children)) { + const oldName = child.getAttribute("name"); + + // Any inputs that were supposed to be split that were not should be removed. + // (eg. shadow inputs) + if (opcodeData.splitInputs && opcodeData.splitInputs.includes(oldName)) { + xml.removeChild(child); + continue; + } + const newName = opcodeData.remapInputName && opcodeData.remapInputName[oldName]; + if (newName) { + child.setAttribute("name", newName); + } + const newShadowType = opcodeData.remapShadowType && opcodeData.remapShadowType[oldName]; + if (newShadowType) { + const valueNode = child.firstChild; + const fieldNode = valueNode.firstChild; + valueNode.setAttribute("type", newShadowType); + fieldNode.setAttribute("name", getShadowFieldName(newShadowType)); + } + const fieldValueMap = opcodeData.mapFieldValues && opcodeData.mapFieldValues[oldName]; + if (fieldValueMap && child.tagName === "FIELD") { + const oldValue = child.innerText; + const newValue = fieldValueMap[oldValue]; + if (typeof newValue === "string") { + child.innerText = newValue; + } + } + } + if (opcodeData.mutate) { + const mutation = xml.querySelector("mutation"); + for (const [key, value] of Object.entries(opcodeData.mutate)) { + mutation.setAttribute(key, value); + } + } + if (opcodeData.createInputs) { + for (const [inputName, inputData] of Object.entries(opcodeData.createInputs)) { + const valueElement = document.createElement("value"); + valueElement.setAttribute("name", inputName); + const shadowElement = document.createElement("shadow"); + shadowElement.setAttribute("type", inputData.shadowType); + const shadowFieldElement = document.createElement("field"); + shadowFieldElement.setAttribute("name", getShadowFieldName(inputData.shadowType)); + shadowFieldElement.innerText = callIfFunction(inputData.value); + shadowElement.appendChild(shadowFieldElement); + valueElement.appendChild(shadowElement); + xml.appendChild(valueElement); + } + } + + // Remove the old block and insert the new one. + block.dispose(); + const newBlock = pasteBlockXML(workspace, xml); + if (parentConnection) { + // Search for the same type of connection on the new block as on the old block. + const newBlockConnections = newBlock.getConnections_(); + const newBlockConnection = newBlockConnections.find(c => c.type === blockConnectionType); + newBlockConnection.connect(parentConnection); + } + for (const otherBlock of blocksToBringToForeground) { + // By re-appending the element, we move it to the end, which will make it display + // on top. + const svgRoot = otherBlock.getSvgRoot(); + svgRoot.parentNode.appendChild(svgRoot); + } + } finally { + ScratchBlocks.Events.setGroup(false); + } + }; + const uniques = array => [...new Set(array)]; + addon.tab.createBlockContextMenu((items, block) => { + if (!addon.self.disabled) { + const type = block.type; + let switches = blockSwitches[block.type] || []; + const customArgsMode = addon.settings.get("customargs") ? addon.settings.get("customargsmode") : "off"; + if (customArgsMode !== "off" && ["argument_reporter_boolean", "argument_reporter_string_number"].includes(type) && + // if the arg is a shadow, it's in a procedures_prototype so we don't want it to be switchable + !block.isShadow()) { + const customBlocks = getCustomBlocks(); + if (customArgsMode === "all") { + switch (type) { + case "argument_reporter_string_number": + switches = Object.values(customBlocks).map(cb => cb.stringArgs).flat(1); + break; + case "argument_reporter_boolean": + switches = Object.values(customBlocks).map(cb => cb.boolArgs).flat(1); + break; + } + } else if (customArgsMode === "defOnly") { + const root = block.getRootBlock(); + if (root.type !== "procedures_definition" || root.type !== "procedures_definition_return") return items; + const customBlockObj = customBlocks[root.getChildren(true)[0].getProcCode()]; + switch (type) { + case "argument_reporter_string_number": + switches = customBlockObj.stringArgs; + break; + case "argument_reporter_boolean": + switches = customBlockObj.boolArgs; + break; + } + } + const currentValue = block.getFieldValue("VALUE"); + switches = uniques(switches).map(i => ({ + isNoop: i === currentValue, + fieldValue: i, + msg: i + })); + } + if (block.type === "procedures_call") { + const proccode = block.getProcCode(); + if (procedureSwitches[proccode]) { + switches = procedureSwitches[proccode]; + } + } + if (!addon.settings.get("noop")) { + switches = switches.filter(i => !i.isNoop); + } + switches.forEach((opcodeData, i) => { + const makeSpaceItemIndex = items.findIndex(obj => obj._isDevtoolsFirstItem); + const insertBeforeIndex = makeSpaceItemIndex !== -1 ? + // If "make space" button exists, add own items before it + makeSpaceItemIndex : + // If there's no such button, insert at end + items.length; + const text = opcodeData.msg ? opcodeData.msg : opcodeData.opcode ? msg(opcodeData.opcode) : msg(block.type); + items.splice(insertBeforeIndex, 0, { + enabled: true, + text, + callback: menuCallbackFactory(block, opcodeData), + separator: i === 0 + }); + }); + if (block.type === "data_variable" || block.type === "data_listcontents") { + // Add top border to first variable (if it exists) + const delBlockIndex = items.findIndex(item => item.text === ScratchBlocks.Msg.DELETE_BLOCK); + // firstVariableItem might be undefined, a variable to switch to, + // or an item added by editor-devtools (or any addon before this one) + const firstVariableItem = items[delBlockIndex + 1]; + if (firstVariableItem) firstVariableItem.separator = true; + } + } + return items; + }, { + blocks: true + }); + + // https://github.com/LLK/scratch-blocks/blob/abbfe93136fef57fdfb9a077198b0bc64726f012/blocks_vertical/procedures.js#L207-L215 + // Returns a list like ["%s", "%d"] + const parseArguments = code => code.split(/(?=[^\\]%[nbs])/g).map(i => i.trim()).filter(i => i.charAt(0) === "%").map(i => i.substring(0, 2)); + const getCustomBlocks = () => { + const customBlocks = {}; + const target = vm.editingTarget; + Object.values(target.blocks._blocks).filter(block => block.opcode === "procedures_prototype").forEach(block => { + const procCode = block.mutation.proccode; + const argumentNames = JSON.parse(block.mutation.argumentnames); + // argumentdefaults is unreliable, so we have to parse the procedure code to determine argument types + const parsedArguments = parseArguments(procCode); + const stringArgs = []; + const boolArgs = []; + for (let i = 0; i < argumentNames.length; i++) { + if (parsedArguments[i] === "%b") { + boolArgs.push(argumentNames[i]); + } else { + stringArgs.push(argumentNames[i]); + } + } + customBlocks[procCode] = { + stringArgs, + boolArgs + }; + }); + return customBlocks; + }; +}); + +/***/ }), + +/***/ "./src/addons/addons/color-picker/_runtime_entry.js": +/*!**********************************************************!*\ + !*** ./src/addons/addons/color-picker/_runtime_entry.js ***! + \**********************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/color-picker/userscript.js"); +/* harmony import */ var _css_loader_style_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! css-loader!./style.css */ "./node_modules/css-loader/index.js!./src/addons/addons/color-picker/style.css"); +/* harmony import */ var _css_loader_style_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_css_loader_style_css__WEBPACK_IMPORTED_MODULE_1__); +/* generated by pull.js */ + + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"], + "style.css": _css_loader_style_css__WEBPACK_IMPORTED_MODULE_1___default.a +}; + +/***/ }), + +/***/ "./src/addons/addons/color-picker/code-editor.js": +/*!*******************************************************!*\ + !*** ./src/addons/addons/color-picker/code-editor.js ***! + \*******************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _libraries_common_cs_normalize_color_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../libraries/common/cs/normalize-color.js */ "./src/addons/libraries/common/cs/normalize-color.js"); +/* harmony import */ var _libraries_common_cs_rate_limiter_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../libraries/common/cs/rate-limiter.js */ "./src/addons/libraries/common/cs/rate-limiter.js"); +/* harmony import */ var _libraries_thirdparty_cs_tinycolor_min_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../libraries/thirdparty/cs/tinycolor-min.js */ "./src/addons/libraries/thirdparty/cs/tinycolor-min.js"); + + + +/* harmony default export */ __webpack_exports__["default"] = (async _ref => { + let { + addon, + console, + msg + } = _ref; + // 250-ms rate limit + const rateLimiter = new _libraries_common_cs_rate_limiter_js__WEBPACK_IMPORTED_MODULE_1__["default"](250); + const getColor = element => { + const { + children + } = element.parentElement; + // h: 0 - 360 + const h = children[1].getAttribute("aria-valuenow"); + // s: 0 - 1 + const s = children[3].getAttribute("aria-valuenow"); + // v: 0 - 255, divide by 255 + const vMultipliedBy255 = children[5].getAttribute("aria-valuenow"); + const v = Number(vMultipliedBy255) / 255; + return Object(_libraries_thirdparty_cs_tinycolor_min_js__WEBPACK_IMPORTED_MODULE_2__["default"])("hsv(".concat(h, ", ").concat(s, ", ").concat(v || 0, ")")).toHexString(); + }; + const setColor = (hex, element) => { + hex = Object(_libraries_common_cs_normalize_color_js__WEBPACK_IMPORTED_MODULE_0__["normalizeHex"])(hex); + if (!addon.tab.redux.state || !addon.tab.redux.state.scratchGui) return; + // The only way to reliably set color is to invoke eye dropper via click() + // then faking that the eye dropper reported the value. + const onEyeDropperClosed = _ref2 => { + let { + detail + } = _ref2; + if (detail.action.type !== "scratch-gui/color-picker/DEACTIVATE_COLOR_PICKER") return; + addon.tab.redux.removeEventListener("statechanged", onEyeDropperClosed); + setTimeout(() => { + document.body.classList.remove("sa-hide-eye-dropper-background"); + }, 50); + }; + const onEyeDropperOpened = _ref3 => { + let { + detail + } = _ref3; + if (detail.action.type !== "scratch-gui/color-picker/ACTIVATE_COLOR_PICKER") return; + addon.tab.redux.removeEventListener("statechanged", onEyeDropperOpened); + addon.tab.redux.addEventListener("statechanged", onEyeDropperClosed); + setTimeout(() => { + addon.tab.redux.dispatch({ + type: "scratch-gui/color-picker/DEACTIVATE_COLOR_PICKER", + color: hex + }); + }, 50); + }; + addon.tab.redux.addEventListener("statechanged", onEyeDropperOpened); + document.body.classList.add("sa-hide-eye-dropper-background"); + element.click(); + }; + const addColorPicker = () => { + const element = document.querySelector("button.scratchEyedropper"); + rateLimiter.abort(false); + addon.tab.redux.initialize(); + const defaultColor = getColor(element); + const saColorPicker = Object.assign(document.createElement("div"), { + className: "sa-color-picker sa-color-picker-code" + }); + addon.tab.displayNoneWhileDisabled(saColorPicker, { + display: "flex" + }); + const saColorPickerColor = Object.assign(document.createElement("input"), { + className: "sa-color-picker-color sa-color-picker-code-color", + type: "color", + value: defaultColor || "#000000" + }); + const saColorPickerText = Object.assign(document.createElement("input"), { + className: addon.tab.scratchClass("input_input-form", { + others: "sa-color-picker-text sa-color-picker-code-text" + }), + type: "text", + pattern: "^#?([0-9a-fA-F]{3}){1,2}$", + placeholder: msg("hex"), + value: defaultColor || "" + }); + saColorPickerColor.addEventListener("input", () => rateLimiter.limit(() => setColor(saColorPickerText.value = saColorPickerColor.value, element))); + saColorPickerText.addEventListener("change", () => { + const { + value + } = saColorPickerText; + if (!Object(_libraries_common_cs_normalize_color_js__WEBPACK_IMPORTED_MODULE_0__["getHexRegex"])().test(value)) return; + setColor(saColorPickerColor.value = Object(_libraries_common_cs_normalize_color_js__WEBPACK_IMPORTED_MODULE_0__["normalizeHex"])(value), element); + }); + saColorPicker.appendChild(saColorPickerColor); + saColorPicker.appendChild(saColorPickerText); + element.parentElement.insertBefore(saColorPicker, element); + }; + const ScratchBlocks = await addon.tab.traps.getBlockly(); + const originalShowEditor = ScratchBlocks.FieldColourSlider.prototype.showEditor_; + ScratchBlocks.FieldColourSlider.prototype.showEditor_ = function () { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + const r = originalShowEditor.call(this, ...args); + addColorPicker(); + return r; + }; +}); + +/***/ }), + +/***/ "./src/addons/addons/color-picker/userscript.js": +/*!******************************************************!*\ + !*** ./src/addons/addons/color-picker/userscript.js ***! + \******************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _code_editor_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./code-editor.js */ "./src/addons/addons/color-picker/code-editor.js"); + +/* harmony default export */ __webpack_exports__["default"] = (async api => { + Object(_code_editor_js__WEBPACK_IMPORTED_MODULE_0__["default"])(api); +}); + +/***/ }), + +/***/ "./src/addons/addons/editor-animations/_runtime_entry.js": +/*!***************************************************************!*\ + !*** ./src/addons/addons/editor-animations/_runtime_entry.js ***! + \***************************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/editor-animations/userscript.js"); +/* generated by pull.js */ + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"] +}; + +/***/ }), + +/***/ "./src/addons/addons/editor-animations/userscript.js": +/*!***********************************************************!*\ + !*** ./src/addons/addons/editor-animations/userscript.js ***! + \***********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +// Editor Animations (remake of Reactive Animation by ) +// By: SharkPool +// By: reflow + +/* TODO +- patch custom modal api when added +- patch adding modals from addons (they dont use react) +*/ + +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon + } = _ref; + const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)"); + const addonKey = "addonAnimations-"; + const animationTypes = { + "default": "cubic-bezier(0.63, 0.32, 0.08, 0.95)", + "easeIn": "cubic-bezier(0.42, 0, 1.0, 1.0)", + "easeOut": "cubic-bezier(0, 0, 0.58, 1.0)", + "easeInOut": "cubic-bezier(0.42, 0, 0.58, 1.0)", + "smoothStep": "cubic-bezier(0.25, 0.1, 0.25, 1.0)", + "fastInSlowOut": "cubic-bezier(0.4, 0.0, 0.2, 1.0)", + "sineIn": "cubic-bezier(0.47, 0, 0.745, 0.715)", + "sineOut": "cubic-bezier(0.39, 0.575, 0.565, 1)", + "sineInOut": "cubic-bezier(0.445, 0.05, 0.55, 0.95)", + "quadIn": "cubic-bezier(0.55, 0.085, 0.68, 0.53)", + "quadOut": "cubic-bezier(0.25, 0.46, 0.45, 0.94)", + "quadInOut": "cubic-bezier(0.455, 0.03, 0.515, 0.955)", + "cubicIn": "cubic-bezier(0.55, 0.055, 0.675, 0.19)", + "cubicOut": "cubic-bezier(0.215, 0.61, 0.355, 1)", + "cubicInOut": "cubic-bezier(0.645, 0.045, 0.355, 1)", + "quartIn": "cubic-bezier(0.895, 0.03, 0.685, 0.22)", + "quartOut": "cubic-bezier(0.165, 0.84, 0.44, 1)", + "quartInOut": "cubic-bezier(0.77, 0, 0.175, 1)", + "quintIn": "cubic-bezier(0.755, 0.05, 0.855, 0.06)", + "quintOut": "cubic-bezier(0.23, 1, 0.32, 1)", + "quintInOut": "cubic-bezier(0.86, 0, 0.07, 1)", + "backIn": "cubic-bezier(0.6, -0.28, 0.74, 0.05)", + "backOut": "cubic-bezier(0.18, 0.89, 0.32, 1.28)", + "backInOut": "cubic-bezier(0.68, -0.55, 0.27, 1.55)", + "elastic": "linear(0 0%, 0.22 2.1%, 0.86 6.5%, 1.11 8.6%, 1.3 10.7%, 1.35 11.8%, 1.37 12.9%, 1.37 13.7%, 1.36 14.5%, 1.32 16.2%, 1.03 21.8%, 0.94 24%, 0.89 25.9%, 0.88 26.85%, 0.87 27.8%, 0.87 29.25%, 0.88 30.7%, 0.91 32.4%, 0.98 36.4%, 1.01 38.3%, 1.04 40.5%, 1.05 42.7%, 1.05 44.1%, 1.04 45.7%, 1 53.3%, 0.99 55.4%, 0.98 57.5%, 0.99 60.7%, 1 68.1%, 1.01 72.2%, 1 86.7%, 1 100%)", + "bounce": "linear(0 0%, 0 2.27%, 0.02 4.53%, 0.04 6.8%, 0.06 9.07%, 0.1 11.33%, 0.14 13.6%, 0.25 18.15%, 0.39 22.7%, 0.56 27.25%, 0.77 31.8%, 1 36.35%, 0.89 40.9%, 0.85 43.18%, 0.81 45.45%, 0.79 47.72%, 0.77 50%, 0.75 52.27%, 0.75 54.55%, 0.75 56.82%, 0.77 59.1%, 0.79 61.38%, 0.81 63.65%, 0.85 65.93%, 0.89 68.2%, 1 72.7%, 0.97 74.98%, 0.95 77.25%, 0.94 79.53%, 0.94 81.8%, 0.94 84.08%, 0.95 86.35%, 0.97 88.63%, 1 90.9%, 0.99 93.18%, 0.98 95.45%, 0.99 97.73%, 1 100%)", + "emphasis": "linear(0 0%, 0 1.8%, 0.01 3.6%, 0.03 6.35%, 0.07 9.1%, 0.13 11.4%, 0.19 13.4%, 0.27 15%, 0.34 16.1%, 0.54 18.35%, 0.66 20.6%, 0.72 22.4%, 0.77 24.6%, 0.81 27.3%, 0.85 30.4%, 0.88 35.1%, 0.92 40.6%, 0.94 47.2%, 0.96 55%, 0.98 64%, 0.99 74.4%, 1 86.4%, 1 100%)" + }; + const hasNoVariation = ["default", "fastInSlowOut", "smoothStep", "elastic", "bounce", "emphasis"]; + let needsInit = true, + animateModals = true, + animateLibraries = true, + animateButtons = true, + animationSpeed = 1, + animationType = "default", + animationDir = "InOut"; + let patchedBody = false, + sbPatched = false, + sbEverPatched = false, + listenerAttached = false; + const genStyles = () => "\n/* Top Bar Items */\n.".concat(addonKey, "top-bar-scaler {\n transition: transform ").concat(getAnim(.1), ";\n transform-origin: center center;\n transform-box: fill-box;\n}\n.").concat(addonKey, "top-bar-scaler:hover:not([addon-scale-stop=\"true\"]) {\n transform: scale(1.05);\n}\n.").concat(addonKey, "top-bar-scaler:active:not([addon-scale-stop=\"true\"]) {\n transform: scale(.95);\n}\n\n/*\n Assets, Blockly Button Texts\n Costume/Extension/Sprite/Sound Library UI\n*/\n.").concat(addonKey, "static-scaler {\n transition: transform ").concat(getAnim(.1), ";\n transform-origin: center center;\n transform-box: fill-box;\n}\n.").concat(addonKey, "static-scaler:hover:not([addon-scale-stop=\"true\"]) {\n transform: scale(1.05);\n}\n.").concat(addonKey, "static-scaler:active:not([addon-scale-stop=\"true\"]) {\n transform: scale(.95);\n}\n\n/*\n Sound & Costume Editor Buttons,\n Project Controls, Blockly Zoom\n*/\n.").concat(addonKey, "static-scaler-big {\n transition: transform ").concat(getAnim(.2), " !important;\n transform-origin: center center;\n transform-box: fill-box;\n}\n.").concat(addonKey, "static-scaler-big:hover {\n transform: scale(1.1);\n}\n.").concat(addonKey, "static-scaler-big:active {\n transform: scale(.9);\n}\n\n/* Custom Extension Button (Library) */\n.").concat(addonKey, "custom-ext-hover {\n transition: transform ").concat(getAnim(.2), ", border ").concat(getAnim(.5), ";\n justify-content: center;\n border: none;\n}\n.").concat(addonKey, "custom-ext-hover:hover {\n border: solid 3px #00000050;\n}\n.").concat(addonKey, "custom-ext-hover:active {\n transform: scale(.95);\n border: none;\n}\n\n/* Library Items */\n.").concat(addonKey, "library-item-scaler div[class^=\"library-item_library-item\"] {\n transition: transform ").concat(getAnim(.1), ";\n transform-origin: center center;\n transform-box: fill-box;\n}\n.").concat(addonKey, "library-item-scaler div[class^=\"library-item_library-item\"]:hover {\n transform: scale(1.05);\n}\n.").concat(addonKey, "library-item-scaler div[class^=\"library-item_library-item\"]:active {\n transform: scale(.95);\n}\n\n/* Categories */\n.").concat(addonKey, "category-scaler div div[class=\"scratchCategoryMenuRow\"] {\n transition: transform ").concat(getAnim(.1), ";\n transform-origin: center center;\n transform-box: fill-box;\n}\n.").concat(addonKey, "category-scaler div div[class=\"scratchCategoryMenuRow\"]:hover {\n transform: scale(1.05);\n}\n.").concat(addonKey, "category-scaler div div[class=\"scratchCategoryMenuRow\"]:active {\n transform: scale(.95);\n}\n"); + const styleElement = document.createElement("style"); + styleElement.classList.add("addon-editorAnimations"); + styleElement.textContent = genStyles(); + document.head.appendChild(styleElement); + let animationEnabled = !mediaQuery.matches; + mediaQuery.addEventListener("change", e => { + animationEnabled = !e.matches; + }); + function requestAddonState() { + animateModals = addon.settings.get("animateModals"); + animateLibraries = addon.settings.get("animateLibraries"); + animateButtons = addon.settings.get("animateButtons"); + animationType = addon.settings.get("animationType"); + animationDir = addon.settings.get("animationDir"); + const oldSpeed = animationSpeed; + animationSpeed = 1 / (Number(addon.settings.get("animateSpeed")) / 100); + if (oldSpeed !== animationSpeed) styleElement.textContent = genStyles(); + } + function getEasing() { + if (hasNoVariation.includes(animationType)) { + return animationTypes[animationType]; + } else { + return animationTypes[animationType + animationDir]; + } + } + function getAnim(time) { + time *= animationSpeed; + return "".concat(time, "s ").concat(getEasing()); + } + ; + function observeMenuScalers(element, observerSub, observerAtt) { + if (!animateModals) return; + if (element.hasAttribute("addon-scale-listeners-bound")) return; + const onMouseOver = () => element.setAttribute("addon-scale-stop", true); + const onMouseOut = () => element.setAttribute("addon-scale-stop", false); + element.addEventListener("mouseover", onMouseOver); + element.addEventListener("mouseout", onMouseOut); + element.setAttribute("addon-scale-listeners-bound", "true"); + element.setAttribute("addon-scale-stop", true); + const observer = new MutationObserver(() => { + var _element$querySelecto, _element$querySelecto2; + if (!element.classList.contains("menu-bar_active") && ((_element$querySelecto = element.querySelector("nav")) === null || _element$querySelecto === void 0 ? void 0 : (_element$querySelecto2 = _element$querySelecto.style) === null || _element$querySelecto2 === void 0 ? void 0 : _element$querySelecto2.opacity) !== "1") { + element.removeEventListener("mouseover", onMouseOver); + element.removeEventListener("mouseout", onMouseOut); + element.removeAttribute("addon-scale-listeners-bound"); + element.setAttribute("addon-scale-stop", false); + observer.disconnect(); + } + }); + observer.observe(element, { + subtree: observerSub, + attributes: true, + attributeFilter: observerAtt + }); + } + function handleOpenAnimation(elementName) { + var _document$querySelect; + const type = elementName.endsWith("Library") ? "library" : elementName.endsWith("Menu") ? "menu" : "modal"; + if (!animateLibraries && type === "library") return; + if (!animateModals && type !== "library") return; + let element; + let animTime = 200; + if (type === "menu") { + if (elementName === "ctxMenu") element = document.querySelector("div[class*=\"blocklyContextMenu\"]");else if (elementName === "guiCtxMenu") element = document.querySelector("nav[class*=\"context-menu_context-menu\"][class*=\"react-contextmenu--visible\"]");else { + element = Array.from(document.querySelectorAll("div[class*=\"menu-bar_menu-bar-menu_\"] ul[class*=\"menu_menu_\"]")); + if (!element.length) return; + element = element.find(e => !e.hasAttribute("style")); + } + if (!element) return; + if (type === "menu") { + const menuItem = element.parentNode.parentNode; + setTimeout(() => observeMenuScalers(menuItem, false, ["class"]), 10); + } + const ogHeight = element.getBoundingClientRect().height; + element.style.overflow = "hidden"; + element.style.transition = "transform ".concat(getAnim(.2)); + element.style.transformOrigin = "left top"; + if (elementName === "guiCtxMenu") animTime = 500;else element.style.transform = "translateY(-2px) scale(.999)"; + const animation = element.animate([{ + height: "0px", + opacity: 0 + }, { + height: "".concat(ogHeight, "px"), + opacity: 1 + }], { + duration: animTime * animationSpeed, + easing: getEasing() + }); + animation.onfinish = () => { + element.style.overflow = "hidden"; + }; + return; + } + element = (_document$querySelect = document.querySelector("div[class=\"ReactModalPortal\"] div[class*=\"ReactModal__Overlay\"]")) === null || _document$querySelect === void 0 ? void 0 : _document$querySelect.firstChild; + if (!element) return; + if (type === "library") { + animTime = 500; + if (elementName === "extensionLibrary" || elementName === "costumeLibrary") element.style.transformOrigin = "left bottom";else element.style.transformOrigin = "center bottom"; + } + element.animate([{ + transform: "scale(0)", + opacity: 0 + }, { + transform: "scale(1)", + opacity: 1 + }], { + duration: animTime * animationSpeed, + easing: getEasing() + }); + } + function attachCloseHijack(elementName) { + const type = elementName.endsWith("Library") ? "library" : elementName.endsWith("Menu") ? "menu" : "modal"; + if (type === "menu" || patchedBody) return; + if (!animateLibraries && type === "library") return; + if (!animateModals && type !== "library") return; + + // Monkey Patch + const ogRemoveChild = document.body.constructor.prototype.removeChild; + document.body.constructor.prototype.removeChild = function (child) { + const element = document.querySelector("div[class=\"ReactModalPortal\"]"); + if (!element) return ogRemoveChild.call(this, child); + let animTime = 200; + patchedBody = true; + if (child === element) { + const child = element.firstChild; + if (child) { + const animClone = child.cloneNode(true); + animClone.style.position = "fixed"; + animClone.style.top = child.getBoundingClientRect().top + "px"; + animClone.style.left = child.getBoundingClientRect().left + "px"; + animClone.style.zIndex = "99999"; + animClone.style.pointerEvents = "none"; + if (type === "library") { + animTime = 500; + if (elementName === "extensionLibrary" || elementName === "costumeLibrary") animClone.style.transformOrigin = "left bottom";else animClone.style.transformOrigin = "center bottom"; + } + document.body.appendChild(animClone); + animClone.animate([{ + opacity: 1 + }, { + opacity: 0 + }], { + duration: animTime * animationSpeed, + easing: getEasing() + }); + const animation = animClone.firstChild.animate([{ + transform: "scale(1)", + opacity: 1 + }, { + transform: "scale(0)", + opacity: 0 + }], { + duration: animTime * animationSpeed, + easing: getEasing() + }); + animation.onfinish = () => { + animClone.remove(); + ogRemoveChild.call(element.parentNode, element); + }; + document.body.constructor.prototype.removeChild = ogRemoveChild; + patchedBody = false; + return child; + } + } + return ogRemoveChild.call(this, child); + }; + } + function compileClasses(optLibrary) { + if (!animateButtons) return; + const classMapper = new Map(); + if (optLibrary) { + const collapser = document.querySelector("button[class^=\"library_library-filter-collapse\"]"); + const filterDiv = document.querySelector("div[class^=\"library_library-filter-bar\"]"); + collapser.style.transform = "rotateY(180deg)"; + collapser.addEventListener("click", e => { + e.preventDefault(); + const isClosed = collapser.hasAttribute("closed"); + if (isClosed) { + collapser.style.transform = "rotateY(180deg)"; + collapser.removeAttribute("closed"); + filterDiv.style.display = ""; + filterDiv.animate([{ + width: "0px", + opacity: 0 + }, { + width: "342px", + opacity: 1 + }], { + duration: 300, + easing: getEasing() + }); + } else { + collapser.style.transform = "rotateY(0deg)"; + const animation = filterDiv.animate([{ + width: "342px", + opacity: 1 + }, { + width: "0px", + opacity: 0 + }], { + duration: 300, + easing: getEasing() + }); + animation.onfinish = () => { + collapser.setAttribute("closed", "true"); + filterDiv.style.display = "none"; + }; + } + e.stopPropagation(); + }); + if (optLibrary === "extensionLibrary") { + classMapper.set("custom-ext-hover", [document.querySelector("span[class*=\"button_outlined-button\"][class*=\"tag-button_tag-button\"]")]); + } + classMapper.set("library-item-scaler", [document.querySelector("div[class*=\"library_library-scroll-grid\"]")]); + classMapper.set("static-scaler", [document.querySelector("span[class*=\"modal_back-button_\"]"), collapser]); + } else { + classMapper.set("top-bar-scaler", document.querySelectorAll("div[class*=\"menu-bar_main-menu\"] div[class*=\"menu-bar_menu-bar-item\"][class*=\"hoverable\"]")); + classMapper.set("category-scaler", [document.querySelector("div[class=\"blocklyToolboxDiv\"]")]); + classMapper.set("static-scaler", [/* Blockly Button Texts */ + ...document.querySelectorAll("g[class=\"blocklyFlyoutButton\"] text[class=\"blocklyText\"]"), /* Costume & Sound Assets */ + ...document.querySelectorAll("div[class*=\"selector_list-item\"][class*=\"sprite-selector-item\"]"), /* Sprite Selector */ + ...document.querySelectorAll("div[class*=\"sprite-selector_sprite\"][class*=\"sprite-selector-item\"]"), /* Backpack Selector */ + ...document.querySelectorAll("div[class*=\"backpack_backpack-item\"][class*=\"sprite-selector-item\"]")]); + classMapper.set("static-scaler-big", [/* Sound & Costume Editor Buttons */ + ...document.querySelectorAll("div[class*=\"sound-editor_effect-button\"]"), ...document.querySelectorAll("div[class*=\"sound-editor_tool-button\"]"), ...document.querySelectorAll("button[class*=\"sound-editor_round-button\"]"), ...document.querySelectorAll("span[class*=\"tool-select-base_mod-tool-select\"]"), /* Project Controls */ + ...document.querySelectorAll("div[class^=\"controls_controls-container\"] img"), /* Blockly Zoom */ + ...document.querySelectorAll("g[class=\"blocklyZoom\"] image")]); + } + classMapper.forEach((elements, classN) => { + for (const element of elements) { + if (!element) continue; + element.classList.add(addonKey + classN); + } + }); + needsInit = false; + } + function tryPatchScratchBlocks() { + if (typeof ScratchBlocks !== "object") return; + sbPatched = true; + + // some modals are from ScratchBlocks, patch them! + queueMicrotask(() => { + const ogSBPrompt = ScratchBlocks.prompt; + ScratchBlocks.prompt = function () { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + ogSBPrompt.call(this, ...args); + handleOpenAnimation("modal"); + attachCloseHijack("modal"); + }; + if (sbEverPatched) return; + sbEverPatched = true; + const ogSBProcCreate = ScratchBlocks.Procedures.createProcedureDefCallback_; + ScratchBlocks.Procedures.createProcedureDefCallback_ = function () { + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + ogSBProcCreate.call(this, ...args); + handleOpenAnimation("modal"); + attachCloseHijack("modal"); + }; + const ogSBProcEdit = ScratchBlocks.Procedures.editProcedureCallback_; + ScratchBlocks.Procedures.editProcedureCallback_ = function () { + for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } + ogSBProcEdit.call(this, ...args); + handleOpenAnimation("modal"); + attachCloseHijack("modal"); + }; + const ogContextMenuShow = ScratchBlocks.ContextMenu.show; + ScratchBlocks.ContextMenu.show = function () { + for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + ogContextMenuShow.call(this, ...args); + handleOpenAnimation("ctxMenu"); + }; + + /* this isnt a modal, but we still want to patch it for animations */ + const ogInitButton = ScratchBlocks.FlyoutButton.prototype.show; + ScratchBlocks.FlyoutButton.prototype.show = function () { + for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + args[_key5] = arguments[_key5]; + } + ogInitButton.call(this, ...args); + queueMicrotask(() => compileClasses()); + }; + }); + } + function attachListeners() { + const spriteRow = document.querySelector("div[class^=\"sprite-selector_items-wrapper\"]"); + if (!spriteRow) return; + document.addEventListener("contextmenu", event => { + let element = event.target.closest("div[class*=\"sprite-selector_sprite-wrapper\"]"); + if (element) element = element.firstChild;else element = event.target.closest("div[class^=\"react-contextmenu-wrapper\"][class*=\"sprite-selector-item_sprite-selector\"]"); + if (element) { + setTimeout(() => { + element.querySelector("nav").style.opacity = 1; + handleOpenAnimation("guiCtxMenu"); + observeMenuScalers(element, true, ["class", "style"]); + }, 10); + } + }); + listenerAttached = true; + } + function startListenerWorker() { + const checkInEditor = () => !ReduxStore.getState().scratchGui.mode.isPlayerOnly; + window.vm.on("workspaceUpdate", () => { + queueMicrotask(() => compileClasses()); + }); + let lastModalStateID, inEditor; + ReduxStore.subscribe(() => { + const reduxState = ReduxStore.getState().scratchGui; + let entries = Object.entries(reduxState.modals); + entries.push(...Object.entries(reduxState.menus)); + const genID = [...entries, ["tab", reduxState.editorTab.activeTabIndex]]; + const modalStateID = genID.map(entry => entry[1]).join("."); + const currentlyInEditor = checkInEditor(); + if (inEditor !== currentlyInEditor) { + inEditor = currentlyInEditor; + if (inEditor) { + sbPatched = false; + listenerAttached = false; + } + } + if (!sbPatched) tryPatchScratchBlocks(); + if (!listenerAttached) attachListeners(); + if (!needsInit && lastModalStateID === modalStateID) return; + lastModalStateID = modalStateID; + queueMicrotask(() => { + compileClasses(); + for (const entry of entries) { + if (entry[1] === true) { + const name = entry[0]; + handleOpenAnimation(name); + attachCloseHijack(name); + compileClasses(name.endsWith("Library") ? name : undefined); + break; + } + } + }); + }); + } + if (typeof scaffolding === "undefined") startListenerWorker(); + addon.settings.addEventListener("change", requestAddonState); + addon.self.addEventListener("disabled", () => { + animateModals = false; + animateLibraries = false; + animateButtons = false; + }); + addon.self.addEventListener("reenabled", () => { + animateModals = true; + animateLibraries = true; + animateButtons = true; + }); +}); + +/***/ }), + +/***/ "./src/addons/addons/editor-block-chomping/_runtime_entry.js": +/*!*******************************************************************!*\ + !*** ./src/addons/addons/editor-block-chomping/_runtime_entry.js ***! + \*******************************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/editor-block-chomping/userscript.js"); +/* generated by pull.js */ + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"] +}; + +/***/ }), + +/***/ "./src/addons/addons/editor-block-chomping/userscript.js": +/*!***************************************************************!*\ + !*** ./src/addons/addons/editor-block-chomping/userscript.js ***! + \***************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon + } = _ref; + const ScratchBlocks = await addon.tab.traps.getBlockly(); + + // Rerender the dragged block when updating the insertion marker + const ogConnectMarker = ScratchBlocks.InsertionMarkerManager.prototype.connectMarker_; + ScratchBlocks.InsertionMarkerManager.prototype.connectMarker_ = function () { + ogConnectMarker.call(this); + if (!addon.self.disabled && this.firstMarker_) { + var _this$workspace_, _this$workspace_$curr, _this$workspace_$curr2; + const block = this === null || this === void 0 ? void 0 : (_this$workspace_ = this.workspace_) === null || _this$workspace_ === void 0 ? void 0 : (_this$workspace_$curr = _this$workspace_.currentGesture_) === null || _this$workspace_$curr === void 0 ? void 0 : (_this$workspace_$curr2 = _this$workspace_$curr.blockDragger_) === null || _this$workspace_$curr2 === void 0 ? void 0 : _this$workspace_$curr2.draggingBlock_; + block.noMoveConnection = true; + if (block) block.render(false); + } + }; + const ogDisconnectMarker = ScratchBlocks.InsertionMarkerManager.prototype.disconnectMarker_; + ScratchBlocks.InsertionMarkerManager.prototype.disconnectMarker_ = function () { + ogDisconnectMarker.call(this); + if (!addon.self.disabled && this.firstMarker_) { + var _this$workspace_2, _this$workspace_2$cur, _this$workspace_2$cur2; + const block = this === null || this === void 0 ? void 0 : (_this$workspace_2 = this.workspace_) === null || _this$workspace_2 === void 0 ? void 0 : (_this$workspace_2$cur = _this$workspace_2.currentGesture_) === null || _this$workspace_2$cur === void 0 ? void 0 : (_this$workspace_2$cur2 = _this$workspace_2$cur.blockDragger_) === null || _this$workspace_2$cur2 === void 0 ? void 0 : _this$workspace_2$cur2.draggingBlock_; + block.noMoveConnection = true; + if (block) block.render(false); + } + }; + const ogDraw = ScratchBlocks.BlockSvg.prototype.renderDraw_; + const ogMoveConnections = ScratchBlocks.BlockSvg.prototype.renderMoveConnections_; + ScratchBlocks.BlockSvg.prototype.renderDraw_ = function (iconWidth, inputRows) { + var _this$workspace, _this$workspace$curre, _this$workspace$curre2; + if (addon.self.disabled) return ogDraw.call(this, iconWidth, inputRows); + + // If the block contains a statement (C) input and has an insertion marker, + // use that to calculate the height of the statement inputs + let computeBlock = this; + if (this !== null && this !== void 0 && (_this$workspace = this.workspace) !== null && _this$workspace !== void 0 && (_this$workspace$curre = _this$workspace.currentGesture_) !== null && _this$workspace$curre !== void 0 && (_this$workspace$curre2 = _this$workspace$curre.blockDragger_) !== null && _this$workspace$curre2 !== void 0 && _this$workspace$curre2.draggedConnectionManager_) { + const dragger = this.workspace.currentGesture_.blockDragger_; + const manager = dragger.draggedConnectionManager_; + if (manager.markerConnection_ && manager.firstMarker_ && dragger.draggingBlock_ == this && dragger.draggingBlock_.type == manager.firstMarker_.type) { + if (inputRows.some(row => row.some(input => input.type === ScratchBlocks.NEXT_STATEMENT))) { + computeBlock = manager.firstMarker_; + } + } + } + + // Change the height of substacks + // (If we set inputRows to computeBlock.renderCompute_, + // the references to the inputs would be wrong + // so they just won't update properly) + if (computeBlock !== this) { + const _inputRows = computeBlock.renderCompute_(iconWidth); + for (let i = 0; i < inputRows.length; i++) { + const row = inputRows[i]; + let update = false; + for (const input of row) { + if (input.type === ScratchBlocks.NEXT_STATEMENT) update = true; + } + if (update) row.height = Math.max(row.height, _inputRows[i].height); + } + } + ogDraw.call(this, iconWidth, inputRows); + + // Moving the connections of a block while it's being dragged breaks it, + // so don't + if (computeBlock === this && !this.noMoveConnection) ogMoveConnections.call(this); + this.noMoveConnection = false; + }; + ScratchBlocks.BlockSvg.prototype.renderMoveConnections_ = function () { + if (addon.self.disabled) return ogMoveConnections.call(this); + // Do nothing (this function is instead called by renderDraw_) + }; +}); + +/***/ }), + +/***/ "./src/addons/addons/editor-comment-previews/_runtime_entry.js": +/*!*********************************************************************!*\ + !*** ./src/addons/addons/editor-comment-previews/_runtime_entry.js ***! + \*********************************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/editor-comment-previews/userscript.js"); +/* harmony import */ var _css_loader_userstyle_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! css-loader!./userstyle.css */ "./node_modules/css-loader/index.js!./src/addons/addons/editor-comment-previews/userstyle.css"); +/* harmony import */ var _css_loader_userstyle_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_css_loader_userstyle_css__WEBPACK_IMPORTED_MODULE_1__); +/* generated by pull.js */ + + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"], + "userstyle.css": _css_loader_userstyle_css__WEBPACK_IMPORTED_MODULE_1___default.a +}; + +/***/ }), + +/***/ "./src/addons/addons/editor-comment-previews/userscript.js": +/*!*****************************************************************!*\ + !*** ./src/addons/addons/editor-comment-previews/userscript.js ***! + \*****************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon, + console + } = _ref; + const vm = addon.tab.traps.vm; + const updateStyles = () => { + previewInner.classList.toggle("sa-comment-preview-delay", addon.settings.get("delay") !== "none"); + previewInner.classList.toggle("sa-comment-preview-reduce-transparency", addon.settings.get("reduce-transparency")); + previewInner.classList.toggle("sa-comment-preview-fade", !addon.settings.get("reduce-animation")); + }; + const afterDelay = cb => { + if (!previewInner.classList.contains("sa-comment-preview-hidden")) { + // If not hidden, updating immediately is preferred + cb(); + return; + } + const delay = addon.settings.get("delay"); + if (delay === "long") return setTimeout(cb, 500); + if (delay === "short") return setTimeout(cb, 300); + cb(); + }; + let hoveredElement = null; + let showTimeout = null; + let mouseX = 0; + let mouseY = 0; + let doNotShowUntilMoveMouse = false; + const previewOuter = document.createElement("div"); + previewOuter.classList.add("sa-comment-preview-outer"); + const previewInner = document.createElement("div"); + previewInner.classList.add("sa-comment-preview-inner"); + previewInner.classList.add("sa-comment-preview-hidden"); + updateStyles(); + addon.settings.addEventListener("change", updateStyles); + previewOuter.appendChild(previewInner); + document.body.appendChild(previewOuter); + const getBlock = id => vm.editingTarget.blocks.getBlock(id) || vm.runtime.flyoutBlocks.getBlock(id); + const getComment = block => block && block.comment && vm.editingTarget.comments[block.comment]; + const getProcedureDefinitionBlock = procCode => { + const procedurePrototype = Object.values(vm.editingTarget.blocks._blocks).find(i => i.opcode === "procedures_prototype" && i.mutation.proccode === procCode); + if (procedurePrototype) { + // Usually `parent` will exist but sometimes it doesn't + if (procedurePrototype.parent) { + return getBlock(procedurePrototype.parent); + } + const id = procedurePrototype.id; + return Object.values(vm.editingTarget.blocks._blocks).find(i => (i.opcode === "procedures_definition" || i.opcode === "procedures_definition_return") && i.inputs.custom_block && i.inputs.custom_block.block === id); + } + return null; + }; + const setText = text => { + previewInner.innerText = text; + previewInner.classList.remove("sa-comment-preview-hidden"); + updateMousePosition(); + }; + const updateMousePosition = () => { + previewOuter.style.transform = "translate(".concat(mouseX + 8, "px, ").concat(mouseY + 8, "px)"); + }; + const hidePreview = () => { + if (hoveredElement) { + hoveredElement = null; + previewInner.classList.add("sa-comment-preview-hidden"); + } + }; + document.addEventListener("mouseover", e => { + if (addon.self.disabled) { + return; + } + clearTimeout(showTimeout); + if (doNotShowUntilMoveMouse) { + return; + } + const el = e.target.closest(".blocklyBubbleCanvas > g, .blocklyBlockCanvas .blocklyDraggable[data-id]"); + if (el === hoveredElement) { + // Nothing to do. + return; + } + if (!el) { + hidePreview(); + return; + } + let text = null; + if (addon.settings.get("hover-view") && e.target.closest(".blocklyBubbleCanvas > g") && + // Hovering over the thin line that connects comments to blocks should never show a preview + !e.target.closest("line")) { + const collapsedText = el.querySelector("text.scratchCommentText"); + if (!collapsedText) return; + if (collapsedText.getAttribute("display") !== "none") { + const textarea = el.querySelector("textarea"); + text = textarea.value; + } + } else if (e.target.closest(".blocklyBlockCanvas .blocklyDraggable[data-id]")) { + const id = el.dataset.id; + const block = getBlock(id); + const comment = getComment(block); + if (addon.settings.get("hover-view-block") && comment) { + text = comment.text; + } else if (block && block.opcode === "procedures_call" && addon.settings.get("hover-view-procedure")) { + const procCode = block.mutation.proccode; + const procedureDefinitionBlock = getProcedureDefinitionBlock(procCode); + const procedureComment = getComment(procedureDefinitionBlock); + if (procedureComment) { + text = procedureComment.text; + } + } + } + if (text !== null && text.trim() !== "") { + showTimeout = afterDelay(() => { + hoveredElement = el; + setText(text); + }); + } else { + hidePreview(); + } + }); + document.addEventListener("mousemove", e => { + mouseX = e.clientX; + mouseY = e.clientY; + doNotShowUntilMoveMouse = false; + if (addon.settings.get("follow-mouse") && !previewInner.classList.contains("sa-comment-preview-hidden")) { + updateMousePosition(); + } + }); + document.addEventListener("mousedown", () => { + hidePreview(); + doNotShowUntilMoveMouse = true; + }, { + capture: true + }); +}); + +/***/ }), + +/***/ "./src/addons/addons/editor-devtools/DevTools.js": +/*!*******************************************************!*\ + !*** ./src/addons/addons/editor-devtools/DevTools.js ***! + \*******************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return DevTools; }); +/* harmony import */ var _DomHelpers_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./DomHelpers.js */ "./src/addons/addons/editor-devtools/DomHelpers.js"); +/* harmony import */ var _UndoGroup_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./UndoGroup.js */ "./src/addons/addons/editor-devtools/UndoGroup.js"); +// import ShowBroadcast from "./show-broadcast.js"; + + +class DevTools { + constructor(addon, msg, m) { + this.addon = addon; + this.msg = msg; + this.m = m; + /** + * @type {VirtualMachine} + */ + this.domHelpers = new _DomHelpers_js__WEBPACK_IMPORTED_MODULE_0__["default"](addon); + this.codeTab = null; + this.costTab = null; + this.costTabBody = null; + this.selVarID = null; + this.canShare = false; + this.mouseXY = { + x: 0, + y: 0 + }; + } + async init() { + this.addContextMenus(); + while (true) { + const root = await this.addon.tab.waitForElement("ul[class*=gui_tab-list_]", { + markAsSeen: true, + reduxEvents: ["scratch-gui/mode/SET_PLAYER", "fontsLoaded/SET_FONTS_LOADED", "scratch-gui/locales/SELECT_LOCALE"], + reduxCondition: state => !state.scratchGui.mode.isPlayerOnly + }); + this.initInner(root); + } + } + async addContextMenus() { + const blockly = await this.addon.tab.traps.getBlockly(); + const oldCleanUpFunc = blockly.WorkspaceSvg.prototype.cleanUp; + const self = this; + blockly.WorkspaceSvg.prototype.cleanUp = function () { + if (self.addon.settings.get("enableCleanUpPlus")) { + self.doCleanUp(); + } else { + oldCleanUpFunc.call(this); + } + }; + let originalMsg = blockly.Msg.CLEAN_UP; + if (this.addon.settings.get("enableCleanUpPlus")) blockly.Msg.CLEAN_UP = this.m("clean-plus"); + this.addon.settings.addEventListener("change", () => { + if (this.addon.settings.get("enableCleanUpPlus")) blockly.Msg.CLEAN_UP = this.m("clean-plus");else blockly.Msg.CLEAN_UP = originalMsg; + }); + this.addon.tab.createBlockContextMenu((items, block) => { + items.push({ + enabled: blockly.clipboardXml_, + text: this.m("paste"), + separator: true, + _isDevtoolsFirstItem: true, + callback: () => { + let ids = this.getTopBlockIDs(); + document.dispatchEvent(new KeyboardEvent("keydown", { + keyCode: 86, + ctrlKey: true, + griff: true + })); + setTimeout(() => { + this.beginDragOfNewBlocksNotInIDs(ids); + }, 10); + } + }); + return items; + }, { + workspace: true + }); + this.addon.tab.createBlockContextMenu((items, block) => { + items.push({ + enabled: true, + text: this.m("make-space"), + _isDevtoolsFirstItem: true, + callback: () => { + this.doCleanUp(block); + }, + separator: true + }, { + enabled: true, + text: this.m("copy-all"), + callback: () => { + this.eventCopyClick(block); + }, + separator: true + }, { + enabled: true, + text: this.m("copy-block"), + callback: () => { + this.eventCopyClick(block, 1); + } + }, { + enabled: true, + text: this.m("cut-block"), + callback: () => { + this.eventCopyClick(block, 2); + } + }); + // const BROADCAST_BLOCKS = ["event_whenbroadcastreceived", "event_broadcast", "event_broadcastandwait"]; + // if (BROADCAST_BLOCKS.includes(block.type)) { + // // Show Broadcast + // const broadcastId = this.showBroadcastSingleton.getAssociatedBroadcastId(block.id); + // if (broadcastId) { + // ["Senders", "Receivers"].forEach((showKey, i) => { + // items.push({ + // enabled: true, + // text: this.msg(`show-${showKey}`.toLowerCase()), + // callback: () => { + // this.showBroadcastSingleton[`show${showKey}`](broadcastId); + // }, + // separator: i == 0, + // }); + // }); + // } + // } + return items; + }, { + blocks: true + }); + this.addon.tab.createBlockContextMenu((items, block) => { + if (block.getCategory() === "data" || block.getCategory() === "data-lists") { + this.selVarID = block.getVars()[0]; + items.push({ + enabled: true, + text: this.m("swap", { + var: block.getCategory() === "data" ? this.m("variables") : this.m("lists") + }), + callback: async () => { + let wksp = this.getWorkspace(); + let v = wksp.getVariableById(this.selVarID); + // prompt() returns Promise in desktop app + let varName = await window.prompt(this.msg("replace", { + name: v.name + })); + if (varName) { + this.doReplaceVariable(this.selVarID, varName, v.type); + } + }, + separator: true + }); + } + return items; + }, { + blocks: true, + flyout: true + }); + } + getWorkspace() { + return Blockly.getMainWorkspace(); + } + isCostumeEditor() { + return this.costTab.className.indexOf("gui_is-selected") >= 0; + } + + /** + * A nicely ordered version of the top blocks + * @returns {[Blockly.Block]} + */ + getTopBlocks() { + let result = this.getOrderedTopBlockColumns(); + let columns = result.cols; + /** + * @type {[[Blockly.Block]]} + */ + let topBlocks = []; + for (const col of columns) { + topBlocks = topBlocks.concat(col.blocks); + } + return topBlocks; + } + + /** + * A much nicer way of laying out the blocks into columns + */ + doCleanUp(block) { + let workspace = this.getWorkspace(); + let makeSpaceForBlock = block && block.getRootBlock(); + _UndoGroup_js__WEBPACK_IMPORTED_MODULE_1__["default"].startUndoGroup(workspace); + let result = this.getOrderedTopBlockColumns(true); + let columns = result.cols; + let orphanCount = result.orphans.blocks.length; + if (orphanCount > 0 && !block) { + let message = this.msg("orphaned", { + count: orphanCount + }); + if (confirm(message)) { + for (const block of result.orphans.blocks) { + block.dispose(); + } + } else { + columns.unshift(result.orphans); + } + } + let cursorX = 48; + let maxWidths = result.maxWidths; + for (const column of columns) { + let cursorY = 64; + let maxWidth = 0; + for (const block of column.blocks) { + let extraWidth = block === makeSpaceForBlock ? 380 : 0; + let extraHeight = block === makeSpaceForBlock ? 480 : 72; + let xy = block.getRelativeToSurfaceXY(); + if (cursorX - xy.x !== 0 || cursorY - xy.y !== 0) { + block.moveBy(cursorX - xy.x, cursorY - xy.y); + } + let heightWidth = block.getHeightWidth(); + cursorY += heightWidth.height + extraHeight; + let maxWidthWithComments = maxWidths[block.id] || 0; + maxWidth = Math.max(maxWidth, Math.max(heightWidth.width + extraWidth, maxWidthWithComments)); + } + cursorX += maxWidth + 96; + } + let topComments = workspace.getTopComments(); + for (const comment of topComments) { + if (comment.setVisible) { + comment.setVisible(false); + comment.needsAutoPositioning_ = true; + comment.setVisible(true); + } + } + setTimeout(() => { + // Locate unused local variables... + let workspace = this.getWorkspace(); + let map = workspace.getVariableMap(); + let vars = map.getVariablesOfType(""); + let unusedLocals = []; + for (const row of vars) { + if (row.isLocal) { + let usages = map.getVariableUsesById(row.getId()); + if (!usages || usages.length === 0) { + unusedLocals.push(row); + } + } + } + if (unusedLocals.length > 0) { + const unusedCount = unusedLocals.length; + let message = this.msg("unused-var", { + count: unusedCount + }); + for (let i = 0; i < unusedLocals.length; i++) { + let orphan = unusedLocals[i]; + if (i > 0) { + message += ", "; + } + message += orphan.name; + } + if (confirm(message)) { + for (const orphan of unusedLocals) { + workspace.deleteVariableById(orphan.getId()); + } + } + } + + // Locate unused local lists... + let lists = map.getVariablesOfType("list"); + let unusedLists = []; + for (const row of lists) { + if (row.isLocal) { + let usages = map.getVariableUsesById(row.getId()); + if (!usages || usages.length === 0) { + unusedLists.push(row); + } + } + } + if (unusedLists.length > 0) { + const unusedCount = unusedLists.length; + let message = this.msg("unused-list", { + count: unusedCount + }); + for (let i = 0; i < unusedLists.length; i++) { + let orphan = unusedLists[i]; + if (i > 0) { + message += ", "; + } + message += orphan.name; + } + if (confirm(message)) { + for (const orphan of unusedLists) { + workspace.deleteVariableById(orphan.getId()); + } + } + } + _UndoGroup_js__WEBPACK_IMPORTED_MODULE_1__["default"].endUndoGroup(workspace); + }, 100); + } + + /** + * Badly Orphaned - might want to delete these! + * @param topBlock + * @returns {boolean} + */ + isBlockAnOrphan(topBlock) { + return !!topBlock.outputConnection; + } + + /** + * Split the top blocks into ordered columns + * @param separateOrphans true to keep all orphans separate + * @returns {{orphans: {blocks: [Block], x: number, count: number}, cols: [Col]}} + */ + getOrderedTopBlockColumns(separateOrphans) { + let w = this.getWorkspace(); + let topBlocks = w.getTopBlocks(); + let maxWidths = {}; + if (separateOrphans) { + let topComments = w.getTopComments(); + + // todo: tie comments to blocks... find widths and width of block stack row... + for (const comment of topComments) { + // comment.autoPosition_(); + // Hiding and showing repositions the comment right next to it's block - nice! + if (comment.setVisible) { + comment.setVisible(false); + comment.needsAutoPositioning_ = true; + comment.setVisible(true); + + // let bb = comment.block_.svgPath_.getBBox(); + let right = comment.getBoundingRectangle().bottomRight.x; + + // Get top block for stack... + let root = comment.block_.getRootBlock(); + let left = root.getBoundingRectangle().topLeft.x; + maxWidths[root.id] = Math.max(right - left, maxWidths[root.id] || 0); + } + } + } + + // Default scratch ordering is horrid... Lets try something more clever. + + /** + * @type {Col[]} + */ + let cols = []; + const TOLERANCE = 256; + let orphans = { + x: -999999, + count: 0, + blocks: [] + }; + for (const topBlock of topBlocks) { + // let r = b.getBoundingRectangle(); + let position = topBlock.getRelativeToSurfaceXY(); + /** + * @type {Col} + */ + let bestCol = null; + let bestError = TOLERANCE; + if (separateOrphans && this.isBlockAnOrphan(topBlock)) { + orphans.blocks.push(topBlock); + continue; + } + + // Find best columns + for (const col of cols) { + let err = Math.abs(position.x - col.x); + if (err < bestError) { + bestError = err; + bestCol = col; + } + } + if (bestCol) { + // We found a column that we fitted into + bestCol.x = (bestCol.x * bestCol.count + position.x) / ++bestCol.count; // re-average the columns as more items get added... + bestCol.blocks.push(topBlock); + } else { + // Create a new column + cols.push(new Col(position.x, 1, [topBlock])); + } + } + + // if (orphans.blocks.length > 0) { + // cols.push(orphans); + // } + + // Sort columns, then blocks inside the columns + cols.sort((a, b) => a.x - b.x); + for (const col of cols) { + col.blocks.sort((a, b) => a.getRelativeToSurfaceXY().y - b.getRelativeToSurfaceXY().y); + } + return { + cols: cols, + orphans: orphans, + maxWidths: maxWidths + }; + } + + /** + * Find all the uses of a named variable. + * @param {string} id ID of the variable to find. + * @return {!Array.} Array of block usages. + */ + getVariableUsesById(id) { + let uses = []; + let topBlocks = this.getTopBlocks(true); // todo: Confirm this was the right getTopBlocks? + for (const topBlock of topBlocks) { + /** @type {!Array} */ + let kids = topBlock.getDescendants(); + for (const block of kids) { + /** @type {!Array} */ + let blockVariables = block.getVarModels(); + if (blockVariables) { + for (const blockVar of blockVariables) { + if (blockVar.getId() === id) { + uses.push(block); + } + } + } + } + } + return uses; + } + + /** + * Quick and dirty replace all instances of one variable / list with another variable / list + * @param varId original variable name + * @param newVarName new variable name + * @param type type of variable ("" = variable, anything else is a list? + */ + doReplaceVariable(varId, newVarName, type) { + let wksp = this.getWorkspace(); + let v = wksp.getVariable(newVarName, type); + if (!v) { + alert(this.msg("var-not-exist")); + return; + } + let newVId = v.getId(); + _UndoGroup_js__WEBPACK_IMPORTED_MODULE_1__["default"].startUndoGroup(wksp); + let blocks = this.getVariableUsesById(varId); + for (const block of blocks) { + try { + if (type === "") { + block.getField("VARIABLE").setValue(newVId); + } else { + block.getField("LIST").setValue(newVId); + } + } catch (e) { + // ignore + } + } + _UndoGroup_js__WEBPACK_IMPORTED_MODULE_1__["default"].endUndoGroup(wksp); + } + + /* + function doInjectScripts(codeString) { + let w = getWorkspace(); + let xml = new XML(); // document.implementation.createDocument(null, "xml"); + let x = xml.xmlDoc.firstChild; + let tree = math.parse(codeString); + console.log(tree); + const binaryOperatorTypes = { + add: "operator_add", + subtract: "operator_subtract", + this.multiply: "operator_multiply", + divide: "operator_divide", + }; + const BLOCK_TYPE = { + number: "math_number", + text: "text", + }; + function translateMathToXml(x, tree, shadowType) { + let xShadowField = null; + if (shadowType) { + let xShadow = xml.newXml(x, "shadow", { type: shadowType }); + if (shadowType === BLOCK_TYPE.number) { + xShadowField = xml.newXml(xShadow, "field", { name: "NUM" }); + } else if (shadowType === BLOCK_TYPE.text) { + xShadowField = xml.newXml(xShadow, "field", { name: "TEXT" }); + } + } + if (!tree || !tree.type) { + return; + } + if (tree.type === "OperatorNode") { + let operatorType = binaryOperatorTypes[tree.fn]; + if (operatorType) { + let xOp = newXml(x, "block", { type: operatorType }); + translateMathToXml(xml.newXml(xOp, "value", { name: "NUM1" }), tree.args[0], BLOCK_TYPE.number); + translateMathToXml(xml.newXml(xOp, "value", { name: "NUM2" }), tree.args[1], BLOCK_TYPE.number); + return; + } + return; + } + if (tree.type === "ConstantNode") { + // number or text in quotes + if (xShadowField) { + xml.setAttr(xShadowField, { text: tree.value }); + } + return; + } + if (tree.type === "SymbolNode") { + // variable + let xVar = xml.newXml(x, "block", { type: "data_variable" }); + xml.newXml(xVar, "field", { name: "VARIABLE", text: tree.name }); + return; + } + if (tree.type === "FunctionNode") { + // Method Call + if (tree.fn.name === "join") { + let xOp = newXml(x, "block", { type: "operator_join" }); + translateMathToXml(xml.newXml(xOp, "value", { name: "STRING1" }), tree.args[0], BLOCK_TYPE.text); + translateMathToXml(xml.newXml(xOp, "value", { name: "STRING2" }), tree.args[1], BLOCK_TYPE.text); + return; + } + } + } + translateMathToXml(x, tree); + console.log(x); + let ids = Blockly.Xml.domToWorkspace(x, w); + console.log(ids); + } + */ + /* + function clickInject(e) { + let codeString = window.prompt("Griffpatch: Enter an expression (i.e. a+2*3)"); + if (codeString) { + doInjectScripts(codeString); + } + e.preventDefault(); + return false; + } + */ + + /** + * Returns a Set of the top blocks in this workspace / sprite + * @returns {Set} Set of top blocks + */ + getTopBlockIDs() { + let wksp = this.getWorkspace(); + let topBlocks = wksp.getTopBlocks(); + let ids = new Set(); + for (const block of topBlocks) { + ids.add(block.id); + } + return ids; + } + + /** + * Initiates a drag event for all block stacks except those in the set of ids. + * But why? - Because we know all the ids of the existing stacks before we paste / duplicate - so we can find the + * new stack by excluding all the known ones. + * @param ids Set of previously known ids + */ + beginDragOfNewBlocksNotInIDs(ids) { + if (!this.addon.settings.get("enablePasteBlocksAtMouse")) { + return; + } + let wksp = this.getWorkspace(); + let topBlocks = wksp.getTopBlocks(); + for (const block of topBlocks) { + if (!ids.has(block.id)) { + // console.log("I found a new block!!! - " + block.id); + // todo: move the block to the mouse pointer? + let mouseXYClone = { + x: this.mouseXY.x, + y: this.mouseXY.y + }; + block.setIntersects(true); // fixes offscreen block pasting in Turbo Warp + this.domHelpers.triggerDragAndDrop(block.svgPath_, null, mouseXYClone); + } + } + } + updateMousePosition(e) { + this.mouseXY.x = e.clientX; + this.mouseXY.y = e.clientY; + } + eventMouseMove(e) { + this.updateMousePosition(e); + } + eventKeyDown(e) { + const switchCostume = up => { + // todo: select previous costume + let selected = this.costTabBody.querySelector("div[class*='sprite-selector-item_is-selected']"); + let node = up ? selected.parentNode.previousSibling : selected.parentNode.nextSibling; + if (node) { + let wrapper = node.closest("div[class*=gui_flex-wrapper]"); + node.querySelector("div[class^='sprite-selector-item_sprite-name']").click(); + node.scrollIntoView({ + behavior: "auto", + block: "center", + inline: "start" + }); + wrapper.scrollTop = 0; + } + }; + if (document.URL.indexOf("editor") <= 0) { + return; + } + let ctrlKey = e.ctrlKey || e.metaKey; + if (e.keyCode === 37 && ctrlKey) { + // Ctrl + Left Arrow Key + if (document.activeElement.tagName === "INPUT") { + return; + } + if (this.isCostumeEditor()) { + switchCostume(true); + e.cancelBubble = true; + e.preventDefault(); + return true; + } + } + if (e.keyCode === 39 && ctrlKey) { + // Ctrl + Right Arrow Key + if (document.activeElement.tagName === "INPUT") { + return; + } + if (this.isCostumeEditor()) { + switchCostume(false); + e.cancelBubble = true; + e.preventDefault(); + return true; + } + } + if (e.keyCode === 86 && ctrlKey && !e.griff) { + // Ctrl + V + // Set a timeout so we can take control of the paste after the event + let ids = this.getTopBlockIDs(); + setTimeout(() => { + this.beginDragOfNewBlocksNotInIDs(ids); + }, 10); + } + + // if (e.keyCode === 220 && (!document.activeElement || document.activeElement.tagName === 'INPUT')) { + // + // } + } + eventCopyClick(block, blockOnly) { + let wksp = this.getWorkspace(); + if (block) { + block.select(); + let next = blockOnly ? block.getNextBlock() : null; + if (next) { + next.unplug(false); // setParent(null); + } + + // separate child temporarily + document.dispatchEvent(new KeyboardEvent("keydown", { + keyCode: 67, + ctrlKey: true + })); + if (next || blockOnly === 2) { + setTimeout(() => { + if (next) { + wksp.undo(); // undo the unplug above... + } + if (blockOnly === 2) { + _UndoGroup_js__WEBPACK_IMPORTED_MODULE_1__["default"].startUndoGroup(wksp); + block.dispose(true); + _UndoGroup_js__WEBPACK_IMPORTED_MODULE_1__["default"].endUndoGroup(wksp); + } + }, 0); + } + } + } + eventMouseDown(e) { + this.updateMousePosition(e); + } + eventMouseUp(e) { + this.updateMousePosition(e); + } + initInner(root) { + var _this = this; + let guiTabs = root.childNodes; + if (this.codeTab && guiTabs[0] !== this.codeTab) { + // We have been CHANGED!!! - Happens when going to project page, and then back inside again!!! + this.domHelpers.unbindAllEvents(); + } + this.codeTab = guiTabs[0]; + this.costTab = guiTabs[1]; + this.costTabBody = document.querySelector("div[aria-labelledby=" + this.costTab.id + "]"); + this.domHelpers.bindOnce(document, "keydown", function () { + return _this.eventKeyDown(...arguments); + }, true); + this.domHelpers.bindOnce(document, "mousemove", function () { + return _this.eventMouseMove(...arguments); + }, true); + this.domHelpers.bindOnce(document, "mousedown", function () { + return _this.eventMouseDown(...arguments); + }, true); // true to capture all mouse downs 'before' the dom events handle them + this.domHelpers.bindOnce(document, "mouseup", function () { + return _this.eventMouseUp(...arguments); + }, true); + } +} +class Col { + /** + * @param x {Number} x position (for ordering) + * @param count {Number} + * @param blocks {[Block]} + */ + constructor(x, count, blocks) { + /** + * x position (for ordering) + * @type {Number} + */ + this.x = x; + /** + * @type {Number} + */ + this.count = count; + /** + * @type {[Blockly.Block]} + */ + this.blocks = blocks; + } +} + +/***/ }), + +/***/ "./src/addons/addons/editor-devtools/DomHelpers.js": +/*!*********************************************************!*\ + !*** ./src/addons/addons/editor-devtools/DomHelpers.js ***! + \*********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return DomHelpers; }); +class DomHelpers { + constructor(addon) { + this.addon = addon; + this.vm = addon.tab.traps.vm; + /** + * @type {eventDetails[]} + */ + this.events = []; + } + + /** + * Simulate a drag and drop programmatically through javascript + * @param selectorDrag + * @param selectorDrop + * @param mouseXY + * @param [shiftKey=false] + * @returns {boolean} + */ + triggerDragAndDrop(selectorDrag, selectorDrop, mouseXY, shiftKey) { + // function for triggering mouse events + shiftKey = shiftKey || false; + let fireMouseEvent = function fireMouseEvent(type, elem, centerX, centerY) { + let evt = document.createEvent("MouseEvents"); + evt.initMouseEvent(type, true, true, window, 1, 1, 1, centerX, centerY, shiftKey, false, false, false, 0, elem); + elem.dispatchEvent(evt); + }; + + // fetch target elements + let elemDrag = selectorDrag; // document.querySelector(selectorDrag); + let elemDrop = selectorDrop; // document.querySelector(selectorDrop); + if (!elemDrag /* || !elemDrop*/) { + return false; + } + + // calculate positions + let pos = elemDrag.getBoundingClientRect(); + let center1X = Math.floor((pos.left + pos.right) / 2); + let center1Y = Math.floor((pos.top + pos.bottom) / 2); + + // mouse over dragged element and mousedown + fireMouseEvent("mouseover", elemDrag, center1X, center1Y); + fireMouseEvent("mousedown", elemDrag, center1X, center1Y); + + // start dragging process over to drop target + fireMouseEvent("dragstart", elemDrag, center1X, center1Y); + fireMouseEvent("drag", elemDrag, center1X, center1Y); + fireMouseEvent("mousemove", elemDrag, center1X, center1Y); + if (!elemDrop) { + if (mouseXY) { + // console.log(mouseXY); + let center2X = mouseXY.x; + let center2Y = mouseXY.y; + fireMouseEvent("drag", elemDrag, center2X, center2Y); + fireMouseEvent("mousemove", elemDrag, center2X, center2Y); + } + return false; + } + pos = elemDrop.getBoundingClientRect(); + let center2X = Math.floor((pos.left + pos.right) / 2); + let center2Y = Math.floor((pos.top + pos.bottom) / 2); + fireMouseEvent("drag", elemDrag, center2X, center2Y); + fireMouseEvent("mousemove", elemDrop, center2X, center2Y); + + // trigger dragging process on top of drop target + fireMouseEvent("mouseenter", elemDrop, center2X, center2Y); + fireMouseEvent("dragenter", elemDrop, center2X, center2Y); + fireMouseEvent("mouseover", elemDrop, center2X, center2Y); + fireMouseEvent("dragover", elemDrop, center2X, center2Y); + + // release dragged element on top of drop target + fireMouseEvent("drop", elemDrop, center2X, center2Y); + fireMouseEvent("dragend", elemDrag, center2X, center2Y); + fireMouseEvent("mouseup", elemDrag, center2X, center2Y); + return true; + } + bindOnce(dom, event, func, capture) { + capture = !!capture; + dom.removeEventListener(event, func, capture); + dom.addEventListener(event, func, capture); + this.events.push(new eventDetails(dom, event, func, capture)); + } + unbindAllEvents() { + for (const event of this.events) { + event.dom.removeEventListener(event.event, event.func, event.capture); + } + this.events = []; + } +} + +/** + * A record of an event + */ +class eventDetails { + constructor(dom, event, func, capture) { + this.dom = dom; + this.event = event; + this.func = func; + this.capture = capture; + } +} + +/***/ }), + +/***/ "./src/addons/addons/editor-devtools/UndoGroup.js": +/*!********************************************************!*\ + !*** ./src/addons/addons/editor-devtools/UndoGroup.js ***! + \********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return UndoGroup; }); +/** + * This class is dedicated to maintaining the Undo stack of Blockly + * It allows us to initiate an undo group such that all subsequent operations are recorded as a single + * undoable transaction. + */ +class UndoGroup { + /** + * Start an Undo group - begin recording + * @param workspace the workspace + */ + static startUndoGroup(workspace) { + const undoStack = workspace.undoStack_; + if (undoStack.length) { + undoStack[undoStack.length - 1]._devtoolsLastUndo = true; + } + } + + /** + * End an Undo group - stops recording + * @param workspace the workspace + */ + static endUndoGroup(workspace) { + const undoStack = workspace.undoStack_; + // Events (responsible for undoStack updates) are delayed with a setTimeout(f, 0) + // https://github.com/LLK/scratch-blocks/blob/f159a1779e5391b502d374fb2fdd0cb5ca43d6a2/core/events.js#L182 + setTimeout(() => { + const group = generateUID(); + for (let i = undoStack.length - 1; i >= 0 && !undoStack[i]._devtoolsLastUndo; i--) { + undoStack[i].group = group; + } + }, 0); + } +} + +/** + * https://github.com/LLK/scratch-blocks/blob/f159a1779e5391b502d374fb2fdd0cb5ca43d6a2/core/events.js#L182 + * @returns {string} + * @private + */ +function generateUID() { + const CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%()*+,-./:;=?@[]^_`{|}~"; + let result = ""; + for (let i = 0; i < 20; i++) { + result += CHARACTERS[Math.floor(Math.random() * CHARACTERS.length)]; + } + return result; +} + +/***/ }), + +/***/ "./src/addons/addons/editor-devtools/_runtime_entry.js": +/*!*************************************************************!*\ + !*** ./src/addons/addons/editor-devtools/_runtime_entry.js ***! + \*************************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/editor-devtools/userscript.js"); +/* harmony import */ var _url_loader_icon_close_svg__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! url-loader!./icon--close.svg */ "./node_modules/url-loader/dist/cjs.js!./src/addons/addons/editor-devtools/icon--close.svg"); +/* generated by pull.js */ + + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"], + "icon--close.svg": _url_loader_icon_close_svg__WEBPACK_IMPORTED_MODULE_1__["default"] +}; + +/***/ }), + +/***/ "./src/addons/addons/editor-devtools/userscript.js": +/*!*********************************************************!*\ + !*** ./src/addons/addons/editor-devtools/userscript.js ***! + \*********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _DevTools_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./DevTools.js */ "./src/addons/addons/editor-devtools/DevTools.js"); + +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon, + console, + msg, + safeMsg: m + } = _ref; + const devTools = new _DevTools_js__WEBPACK_IMPORTED_MODULE_0__["default"](addon, msg, m); + devTools.init(); +}); + +/***/ }), + +/***/ "./src/addons/addons/editor-searchable-dropdowns/_runtime_entry.js": +/*!*************************************************************************!*\ + !*** ./src/addons/addons/editor-searchable-dropdowns/_runtime_entry.js ***! + \*************************************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/editor-searchable-dropdowns/userscript.js"); +/* harmony import */ var _css_loader_userscript_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! css-loader!./userscript.css */ "./node_modules/css-loader/index.js!./src/addons/addons/editor-searchable-dropdowns/userscript.css"); +/* harmony import */ var _css_loader_userscript_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_css_loader_userscript_css__WEBPACK_IMPORTED_MODULE_1__); +/* generated by pull.js */ + + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"], + "userscript.css": _css_loader_userscript_css__WEBPACK_IMPORTED_MODULE_1___default.a +}; + +/***/ }), + +/***/ "./src/addons/addons/editor-searchable-dropdowns/userscript.js": +/*!*********************************************************************!*\ + !*** ./src/addons/addons/editor-searchable-dropdowns/userscript.js ***! + \*********************************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* eslint-disable */ +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon, + console, + msg + } = _ref; + const Blockly = await addon.tab.traps.getBlockly(); + const vm = addon.tab.traps.vm; + const SCRATCH_ITEMS_TO_HIDE = ["RENAME_VARIABLE_ID", "DELETE_VARIABLE_ID", "NEW_BROADCAST_MESSAGE_ID", + // From rename-broadcasts addon + "RENAME_BROADCAST_MESSAGE_ID"]; + const canUseAsGlobalVariableName = (name, type) => { + return !vm.runtime.getAllVarNamesOfType(type).includes(name); + }; + const canUseAsLocalVariableName = (name, type) => { + return !vm.editingTarget.lookupVariableByNameAndType(name, type); + }; + const ADDON_ITEMS = { + createGlobalVariable: { + enabled: name => canUseAsGlobalVariableName(name, ""), + createVariable: (workspace, name) => workspace.createVariable(name) + }, + createLocalVariable: { + enabled: name => canUseAsLocalVariableName(name, ""), + createVariable: (workspace, name) => workspace.createVariable(name, "", null, true) + }, + createGlobalList: { + enabled: name => canUseAsGlobalVariableName(name, "list"), + createVariable: (workspace, name) => workspace.createVariable(name, "list") + }, + createLocalList: { + enabled: name => canUseAsLocalVariableName(name, "list"), + createVariable: (workspace, name) => workspace.createVariable(name, "list", null, true) + }, + createBroadcast: { + enabled: name => canUseAsGlobalVariableName(name, "broadcast_msg"), + createVariable: (workspace, name) => workspace.createVariable(name, "broadcast_msg") + } + }; + let blocklyDropDownContent = null; + let blocklyDropdownMenu = null; + let searchBar = null; + // Contains DOM and addon state + let items = []; + let searchedItems = []; + // Tracks internal Scratch state + let currentDropdownOptions = []; + let resultOfLastGetOptions = []; + const oldDropDownDivShow = Blockly.DropDownDiv.show; + Blockly.DropDownDiv.show = function () { + blocklyDropdownMenu = document.querySelector(".blocklyDropdownMenu"); + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + if (!blocklyDropdownMenu) { + return oldDropDownDivShow.call(this, ...args); + } + blocklyDropdownMenu.focus = () => {}; // no-op focus() so it can't steal it from the search bar + + searchBar = document.createElement("input"); + addon.tab.displayNoneWhileDisabled(searchBar, { + display: "flex" + }); + searchBar.type = "text"; + searchBar.addEventListener("input", updateSearch); + searchBar.addEventListener("keydown", handleKeyDownEvent); + searchBar.classList.add("u-dropdown-searchbar"); + blocklyDropdownMenu.insertBefore(searchBar, blocklyDropdownMenu.firstChild); + items = Array.from(blocklyDropdownMenu.children).filter(child => child.tagName !== "INPUT").map(element => ({ + element, + text: element.textContent + })); + currentDropdownOptions = resultOfLastGetOptions; + updateSearch(); + + // Call the original show method after adding everything so that it can perform the correct size calculations + const ret = oldDropDownDivShow.call(this, ...args); + + // Lock the size of the dropdown + blocklyDropDownContent = Blockly.DropDownDiv.getContentDiv(); + blocklyDropDownContent.style.width = getComputedStyle(blocklyDropDownContent).width; + blocklyDropDownContent.style.height = getComputedStyle(blocklyDropDownContent).height; + + // This is really strange, but if you don't reinsert the search bar into the DOM then focus() doesn't work + blocklyDropdownMenu.insertBefore(searchBar, blocklyDropdownMenu.firstChild); + searchBar.focus(); + return ret; + }; + const oldDropDownDivClearContent = Blockly.DropDownDiv.clearContent; + Blockly.DropDownDiv.clearContent = function () { + oldDropDownDivClearContent.call(this); + items = []; + searchedItems = []; + Blockly.DropDownDiv.content_.style.height = ""; + }; + const oldFieldDropdownGetOptions = Blockly.FieldDropdown.prototype.getOptions; + Blockly.FieldDropdown.prototype.getOptions = function () { + const options = oldFieldDropdownGetOptions.call(this); + const block = this.sourceBlock_; + const isStage = vm.editingTarget && vm.editingTarget.isStage; + if (block) { + if (block.category_ === "data") { + options.push(getMenuItemMessage("createGlobalVariable")); + if (!isStage) { + options.push(getMenuItemMessage("createLocalVariable")); + } + } else if (block.category_ === "data-lists") { + options.push(getMenuItemMessage("createGlobalList")); + if (!isStage) { + options.push(getMenuItemMessage("createLocalList")); + } + } else if (block.type === "event_broadcast_menu" || block.type === "event_whenbroadcastreceived") { + options.push(getMenuItemMessage("createBroadcast")); + } + } + // Options aren't normally stored anywhere, so we'll store them ourselves. + resultOfLastGetOptions = options; + return options; + }; + const oldFieldTextDropdownGetOptions = Blockly.FieldTextDropdown.prototype.getOptions; + Blockly.FieldTextDropdown.prototype.getOptions = function () { + const options = oldFieldTextDropdownGetOptions.call(this); + const block = this.sourceBlock_; + const isStage = vm.editingTarget && vm.editingTarget.isStage; + if (block) { + if (block.category_ === "data") { + options.push(getMenuItemMessage("createGlobalVariable")); + if (!isStage) { + options.push(getMenuItemMessage("createLocalVariable")); + } + } else if (block.category_ === "data-lists") { + options.push(getMenuItemMessage("createGlobalList")); + if (!isStage) { + options.push(getMenuItemMessage("createLocalList")); + } + } else if (block.type === "event_broadcast_menu" || block.type === "event_whenbroadcastreceived") { + options.push(getMenuItemMessage("createBroadcast")); + } + } + // Options aren't normally stored anywhere, so we'll store them ourselves. + resultOfLastGetOptions = options; + return options; + }; + const oldFieldVariableOnItemSelected = Blockly.FieldVariable.prototype.onItemSelected; + Blockly.FieldVariable.prototype.onItemSelected = function (menu, menuItem) { + const sourceBlock = this.sourceBlock_; + if (sourceBlock && sourceBlock.workspace && searchBar.value.length !== 0) { + const workspace = sourceBlock.workspace; + const optionId = menuItem.getValue(); + if (Object.prototype.hasOwnProperty.call(ADDON_ITEMS, optionId)) { + const addonItem = ADDON_ITEMS[optionId]; + Blockly.Events.setGroup(true); + const variable = addonItem.createVariable(workspace, searchBar.value.trim()); + if (this.sourceBlock_) this.setValue(variable.getId()); + Blockly.Events.setGroup(false); + return; + } + } + return oldFieldVariableOnItemSelected.call(this, menu, menuItem); + }; + function selectItem(item, click) { + // You can't just use click() or focus() because Blockly uses mousedown and mouseup handlers, not click handlers. + item.dispatchEvent(new MouseEvent("mousedown", { + relatedTarget: item, + bubbles: true + })); + if (click) item.dispatchEvent(new MouseEvent("mouseup", { + relatedTarget: item, + bubbles: true + })); + + // Scroll the item into view if it is offscreen. + const itemTop = item.offsetTop; + const itemEnd = itemTop + item.offsetHeight; + const scrollTop = blocklyDropDownContent.scrollTop; + const scrollHeight = blocklyDropDownContent.offsetHeight; + const scrollEnd = scrollTop + scrollHeight; + if (scrollTop > itemTop) { + blocklyDropDownContent.scrollTop = itemTop; + } else if (itemEnd > scrollEnd) { + blocklyDropDownContent.scrollTop = itemEnd - scrollHeight; + } + } + function performSearch() { + const rawQuery = searchBar.value.trim(); + const query = rawQuery.trim().toLowerCase(); + const rank = (item, index) => { + // Negative number will hide + // Higher numbers will appear first + const option = currentDropdownOptions[index]; + const optionId = option[1]; + if (SCRATCH_ITEMS_TO_HIDE.includes(optionId)) { + return query ? -1 : 0; + } else if (Object.prototype.hasOwnProperty.call(ADDON_ITEMS, optionId)) { + if (!query) { + return -1; + } + const addonInfo = ADDON_ITEMS[optionId]; + if (addonInfo.enabled(rawQuery)) { + item.element.lastChild.lastChild.textContent = getMenuItemMessage(optionId)[0]; + return 0; + } + return -1; + } + const itemText = item.text.toLowerCase(); + if (query === itemText) { + return 2; + } + if (itemText.startsWith(query)) { + return 1; + } + if (itemText.includes(query)) { + return 0; + } + return -1; + }; + return items.map((item, index) => ({ + item, + score: rank(item, index) + })).sort((_ref2, _ref3) => { + let { + score: scoreA + } = _ref2; + let { + score: scoreB + } = _ref3; + return Math.max(0, scoreB) - Math.max(0, scoreA); + }); + } + function updateSearch() { + const previousSearchedItems = searchedItems; + searchedItems = performSearch(); + let needToUpdateDOM = previousSearchedItems.length !== searchedItems.length; + if (!needToUpdateDOM) { + for (let i = 0; i < searchedItems.length; i++) { + if (searchedItems[i].item !== previousSearchedItems[i].item) { + needToUpdateDOM = true; + break; + } + } + } + if (needToUpdateDOM && previousSearchedItems.length > 0) { + for (const { + item + } of previousSearchedItems) { + item.element.remove(); + } + for (const { + item + } of searchedItems) { + blocklyDropdownMenu.appendChild(item.element); + } + } + for (const { + item, + score + } of searchedItems) { + item.element.hidden = score < 0; + } + } + function handleKeyDownEvent(event) { + if (event.key === "Enter") { + // Reimplement enter to select item to account for hidden items and default to the top item. + event.stopPropagation(); + event.preventDefault(); + const selectedItem = document.querySelector(".goog-menuitem-highlight"); + if (selectedItem && !selectedItem.hidden) { + selectItem(selectedItem, true); + return; + } + const selectedBlock = Blockly.selected; + if (searchBar.value === "" && selectedBlock) { + if (selectedBlock.type === "event_broadcast" || selectedBlock.type === "event_broadcastandwait" || selectedBlock.type === "event_whenbroadcastreceived") { + // The top item of these dropdowns is always "New message" + // When pressing enter on an empty search bar, we close the dropdown instead of making a new broadcast. + Blockly.DropDownDiv.hide(); + return; + } + } + for (const { + item + } of searchedItems) { + if (!item.element.hidden) { + selectItem(item.element, true); + break; + } + } + // If there is no top value, do nothing and leave the dropdown open + } else if (event.key === "Escape") { + Blockly.DropDownDiv.hide(); + } else if (event.key === "ArrowDown" || event.key === "ArrowUp") { + // Reimplement keyboard navigation to account for hidden items. + event.preventDefault(); + event.stopPropagation(); + const items = searchedItems.filter(i => i.score >= 0).map(i => i.item); + if (items.length === 0) { + return; + } + let selectedIndex = -1; + for (let i = 0; i < items.length; i++) { + if (items[i].element.classList.contains("goog-menuitem-highlight")) { + selectedIndex = i; + break; + } + } + const lastIndex = items.length - 1; + let newIndex = 0; + if (event.key === "ArrowDown") { + if (selectedIndex === -1 || selectedIndex === lastIndex) { + newIndex = 0; + } else { + newIndex = selectedIndex + 1; + } + } else { + if (selectedIndex === -1 || selectedIndex === 0) { + newIndex = lastIndex; + } else { + newIndex = selectedIndex - 1; + } + } + selectItem(items[newIndex].element, false); + } + } + function getMenuItemMessage(message) { + var _searchBar; + // Format used internally by Scratch: + // [human readable name, internal name] + return [msg(message, { + name: ((_searchBar = searchBar) === null || _searchBar === void 0 ? void 0 : _searchBar.value.trim()) || "" + }), message]; + } +}); + +/***/ }), + +/***/ "./src/addons/addons/find-bar/_runtime_entry.js": +/*!******************************************************!*\ + !*** ./src/addons/addons/find-bar/_runtime_entry.js ***! + \******************************************************/ +/*! exports provided: resources */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "resources", function() { return resources; }); +/* harmony import */ var _userscript_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./userscript.js */ "./src/addons/addons/find-bar/userscript.js"); +/* harmony import */ var _css_loader_userstyle_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! css-loader!./userstyle.css */ "./node_modules/css-loader/index.js!./src/addons/addons/find-bar/userstyle.css"); +/* harmony import */ var _css_loader_userstyle_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_css_loader_userstyle_css__WEBPACK_IMPORTED_MODULE_1__); +/* generated by pull.js */ + + +const resources = { + "userscript.js": _userscript_js__WEBPACK_IMPORTED_MODULE_0__["default"], + "userstyle.css": _css_loader_userstyle_css__WEBPACK_IMPORTED_MODULE_1___default.a +}; + +/***/ }), + +/***/ "./src/addons/addons/find-bar/blockly/BlockItem.js": +/*!*********************************************************!*\ + !*** ./src/addons/addons/find-bar/blockly/BlockItem.js ***! + \*********************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "default", function() { return BlockItem; }); +class BlockItem { + constructor(cls, procCode, labelID, y) { + this.cls = cls; + this.procCode = procCode; + this.labelID = labelID; + this.y = y; + this.lower = procCode.toLowerCase(); + /** + * An Array of block ids + * @type {Array.} + */ + this.clones = null; + this.eventName = null; + } + + /** + * True if the blockID matches a black represented by this BlockItem + * @param id + * @returns {boolean} + */ + matchesID(id) { + if (this.labelID === id) { + return true; + } + if (this.clones) { + for (const cloneID of this.clones) { + if (cloneID === id) { + return true; + } + } + } + return false; + } +} + +/***/ }), + +/***/ "./src/addons/addons/find-bar/userscript.js": +/*!**************************************************!*\ + !*** ./src/addons/addons/find-bar/userscript.js ***! + \**************************************************/ +/*! exports provided: default */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +__webpack_require__.r(__webpack_exports__); +/* harmony import */ var _blockly_BlockItem_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./blockly/BlockItem.js */ "./src/addons/addons/find-bar/blockly/BlockItem.js"); +/* harmony import */ var _blockly_BlockInstance_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./blockly/BlockInstance.js */ "./src/addons/addons/find-bar/blockly/BlockInstance.js"); +/* harmony import */ var _blockly_Utils_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./blockly/Utils.js */ "./src/addons/addons/find-bar/blockly/Utils.js"); + + + +/* harmony default export */ __webpack_exports__["default"] = (async function (_ref) { + let { + addon, + msg, + console + } = _ref; + const Blockly = await addon.tab.traps.getBlockly(); + class FindBar { + constructor() { + this.utils = new _blockly_Utils_js__WEBPACK_IMPORTED_MODULE_2__["default"](addon); + this.prevValue = ""; + this.findBarOuter = null; + this.findWrapper = null; + this.findInput = null; + this.dropdownOut = null; + this.dropdown = new Dropdown(this.utils); + document.addEventListener("keydown", e => this.eventKeyDown(e), true); + } + get workspace() { + return Blockly.getMainWorkspace(); + } + createDom(root) { + this.findBarOuter = document.createElement("div"); + this.findBarOuter.className = "sa-find-bar"; + addon.tab.displayNoneWhileDisabled(this.findBarOuter, { + display: "flex" + }); + root.appendChild(this.findBarOuter); + this.findWrapper = this.findBarOuter.appendChild(document.createElement("span")); + this.findWrapper.className = "sa-find-wrapper"; + this.dropdownOut = this.findWrapper.appendChild(document.createElement("label")); + this.dropdownOut.className = "sa-find-dropdown-out"; + this.findInput = this.dropdownOut.appendChild(document.createElement("input")); + this.findInput.className = addon.tab.scratchClass("input_input-form", { + others: "sa-find-input" + }); + // for