phases 4-6: article system, stem note fields, edit-state cleanup
Phase 4 — remove edit-state flags from domain objects: - ast-parser.js: drop isDirty from buildInstrument, buildBar, buildStemNote - store.js: add resetEditState() - PaneCP.js: use resetEditState() on import; drop flags arg from patchScore - PaneFO.js: isDirty -> _modified for linked instruments; no per-node dirty tracking - PaneSubObjects.js: _spliceNode helper; deletion via splice; _isNew on new bars - exporter.js: on-demand traversal; absence from model means deleted Phase 5 — article parser and exporter: - ast-parser.js: _buildArticleEntry replaces _mergeArticleEntry; stage.article and voice.article dispatch; article properties carry scope and overwritten flag - exporter.js: _buildArticlesBlock emits -important: list for overwrites scope Phase 6 — stem note dead fields: - ast-parser.js: parse weight and articulatory on stem notes; flatten article.definite properties onto stem note model sibling to pitch/chain
This commit is contained in:
@@ -61,10 +61,10 @@ export const PaneFO = {
|
||||
// Guard: first edit to a linked instrument triggers embed-or-discard before committing.
|
||||
function makeChangeHandler(instr) {
|
||||
return (info) => {
|
||||
if (instr.isLinked && !instr.isDirty) {
|
||||
if (instr.isLinked && !instr._modified) {
|
||||
pendingEdit.value = { instr, undo: info?.undo };
|
||||
} else {
|
||||
instr.isDirty = true;
|
||||
instr._modified = true;
|
||||
props.store.markDirty();
|
||||
}
|
||||
};
|
||||
@@ -73,7 +73,7 @@ export const PaneFO = {
|
||||
function embedInstrument(instr) {
|
||||
instr.name = instr.name.split('/').pop();
|
||||
instr.isLinked = false;
|
||||
instr.isDirty = true;
|
||||
instr._modified = true;
|
||||
pendingEdit.value = null;
|
||||
props.store.markDirty();
|
||||
}
|
||||
@@ -152,7 +152,7 @@ export const PaneFO = {
|
||||
: null,
|
||||
);
|
||||
} else if (node.type === 'article') {
|
||||
const markDirty = () => { node.isDirty = true; props.store.markDirty(); };
|
||||
const markDirty = () => { props.store.markDirty(); };
|
||||
const rowStyle = 'display:flex;gap:0.4rem;align-items:center;padding:0.2rem 0';
|
||||
children.push(
|
||||
h('h4', H4, `Article: ${node.name}`),
|
||||
@@ -209,12 +209,12 @@ export const PaneFO = {
|
||||
]),
|
||||
);
|
||||
} else if (node.type === 'bar') {
|
||||
const markBarDirty = () => { node.isDirty = true; props.store.markDirty(); };
|
||||
const markBarDirty = () => { props.store.markDirty(); };
|
||||
children.push(
|
||||
h('h4', H4, `Bar: ${node.id}`),
|
||||
h(ObjectExtended, {
|
||||
fields: [
|
||||
{ key: 'id', value: node.id, editable: node.isNew ?? false },
|
||||
{ key: 'id', value: node.id, editable: node._isNew ?? false },
|
||||
{ key: 'beats_per_minute', value: node.tempoLevels ?? '', editable: true, type: 'number' },
|
||||
{ key: 'stress_pattern', value: stressorToString(node.stressor), editable: true },
|
||||
],
|
||||
@@ -234,7 +234,7 @@ export const PaneFO = {
|
||||
h('h4', H4, `Voice: ${node.name}`),
|
||||
h(ObjectExtended, {
|
||||
fields: [
|
||||
{ key: 'articles', value: node.articles.join(', ') || '—', editable: false },
|
||||
{ key: 'articles', value: node.articles.map(a => a.name).join(', ') || '—', editable: false },
|
||||
{ key: 'motifs', value: node.motifs.map(m => m.label).join(', ') || '—', editable: false },
|
||||
{ key: 'offsets', value: String(node.offsets.length), editable: false },
|
||||
],
|
||||
@@ -273,10 +273,7 @@ export const PaneFO = {
|
||||
}),
|
||||
);
|
||||
} else if (node.type === 'stem_note') {
|
||||
const bar = props.store.focusPath.find(n => n.type === 'bar') ?? null;
|
||||
const markDirty = () => {
|
||||
node.isDirty = true;
|
||||
if (bar) bar.isDirty = true;
|
||||
props.store.markDirty();
|
||||
};
|
||||
children.push(
|
||||
|
||||
Reference in New Issue
Block a user