horiyouta's picture
2410232053
c3de7ac
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);