404 lines
12 KiB
JavaScript
404 lines
12 KiB
JavaScript
let _seListEl = document.getElementById('sets-editor-list');
|
|
let _seDetailEl = document.getElementById('sets-editor-detail');
|
|
let _seSelectedIdx = 0;
|
|
let _seEditingIdx = -1;
|
|
let _seFrets = [];
|
|
let _seNameInput = null;
|
|
let _seAutoLabel = null;
|
|
|
|
function _seDbg() {
|
|
if (window.dbg) window.dbg.apply(null, ['[sets-editor]'].concat(Array.prototype.slice.call(arguments)));
|
|
}
|
|
|
|
function _seData() {
|
|
return window.getScoreSetsData();
|
|
}
|
|
|
|
function _seDensity(set) { return set && set.type === 'density'; }
|
|
|
|
document.getElementById('btn-back-explorer').addEventListener('click', function() {
|
|
_seEditingIdx = -1;
|
|
window.setScoreSetsData(_seData());
|
|
window.switchToView('shapes');
|
|
});
|
|
|
|
window.initSetsEditor = function() {
|
|
_seDbg('init');
|
|
var data = _seData();
|
|
_seSelectedIdx = data.selected;
|
|
_seEditingIdx = -1;
|
|
seRenderList();
|
|
seRenderDetail();
|
|
};
|
|
|
|
function seSelectSet(i) {
|
|
_seDbg('selectSet', i);
|
|
_seSelectedIdx = i;
|
|
_seEditingIdx = -1;
|
|
seRenderList();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seNewSet() {
|
|
_seDbg('newSet');
|
|
var name = prompt('New score set name:');
|
|
if (!name || !name.trim()) return;
|
|
var data = _seData();
|
|
data.sets.push({ name: name.trim(), type: '', shapes: [] });
|
|
_seSelectedIdx = data.sets.length - 1;
|
|
_seEditingIdx = -1;
|
|
window.persistSets();
|
|
seRenderList();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seRenderList() {
|
|
_seListEl.innerHTML = '';
|
|
var data = _seData();
|
|
data.sets.forEach(function(set, i) {
|
|
var item = document.createElement('div');
|
|
item.className = 'se-set-item' + (i === _seSelectedIdx ? ' selected' : '');
|
|
var nm = document.createElement('span');
|
|
nm.className = 'se-set-name';
|
|
nm.textContent = set.name;
|
|
var badges = document.createElement('span');
|
|
badges.className = 'se-set-badges';
|
|
var ct = document.createElement('span');
|
|
ct.className = 'se-badge';
|
|
ct.textContent = set.shapes.length;
|
|
badges.appendChild(ct);
|
|
if (_seDensity(set)) {
|
|
var db = document.createElement('span');
|
|
db.className = 'se-badge se-badge-density';
|
|
db.textContent = 'density';
|
|
badges.appendChild(db);
|
|
}
|
|
item.appendChild(nm);
|
|
item.appendChild(badges);
|
|
item.setAttribute('onclick', 'seSelectSet(' + i + ')');
|
|
_seListEl.appendChild(item);
|
|
});
|
|
var btn = document.createElement('button');
|
|
btn.className = 'btn-small se-btn-new-set';
|
|
btn.textContent = 'New Set';
|
|
btn.setAttribute('onclick', 'seNewSet()');
|
|
_seListEl.appendChild(btn);
|
|
}
|
|
|
|
function seRenameSet() {
|
|
_seDbg('rename');
|
|
var set = _seData().sets[_seSelectedIdx];
|
|
if (!set) return;
|
|
var name = prompt('Rename set:', set.name);
|
|
if (!name || !name.trim()) return;
|
|
set.name = name.trim();
|
|
window.persistSets();
|
|
seRenderList();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seDeleteSet() {
|
|
_seDbg('deleteSet');
|
|
var data = _seData();
|
|
var set = data.sets[_seSelectedIdx];
|
|
if (!set || !confirm('Delete "' + set.name + '"?')) return;
|
|
data.sets.splice(_seSelectedIdx, 1);
|
|
if (_seSelectedIdx >= data.sets.length) _seSelectedIdx = data.sets.length - 1;
|
|
data.selected = _seSelectedIdx;
|
|
window.persistSets();
|
|
seRenderList();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seMoveShape(i, dir) {
|
|
_seDbg('move', i, dir);
|
|
var set = _seData().sets[_seSelectedIdx];
|
|
if (!set) return;
|
|
var j = i + dir;
|
|
if (j < 0 || j >= set.shapes.length) return;
|
|
var tmp = set.shapes[i];
|
|
set.shapes[i] = set.shapes[j];
|
|
set.shapes[j] = tmp;
|
|
window.persistSets();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seEditShape(i) {
|
|
_seDbg('edit', i);
|
|
_seEditingIdx = i;
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seDupShape(i) {
|
|
_seDbg('dup', i);
|
|
var set = _seData().sets[_seSelectedIdx];
|
|
if (!set) return;
|
|
var orig = set.shapes[i];
|
|
set.shapes.splice(i + 1, 0, { name: '', frets: orig.frets.slice() });
|
|
window.persistSets();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seDelShape(i) {
|
|
_seDbg('del', i);
|
|
var set = _seData().sets[_seSelectedIdx];
|
|
if (!set) return;
|
|
set.shapes.splice(i, 1);
|
|
window.persistSets();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seAddShape() {
|
|
_seDbg('add');
|
|
var set = _seData().sets[_seSelectedIdx];
|
|
if (!set) return;
|
|
set.shapes.push({ name: '', frets: [0, 0, 0, 0, 0, 0] });
|
|
_seEditingIdx = set.shapes.length - 1;
|
|
window.persistSets();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seRenderDetail() {
|
|
_seDetailEl.innerHTML = '';
|
|
var data = _seData();
|
|
var set = data.sets[_seSelectedIdx];
|
|
if (!set) return;
|
|
|
|
if (_seEditingIdx >= 0) {
|
|
seRenderShapeEditor(set);
|
|
return;
|
|
}
|
|
|
|
var density = _seDensity(set);
|
|
var header = document.createElement('div');
|
|
header.className = 'se-detail-header';
|
|
var h3 = document.createElement('h3');
|
|
h3.textContent = set.name;
|
|
header.appendChild(h3);
|
|
|
|
if (!density) {
|
|
var btnR = document.createElement('button');
|
|
btnR.className = 'btn-small';
|
|
btnR.textContent = 'Rename';
|
|
btnR.setAttribute('onclick', 'seRenameSet()');
|
|
header.appendChild(btnR);
|
|
if (data.sets.length > 1) {
|
|
var btnD = document.createElement('button');
|
|
btnD.className = 'btn-small se-btn-danger';
|
|
btnD.textContent = 'Delete Set';
|
|
btnD.setAttribute('onclick', 'seDeleteSet()');
|
|
header.appendChild(btnD);
|
|
}
|
|
}
|
|
_seDetailEl.appendChild(header);
|
|
|
|
var listEl = document.createElement('div');
|
|
listEl.className = 'se-shape-list';
|
|
|
|
set.shapes.forEach(function(shape, i) {
|
|
var row = document.createElement('div');
|
|
row.className = 'se-shape-row';
|
|
|
|
var fb = document.createElement('div');
|
|
fb.className = 'fretboard alternative-fretboard se-mini-fb';
|
|
var fingering = shape.frets.map(function(f) { return f === -1 ? 'x' : String(f); });
|
|
var mx = Math.max.apply(null, shape.frets.filter(function(f) { return f >= 0; }).concat([1]));
|
|
window.renderSingleFretboard(fb, fingering, Math.max(mx, 4));
|
|
row.appendChild(fb);
|
|
|
|
var info = document.createElement('div');
|
|
info.className = 'se-shape-info';
|
|
var nameEl = document.createElement('span');
|
|
nameEl.className = 'se-shape-name';
|
|
if (shape.name) {
|
|
nameEl.textContent = shape.name;
|
|
} else {
|
|
nameEl.classList.add('se-auto-name');
|
|
nameEl.textContent = 'detecting...';
|
|
_seAutoDetect(shape.frets).then(function(n) { nameEl.textContent = n || '(unknown)'; });
|
|
}
|
|
info.appendChild(nameEl);
|
|
var fretsEl = document.createElement('span');
|
|
fretsEl.className = 'se-shape-frets';
|
|
fretsEl.textContent = shape.frets.map(function(f) { return f === -1 ? 'x' : f; }).join(' ');
|
|
info.appendChild(fretsEl);
|
|
row.appendChild(info);
|
|
|
|
if (!density) {
|
|
var acts = document.createElement('div');
|
|
acts.className = 'se-shape-actions';
|
|
if (i > 0) {
|
|
var up = document.createElement('button');
|
|
up.className = 'btn-small';
|
|
up.textContent = '\u25B2';
|
|
up.title = 'Move up';
|
|
up.setAttribute('onclick', 'seMoveShape(' + i + ',-1)');
|
|
acts.appendChild(up);
|
|
}
|
|
if (i < set.shapes.length - 1) {
|
|
var dn = document.createElement('button');
|
|
dn.className = 'btn-small';
|
|
dn.textContent = '\u25BC';
|
|
dn.title = 'Move down';
|
|
dn.setAttribute('onclick', 'seMoveShape(' + i + ',1)');
|
|
acts.appendChild(dn);
|
|
}
|
|
var ed = document.createElement('button');
|
|
ed.className = 'btn-small';
|
|
ed.textContent = 'edit';
|
|
ed.setAttribute('onclick', 'seEditShape(' + i + ')');
|
|
acts.appendChild(ed);
|
|
var dp = document.createElement('button');
|
|
dp.className = 'btn-small';
|
|
dp.textContent = 'dup';
|
|
dp.title = 'Duplicate';
|
|
dp.setAttribute('onclick', 'seDupShape(' + i + ')');
|
|
acts.appendChild(dp);
|
|
var dl = document.createElement('button');
|
|
dl.className = 'btn-small se-btn-danger';
|
|
dl.textContent = 'del';
|
|
dl.setAttribute('onclick', 'seDelShape(' + i + ')');
|
|
acts.appendChild(dl);
|
|
row.appendChild(acts);
|
|
}
|
|
listEl.appendChild(row);
|
|
});
|
|
|
|
_seDetailEl.appendChild(listEl);
|
|
|
|
if (!density) {
|
|
var btnA = document.createElement('button');
|
|
btnA.className = 'btn-small se-btn-add-shape';
|
|
btnA.textContent = 'Add Shape';
|
|
btnA.setAttribute('onclick', 'seAddShape()');
|
|
_seDetailEl.appendChild(btnA);
|
|
}
|
|
}
|
|
|
|
function seShapeDone() {
|
|
_seDbg('done');
|
|
var set = _seData().sets[_seSelectedIdx];
|
|
if (!set) return;
|
|
var shape = set.shapes[_seEditingIdx];
|
|
if (!shape) return;
|
|
shape.frets = _seFrets.slice();
|
|
shape.name = _seNameInput ? _seNameInput.value.trim() : '';
|
|
_seEditingIdx = -1;
|
|
window.persistSets();
|
|
seRenderList();
|
|
seRenderDetail();
|
|
}
|
|
|
|
function seFbCell(s, f) {
|
|
var cur = _seFrets[s];
|
|
if (f === 0) {
|
|
_seFrets[s] = (cur === -1) ? 0 : -1;
|
|
} else {
|
|
_seFrets[s] = (cur === f) ? 0 : f;
|
|
}
|
|
_seBuildGrid();
|
|
_seUpdateAutoName();
|
|
}
|
|
|
|
function _seBuildGrid() {
|
|
var wrap = document.getElementById('se-fb-wrap');
|
|
if (!wrap) return;
|
|
wrap.innerHTML = '';
|
|
var nf = 12;
|
|
var table = document.createElement('div');
|
|
table.className = 'se-fb-grid';
|
|
|
|
var hdr = document.createElement('div');
|
|
hdr.className = 'se-fb-header-row';
|
|
var lbl = document.createElement('div');
|
|
lbl.className = 'se-fb-label';
|
|
hdr.appendChild(lbl);
|
|
for (var f = 0; f <= nf; f++) {
|
|
var c = document.createElement('div');
|
|
c.className = 'se-fb-fret-num';
|
|
c.textContent = f === 0 ? 'nut' : f;
|
|
hdr.appendChild(c);
|
|
}
|
|
table.appendChild(hdr);
|
|
|
|
var labels = ['1 (low)', '2', '3', '4', '5', '6 (high)'];
|
|
for (var s = 0; s < 6; s++) {
|
|
var row = document.createElement('div');
|
|
row.className = 'se-fb-row';
|
|
var sl = document.createElement('div');
|
|
sl.className = 'se-fb-label';
|
|
sl.textContent = labels[s];
|
|
row.appendChild(sl);
|
|
for (var f = 0; f <= nf; f++) {
|
|
var cell = document.createElement('div');
|
|
cell.className = 'se-fb-cell';
|
|
if (f === 0) cell.classList.add('se-fb-nut');
|
|
var cur = _seFrets[s];
|
|
if (f === 0) {
|
|
if (cur === -1) { cell.classList.add('se-muted'); cell.textContent = 'x'; }
|
|
else if (cur === 0) { cell.classList.add('se-open'); cell.textContent = 'o'; }
|
|
} else if (cur === f) {
|
|
cell.classList.add('se-dot-active');
|
|
}
|
|
cell.setAttribute('onclick', 'seFbCell(' + s + ',' + f + ')');
|
|
row.appendChild(cell);
|
|
}
|
|
table.appendChild(row);
|
|
}
|
|
wrap.appendChild(table);
|
|
}
|
|
|
|
function _seUpdateAutoName() {
|
|
_seAutoDetect(_seFrets).then(function(n) {
|
|
if (_seAutoLabel) _seAutoLabel.textContent = n ? 'Detected: ' + n : '';
|
|
});
|
|
}
|
|
|
|
function seRenderShapeEditor(set) {
|
|
var shape = set.shapes[_seEditingIdx];
|
|
if (!shape) { _seEditingIdx = -1; seRenderDetail(); return; }
|
|
_seFrets = shape.frets.slice();
|
|
_seDetailEl.innerHTML = '';
|
|
|
|
var header = document.createElement('div');
|
|
header.className = 'se-editor-header';
|
|
var btnDone = document.createElement('button');
|
|
btnDone.className = 'btn-small btn-apply';
|
|
btnDone.textContent = 'Done';
|
|
btnDone.setAttribute('onclick', 'seShapeDone()');
|
|
header.appendChild(btnDone);
|
|
var title = document.createElement('h3');
|
|
title.textContent = 'Edit Shape';
|
|
header.appendChild(title);
|
|
_seDetailEl.appendChild(header);
|
|
|
|
var nameRow = document.createElement('div');
|
|
nameRow.className = 'se-editor-name-row';
|
|
var nl = document.createElement('label');
|
|
nl.textContent = 'Name';
|
|
_seNameInput = document.createElement('input');
|
|
_seNameInput.type = 'text';
|
|
_seNameInput.className = 'se-editor-name-input';
|
|
_seNameInput.placeholder = 'Auto-detect name';
|
|
_seNameInput.value = shape.name;
|
|
_seAutoLabel = document.createElement('span');
|
|
_seAutoLabel.className = 'se-auto-label';
|
|
nameRow.appendChild(nl);
|
|
nameRow.appendChild(_seNameInput);
|
|
nameRow.appendChild(_seAutoLabel);
|
|
_seDetailEl.appendChild(nameRow);
|
|
|
|
var fbWrap = document.createElement('div');
|
|
fbWrap.id = 'se-fb-wrap';
|
|
fbWrap.className = 'se-clickable-fb';
|
|
_seDetailEl.appendChild(fbWrap);
|
|
|
|
_seBuildGrid();
|
|
_seUpdateAutoName();
|
|
}
|
|
|
|
function _seAutoDetect(frets) {
|
|
if (!window.go || !window.go.main || !window.go.main.App) return Promise.resolve('');
|
|
return window.go.main.App.IdentifyShape(frets).then(function(n) { return n || ''; }).catch(function() { return ''; });
|
|
}
|