82 lines
3.2 KiB
HTML
82 lines
3.2 KiB
HTML
<!doctype html><html lang="ja"><head><meta charset="utf-8" />
|
|
<style>
|
|
body{font:14px system-ui;margin:0;padding:16px}
|
|
.row{display:flex;gap:8px;align-items:center;margin-bottom:8px}
|
|
ul{list-style:none;padding:0;margin:0}
|
|
li[data-testid="file-item"]{cursor:pointer;padding:4px 8px;border-radius:4px;background:#f0f0f0;margin-bottom:4px}
|
|
li[data-testid="file-item"]:hover{background:#dce8ff}
|
|
pre[data-testid="preview"]{background:#f9f9f9;border:1px solid #ddd;padding:12px;overflow:auto;max-height:50vh;white-space:pre-wrap}
|
|
table{border-collapse:collapse;width:100%}
|
|
table th,table td{border:1px solid #ccc;padding:4px 8px;text-align:left}
|
|
table th{background:#eee}
|
|
</style></head>
|
|
<body>
|
|
<div class="row">
|
|
<input id="dir" data-testid="dir" value="output" style="flex:1" />
|
|
<button id="listBtn" data-testid="list">一覧取得</button>
|
|
<span id="status" data-testid="status"></span>
|
|
</div>
|
|
<ul id="files" data-testid="files"></ul>
|
|
<div id="preview-wrap"></div>
|
|
<script>
|
|
let seq=0;const pending=new Map();
|
|
function call(req){return new Promise((res,rej)=>{const id=++seq;pending.set(id,{res,rej});
|
|
window.parent.postMessage({...req,id},'*');});}
|
|
window.addEventListener('message',e=>{const r=e.data;const p=pending.get(r&&r.id);if(!p)return;
|
|
pending.delete(r.id);r.ok?p.res(r.data):p.rej(new Error(r.error));});
|
|
const $=id=>document.getElementById(id);
|
|
|
|
function renderCsv(text){
|
|
const rows=text.trim().split('\n').map(r=>r.split(','));
|
|
const table=document.createElement('table');
|
|
rows.forEach((cols,i)=>{const tr=document.createElement('tr');
|
|
cols.forEach(c=>{const cell=document.createElement(i===0?'th':'td');cell.textContent=c;tr.appendChild(cell);});
|
|
table.appendChild(tr);});
|
|
return table;
|
|
}
|
|
|
|
async function listDir(){
|
|
const dir=$('dir').value.trim()||'output';
|
|
$('status').textContent='取得中…';
|
|
$('files').innerHTML='';
|
|
$('preview-wrap').innerHTML='';
|
|
try{
|
|
const d=await call({type:'listFiles',dir});
|
|
const entries=d.entries||[];
|
|
if(entries.length===0){$('files').innerHTML='<li>(ファイルなし)</li>';}
|
|
entries.forEach(name=>{
|
|
const li=document.createElement('li');
|
|
li.setAttribute('data-testid','file-item');
|
|
li.textContent=name;
|
|
li.onclick=()=>openFile(dir,name);
|
|
$('files').appendChild(li);
|
|
});
|
|
$('status').textContent='取得OK';
|
|
}catch(err){$('status').textContent='エラー:'+err.message;}
|
|
}
|
|
|
|
async function openFile(dir,name){
|
|
$('status').textContent='読込中…';
|
|
$('preview-wrap').innerHTML='';
|
|
try{
|
|
const path=dir.replace(/\/$/,'')+'/'+name;
|
|
const d=await call({type:'readFile',path});
|
|
const content=d.content||'';
|
|
if(name.endsWith('.csv')){
|
|
const wrap=document.createElement('div');
|
|
wrap.setAttribute('data-testid','preview');
|
|
wrap.appendChild(renderCsv(content));
|
|
$('preview-wrap').appendChild(wrap);
|
|
}else{
|
|
const pre=document.createElement('pre');
|
|
pre.setAttribute('data-testid','preview');
|
|
pre.textContent=content;
|
|
$('preview-wrap').appendChild(pre);
|
|
}
|
|
$('status').textContent='読込OK';
|
|
}catch(err){$('status').textContent='読込失敗:'+err.message;}
|
|
}
|
|
|
|
$('listBtn').onclick=listDir;
|
|
</script></body></html>
|