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 } */ (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);