Spaces:
Running
Running
| const workspace = Blockly.inject(`blocklyDiv`, { | |
| toolbox: document.getElementById(`toolbox`), | |
| renderer: `zelos`, | |
| move: { wheel: true }, | |
| zoom: { | |
| controls: true, | |
| startScale: 0.7, | |
| maxScale: 3, | |
| minScale: 0.3, | |
| scaleSpeed: 1.2, | |
| pinch: true | |
| }, | |
| grid: { | |
| spacing: 40, | |
| length: 3, | |
| colour: '#ccc', | |
| snap: true | |
| }, | |
| trashcan: false, | |
| ADD_START_HATS: true, | |
| theme: Blockly.Theme.defineTheme('mmm', { | |
| 'blockStyles': { | |
| 'motion': { | |
| 'colourPrimary': `#5597fc`, | |
| 'colourSecondary': `#3b73ca` | |
| }, | |
| 'looks': { | |
| 'colourPrimary': `#9a65fc`, | |
| 'colourSecondary': `#784cc9` | |
| }, | |
| 'sound': { | |
| 'colourPrimary': `#ce62cd`, | |
| 'colourSecondary': `#bb40bb` | |
| }, | |
| 'events': { | |
| 'colourPrimary': `#fcbf29`, | |
| 'colourSecondary': `#ca991f` | |
| }, | |
| 'control': { | |
| 'colourPrimary': `#fcaa2f`, | |
| 'colourSecondary': `#cd8a27` | |
| }, | |
| 'sensing': { | |
| 'colourPrimary': `#62b1d4`, | |
| 'colourSecondary': `#388eb6` | |
| }, | |
| 'operators': { | |
| 'colourPrimary': `#5dc05d`, | |
| 'colourSecondary': `#3c943c` | |
| }, | |
| 'variables': { | |
| 'colourPrimary': `#fc8b2d`, | |
| 'colourSecondary': `#d86d1b` | |
| }, | |
| 'data': { | |
| 'colourPrimary': `#fb642a`, | |
| 'colourSecondary': `#e34b1a` | |
| } | |
| }, | |
| 'componentStyles': { | |
| 'workspaceBackgroundColour': `#f9f9f9`, | |
| 'toolboxBackgroundColour': `#ffffff`, | |
| 'toolboxForegroundColour': `6f6f6f`, | |
| 'flyoutBackgroundColour': `#f9f9f9` | |
| }, | |
| 'startHats': true | |
| }) | |
| }); | |
| workspace.registerButtonCallback(`createVar`, Button => { | |
| Blockly.Variables.createVariableButtonHandler(Button.getTargetWorkspace(), null, ``); | |
| }); | |
| const style = document.getElementsByTagName(`style`)[0]; | |
| style.textContent = style.textContent.replace(/\.blocklyText/g, ``); | |
| const sideBtns = /** @type { HTMLCollectionOf<HTMLButtonElement> } */ (document.getElementsByClassName(`sideBtn`)); | |
| const cosBtn = /** @type { HTMLButtonElement } */ (document.getElementById(`cosBtn`)); | |
| const coses = /** @type { HTMLDivElement } */ (document.getElementById(`costumes`)); | |
| let costumes = []; | |
| const reloadCos = () => { | |
| [...coses.childNodes].forEach(v => { if (v.nodeName == `DIV`) v.remove() }); | |
| for (let i = 0; i < costumes.length; i++) { | |
| const div = document.createElement(`div`); | |
| const div2 = document.createElement(`div`); | |
| const div3 = document.createElement(`div`); | |
| const img = document.createElement(`img`); | |
| div.classList.add(`cos`); | |
| div2.textContent = i + 1; | |
| img.src = costumes[i]; | |
| div3.appendChild(img); | |
| div.append(div2, div3); | |
| div.addEventListener(`click`, () => { | |
| if (confirm(`削除しますか?`)) { | |
| costumes.splice(costumes.indexOf(div.childNodes[1].childNodes[0].src), 1); | |
| reloadCos(); | |
| } | |
| }); | |
| coses.appendChild(div); | |
| } | |
| } | |
| const addCos = () => { | |
| const file = document.createElement(`input`); | |
| file.accept = `.png`; | |
| file.type = `file`; | |
| file.click(); | |
| file.addEventListener(`change`, () => { | |
| const fileReader = new FileReader(); | |
| fileReader.addEventListener(`load`, () => { | |
| costumes.push(fileReader.result); | |
| reloadCos(); | |
| }); | |
| fileReader.readAsDataURL(file.files[0]); | |
| }); | |
| } | |
| const sb3 = async () => { | |
| fetch(`/api/check`) | |
| .then(res => res.text()) | |
| .then(resData => { | |
| if (resData == `"ok"`) { | |
| fetch(`/api/sb3`, { | |
| method: `POST`, | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ text: JSON.stringify([Blockly.JavaScript.workspaceToCode(workspace).split('$')[1], ...costumes]) }) | |
| }) | |
| .then(data => data.json()) | |
| .then(sb3Base64 => { | |
| const sb3Data = Uint8Array.from(atob(sb3Base64), c => c.charCodeAt(0)); | |
| const a = document.createElement('a'); | |
| a.href = URL.createObjectURL(new Blob([sb3Data], { type: 'application/x-scratch-project' })); | |
| a.download = 'project.sb3'; | |
| a.click(); | |
| }); | |
| } else alert(`.sb3 出力中のユーザーがいるため、時間を空けてから押してください`); | |
| }) | |
| }; | |
| const save = async () => { | |
| fetch(`/api/save`, { | |
| method: `POST`, | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ text: JSON.stringify([Blockly.Xml.domToText(Blockly.Xml.workspaceToDom(workspace)), Blockly.JavaScript.workspaceToCode(workspace), ...costumes]) }) | |
| }) | |
| .then(data => data.json()) | |
| .then(base64Zip => { | |
| const zipData = Uint8Array.from(atob(base64Zip), c => c.charCodeAt(0)); | |
| const a = document.createElement(`a`); | |
| a.href = URL.createObjectURL(new Blob([zipData], { type: `application/zip` })); | |
| a.download = `project.mf4`; | |
| a.click(); | |
| }); | |
| }; | |
| const load = async () => { | |
| const file = document.createElement(`input`); | |
| file.type = `file`; | |
| file.accept = `.mf4`; | |
| file.click(); | |
| file.addEventListener(`change`, async () => { | |
| const fileReader = new FileReader(); | |
| fileReader.addEventListener(`load`, async () => { | |
| const base64Data = btoa(String.fromCharCode.apply(null, new Uint8Array(fileReader.result))); | |
| fetch(`/api/load`, { | |
| method: `post`, | |
| headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify({ text: base64Data }) | |
| }) | |
| .then(res => res.json()) | |
| .then(data => { | |
| const dom = (new DOMParser()).parseFromString(data[0], `application/xml`); | |
| workspace.clear(); | |
| Blockly.Xml.domToWorkspace(dom.documentElement, workspace); | |
| costumes = data.slice(2, data.length); | |
| reloadCos(); | |
| }); | |
| }); | |
| fileReader.readAsArrayBuffer(file.files[0]); | |
| }); | |
| } | |
| cosBtn.addEventListener(`click`, addCos); | |
| sideBtns[0].addEventListener(`click`, sb3); | |
| sideBtns[1].addEventListener(`click`, save); | |
| sideBtns[2].addEventListener(`click`, load); |