diff --git a/packages/hydrooj/src/lib/avatar.ts b/packages/hydrooj/src/lib/avatar.ts index 69223f509..ca51480e8 100644 --- a/packages/hydrooj/src/lib/avatar.ts +++ b/packages/hydrooj/src/lib/avatar.ts @@ -9,8 +9,11 @@ export const providers: Record = { url: (url) => url, }; -function avatar(src: string, size = 64) { - const index = (src || '').indexOf(':'); +function avatar(src: string, size = 64, fallback = '') { + src = src || fallback; + let index = src.indexOf(':'); + if (index === -1) src = fallback; + index = src.indexOf(':'); if (index === -1) return providers.gravatar('', size); const [provider, str] = [src.substr(0, index), src.substr(index + 1, src.length)]; if (!providers[provider] || !str) return providers.gravatar('', size); diff --git a/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx b/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx index 1ad635fcb..8b990e268 100644 --- a/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx +++ b/packages/ui-default/components/scratchpad/ScratchpadEditorContainer.jsx @@ -22,9 +22,22 @@ const mapDispatchToProps = (dispatch) => ({ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor extends React.PureComponent { disposable = []; + blockly = false; + componentDidMount() { const value = this.props.value || ''; const { language, theme } = this.props; + if (this.props.language === 'blockly') { + if (!this.blockly) { + import('./blockly.jsx').then(({ default: Blockly }) => { + if (!this.blockly) return; + Blockly.inject(this.containerElement, { + }); + }); + } + this.blockly = true; + return; + } this.model = monaco.editor.createModel(value, language, monaco.Uri.parse('file://model')); if (this.containerElement) { /** @type {monaco.editor.IStandaloneEditorConstructionOptions} */ @@ -49,11 +62,23 @@ export default connect(mapStateToProps, mapDispatchToProps)(class MonacoEditor e localStorage.setItem('scratchpad.editor.fontSize', current); }) ); - window.editor = this.editor; } } componentDidUpdate(prevProps) { + if (this.props.language === 'blockly') { + if (!this.blockly) { + this.editor.dispose(); + import('./blockly.jsx').then(({ default: Blockly, toolbox }) => { + if (!this.blockly) return; + Blockly.inject(this.containerElement, { + toolbox, + }); + }); + } + this.blockly = true; + return; + } const { value, language, theme, mainSize, recordSize, pretestSize, } = this.props; diff --git a/packages/ui-default/components/scratchpad/blockly.jsx b/packages/ui-default/components/scratchpad/blockly.jsx new file mode 100644 index 000000000..22023c9dd --- /dev/null +++ b/packages/ui-default/components/scratchpad/blockly.jsx @@ -0,0 +1,337 @@ +import ReactDOMServer from 'react-dom/server'; +import * as Blockly from 'blockly/core'; +import 'blockly/blocks'; +import 'blockly/python'; +import 'blockly/javascript'; +import 'blockly/php'; +import * as zhHans from 'blockly/msg/zh-hans'; +import * as zhHant from 'blockly/msg/zh-hant'; +import * as ko from 'blockly/msg/ko'; +import * as en from 'blockly/msg/en'; + +const locales = { + zh: zhHans, + zh_CN: zhHans, + zh_TW: zhHant, + ko, + ko_KR: ko, + en, + en_US: en, +}; + +Blockly.setLocale(locales[UserContext.viewLang] || locales.en); + +export default Blockly; +export const toolbox = ReactDOMServer.renderToString( + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + i + + + 1 + + + + + 10 + + + + + 1 + + + + + + + + + 123 + + + + + + + + + + + + + 1 + + + + + 100 + + + + + + + 1 + + + + + 100 + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + randomize + + + x + + + 1 + + + + + + + list + + + + + + + 1 + + + + + y + + + + + 1 + + + + + + + list + + + + + + + + + temp + + + + GET + FROM_START + + + y + + + + + list + + + + + + + + + y + + + + + list + + + + + + GET + FROM_START + + + x + + + + + list + + + + + + + + + x + + + + + list + + + + + temp + + + + + + + + + + + + + + + + + + + 'Twas brillig, and the slithy toves + + + + + + + Did gyre and gimble in the wabe: + + + + + + + All mimsy were the borogroves, + + + + + + + And the mome raths outgrabe. + + + + + + + + + + + + + "Beware the Jabberwock, my son! + + + + + + + The jaws that bite, the claws that catch! + + + + + + + Beware the Jubjub bird, and shun + + + + + + + The frumious Bandersnatch!" + + + + + + + + + + + + +); diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 2af631aa4..bb0b75140 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -23,6 +23,7 @@ "@babel/preset-react": "^7.14.5", "@babel/register": "^7.14.5", "@babel/runtime-corejs3": "^7.14.7", + "@blockly/block-extension-tooltip": "^1.0.13", "@blueprintjs/core": "^3.47.0", "@blueprintjs/icons": "^3.27.0", "@blueprintjs/select": "^3.16.6", @@ -35,6 +36,7 @@ "babel-loader": "^8.2.2", "babel-plugin-lodash": "^3.3.4", "babel-plugin-prismjs": "^2.1.0", + "blockly": "^6.20210701.0", "chalk": "^4.1.1", "classnames": "^2.3.1", "clipboard": "^2.0.8", diff --git a/packages/vjudge/package.json b/packages/vjudge/package.json index a0a8ef3e1..c88d0488e 100644 --- a/packages/vjudge/package.json +++ b/packages/vjudge/package.json @@ -11,8 +11,7 @@ "@hydrooj/utils": "workspace:*", "jsdom": "^16.6.0", "superagent": "^6.1.0", - "superagent-proxy": "^2.1.0", - "turndown": "^7.1.1" + "superagent-proxy": "^2.1.0" }, "devDependencies": { "@types/jsdom": "^16.2.13",