nadesiko3
Version:
Japanese Programming Language
162 lines (147 loc) • 6.06 kB
HTML
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Nadesiko3 Editor</title>
<link rel="stylesheet" href="../src/wnako3_editor.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ace.js" integrity="sha512-GZ1RIgZaSc8rnco/8CXfRdCpDxRCphenIiZ2ztLy3XQfCbQUSCuk8IudvNHxkRA3oUg6q0qejgN/qqyG1duv5Q==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-language_tools.min.js" integrity="sha512-8qx1DL/2Wsrrij2TWX5UzvEaYOFVndR7BogdpOyF4ocMfnfkw28qt8ULkXD9Tef0bLvh3TpnSAljDC7uyniEuQ==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-options.min.js" integrity="sha512-oHR+WVzBiVZ6njlMVlDDLUIOLRDfUUfRQ55PfkZvgjwuvGqL4ohCTxaahJIxTmtya4jgyk0zmOxDMuLzbfqQDA==" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.12/ext-code_lens.min.js" integrity="sha512-gsDyyKTnOmSWRDzUbpYcPjzVsEyFGSWeWefzVKvbMULPR2ElIlKKsOtU3ycfybN9kncZXKLFSsUiG3cgJUbc/g==" crossorigin="anonymous"></script>
<script src="../release/wnako3.js"></script>
<script src="../release/version.js"></script>
<script src="../release/plugin_markup.js"></script>
<script src="../release/plugin_csv.js"></script>
<script src="../release/plugin_kansuji.js"></script>
<script src="../release/plugin_datetime.js"></script>
<script src="../release/plugin_turtle.js"></script>
<script src="../release/plugin_caniuse.js"></script>
<script src="../release/plugin_webworker.js"></script>
<!-- mochaを一番最後に読み込む必要がある -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mocha/8.3.0/mocha.min.js" integrity="sha512-LA/TpBXau/JNubKzHQhdi5vGkRLyQjs1vpuk2W1nc8WNgf/pCqBplD8MzlzeKJQTZPvkEZi0HqBDfRC2EyLMXw==" crossorigin="anonymous"></script>
<style>
/* ボタンの高さを揃える */
.toolbar button, .toolbar input {
font-size: 12px;
height: 28px;
margin: 0;
padding: 0;
box-sizing: border-box;
vertical-align: top;
}
/* 出力の文字サイズと文字色 */
#output {
font-size: 13px;
color: rgb(77, 77, 77);
}
</style>
</head>
<body>
<div class="toolbar">
<button id="add">📁 ファイルを追加</button>
<button id="remove">🗑 ファイルを削除</button>
<span id="file-list"></span>
</div>
<div id="editor" data-nako3-resizable="true"></div>
<div class="toolbar">
<button id="run">表示中のファイルを実行</button>
</div>
<div id="output"></div>
<script>
/** @type {import('../src/wnako3.js')} */
const nako3 = navigator.nako3
const { editor, editorMarkers, editorTabs, retokenize, run, codeLensListeners } = nako3.setupEditor('editor')
/** @type {Map<number, HTMLButtonElement>} */
const tabButtons = new Map()
/** @type {Map<number, import('../src/wnako3_editor.js').EditorTabState>} */
const hiddenTabStates = new Map()
let fileCount = 0
let activeFile = 1
// タブの切り替え
const switchTab = (fileName) => {
hiddenTabStates.set(activeFile, editorTabs.getTab())
editorTabs.setTab(hiddenTabStates.get(fileName))
activeFile = fileName
}
// ファイルの追加
const addFile = () => {
const id = ++fileCount
// <button class="file">{id}.nako3</button> を挿入する。
const button = document.createElement('button')
button.innerText = id + '.nako3'
button.classList.add('file')
button.addEventListener('click', () => {
tabButtons.get(activeFile).disabled = false
button.disabled = true
switchTab(id)
})
document.getElementById('file-list').appendChild(button)
tabButtons.set(id, button)
// エディタの状態を生成
hiddenTabStates.set(id, editorTabs.newTab(`// ${id}.nako3\n`))
}
document.getElementById('add').addEventListener('click', () => { addFile() })
// ファイルの削除
const removeFile = () => {
if (tabButtons.size <= 1) {
alert('全てのファイルを削除することはできません。')
return
}
const input = prompt('削除するファイル名を指定してください。', tabButtons.size + '.nako3')
if (input === null) {
return
}
const id = +input.replace(/\.nako3$/, '')
if (!Number.isInteger(id)) {
alert(`${id}.nako3 は存在しません。`)
return
}
if (id === activeFile) {
alert(`表示中のファイルは削除できません。`)
return
}
document.getElementById('file-list').removeChild(tabButtons.get(id))
tabButtons.delete(id)
}
document.getElementById('remove').addEventListener('click', () => { removeFile() })
// 実行
document.getElementById('run').addEventListener('click', () => {
/** @type {Record<string, string>} */
const localFiles = {}
for (const [k, v] of hiddenTabStates) {
localFiles[`${k}.nako3`] = v.content
}
run({ outputContainer: document.getElementById('output'), file: `${activeFile}.nako3`, localFiles })
})
// テスト実行
codeLensListeners.push({
name: 'test',
callback: (/** @type {string | undefined} */testName) => {
/** @type {Record<string, string>} */
const localFiles = {}
for (const [k, v] of hiddenTabStates) {
localFiles[`${k}.nako3`] = v.content
}
run({ outputContainer: document.getElementById('output'), file: `${activeFile}.nako3`, localFiles, method: 'test', testName })
},
})
// 1.nako3の値を設定する
addFile()
tabButtons.get(1).disabled = true
editor.setValue(`\
!「2.nako3」を取り込む
「1.nako3」を表示
Aを表示
`)
editor.session.selection.clearSelection()
// 2.nako3の値を設定する
addFile()
hiddenTabStates.get(2).content = `\
「2.nako3」を表示
A=2
`
</script>
</body>
</html>