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); |