From 6e8236d10782bb101ea136e947046e8e8ca3c8a3 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Mon, 13 Nov 2023 17:13:59 +0800 Subject: [PATCH] feat: initial commit! Update README.md Update README.md Remove potentially ToS breaking assets. Update README.md Add back potentially ToS breaking assets. (Sorry ST, the Scratch cat looks too good!) Update README.md Add feature list to readme.md Update README.md Update README.md Added: Network extension, echo effect in sounds, a variety of ScratchAddons, letters x to y of z, startswith, endswith, fastpower Update README.md Remove backpack and annoying coming soon tooltips v0.3 --- .husky/commit-msg | 2 - README.md | 108 +-- src/components/gui/gui.jsx | 4 +- src/components/menu-bar/menu-bar.css | 1 + src/components/menu-bar/menu-bar.jsx | 839 +++++++++++------- src/components/menu-bar/scratch-logo-old.svg | 1 + src/components/menu-bar/scratch-logo.svg | 2 +- src/components/menu-bar/settings-menu.jsx | 8 +- src/components/prompt/prompt.jsx | 107 ++- src/components/sound-editor/sound-editor.jsx | 8 +- src/components/stage-header/stage-header.jsx | 4 +- src/containers/gui.jsx | 1 + src/containers/prompt.jsx | 61 +- src/containers/sb3-downloader.jsx | 34 +- src/lib/alerts/index.jsx | 15 + src/lib/blocks.js | 2 + src/lib/cloud-manager-hoc.jsx | 5 +- .../0fb9be3e8397c983338cb71dc84d0b25.svg | 82 +- .../bcf454acf82e4504149f7ffe07081dbc.svg | 82 +- src/lib/libraries/extensions/index.jsx | 22 + .../libraries/extensions/network/network.svg | 26 + .../extensions/network/networkBig.png | Bin 0 -> 1221 bytes src/lib/make-toolbox-xml.js | 158 ++++ src/lib/sb-file-uploader-hoc.jsx | 6 +- src/playground/index.ejs | 169 +++- src/playground/index.jsx | 2 + src/playground/userscripts/blocks2image.js | 293 ++++++ src/playground/userscripts/catblocks.js | 266 ++++++ src/playground/userscripts/cherrypicking.js | 99 +++ src/playground/userscripts/index.js | 77 ++ src/playground/userscripts/numberpad.js | 11 + static/favicon.ico | Bin 34494 -> 0 bytes static/favicon.png | Bin 0 -> 50380 bytes test/integration/localization.test.js | 2 +- test/integration/menu-bar.test.js | 6 +- test/integration/sb-file-uploader-hoc.test.js | 16 +- webpack.config.js | 8 +- 37 files changed, 1930 insertions(+), 597 deletions(-) create mode 100644 src/components/menu-bar/scratch-logo-old.svg create mode 100644 src/lib/libraries/extensions/network/network.svg create mode 100644 src/lib/libraries/extensions/network/networkBig.png create mode 100644 src/playground/userscripts/blocks2image.js create mode 100644 src/playground/userscripts/catblocks.js create mode 100644 src/playground/userscripts/cherrypicking.js create mode 100644 src/playground/userscripts/index.js create mode 100644 src/playground/userscripts/numberpad.js delete mode 100644 static/favicon.ico create mode 100644 static/favicon.png diff --git a/.husky/commit-msg b/.husky/commit-msg index 80416c7b176..15259826991 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1,4 +1,2 @@ #!/usr/bin/env sh . "$(dirname -- "$0")/_/husky.sh" - -npx --no-install commitlint --edit "$1" diff --git a/README.md b/README.md index 77aeb5f0941..a679b1d9924 100644 --- a/README.md +++ b/README.md @@ -1,66 +1,74 @@ -# scratch-gui -#### Scratch GUI is a set of React components that comprise the interface for creating and running Scratch 3.0 projects +# Scratch++ +#### Scratch++ is a Scratch mod that adds new blocks which can compile to normal Scratch. + +## How to use +Example: +In the editor, write a script with a new block (like the power operator). +```scratchblocks +when 🏳️ clicked +say ( 5 ^ 3 ) +``` +Then, click on `File` > `Compile to Scratch (.sb3)`. It should download an sb3 file that is fully compatible with normal Scratch. ## Installation -This requires you to have Git and Node.js installed. +Go to the [releases tab](https://github.com/ZXMushroom63/scratch-gui/releases/latest), and download the zip file from the assets section. +Create a new folder on your computer, naming it whateverr you want. +Extract the zip file to this folder. +Open index.html in Chrome or your preferred browser! -In your own node environment/application: -```bash -npm install https://github.com/LLK/scratch-gui.git -``` -If you want to edit/play yourself: -```bash -git clone https://github.com/LLK/scratch-gui.git -cd scratch-gui -npm install -``` -**You may want to add `--depth=1` to the `git clone` command because there are some [large files in the git repository history](https://github.com/LLK/scratch-gui/issues/5140).** +## Building +This requires you to have Git and Node.js installed. -## Getting started -Running the project requires Node.js to be installed. -## Running -Open a Command Prompt or Terminal in the repository and run: ```bash -npm start -``` -Then go to [http://localhost:8601/](http://localhost:8601/) - the playground outputs the default GUI component - -## Developing alongside other Scratch repositories +cd scratchplusplus #Folder dedicated to Scratch++ -### Getting another repo to point to this code - - -If you wish to develop `scratch-gui` alongside other scratch repositories that depend on it, you may wish -to have the other repositories use your local `scratch-gui` build instead of fetching the current production -version of the scratch-gui that is found by default using `npm install`. - -Here's how to link your local `scratch-gui` code to another project's `node_modules/scratch-gui`. - -#### Configuration - -1. In your local `scratch-gui` repository's top level: - 1. Make sure you have run `npm install` - 2. Build the `dist` directory by running `BUILD_MODE=dist npm run build` - 3. Establish a link to this repository by running `npm link` +git clone --depth=1 https://github.com/ZXMushroom63/scratch-gui.git +cd scratch-gui +npm install -2. From the top level of each repository (such as `scratch-www`) that depends on `scratch-gui`: - 1. Make sure you have run `npm install` - 2. Run `npm link scratch-gui` - 3. Build or run the repository +cd .. +git clone --depth=1 https://github.com/ZXMushroom63/scratch-vm.git +cd scratch-vm +npm install -#### Using `npm run watch` +cd .. +git clone --depth=1 https://github.com/ZXMushroom63/scratch-blocks.git +cd scratch-blocks +npm install +npm run translate +sudo npm run prepublish #Requires python 2 and Java installed!!! -Instead of `BUILD_MODE=dist npm run build`, you can use `BUILD_MODE=dist npm run watch` instead. This will watch for changes to your `scratch-gui` code, and automatically rebuild when there are changes. Sometimes this has been unreliable; if you are having problems, try going back to `BUILD_MODE=dist npm run build` until you resolve them. +cd ../scratch-gui +npm link ../scratch-blocks ../scratch-vm #Might also need sudo -#### Oh no! It didn't work! +# Now, to run it in localhost: +npm start -If you can't get linking to work right, try: -* Follow the recipe above step by step and don't change the order. It is especially important to run `npm install` _before_ `npm link` as installing after the linking will reset the linking. -* Make sure the repositories are siblings on your machine's file tree, like `.../.../MY_SCRATCH_DEV_DIRECTORY/scratch-gui/` and `.../.../MY_SCRATCH_DEV_DIRECTORY/scratch-www/`. -* Consistent node.js version: If you have multiple Terminal tabs or windows open for the different Scratch repositories, make sure to use the same node version in all of them. -* If nothing else works, unlink the repositories by running `npm unlink` in both, and start over. +# Or, to make a build: +npm run build +# Outputs to the build folder +``` +## Current feature list +- fencing control blocks +- power operator +- previous costume & previous backdrop +- force set size +- point to X Y +- min operator +- max operator +- if operator +- replace x with y in z operator +- newline reporter +- decimal to hexadecimal operator +- color at my position reporter +- set list to x split by y +- Network extension +- fastpower +- letters x to y of string +- starts with +- ends with ## Testing ### Documentation diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index f48e5a6ec33..a8d5b13dcb9 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -343,9 +343,11 @@ const GUIComponent = props => { {soundsTabVisible ? : null} + {/*/ {backpackVisible ? ( ) : null} + /*/} @@ -452,7 +454,7 @@ GUIComponent.defaultProps = { canSave: false, canCreateCopy: false, canShare: false, - canUseCloud: false, + canUseCloud: true, enableCommunity: false, isCreating: false, isShared: false, diff --git a/src/components/menu-bar/menu-bar.css b/src/components/menu-bar/menu-bar.css index 7f7e1bf1a5e..0d8bf43346e 100644 --- a/src/components/menu-bar/menu-bar.css +++ b/src/components/menu-bar/menu-bar.css @@ -48,6 +48,7 @@ } .scratch-logo.clickable { + transition: 0.125s; cursor: pointer; } diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx index ab3081775ad..b326960c7ce 100644 --- a/src/components/menu-bar/menu-bar.jsx +++ b/src/components/menu-bar/menu-bar.jsx @@ -1,44 +1,49 @@ -import classNames from 'classnames'; -import {connect} from 'react-redux'; -import {compose} from 'redux'; -import {defineMessages, FormattedMessage, injectIntl, intlShape} from 'react-intl'; -import PropTypes from 'prop-types'; -import bindAll from 'lodash.bindall'; -import bowser from 'bowser'; -import React from 'react'; +import classNames from "classnames"; +import { connect } from "react-redux"; +import { compose } from "redux"; +import { + defineMessages, + FormattedMessage, + injectIntl, + intlShape, +} from "react-intl"; +import PropTypes from "prop-types"; +import bindAll from "lodash.bindall"; +import bowser from "bowser"; +import React from "react"; -import VM from 'scratch-vm'; +import VM from "scratch-vm"; -import Box from '../box/box.jsx'; -import Button from '../button/button.jsx'; -import CommunityButton from './community-button.jsx'; -import ShareButton from './share-button.jsx'; -import {ComingSoonTooltip} from '../coming-soon/coming-soon.jsx'; -import Divider from '../divider/divider.jsx'; -import SaveStatus from './save-status.jsx'; -import ProjectWatcher from '../../containers/project-watcher.jsx'; -import MenuBarMenu from './menu-bar-menu.jsx'; -import {MenuItem, MenuSection} from '../menu/menu.jsx'; -import ProjectTitleInput from './project-title-input.jsx'; -import AuthorInfo from './author-info.jsx'; -import AccountNav from '../../containers/account-nav.jsx'; -import LoginDropdown from './login-dropdown.jsx'; -import SB3Downloader from '../../containers/sb3-downloader.jsx'; -import DeletionRestorer from '../../containers/deletion-restorer.jsx'; -import TurboMode from '../../containers/turbo-mode.jsx'; -import MenuBarHOC from '../../containers/menu-bar-hoc.jsx'; -import SettingsMenu from './settings-menu.jsx'; +import Box from "../box/box.jsx"; +import Button from "../button/button.jsx"; +import CommunityButton from "./community-button.jsx"; +import ShareButton from "./share-button.jsx"; +import { ComingSoonTooltip } from "../coming-soon/coming-soon.jsx"; +import Divider from "../divider/divider.jsx"; +import SaveStatus from "./save-status.jsx"; +import ProjectWatcher from "../../containers/project-watcher.jsx"; +import MenuBarMenu from "./menu-bar-menu.jsx"; +import { MenuItem, MenuSection } from "../menu/menu.jsx"; +import ProjectTitleInput from "./project-title-input.jsx"; +import AuthorInfo from "./author-info.jsx"; +import AccountNav from "../../containers/account-nav.jsx"; +import LoginDropdown from "./login-dropdown.jsx"; +import SB3Downloader from "../../containers/sb3-downloader.jsx"; +import DeletionRestorer from "../../containers/deletion-restorer.jsx"; +import TurboMode from "../../containers/turbo-mode.jsx"; +import MenuBarHOC from "../../containers/menu-bar-hoc.jsx"; +import SettingsMenu from "./settings-menu.jsx"; -import {openTipsLibrary} from '../../reducers/modals'; -import {setPlayer} from '../../reducers/mode'; +import { openTipsLibrary } from "../../reducers/modals"; +import { setPlayer } from "../../reducers/mode"; import { isTimeTravel220022BC, isTimeTravel1920, isTimeTravel1990, isTimeTravel2020, isTimeTravelNow, - setTimeTravel -} from '../../reducers/time-travel'; + setTimeTravel, +} from "../../reducers/time-travel"; import { autoUpdateProject, getIsUpdating, @@ -46,8 +51,8 @@ import { manualUpdateProject, requestNewProject, remixProject, - saveProjectAsCopy -} from '../../reducers/project-state'; + saveProjectAsCopy, +} from "../../reducers/project-state"; import { openAboutMenu, closeAboutMenu, @@ -69,36 +74,36 @@ import { modeMenuOpen, settingsMenuOpen, openSettingsMenu, - closeSettingsMenu -} from '../../reducers/menus'; + closeSettingsMenu, +} from "../../reducers/menus"; -import collectMetadata from '../../lib/collect-metadata'; +import collectMetadata from "../../lib/collect-metadata"; -import styles from './menu-bar.css'; +import styles from "./menu-bar.css"; -import helpIcon from '../../lib/assets/icon--tutorials.svg'; -import mystuffIcon from './icon--mystuff.png'; -import profileIcon from './icon--profile.png'; -import remixIcon from './icon--remix.svg'; -import dropdownCaret from './dropdown-caret.svg'; -import aboutIcon from './icon--about.svg'; -import fileIcon from './icon--file.svg'; -import editIcon from './icon--edit.svg'; +import helpIcon from "../../lib/assets/icon--tutorials.svg"; +import mystuffIcon from "./icon--mystuff.png"; +import profileIcon from "./icon--profile.png"; +import remixIcon from "./icon--remix.svg"; +import dropdownCaret from "./dropdown-caret.svg"; +import aboutIcon from "./icon--about.svg"; +import fileIcon from "./icon--file.svg"; +import editIcon from "./icon--edit.svg"; -import scratchLogo from './scratch-logo.svg'; -import ninetiesLogo from './nineties_logo.svg'; -import catLogo from './cat_logo.svg'; -import prehistoricLogo from './prehistoric-logo.svg'; -import oldtimeyLogo from './oldtimey-logo.svg'; +import scratchLogo from "./scratch-logo.svg"; +import ninetiesLogo from "./nineties_logo.svg"; +import catLogo from "./cat_logo.svg"; +import prehistoricLogo from "./prehistoric-logo.svg"; +import oldtimeyLogo from "./oldtimey-logo.svg"; -import sharedMessages from '../../lib/shared-messages'; +import sharedMessages from "../../lib/shared-messages"; const ariaMessages = defineMessages({ tutorials: { - id: 'gui.menuBar.tutorialsLibrary', - defaultMessage: 'Tutorials', - description: 'accessibility text for the tutorials button' - } + id: "gui.menuBar.tutorialsLibrary", + defaultMessage: "Tutorials", + description: "accessibility text for the tutorials button", + }, }); const MenuBarItemTooltip = ({ @@ -106,41 +111,42 @@ const MenuBarItemTooltip = ({ className, enable, id, - place = 'bottom' + place = "bottom", }) => { - if (enable) { - return ( - - {children} - - ); - } - return ( - - {children} - - ); -}; + // if (enable) { + // return ( + // + // {children} + // + // ); + // } + // return ( + // + // {children} + // + // ); + return {children}; +}; MenuBarItemTooltip.propTypes = { children: PropTypes.node, className: PropTypes.string, enable: PropTypes.bool, id: PropTypes.string, - place: PropTypes.oneOf(['top', 'bottom', 'left', 'right']) + place: PropTypes.oneOf(["top", "bottom", "left", "right"]), }; -const MenuItemTooltip = ({id, isRtl, children, className}) => ( +const MenuItemTooltip = ({ id, isRtl, children, className }) => ( @@ -152,10 +158,10 @@ MenuItemTooltip.propTypes = { children: PropTypes.node, className: PropTypes.string, id: PropTypes.string, - isRtl: PropTypes.bool + isRtl: PropTypes.bool, }; -const AboutButton = props => ( +const AboutButton = (props) => ( - + +

+ Scratch++ is a Scratch mod that adds new features like fencing + controls and the power operator. However, unlike other scratch + mods, it also adds the ability to compile the project for use in + normal Scratch!

+ + For example, try using a disable fencing block (or any modded block). Then, convert your project to a regular Scratch project by clicking on File > Compile to Scratch. It should be able to load and work in normal Scratch! Just make sure your remember that all the custom blocks have Scratch definitions, so things will likely run slower in normal Scratch. + + Credits: +

    +
  • ZXMushroom63 - Scratch++ concept, compiler, GUI, and many custom block definitions.
  • +
  • DadOfMrLog - Power script
  • +
  • NitroCipher - Decimal Color at X Y calculator
  • +
  • EncloCreations - Decimal to Hexadecimal
  • +
+

+ +
+

+ Scratch++ Settings + +

+

Changing these settings requires a reload.

+ + + + + + + + + + + + + + + + + + + + + +
+ Cat Blocks + + + + Brings back the 2020 cat blocks.
+ Blocks2Image + + + + Adds export to image options to the right-click menu.
+ Numberpad + + + + Force shows the number pad on number inputs.
+ Cherry Picking + + + + Grab single blocks by dragging with the Ctrl key.
+
+ diff --git a/src/playground/index.jsx b/src/playground/index.jsx index 6ff33f7e8b5..e5b64d0ae3a 100644 --- a/src/playground/index.jsx +++ b/src/playground/index.jsx @@ -29,3 +29,5 @@ if (supportedBrowser()) { // eslint-disable-next-line react/jsx-no-bind ReactDOM.render(, appTarget); } + +require("./userscripts"); \ No newline at end of file diff --git a/src/playground/userscripts/blocks2image.js b/src/playground/userscripts/blocks2image.js new file mode 100644 index 00000000000..d0bd03b9a49 --- /dev/null +++ b/src/playground/userscripts/blocks2image.js @@ -0,0 +1,293 @@ +module.exports = { + func: function (createBlockContextMenu) { + function makeStyle() { + let style = document.createElement("style"); + style.textContent = ` + .blocklyText { + fill: #fff; + font-family: "Helvetica Neue", Helvetica, sans-serif; + font-size: 12pt; + font-weight: 500; + } + .blocklyNonEditableText>text, .blocklyEditableText>text { + fill: #575E75; + } + .blocklyDropdownText { + fill: #fff !important; + } + `; + for (let userstyle of document.querySelectorAll( + ".scratch-addons-style[data-addon-id='editor-theme3']" + )) { + if (userstyle.disabled) continue; + style.textContent += userstyle.textContent; + } + return style; + } + + function setCSSVars(element) { + for (let property of document.documentElement.style) { + if (property.startsWith("--editorTheme3-")) + element.style.setProperty( + property, + document.documentElement.style.getPropertyValue(property) + ); + } + } + if (localStorage.getItem("blocks2image") === "true") { + let exSVG = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + exSVG.setAttribute("xmlns:html", "http://www.w3.org/1999/xhtml"); + exSVG.setAttribute("xmlns:xlink", "http://www.w3.org/1999/xlink"); + exSVG.setAttribute("version", "1.1"); + + let blocksMedia = new Map(); + blocksMedia.set( + "repeat.svg", + "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIxLjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9InJlcGVhdCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgdmlld0JveD0iMCAwIDI0IDI0IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNCAyNDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiNDRjhCMTc7fQoJLnN0MXtmaWxsOiNGRkZGRkY7fQo8L3N0eWxlPgo8dGl0bGU+cmVwZWF0PC90aXRsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTIzLjMsMTFjLTAuMywwLjYtMC45LDEtMS41LDFoLTEuNmMtMC4xLDEuMy0wLjUsMi41LTEuMSwzLjZjLTAuOSwxLjctMi4zLDMuMi00LjEsNC4xCgljLTEuNywwLjktMy42LDEuMi01LjUsMC45Yy0xLjgtMC4zLTMuNS0xLjEtNC45LTIuM2MtMC43LTAuNy0wLjctMS45LDAtMi42YzAuNi0wLjYsMS42LTAuNywyLjMtMC4ySDdjMC45LDAuNiwxLjksMC45LDIuOSwwLjkKCXMxLjktMC4zLDIuNy0wLjljMS4xLTAuOCwxLjgtMi4xLDEuOC0zLjVoLTEuNWMtMC45LDAtMS43LTAuNy0xLjctMS43YzAtMC40LDAuMi0wLjksMC41LTEuMmw0LjQtNC40YzAuNy0wLjYsMS43LTAuNiwyLjQsMEwyMyw5LjIKCUMyMy41LDkuNywyMy42LDEwLjQsMjMuMywxMXoiLz4KPHBhdGggY2xhc3M9InN0MSIgZD0iTTIxLjgsMTFoLTIuNmMwLDEuNS0wLjMsMi45LTEsNC4yYy0wLjgsMS42LTIuMSwyLjgtMy43LDMuNmMtMS41LDAuOC0zLjMsMS4xLTQuOSwwLjhjLTEuNi0wLjItMy4yLTEtNC40LTIuMQoJYy0wLjQtMC4zLTAuNC0wLjktMC4xLTEuMmMwLjMtMC40LDAuOS0wLjQsMS4yLTAuMWwwLDBjMSwwLjcsMi4yLDEuMSwzLjQsMS4xczIuMy0wLjMsMy4zLTFjMC45LTAuNiwxLjYtMS41LDItMi42CgljMC4zLTAuOSwwLjQtMS44LDAuMi0yLjhoLTIuNGMtMC40LDAtMC43LTAuMy0wLjctMC43YzAtMC4yLDAuMS0wLjMsMC4yLTAuNGw0LjQtNC40YzAuMy0wLjMsMC43LTAuMywwLjksMEwyMiw5LjgKCWMwLjMsMC4zLDAuNCwwLjYsMC4zLDAuOVMyMiwxMSwyMS44LDExeiIvPgo8L3N2Zz4K" + ); + blocksMedia.set( + "green-flag.svg", + "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDIxLjAuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPgo8c3ZnIHZlcnNpb249IjEuMSIgaWQ9ImdyZWVuZmxhZyIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiCgkgdmlld0JveD0iMCAwIDI0IDI0IiBzdHlsZT0iZW5hYmxlLWJhY2tncm91bmQ6bmV3IDAgMCAyNCAyNDsiIHhtbDpzcGFjZT0icHJlc2VydmUiPgo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPgoJLnN0MHtmaWxsOiM0NTk5M0Q7fQoJLnN0MXtmaWxsOiM0Q0JGNTY7fQo8L3N0eWxlPgo8dGl0bGU+Z3JlZW5mbGFnPC90aXRsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0iTTIwLjgsMy43Yy0wLjQtMC4yLTAuOS0wLjEtMS4yLDAuMmMtMiwxLjYtNC44LDEuNi02LjgsMGMtMi4zLTEuOS01LjYtMi4zLTguMy0xVjIuNWMwLTAuNi0wLjUtMS0xLTEKCXMtMSwwLjQtMSwxdjE4LjhjMCwwLjUsMC41LDEsMSwxaDAuMWMwLjUsMCwxLTAuNSwxLTF2LTYuNGMxLTAuNywyLjEtMS4yLDMuNC0xLjNjMS4yLDAsMi40LDAuNCwzLjQsMS4yYzIuOSwyLjMsNywyLjMsOS44LDAKCWMwLjMtMC4yLDAuNC0wLjUsMC40LTAuOVY0LjdDMjEuNiw0LjIsMjEuMywzLjgsMjAuOCwzLjd6IE0yMC41LDEzLjlDMjAuNSwxMy45LDIwLjUsMTMuOSwyMC41LDEzLjlDMTgsMTYsMTQuNCwxNiwxMS45LDE0CgljLTEuMS0wLjktMi41LTEuNC00LTEuNGMtMS4yLDAuMS0yLjMsMC41LTMuNCwxLjFWNEM3LDIuNiwxMCwyLjksMTIuMiw0LjZjMi40LDEuOSw1LjcsMS45LDguMSwwYzAuMSwwLDAuMSwwLDAuMiwwCgljMCwwLDAuMSwwLjEsMC4xLDAuMUwyMC41LDEzLjl6Ii8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Ik0yMC42LDQuOGwtMC4xLDkuMWMwLDAsMCwwLjEsMCwwLjFjLTIuNSwyLTYuMSwyLTguNiwwYy0xLjEtMC45LTIuNS0xLjQtNC0xLjRjLTEuMiwwLjEtMi4zLDAuNS0zLjQsMS4xVjQKCUM3LDIuNiwxMCwyLjksMTIuMiw0LjZjMi40LDEuOSw1LjcsMS45LDguMSwwYzAuMSwwLDAuMSwwLDAuMiwwQzIwLjUsNC43LDIwLjYsNC43LDIwLjYsNC44eiIvPgo8L3N2Zz4K" + ); + blocksMedia.set( + "rotate-left.svg", + "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIGlkPSJyb3RhdGUtY2xvY2t3aXNlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHN0eWxlPi5jbHMtMXtmaWxsOiMzZDc5Y2M7fS5jbHMtMntmaWxsOiNmZmY7fTwvc3R5bGU+PHRpdGxlPnJvdGF0ZS1jbG9ja3dpc2U8L3RpdGxlPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTIwLjM0LDE4LjIxYTEwLjI0LDEwLjI0LDAsMCwxLTguMSw0LjIyLDIuMjYsMi4yNiwwLDAsMS0uMTYtNC41MmgwYTUuNTgsNS41OCwwLDAsMCw0LjI1LTIuNTMsNS4wNiw1LjA2LDAsMCwwLC41NC00LjYyQTQuMjUsNC4yNSwwLDAsMCwxNS41NSw5YTQuMzEsNC4zMSwwLDAsMC0yLS44QTQuODIsNC44MiwwLDAsMCwxMC40LDlsMS4xMiwxLjQxQTEuNTksMS41OSwwLDAsMSwxMC4zNiwxM0gyLjY3YTEuNTYsMS41NiwwLDAsMS0xLjI2LS42M0ExLjU0LDEuNTQsMCwwLDEsMS4xMywxMUwyLjg1LDMuNTdBMS41OSwxLjU5LDAsMCwxLDQuMzgsMi40LDEuNTcsMS41NywwLDAsMSw1LjYyLDNMNi43LDQuMzVhMTAuNjYsMTAuNjYsMCwwLDEsNy43Mi0xLjY4QTkuODgsOS44OCwwLDAsMSwxOSw0LjgxLDkuNjEsOS42MSwwLDAsMSwyMS44Myw5LDEwLjA4LDEwLjA4LDAsMCwxLDIwLjM0LDE4LjIxWiIvPjxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTE5LjU2LDE3LjY1YTkuMjksOS4yOSwwLDAsMS03LjM1LDMuODMsMS4zMSwxLjMxLDAsMCwxLS4wOC0yLjYyLDYuNTMsNi41MywwLDAsMCw1LTIuOTIsNi4wNSw2LjA1LDAsMCwwLC42Ny01LjUxLDUuMzIsNS4zMiwwLDAsMC0xLjY0LTIuMTYsNS4yMSw1LjIxLDAsMCwwLTIuNDgtMUE1Ljg2LDUuODYsMCwwLDAsOSw4Ljg0TDEwLjc0LDExYS41OS41OSwwLDAsMS0uNDMsMUgyLjdhLjYuNiwwLDAsMS0uNi0uNzVMMy44MSwzLjgzYS41OS41OSwwLDAsMSwxLS4yMWwxLjY3LDIuMWE5LjcxLDkuNzEsMCwwLDEsNy43NS0yLjA3LDguODQsOC44NCwwLDAsMSw0LjEyLDEuOTIsOC42OCw4LjY4LDAsMCwxLDIuNTQsMy43MkE5LjE0LDkuMTQsMCwwLDEsMTkuNTYsMTcuNjVaIi8+PC9zdmc+" + ); + blocksMedia.set( + "rotate-right.svg", + "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48c3ZnIGlkPSJyb3RhdGUtY291bnRlci1jbG9ja3dpc2UiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6IzNkNzljYzt9LmNscy0ye2ZpbGw6I2ZmZjt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPnJvdGF0ZS1jb3VudGVyLWNsb2Nrd2lzZTwvdGl0bGU+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNMjIuNjgsMTIuMmExLjYsMS42LDAsMCwxLTEuMjcuNjNIMTMuNzJhMS41OSwxLjU5LDAsMCwxLTEuMTYtMi41OGwxLjEyLTEuNDFhNC44Miw0LjgyLDAsMCwwLTMuMTQtLjc3LDQuMzEsNC4zMSwwLDAsMC0yLC44LDQuMjUsNC4yNSwwLDAsMC0xLjM0LDEuNzMsNS4wNiw1LjA2LDAsMCwwLC41NCw0LjYyQTUuNTgsNS41OCwwLDAsMCwxMiwxNy43NGgwYTIuMjYsMi4yNiwwLDAsMS0uMTYsNC41MkExMC4yNSwxMC4yNSwwLDAsMSwzLjc0LDE4LDEwLjE0LDEwLjE0LDAsMCwxLDIuMjUsOC43OCw5LjcsOS43LDAsMCwxLDUuMDgsNC42NCw5LjkyLDkuOTIsMCwwLDEsOS42NiwyLjVhMTAuNjYsMTAuNjYsMCwwLDEsNy43MiwxLjY4bDEuMDgtMS4zNWExLjU3LDEuNTcsMCwwLDEsMS4yNC0uNiwxLjYsMS42LDAsMCwxLDEuNTQsMS4yMWwxLjcsNy4zN0ExLjU3LDEuNTcsMCwwLDEsMjIuNjgsMTIuMloiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0yMS4zOCwxMS44M0gxMy43N2EuNTkuNTksMCwwLDEtLjQzLTFsMS43NS0yLjE5YTUuOSw1LjksMCwwLDAtNC43LTEuNTgsNS4wNyw1LjA3LDAsMCwwLTQuMTEsMy4xN0E2LDYsMCwwLDAsNywxNS43N2E2LjUxLDYuNTEsMCwwLDAsNSwyLjkyLDEuMzEsMS4zMSwwLDAsMS0uMDgsMi42Miw5LjMsOS4zLDAsMCwxLTcuMzUtMy44MkE5LjE2LDkuMTYsMCwwLDEsMy4xNyw5LjEyLDguNTEsOC41MSwwLDAsMSw1LjcxLDUuNCw4Ljc2LDguNzYsMCwwLDEsOS44MiwzLjQ4YTkuNzEsOS43MSwwLDAsMSw3Ljc1LDIuMDdsMS42Ny0yLjFhLjU5LjU5LDAsMCwxLDEsLjIxTDIyLDExLjA4QS41OS41OSwwLDAsMSwyMS4zOCwxMS44M1oiLz48L3N2Zz4=" + ); + blocksMedia.set( + "dropdown-arrow.svg", + "data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxMi43MSIgaGVpZ2h0PSI4Ljc5IiB2aWV3Qm94PSIwIDAgMTIuNzEgOC43OSI+PHRpdGxlPmRyb3Bkb3duLWFycm93PC90aXRsZT48ZyBvcGFjaXR5PSIwLjEiPjxwYXRoIGQ9Ik0xMi43MSwyLjQ0QTIuNDEsMi40MSwwLDAsMSwxMiw0LjE2TDguMDgsOC4wOGEyLjQ1LDIuNDUsMCwwLDEtMy40NSwwTDAuNzIsNC4xNkEyLjQyLDIuNDIsMCwwLDEsMCwyLjQ0LDIuNDgsMi40OCwwLDAsMSwuNzEuNzFDMSwwLjQ3LDEuNDMsMCw2LjM2LDBTMTEuNzUsMC40NiwxMiwuNzFBMi40NCwyLjQ0LDAsMCwxLDEyLjcxLDIuNDRaIiBmaWxsPSIjMjMxZjIwIi8+PC9nPjxwYXRoIGQ9Ik02LjM2LDcuNzlhMS40MywxLjQzLDAsMCwxLTEtLjQyTDEuNDIsMy40NWExLjQ0LDEuNDQsMCwwLDEsMC0yYzAuNTYtLjU2LDkuMzEtMC41Niw5Ljg3LDBhMS40NCwxLjQ0LDAsMCwxLDAsMkw3LjM3LDcuMzdBMS40MywxLjQzLDAsMCwxLDYuMzYsNy43OVoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=" + ); + + createBlockContextMenu( + (items) => { + let svgchild = document.querySelector( + "svg.blocklySvg g.blocklyBlockCanvas" + ); + + const pasteItemIndex = items.findIndex((obj) => obj._isDevtoolsFirstItem); + const insertBeforeIndex = + pasteItemIndex !== -1 + ? // If "paste" button exists, add own items before it + pasteItemIndex + : // If there's no such button, insert at end + items.length; + + items.splice( + insertBeforeIndex, + 0, + { + enabled: !!svgchild?.childNodes?.length, + text: "Export All to SVG", + callback: () => { + exportBlock(false); + }, + separator: true, + }, + { + enabled: !!svgchild?.childNodes?.length, + text: "Export All to PNG", + callback: () => { + exportBlock(true); + }, + separator: false, + } + ); + + return items; + }, + { workspace: true } + ); + createBlockContextMenu( + (items, block) => { + 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; + + items.splice( + insertBeforeIndex, + 0, + { + enabled: true, + text: "Export Selected Block to SVG", + callback: () => { + exportBlock(false, block); + }, + separator: true, + }, + { + enabled: true, + text: "Export Selected Block to PNG", + callback: () => { + exportBlock(true, block); + }, + separator: false, + } + ); + + return items; + }, + { blocks: true } + ); + } + + + + function exportBlock(isExportPNG, block) { + let svg; + if (block) { + svg = selectedBlocks(isExportPNG, block); + } else { + svg = allBlocks(isExportPNG); + } + // resolve nbsp whitespace + svg.querySelectorAll("text").forEach((text) => { + text.innerHTML = text.innerHTML.replace(/ /g, " "); + }); + // resolve image path + let scratchURL = window.location.origin; + + svg.querySelectorAll("image").forEach((item) => { + let builtinSvgData = blocksMedia.get( + item + .getAttribute("xlink:href") + .substring(item.getAttribute("xlink:href").lastIndexOf("/") + 1) + ); + if (builtinSvgData) { + // replace svg file path (official) to inline svg + item.setAttribute("xlink:href", builtinSvgData); + } else if (item.getAttribute("xlink:href").indexOf("/static/") === 0) { + // replace link path for third party website + item.setAttribute( + "xlink:href", + scratchURL + item.getAttribute("xlink:href").slice(0) + ); + } else if (item.getAttribute("xlink:href").indexOf("./static/") === 0) { + item.setAttribute( + "xlink:href", + scratchURL + item.getAttribute("xlink:href").slice(1) + ); + } else if (item.getAttribute("xlink:href").indexOf("static/") === 0) { + item.setAttribute( + "xlink:href", + scratchURL + "/" + item.getAttribute("xlink:href") + ); + } + }); + if (!isExportPNG) { + exportData(new XMLSerializer().serializeToString(svg)); + } else { + exportPNG(svg); + } + } + + function selectedBlocks(isExportPNG, block) { + let svg = exSVG.cloneNode(); + + let svgchild = block.svgGroup_; + svgchild = svgchild.cloneNode(true); + let dataShapes = svgchild.getAttribute("data-shapes"); + svgchild.setAttribute( + "transform", + `translate(0,${dataShapes === "hat" ? "18" : "0"}) ${isExportPNG ? "scale(2)" : "" + }` + ); + setCSSVars(svg); + svg.append(makeStyle()); + svg.append(svgchild); + return svg; + } + + function allBlocks(isExportPNG) { + let svg = exSVG.cloneNode(); + + let svgchild = document.querySelector("svg.blocklySvg g.blocklyBlockCanvas"); + svgchild = svgchild.cloneNode(true); + + let xArr = []; + let yArr = []; + + svgchild.childNodes.forEach((g) => { + let x = + g.getAttribute("transform").match(/translate\((.*?),(.*?)\)/)[1] || 0; + let y = + g.getAttribute("transform").match(/translate\((.*?),(.*?)\)/)[2] || 0; + xArr.push(x * (isExportPNG ? 2 : 1)); + yArr.push(y * (isExportPNG ? 2 : 1)); + }); + + svgchild.setAttribute( + "transform", + `translate(${-Math.min(...xArr)},${-Math.min(...yArr) + 18 * (isExportPNG ? 2 : 1) + }) ${isExportPNG ? "scale(2)" : ""}` + ); + setCSSVars(svg); + svg.append(makeStyle()); + svg.append(svgchild); + return svg; + } + + function exportData(text) { + const saveLink = document.createElement("a"); + document.body.appendChild(saveLink); + + const data = new Blob([text], { type: "text" }); + const url = window.URL.createObjectURL(data); + saveLink.href = url; + + const date = new Date(); + const timestamp = `${date.toLocaleDateString()}-${date.toLocaleTimeString()}`; + saveLink.download = `block_${timestamp}.svg`; + saveLink.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(saveLink); + } + + function exportPNG(svg) { + const serializer = new XMLSerializer(); + const iframe = document.createElement("iframe"); + document.body.append(iframe); + iframe.contentDocument.write(serializer.serializeToString(svg)); + let { width, height } = iframe.contentDocument.body + .querySelector("svg g") + .getBoundingClientRect(); + height = height + 20 * 2; + svg.setAttribute("width", width + "px"); + svg.setAttribute("height", height + "px"); + + let canvas = document.createElement("canvas"); + let ctx = canvas.getContext("2d"); + + let img = document.createElement("img"); + + img.setAttribute( + "src", + "data:image/svg+xml;base64," + + btoa(unescape(encodeURIComponent(serializer.serializeToString(svg)))) + ); + img.onload = function () { + canvas.height = img.height; + canvas.width = img.width; + ctx.drawImage(img, 0, 0, img.width, img.height); + let dataURL = canvas.toDataURL("image/png"); + let link = document.createElement("a"); + const date = new Date(); + const timestamp = `${date.toLocaleDateString()}-${date.toLocaleTimeString()}`; + + link.download = `block_${timestamp}.png`; + link.href = dataURL; + link.click(); + iframe.remove(); + }; + } + } +} \ No newline at end of file diff --git a/src/playground/userscripts/catblocks.js b/src/playground/userscripts/catblocks.js new file mode 100644 index 00000000000..6d1d1b0a1a4 --- /dev/null +++ b/src/playground/userscripts/catblocks.js @@ -0,0 +1,266 @@ +module.exports = {func: function () { + if (localStorage.getItem("catblocks") === "true") { + const shouldWatchMouseCursor = !1; + (ScratchBlocks.BlockSvg.START_HAT_HEIGHT = 31), + (ScratchBlocks.BlockSvg.START_HAT_PATH = + "c2.6,-2.3 5.5,-4.3 8.5,-6.2c-1,-12.5 5.3,-23.3 8.4,-24.8c3.7,-1.8 16.5,13.1 18.4,15.4c8.4,-1.3 17,-1.3 25.4,0c1.9,-2.3 14.7,-17.2 18.4,-15.4c3.1,1.5 9.4,12.3 8.4,24.8c3,1.8 5.9,3.9 8.5,6.1"), + (ScratchBlocks.BlockSvg.prototype.renderCatFace_ = function () { + this.catPath_.svgFace.setAttribute("fill", "#000000"); + var t = ScratchBlocks.utils.createSvgElement("path", {}, this.svgFace_); + t.setAttribute( + "d", + "M25.2-1.1c0.1,0,0.2,0,0.2,0l8.3-2.1l-7-4.8c-0.5-0.3-1.1-0.2-1.4,0.3s-0.2,1.1,0.3,1.4L29-4.1l-4,1c-0.5,0.1-0.9,0.7-0.7,1.2C24.3-1.4,24.7-1.1,25.2-1.1z" + ), + t.setAttribute("fill-opacity", "0"), + (this.catPath_.svgFace.closedEye = t); + var e = ScratchBlocks.utils.createSvgElement("path", {}, this.svgFace_); + e.setAttribute( + "d", + "M62.4-1.1c-0.1,0-0.2,0-0.2,0l-8.3-2.1l7-4.8c0.5-0.3,1.1-0.2,1.4,0.3s0.2,1.1-0.3,1.4l-3.4,2.3l4,1c0.5,0.1,0.9,0.7,0.7,1.2C63.2-1.4,62.8-1.1,62.4-1.1z" + ), + e.setAttribute("fill-opacity", "0"), + (this.catPath_.svgFace.closedEye2 = e); + var c = ScratchBlocks.utils.createSvgElement("circle", {}, this.svgFace_); + c.setAttribute("cx", "59.2"), + c.setAttribute("cy", "-3.3"), + c.setAttribute("r", "3.4"), + c.setAttribute("fill-opacity", "0.6"), + (this.catPath_.svgFace.eye = c); + var a = ScratchBlocks.utils.createSvgElement("circle", {}, this.svgFace_); + a.setAttribute("cx", "29.1"), + a.setAttribute("cy", "-3.3"), + a.setAttribute("r", "3.4"), + a.setAttribute("fill-opacity", "0.6"), + (this.catPath_.svgFace.eye2 = a); + var s = ScratchBlocks.utils.createSvgElement("path", {}, this.svgFace_); + s.setAttribute( + "d", + "M45.6,0.1c-0.9,0-1.7-0.3-2.3-0.9c-0.6,0.6-1.3,0.9-2.2,0.9c-0.9,0-1.8-0.3-2.3-0.9c-1-1.1-1.1-2.6-1.1-2.8c0-0.5,0.5-1,1-1l0,0c0.6,0,1,0.5,1,1c0,0.4,0.1,1.7,1.4,1.7c0.5,0,0.7-0.2,0.8-0.3c0.3-0.3,0.4-1,0.4-1.3c0-0.1,0-0.1,0-0.2c0-0.5,0.5-1,1-1l0,0c0.5,0,1,0.4,1,1c0,0,0,0.1,0,0.2c0,0.3,0.1,0.9,0.4,1.2C44.8-2.2,45-2,45.5-2s0.7-0.2,0.8-0.3c0.3-0.4,0.4-1.1,0.3-1.3c0-0.5,0.4-1,0.9-1.1c0.5,0,1,0.4,1.1,0.9c0,0.2,0.1,1.8-0.8,2.8C47.5-0.4,46.8,0.1,45.6,0.1z" + ), + s.setAttribute("fill-opacity", "0.6"), + this.catPath_.ear.setAttribute( + "d", + "M73.1-15.6c1.7-4.2,4.5-9.1,5.8-8.5c1.6,0.8,5.4,7.9,5,15.4c0,0.6-0.7,0.7-1.1,0.5c-3-1.6-6.4-2.8-8.6-3.6C72.8-12.3,72.4-13.7,73.1-15.6z" + ), + this.catPath_.ear.setAttribute("fill", "#FFD5E6"), + this.catPath_.ear2.setAttribute( + "d", + "M22.4-15.6c-1.7-4.2-4.5-9.1-5.8-8.5c-1.6,0.8-5.4,7.9-5,15.4c0,0.6,0.7,0.7,1.1,0.5c3-1.6,6.4-2.8,8.6-3.6C22.8-12.3,23.2-13.7,22.4-15.6z" + ), + this.catPath_.ear2.setAttribute("fill", "#FFD5E6"); + }), + (ScratchBlocks.BlockSvg.prototype.initCatStuff = function () { + if (!this.hasInitCatStuff) { + this.hasInitCatStuff = !0; + var t = "c-1,-12.5 5.3,-23.3 8.4,-24.8c3.7,-1.8 16.5,13.1 18.4,15.4", + e = "c-5.8,-4.8 -8,-18 -4.9,-19.5c3.7,-1.8 24.5,11.1 31.7,10.1", + c = "c1.9,-2.3 14.7,-17.2 18.4,-15.4c3.1,1.5 9.4,12.3 8.4,24.8", + a = "c7.2,1 28,-11.9 31.7,-10.1c3.1,1.5 0.9,14.7 -4.9,19.5", + s = + "c0,-7.1 3.7,-13.3 9.3,-16.9c1.7,-7.5 5.4,-13.2 7.6,-14.2c2.6,-1.3 10,6 14.6,11.1", + i = + "h33c4.6,-5.1 11.9,-12.4 14.6,-11.1c1.9,0.9 4.9,5.2 6.8,11.1c2.6,0,5.2,0,7.8,0", + r = + "c0,-4.6 1.6,-8.9 4.3,-12.3c-2.4,-5.6 -2.9,-12.4 -0.7,-13.4c2.1,-1 9.6,2.6 17,5.8c2.6,0 6.2,0 10.9,0", + o = + "c0,0 25.6,0 44,0c7.4,-3.2 14.8,-6.8 16.9,-5.8c1.2,0.6 1.6,2.9 1.3,5.8", + l = this; + (this.catPath_.ear = ScratchBlocks.utils.createSvgElement( + "path", + {}, + this.catPath_ + )), + (this.catPath_.ear2 = ScratchBlocks.utils.createSvgElement( + "path", + {}, + this.catPath_ + )), + this.RTL && + (this.catPath_.ear.setAttribute("transform", "scale(-1 1)"), + this.catPath_.ear2.setAttribute("transform", "scale(-1 1)")), + this.catPath_.addEventListener("mouseenter", function (t) { + clearTimeout(l.blinkFn), + t.target.svgFace.eye && + (t.target.svgFace.eye.setAttribute("fill-opacity", "0"), + t.target.svgFace.eye2.setAttribute("fill-opacity", "0"), + t.target.svgFace.closedEye.setAttribute("fill-opacity", "0.6"), + t.target.svgFace.closedEye2.setAttribute( + "fill-opacity", + "0.6" + )), + (l.blinkFn = setTimeout(function () { + t.target.svgFace.eye && + (t.target.svgFace.eye.setAttribute("fill-opacity", "0.6"), + t.target.svgFace.eye2.setAttribute("fill-opacity", "0.6"), + t.target.svgFace.closedEye.setAttribute("fill-opacity", "0"), + t.target.svgFace.closedEye2.setAttribute( + "fill-opacity", + "0" + )); + }, 100)); + }), + this.catPath_.ear.addEventListener("mouseenter", function () { + clearTimeout(l.earFn), + clearTimeout(l.ear2Fn), + l.catPath_.ear.setAttribute("fill-opacity", "0"), + l.catPath_.ear2.setAttribute("fill-opacity", ""); + var h = l.catPath_.svgBody.getAttribute("d"); + (h = (h = (h = (h = h.replace(c, a)).replace(i, o)).replace( + e, + t + )).replace(r, s)), + l.catPath_.svgBody.setAttribute("d", h), + (l.earFn = setTimeout(function () { + l.catPath_.ear.setAttribute("fill-opacity", ""); + var t = l.catPath_.svgBody.getAttribute("d"); + (t = (t = t.replace(a, c)).replace(o, i)), + l.catPath_.svgBody.setAttribute("d", t); + }, 50)); + }), + this.catPath_.ear2.addEventListener("mouseenter", function () { + clearTimeout(l.earFn), + clearTimeout(l.ear2Fn), + l.catPath_.ear2.setAttribute("fill-opacity", "0"), + l.catPath_.ear.setAttribute("fill-opacity", ""); + var h = l.catPath_.svgBody.getAttribute("d"); + (h = (h = (h = (h = h.replace(t, e)).replace(s, r)).replace( + a, + c + )).replace(o, i)), + l.catPath_.svgBody.setAttribute("d", h), + (l.ear2Fn = setTimeout(function () { + l.catPath_.ear2.setAttribute("fill-opacity", ""); + var c = l.catPath_.svgBody.getAttribute("d"); + (c = (c = c.replace(e, t)).replace(r, s)), + l.catPath_.svgBody.setAttribute("d", c); + }, 50)); + }), + this.RTL && (this.svgFace_.style.transform = "translate(-87px, 0px)"), + this.shouldWatchMouse() && + ((this.windowListener = function (t) { + var e = Date.now(); + if ( + !(e < l.lastCallTime + l.CALL_FREQUENCY_MS) && + ((l.lastCallTime = e), l.shouldWatchMouse() && l.workspace) + ) { + var c = l.getCatFacePosition(), + a = { + x: t.x / l.workspace.scale, + y: t.y / l.workspace.scale, + }, + s = a.x - c.x, + i = a.y - c.y, + r = Math.atan2(s, i), + o = Math.sqrt(s * s + i * i), + h = o / (o + 1), + n = + 10 / + Math.sqrt( + Math.pow(5 * Math.cos(r), 2) + + Math.pow(2 * Math.sin(r), 2) + ); + (s = n * h * Math.sin(r)), + (i = n * h * Math.cos(r)), + l.RTL && (s -= 87), + (l.svgFace_.style.transform = + "translate(" + s + "px, " + i + "px)"); + } + }), + document.addEventListener("mousemove", this.windowListener)); + } + }); + let workspacePositionRect = null; + (ScratchBlocks.BlockSvg.prototype.getCatFacePosition = function () { + workspacePositionRect || + (workspacePositionRect = this.workspace + .getParentSvg() + .getBoundingClientRect()); + var t = { x: workspacePositionRect.x, y: workspacePositionRect.y }; + !this.isInFlyout && + this.workspace.getFlyout() && + (t.x += this.workspace.getFlyout().getWidth()), + (t.x += this.workspace.scrollX), + (t.y += this.workspace.scrollY); + var e = this.getRelativeToSurfaceXY(this.svgGroup_); + return ( + this.RTL && (e.x = this.workspace.getWidth() - e.x - this.width), + (e.x += t.x / this.workspace.scale), + (e.y += t.y / this.workspace.scale), + (e.x -= 43.5), + (e.y -= 4), + (e.x += 60), + this.RTL && (e.x = screen.width - e.x), + e + ); + }), + (ScratchBlocks.BlockSvg.prototype.shouldWatchMouse = function () { + return !1; + }); + const originalRenderDraw = ScratchBlocks.BlockSvg.prototype.renderDraw_; + ScratchBlocks.BlockSvg.prototype.renderDraw_ = function (...t) { + this.svgFace_ || this.sa_catBlockConstructor(); + const e = originalRenderDraw.call(this, ...t); + return ( + this.outputConnection || this.previousConnection || this.initCatStuff(), + this.startHat_ && !this.svgFace_.firstChild && this.renderCatFace_(), + e + ); + }; + const originalDispose = ScratchBlocks.BlockSvg.prototype.dispose; + ScratchBlocks.BlockSvg.prototype.dispose = function (...t) { + return ( + clearTimeout(this.blinkFn), + clearTimeout(this.earFn), + clearTimeout(this.ear2Fn), + this.windowListener && + document.removeEventListener("mousemove", this.windowListener), + originalDispose.call(this, ...t) + ); + }; + const originalSetGlowStack = ScratchBlocks.BlockSvg.prototype.setGlowStack; + (ScratchBlocks.BlockSvg.prototype.setGlowStack = function (t) { + return ( + this.windowListener && + (t + ? (document.removeEventListener("mousemove", this.windowListener), + this.workspace && + this.svgFace_.style && + (this.RTL + ? (this.svgFace_.style.transform = "translate(-87px, 0px)") + : (this.svgFace_.style.transform = ""))) + : document.addEventListener("mousemove", this.windowListener)), + originalSetGlowStack.call(this, t) + ); + }), + (ScratchBlocks.BlockSvg.prototype.sa_catBlockConstructor = function () { + (this.catPath_ = ScratchBlocks.utils.createSvgElement( + "g", + {}, + this.svgGroup_ + )), + (this.svgFace_ = ScratchBlocks.utils.createSvgElement( + "g", + {}, + this.catPath_ + )), + (this.catPath_.svgFace = this.svgFace_), + (this.catPath_.svgBody = this.svgPath_), + (this.lastCallTime = 0), + (this.CALL_FREQUENCY_MS = 60); + }); + const workspace = ScratchBlocks.getMainWorkspace(); + if (workspace) { + const t = workspace.getFlyout(); + if (t) { + const e = t.getWorkspace(); + ScratchBlocks.Xml.clearWorkspaceAndLoadFromXml( + ScratchBlocks.Xml.workspaceToDom(e), + e + ), + workspace.getToolbox().refreshSelection(), + (workspace.toolboxRefreshEnabled_ = !0); + } + + } + } +}} \ No newline at end of file diff --git a/src/playground/userscripts/cherrypicking.js b/src/playground/userscripts/cherrypicking.js new file mode 100644 index 00000000000..a24c4dbbf59 --- /dev/null +++ b/src/playground/userscripts/cherrypicking.js @@ -0,0 +1,99 @@ +module.exports = { + func: function () { + let enableCherryPicking = localStorage.getItem("cherrypicking") === "true"; + let invertCherryPicking = false; + + let enableDuplication = false; + + + // 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; + + function load() { + if (loaded) { + return; + } + loaded = true; + + // https://github.com/scratchfoundation/scratch-blocks/blob/912b8cc728bea8fd91af85078c64fcdbfe21c87a/core/gesture.js#L454 + const originalStartDraggingBlock = ScratchBlocks.Gesture.prototype.startDraggingBlock_; + ScratchBlocks.Gesture.prototype.startDraggingBlock_ = function (...args) { + 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"; + + 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/scratchfoundation/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); + } + + return originalStartDraggingBlock.call(this, ...args); + }; + } + load(); + } +} \ No newline at end of file diff --git a/src/playground/userscripts/index.js b/src/playground/userscripts/index.js new file mode 100644 index 00000000000..4fbceee64ef --- /dev/null +++ b/src/playground/userscripts/index.js @@ -0,0 +1,77 @@ +const contextMenuCallbacks = []; +const CONTEXT_MENU_ORDER = [ + "editor-devtools", + "block-switching", + "blocks2image", + "swap-local-global", +]; +let createdAnyBlockContextMenus = false; +function createBlockContextMenu( + callback, + { workspace = false, blocks = false, flyout = false, comments = false } = {} +) { + contextMenuCallbacks.push({ + addonId: this._addonId, + callback, + workspace, + blocks, + flyout, + comments, + }); + + contextMenuCallbacks.sort( + (b, a) => + CONTEXT_MENU_ORDER.indexOf(b.addonId) - + CONTEXT_MENU_ORDER.indexOf(a.addonId) + ); + + if (createdAnyBlockContextMenus) return; + createdAnyBlockContextMenus = true; + + const oldShow = ScratchBlocks.ContextMenu.show; + ScratchBlocks.ContextMenu.show = function (event, items, rtl) { + const gesture = ScratchBlocks.mainWorkspace.currentGesture_; + const block = gesture.targetBlock_; + + for (const { + callback, + workspace, + blocks, + flyout, + comments, + } of contextMenuCallbacks) { + let injectMenu = + // Workspace + (workspace && !block && !gesture.flyout_ && !gesture.startBubble_) || + // Block in workspace + (blocks && block && !gesture.flyout_) || + // Block in flyout + (flyout && gesture.flyout_) || + // Comments + (comments && gesture.startBubble_); + if (injectMenu) { + try { + items = callback(items, block); + } catch (e) { + console.error("Error while calling context menu callback: ", e); + } + } + } + + oldShow.call(this, event, items, rtl); + + const blocklyContextMenu = ScratchBlocks.WidgetDiv.DIV.firstChild; + items.forEach((item, i) => { + if (i !== 0 && item.separator) { + const itemElt = blocklyContextMenu.children[i]; + itemElt.style.paddingTop = "2px"; + itemElt.style.borderTop = "1px solid hsla(0, 0%, 0%, 0.15)"; + } + }); + }; +} + +require("./catblocks").func(); +require("./numberpad").func(); +require("./blocks2image").func(createBlockContextMenu); +require("./cherrypicking").func(); \ No newline at end of file diff --git a/src/playground/userscripts/numberpad.js b/src/playground/userscripts/numberpad.js new file mode 100644 index 00000000000..5b6294f3e5f --- /dev/null +++ b/src/playground/userscripts/numberpad.js @@ -0,0 +1,11 @@ +module.exports = { + func: function () { + if (localStorage.getItem("numberpad") === "true") { + const originalShowEditor_ = ScratchBlocks.FieldNumber.prototype.showEditor_; + ScratchBlocks.FieldNumber.prototype.showEditor_ = function (...args) { + this.useTouchInteraction_ = true; + return originalShowEditor_.apply(this, args); + }; + } + } +} \ No newline at end of file diff --git a/static/favicon.ico b/static/favicon.ico deleted file mode 100644 index 7a4cf69ed41a7ea3e21aa15f38c125613d8e223b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34494 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 diff --git a/static/favicon.png b/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c6542f87c58f4fac2669f49a5dc9d1b61596726f GIT binary patch literal 50380 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 { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/monitor-variable.sb3')); // Monitors are present diff --git a/test/integration/menu-bar.test.js b/test/integration/menu-bar.test.js index 45d6ec4e7c9..e87047bc1ba 100644 --- a/test/integration/menu-bar.test.js +++ b/test/integration/menu-bar.test.js @@ -45,7 +45,7 @@ describe('Menu bar settings', () => { test('File->Save should be enabled', async () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); - await findByXpath('//*[li[span[text()="Save to your computer"]] and not(@data-tip="tooltip")]'); + await findByXpath('//*[li[span[text()="Save to your computer (.sbpp)"]] and not(@data-tip="tooltip")]'); }); test('Share button should NOT be enabled', async () => { @@ -72,7 +72,7 @@ describe('Menu bar settings', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/project1.sb3')); // No replace alert since no changes were made await findByText('project1-sprite'); @@ -87,7 +87,7 @@ describe('Menu bar settings', () => { await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/project1.sb3')); await driver.switchTo().alert() .accept(); diff --git a/test/integration/sb-file-uploader-hoc.test.js b/test/integration/sb-file-uploader-hoc.test.js index 1b38f4978d7..037b698c009 100644 --- a/test/integration/sb-file-uploader-hoc.test.js +++ b/test/integration/sb-file-uploader-hoc.test.js @@ -30,7 +30,7 @@ describe('Loading scratch gui', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/project1.sb3')); await findByText('project1-sprite'); // this test will fail if an alert appears, e.g. in SBFileUploaderHOC's onload() function @@ -40,7 +40,7 @@ describe('Loading scratch gui', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/project1.sb3')); await findByText('project1-sprite'); await clickXpath('//input[@value="project1"]'); @@ -50,7 +50,7 @@ describe('Loading scratch gui', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/missing-sprite-svg.sb3')); const spriteTile = await findByText('Blue Square Guy'); const tileVisible = await spriteTile.isDisplayed(); @@ -61,7 +61,7 @@ describe('Loading scratch gui', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/corrupt-svg.sb3')); const spriteTile = await findByText('Blue Square Guy'); const tileVisible = await spriteTile.isDisplayed(); @@ -72,7 +72,7 @@ describe('Loading scratch gui', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/missing-svg.sb2')); const spriteTile = await findByText('Blue Guy'); const tileVisible = await spriteTile.isDisplayed(); @@ -83,7 +83,7 @@ describe('Loading scratch gui', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/corrupt-svg.sb2')); const spriteTile = await findByText('Blue Guy'); const tileVisible = await spriteTile.isDisplayed(); @@ -94,7 +94,7 @@ describe('Loading scratch gui', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/missing-bmp.sb3')); const spriteTile = await findByText('green-bmp-guy'); const tileVisible = await spriteTile.isDisplayed(); @@ -105,7 +105,7 @@ describe('Loading scratch gui', () => { await loadUri(uri); await clickXpath(FILE_MENU_XPATH); await clickText('Load from your computer'); - const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3"]'); + const input = await findByXpath('//input[@accept=".sb,.sb2,.sb3,.sbpp"]'); await input.sendKeys(path.resolve(__dirname, '../fixtures/corrupt-bmp.sb3')); const spriteTile = await findByText('green-bmp-guy'); const tileVisible = await spriteTile.isDisplayed(); diff --git a/webpack.config.js b/webpack.config.js index c692777f4c8..63360699d3e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -166,25 +166,25 @@ module.exports = [ new HtmlWebpackPlugin({ chunks: ['lib.min', 'gui'], template: 'src/playground/index.ejs', - title: 'Scratch 3.0 GUI' + title: 'Scratch++ GUI' }), new HtmlWebpackPlugin({ chunks: ['lib.min', 'blocksonly'], template: 'src/playground/index.ejs', filename: 'blocks-only.html', - title: 'Scratch 3.0 GUI: Blocks Only Example' + title: 'Scratch++ GUI: Blocks Only Example' }), new HtmlWebpackPlugin({ chunks: ['lib.min', 'compatibilitytesting'], template: 'src/playground/index.ejs', filename: 'compatibility-testing.html', - title: 'Scratch 3.0 GUI: Compatibility Testing' + title: 'Scratch++ GUI: Compatibility Testing' }), new HtmlWebpackPlugin({ chunks: ['lib.min', 'player'], template: 'src/playground/index.ejs', filename: 'player.html', - title: 'Scratch 3.0 GUI: Player Example' + title: 'Scratch++ GUI: Player Example' }), new CopyWebpackPlugin({ patterns: [