動画ライブラリ | エマナス
VIDEO LIBRARY

動画ライブラリ
find what you need、すぐに。

救急看護の基本から指導者向けコンテンツまで。STEP・テーマ・キーワードで絞り込んで、いま必要な一本にたどり着きます。

0
ALL
0
STEP1
0
STEP2
0
STEP3
STEP
テーマ
0件のコンテンツ
新着順
(c) 2026 エマナス Video Library Mockup
', '
' + (ICONS[v.icon] || ICONS.heart) + '
', '' + v.num + '', '
' + badges + '
', duration, '
', '
', '
', '' + stepLabel(v.step) + '', '' + esc(v.themes[0] || '') + '', '
', '

' + esc(v.title) + '

', '
' + tags + '
', '', '
', '' + tag + '>' ].join(''); } function applyFilters() { var list = videos.slice(); if (state.step !== 'all') { var s = parseInt(state.step, 10); list = list.filter(function(v) { return v.step === s; }); } var activeThemes = Object.keys(state.themes); if (activeThemes.length > 0) { list = list.filter(function(v) { return v.themes.some(function(t) { return state.themes[t]; }); }); } var q = state.search.trim().toLowerCase(); if (q) { list = list.filter(function(v) { return v.title.toLowerCase().indexOf(q) !== -1 || (v.instructor || '').toLowerCase().indexOf(q) !== -1 || v.themes.some(function(t) { return t.toLowerCase().indexOf(q) !== -1; }); }); } if (state.sort === 'new') list.sort(function(a, b) { return new Date(b.date) - new Date(a.date); }); else if (state.sort === 'step') list.sort(function(a, b) { return a.step - b.step || new Date(b.date) - new Date(a.date); }); else if (state.sort === 'popular') list.sort(function(a, b) { return b.popularity - a.popularity; }); else if (state.sort === 'duration') list.sort(function(a, b) { return (a.duration || 9999) - (b.duration || 9999); }); return list; } function renderGrid() { var list = applyFilters(); var grid = document.getElementById('grid'); document.getElementById('resultCount').textContent = list.length; var parts = []; if (state.step !== 'all') parts.push('STEP' + state.step); var activeThemes = Object.keys(state.themes); if (activeThemes.length) parts.push(activeThemes.join('・')); if (state.search.trim()) parts.push('「' + state.search.trim() + '」'); var sortLabels = { new: '新着順', step: 'STEP順', popular: '人気順', duration: '短い順' }; document.getElementById('activeFilters').textContent = (parts.length ? parts.join(' / ') + ' ・ ' : '') + sortLabels[state.sort]; if (list.length === 0) { grid.innerHTML = '
該当するコンテンツが見つかりません
フィルターや検索条件を変更してみてください
'; return; } grid.innerHTML = list.map(cardHTML).join(''); } function refresh() { updateStats(); renderChips(); Object.keys(state.themes).forEach(function(t) { if (!uniqueThemes().indexOf(t) === -1) delete state.themes[t]; }); renderGrid(); } // ========== Parse ========== function parseInput(text) { var lines = text.split(/\r?\n/); var rows = []; var errors = []; lines.forEach(function(rawLine, i) { var line = rawLine.trim(); if (!line) return; if (i === 0 && /タイトル|title/i.test(line) && /STEP|step|テーマ|theme/i.test(line)) return; if (line.charAt(0) === '#' || line.indexOf('//') === 0) return; var sep = '\t'; if (line.indexOf('\t') !== -1) sep = '\t'; else if (line.indexOf('|') !== -1) sep = '|'; else if (line.indexOf(',') !== -1) sep = ','; var parts = line.split(sep).map(function(p) { return p.trim(); }); if (!parts[0]) { errors.push({ line: i + 1, text: line, reason: 'タイトルが空' }); return; } var step = 2; if (parts[1]) { var n = parseInt(String(parts[1]).replace(/[^0-9]/g, ''), 10); if (!isNaN(n) && n >= 0 && n ' + errors.length + '件読み込めない行: '; errHTML += errors.slice(0, 3).map(function(e) { return '行' + e.line; }).join(', ') + '
'; } var items = rows.map(function(r) { return '
' + '' + stepLabel(r.step) + '' + '' + esc(r.title) + '' + '' + esc(r.themes.join('・') || '—') + '' + '' + (r.duration ? r.duration + '分' : '—') + '' + '' + esc(r.date) + '' + '
'; }).join(''); box.innerHTML = '
' + '
プレビュー' + rows.length + '
' + '
' + items + '
' + errHTML + '
' + '
'; var applyBtn = document.getElementById('applyBtn'); if (applyBtn) { applyBtn.addEventListener('click', function() { var mode = document.querySelector('input[name="mode"]:checked').value; if (mode === 'replace') { videos = parsedRows.map(function(r, i) { return enrich(r, i); }); } else { var start = videos.length; videos = videos.concat(parsedRows.map(function(r, i) { return enrich(r, start + i); })); } save(); refresh(); toast(parsedRows.length + '件を反映しました'); closeModal(); document.getElementById('pasteArea').value = ''; box.innerHTML = ''; }); } } function renderEditTable() { var tbody = document.getElementById('editTableBody'); tbody.innerHTML = videos.map(function(v, i) { return '' + '' + '' + '' + '' + '' + '' + '' + ''; }).join(''); Array.prototype.forEach.call(tbody.querySelectorAll('.row-del'), function(btn) { btn.addEventListener('click', function(e) { var tr = e.currentTarget.closest('tr'); var idx = parseInt(tr.getAttribute('data-idx'), 10); if (confirm('この動画を削除しますか?')) { videos.splice(idx, 1); save(); refresh(); renderEditTable(); } }); }); } // ========== Format guide render ========== function renderFormatGuide() { var el = document.getElementById('formatGuide'); el.innerHTML = FORMAT_GUIDE_LINES.map(function(pair) { var line = pair[0], cls = pair[1]; if (cls) return '' + esc(line) + ''; // Highlight separators return esc(line).replace(/ \| /g, ' | ').replace(/\| $/g, '|'); }).join('\n'); } // ========== Init and bind ========== function bind() { document.getElementById('stepTabs').addEventListener('click', function(e) { var btn = e.target.closest('.step-tab'); if (!btn) return; Array.prototype.forEach.call(document.querySelectorAll('.step-tab'), function(b) { b.classList.remove('active'); }); btn.classList.add('active'); state.step = btn.getAttribute('data-step'); renderGrid(); }); document.getElementById('themeChips').addEventListener('click', function(e) { var chip = e.target.closest('.chip'); if (!chip) return; var theme = chip.getAttribute('data-theme'); if (state.themes[theme]) { delete state.themes[theme]; chip.classList.remove('active'); } else { state.themes[theme] = true; chip.classList.add('active'); } renderGrid(); }); var searchTimer; document.getElementById('searchInput').addEventListener('input', function(e) { clearTimeout(searchTimer); var val = e.target.value; searchTimer = setTimeout(function() { state.search = val; renderGrid(); }, 200); }); document.getElementById('sortSelect').addEventListener('change', function(e) { state.sort = e.target.value; renderGrid(); }); document.getElementById('resetBtn').addEventListener('click', function() { state.step = 'all'; state.themes = {}; state.search = ''; state.sort = 'new'; Array.prototype.forEach.call(document.querySelectorAll('.step-tab'), function(b) { b.classList.toggle('active', b.getAttribute('data-step') === 'all'); }); Array.prototype.forEach.call(document.querySelectorAll('.chip'), function(c) { c.classList.remove('active'); }); document.getElementById('searchInput').value = ''; document.getElementById('sortSelect').value = 'new'; renderGrid(); }); // Modal document.getElementById('openDataBtn').addEventListener('click', openModal); document.getElementById('modalClose').addEventListener('click', closeModal); document.getElementById('modalBackdrop').addEventListener('click', function(e) { if (e.target === e.currentTarget) closeModal(); }); document.addEventListener('keydown', function(e) { if (e.key === 'Escape') closeModal(); }); Array.prototype.forEach.call(document.querySelectorAll('.modal-tab'), function(t) { t.addEventListener('click', function() { Array.prototype.forEach.call(document.querySelectorAll('.modal-tab'), function(x) { x.classList.remove('active'); }); Array.prototype.forEach.call(document.querySelectorAll('.tab-panel'), function(x) { x.classList.remove('active'); }); t.classList.add('active'); document.querySelector('[data-panel="' + t.getAttribute('data-tab') + '"]').classList.add('active'); if (t.getAttribute('data-tab') === 'edit') renderEditTable(); }); }); document.getElementById('loadExampleBtn').addEventListener('click', function() { document.getElementById('pasteArea').value = EXAMPLE_PASTE_LINES.join('\n'); }); document.getElementById('parseBtn').addEventListener('click', function() { var text = document.getElementById('pasteArea').value; if (!text.trim()) { toast('貼り付けてから解析してください'); return; } var result = parseInput(text); parsedRows = result.rows; renderPreview(result.rows, result.errors); }); document.getElementById('addRowBtn').addEventListener('click', function() { videos.push(enrich({ title: '新規動画', step: 2, themes: [], duration: null, date: new Date().toISOString().slice(0, 10), url: '' }, videos.length)); renderEditTable(); }); document.getElementById('saveEditBtn').addEventListener('click', function() { var rows = document.querySelectorAll('#editTableBody tr'); var updated = []; Array.prototype.forEach.call(rows, function(tr, i) { function g(k) { return tr.querySelector('[data-field="' + k + '"]').value.trim(); } updated.push({ title: g('title') || '(無題)', step: parseInt(g('step'), 10) || 2, themes: g('themes').split(/[,、]/).map(function(t) { return t.trim(); }).filter(Boolean), duration: g('duration') ? parseInt(g('duration'), 10) : null, date: g('date') || new Date().toISOString().slice(0, 10), url: g('url') || '', isNew: videos[i] ? videos[i].isNew : false }); }); videos = updated.map(function(v, i) { return enrich(v, i); }); save(); refresh(); toast('保存しました'); }); document.getElementById('exportBtn').addEventListener('click', function() { var blob = new Blob([JSON.stringify(videos, null, 2)], { type: 'application/json' }); var a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = 'emanurse-videos-' + new Date().toISOString().slice(0, 10) + '.json'; document.body.appendChild(a); a.click(); a.remove(); toast('JSONを書き出しました'); }); document.getElementById('importBtn').addEventListener('click', function() { document.getElementById('importInput').click(); }); document.getElementById('importInput').addEventListener('change', function(e) { var file = e.target.files[0]; if (!file) return; var reader = new FileReader(); reader.onload = function(ev) { try { var data = JSON.parse(ev.target.result); if (!Array.isArray(data)) throw new Error('配列形式ではありません'); videos = data.map(function(v, i) { return enrich(v, i); }); save(); refresh(); renderEditTable(); toast(videos.length + '件を読み込みました'); } catch (err) { toast('読み込み失敗: ' + err.message); } }; reader.readAsText(file); e.target.value = ''; }); document.getElementById('resetDataBtn').addEventListener('click', function() { if (!confirm('サンプルデータに戻します。よろしいですか?')) return; videos = SAMPLE.map(function(v, i) { return enrich(v, i); }); save(); refresh(); renderEditTable(); toast('サンプルに戻しました'); }); } // ========== Start ========== function start() { try { initData(); renderFormatGuide(); bind(); refresh(); } catch (err) { document.getElementById('grid').innerHTML = '
初期化エラー
' + esc(err.message) + '
'; } } if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', start); } else { start(); } })();