profiler editor: filetype-driven fields and content view
- Show Size only for transparent/ber_tlv; Record length/count only for linear_fixed/cyclic; hide all size/record fields for df (unknown shows all) - Hide the Contents section entirely for df (existence-only check) - Changing file type clears now-inapplicable fields and resets content (keeps mode) when its kind switches between record and transparent - profilerSetContent defaults content kind from the selected file type Add profilerFileFields + profilerContentKindForFileType helpers + tests. SW cache v45.
This commit is contained in:
+50
-9
@@ -6731,6 +6731,19 @@ function profilerMaskPrefix4(hex) {
|
|||||||
return h.slice(0, 8) + '?'.repeat(h.length - 8);
|
return h.slice(0, 8) + '?'.repeat(h.length - 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Which size/record fields apply to a given file type.
|
||||||
|
function profilerFileFields(ft) {
|
||||||
|
if (ft === 'linear_fixed' || ft === 'cyclic') return { size: false, records: true };
|
||||||
|
if (ft === 'df') return { size: false, records: false };
|
||||||
|
if (ft === 'transparent' || ft === 'ber_tlv') return { size: true, records: false };
|
||||||
|
return { size: true, records: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Content representation ('record' vs 'transparent') for a given file type.
|
||||||
|
function profilerContentKindForFileType(ft) {
|
||||||
|
return (ft === 'linear_fixed' || ft === 'cyclic') ? 'record' : 'transparent';
|
||||||
|
}
|
||||||
|
|
||||||
function profilerValidateProfile(obj) {
|
function profilerValidateProfile(obj) {
|
||||||
if (!obj || typeof obj !== 'object') return 'Not an object';
|
if (!obj || typeof obj !== 'object') return 'Not an object';
|
||||||
if (!obj.name) return 'Missing name';
|
if (!obj.name) return 'Missing name';
|
||||||
@@ -7014,17 +7027,24 @@ function profilerRenderRule(i, r) {
|
|||||||
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('Path')) + '</label>' +
|
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('Path')) + '</label>' +
|
||||||
'<input value="' + escHtml(r.path || '') + '" oninput="profilerUpdateRule(' + i + ',\'path\',this.value)" class="w-full font-mono text-xs border border-gray-300 dark:border-slate-600 rounded px-2 py-1 dark:bg-slate-800" placeholder="MF/7F10/6F3A"></div>';
|
'<input value="' + escHtml(r.path || '') + '" oninput="profilerUpdateRule(' + i + ',\'path\',this.value)" class="w-full font-mono text-xs border border-gray-300 dark:border-slate-600 rounded px-2 py-1 dark:bg-slate-800" placeholder="MF/7F10/6F3A"></div>';
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
|
const vis = profilerFileFields(r.fileType);
|
||||||
html += '<div class="grid grid-cols-2 md:grid-cols-4 gap-2 mb-2">';
|
html += '<div class="grid grid-cols-2 md:grid-cols-4 gap-2 mb-2">';
|
||||||
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('File type')) + '</label>' +
|
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('File type')) + '</label>' +
|
||||||
'<select onchange="profilerUpdateRule(' + i + ',\'fileType\',this.value||null)" class="w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1 dark:bg-slate-800">' + ftOpts + '</select></div>';
|
'<select onchange="profilerUpdateRuleFileType(' + i + ',this.value||null)" class="w-full border border-gray-300 dark:border-slate-600 text-xs rounded px-2 py-1 dark:bg-slate-800">' + ftOpts + '</select></div>';
|
||||||
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('Size')) + '</label>' +
|
if (vis.size) {
|
||||||
'<input type="number" value="' + (r.fileSize === null ? '' : r.fileSize) + '" oninput="profilerUpdateRule(' + i + ',\'fileSize\',this.value===\'\'?null:parseInt(this.value))" class="w-full font-mono text-xs border border-gray-300 dark:border-slate-600 rounded px-2 py-1 dark:bg-slate-800" placeholder="—"></div>';
|
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('Size')) + '</label>' +
|
||||||
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('Record length')) + '</label>' +
|
'<input type="number" value="' + (r.fileSize === null ? '' : r.fileSize) + '" oninput="profilerUpdateRule(' + i + ',\'fileSize\',this.value===\'\'?null:parseInt(this.value))" class="w-full font-mono text-xs border border-gray-300 dark:border-slate-600 rounded px-2 py-1 dark:bg-slate-800" placeholder="—"></div>';
|
||||||
'<input type="number" value="' + (r.recordLen === null ? '' : r.recordLen) + '" oninput="profilerUpdateRule(' + i + ',\'recordLen\',this.value===\'\'?null:parseInt(this.value))" class="w-full font-mono text-xs border border-gray-300 dark:border-slate-600 rounded px-2 py-1 dark:bg-slate-800" placeholder="—"></div>';
|
}
|
||||||
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('Record count')) + '</label>' +
|
if (vis.records) {
|
||||||
'<input type="number" value="' + (r.numRecords === null ? '' : r.numRecords) + '" oninput="profilerUpdateRule(' + i + ',\'numRecords\',this.value===\'\'?null:parseInt(this.value))" class="w-full font-mono text-xs border border-gray-300 dark:border-slate-600 rounded px-2 py-1 dark:bg-slate-800" placeholder="—"></div>';
|
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('Record length')) + '</label>' +
|
||||||
|
'<input type="number" value="' + (r.recordLen === null ? '' : r.recordLen) + '" oninput="profilerUpdateRule(' + i + ',\'recordLen\',this.value===\'\'?null:parseInt(this.value))" class="w-full font-mono text-xs border border-gray-300 dark:border-slate-600 rounded px-2 py-1 dark:bg-slate-800" placeholder="—"></div>';
|
||||||
|
html += '<div><label class="block text-xs text-gray-600 dark:text-slate-400 mb-0.5">' + esc(t('Record count')) + '</label>' +
|
||||||
|
'<input type="number" value="' + (r.numRecords === null ? '' : r.numRecords) + '" oninput="profilerUpdateRule(' + i + ',\'numRecords\',this.value===\'\'?null:parseInt(this.value))" class="w-full font-mono text-xs border border-gray-300 dark:border-slate-600 rounded px-2 py-1 dark:bg-slate-800" placeholder="—"></div>';
|
||||||
|
}
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
html += profilerRenderContentEditor(i, r);
|
if (r.fileType !== 'df') {
|
||||||
|
html += profilerRenderContentEditor(i, r);
|
||||||
|
}
|
||||||
html += '</div>';
|
html += '</div>';
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
@@ -7059,6 +7079,24 @@ function profilerUpdateRule(i, field, value) {
|
|||||||
profilerDraft.rules[i][field] = value;
|
profilerDraft.rules[i][field] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function profilerUpdateRuleFileType(i, value) {
|
||||||
|
if (!profilerDraft) return;
|
||||||
|
const r = profilerDraft.rules[i];
|
||||||
|
r.fileType = value;
|
||||||
|
const vis = profilerFileFields(value);
|
||||||
|
if (!vis.size) r.fileSize = null;
|
||||||
|
if (!vis.records) { r.recordLen = null; r.numRecords = null; }
|
||||||
|
if (r.content) {
|
||||||
|
const kind = profilerContentKindForFileType(value);
|
||||||
|
if (r.content.kind !== kind) {
|
||||||
|
r.content = kind === 'record'
|
||||||
|
? { mode: r.content.mode, kind: 'record', records: [] }
|
||||||
|
: { mode: r.content.mode, kind: 'transparent', expected: '' };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
profilerRenderEditor();
|
||||||
|
}
|
||||||
|
|
||||||
function profilerSetContent(i, mode) {
|
function profilerSetContent(i, mode) {
|
||||||
if (!profilerDraft) return;
|
if (!profilerDraft) return;
|
||||||
const r = profilerDraft.rules[i];
|
const r = profilerDraft.rules[i];
|
||||||
@@ -7067,7 +7105,10 @@ function profilerSetContent(i, mode) {
|
|||||||
} else if (r.content) {
|
} else if (r.content) {
|
||||||
r.content.mode = mode;
|
r.content.mode = mode;
|
||||||
} else {
|
} else {
|
||||||
r.content = { mode: mode, kind: 'transparent', expected: '' };
|
const kind = profilerContentKindForFileType(r.fileType);
|
||||||
|
r.content = kind === 'record'
|
||||||
|
? { mode: mode, kind: 'record', records: [] }
|
||||||
|
: { mode: mode, kind: 'transparent', expected: '' };
|
||||||
}
|
}
|
||||||
profilerRenderEditor();
|
profilerRenderEditor();
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
const CACHE = 'otaman-v44';
|
const CACHE = 'otaman-v45';
|
||||||
const URLS = [
|
const URLS = [
|
||||||
'index.html',
|
'index.html',
|
||||||
'help.html',
|
'help.html',
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ function extractFunc(src, name) {
|
|||||||
return src.slice(m.index, i + 1);
|
return src.slice(m.index, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const FNS = ['profilerNormHex', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerValidateProfile'];
|
const FNS = ['profilerNormHex', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerFileFields', 'profilerContentKindForFileType', 'profilerValidateProfile'];
|
||||||
let code = '';
|
let code = '';
|
||||||
for (const f of FNS) code += extractFunc(html, f) + '\n';
|
for (const f of FNS) code += extractFunc(html, f) + '\n';
|
||||||
eval(code);
|
eval(code);
|
||||||
@@ -74,6 +74,24 @@ test('profilerMaskPrefix4 keeps first 4 bytes and masks the rest', () => {
|
|||||||
assert.strictEqual(profilerMaskPrefix4('1234'), '1234');
|
assert.strictEqual(profilerMaskPrefix4('1234'), '1234');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('profilerFileFields maps file type to applicable fields', () => {
|
||||||
|
assert.deepStrictEqual(profilerFileFields('transparent'), { size: true, records: false });
|
||||||
|
assert.deepStrictEqual(profilerFileFields('ber_tlv'), { size: true, records: false });
|
||||||
|
assert.deepStrictEqual(profilerFileFields('linear_fixed'), { size: false, records: true });
|
||||||
|
assert.deepStrictEqual(profilerFileFields('cyclic'), { size: false, records: true });
|
||||||
|
assert.deepStrictEqual(profilerFileFields('df'), { size: false, records: false });
|
||||||
|
assert.deepStrictEqual(profilerFileFields(null), { size: true, records: true });
|
||||||
|
assert.deepStrictEqual(profilerFileFields(''), { size: true, records: true });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('profilerContentKindForFileType', () => {
|
||||||
|
assert.strictEqual(profilerContentKindForFileType('linear_fixed'), 'record');
|
||||||
|
assert.strictEqual(profilerContentKindForFileType('cyclic'), 'record');
|
||||||
|
assert.strictEqual(profilerContentKindForFileType('transparent'), 'transparent');
|
||||||
|
assert.strictEqual(profilerContentKindForFileType('ber_tlv'), 'transparent');
|
||||||
|
assert.strictEqual(profilerContentKindForFileType('df'), 'transparent');
|
||||||
|
});
|
||||||
|
|
||||||
test('profile validation', () => {
|
test('profile validation', () => {
|
||||||
assert.strictEqual(profilerValidateProfile(null), 'Not an object');
|
assert.strictEqual(profilerValidateProfile(null), 'Not an object');
|
||||||
assert.strictEqual(profilerValidateProfile({ name: 'x' }), 'Missing rules array');
|
assert.strictEqual(profilerValidateProfile({ name: 'x' }), 'Missing rules array');
|
||||||
|
|||||||
Reference in New Issue
Block a user