profiler editor: decoded FCP panel beside the raw FCI field

The exact-FCI row is now a two-column flex layout: the editable raw FCI
textarea on the left, the decoded FCP list on the right (50/50, textarea
4 rows). Preview rendering split into profilerFciPreviewItems; a new
profilerFciInput hook updates the rule and re-decodes the panel on every
keystroke (no editor re-render, no focus loss), showing an empty body
while the hex is incomplete/invalid. Docs wording updated. SW cache
v72 -> v73.
This commit is contained in:
2026-09-11 21:22:18 +03:00
parent 944fccf67b
commit 6bfbb00994
5 changed files with 37 additions and 16 deletions
+20 -5
View File
@@ -21,7 +21,7 @@ function extractFunc(src, name, asyncFn) {
return (asyncFn ? 'async ' : '') + src.slice(m.index, i + 1);
}
const FNS = ['profilerNormHex', 'profilerNormHexStrict', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerFileFields', 'profilerContentKindForFileType', 'profilerEmptyRecordContent', 'profilerValidateProfile', 'profilerCustomNameForPath', 'profilerUpdateRulePath', 'profilerResultAspects', 'profilerAspectSummary', 'profilerNumRanges', 'esc', 'escHtml', 'profilerRawDataCheck', 'profilerRenderReport', 'parseBerLen', 'parseTlvList', 'fcpInt', 'fcpFileDescriptor', 'fcpLifeCycle', 'fcpSfi', 'fcpDo', 'fcpDecode', 'fcpDiffHtml', 'profilerFciPreviewHtml'];
const FNS = ['profilerNormHex', 'profilerNormHexStrict', 'profilerMatch', 'profilerMatchMin', 'profilerMaskPrefix4', 'profilerFileFields', 'profilerContentKindForFileType', 'profilerEmptyRecordContent', 'profilerValidateProfile', 'profilerCustomNameForPath', 'profilerUpdateRulePath', 'profilerResultAspects', 'profilerAspectSummary', 'profilerNumRanges', 'esc', 'escHtml', 'profilerRawDataCheck', 'profilerRenderReport', 'parseBerLen', 'parseTlvList', 'fcpInt', 'fcpFileDescriptor', 'fcpLifeCycle', 'fcpSfi', 'fcpDo', 'fcpDecode', 'fcpDiffHtml', 'profilerFciPreviewItems', 'profilerUpdateFciPreview', 'profilerUpdateRule', 'profilerFciInput'];
let code = '';
for (const f of FNS) code += extractFunc(html, f) + '\n';
code += extractFunc(html, 'profilerBuildFileRule', true) + '\n';
@@ -654,11 +654,26 @@ test('fcpDiffHtml highlights differing FCP parameters', () => {
delete global.t;
});
test('profilerFciPreviewHtml renders a decoded preview and degrades gracefully', () => {
test('profilerFciPreviewItems renders decoded items and degrades gracefully', () => {
global.t = s => s;
assert.ok(profilerFciPreviewHtml(FCP_TRANSPARENT).includes('File size: '));
assert.strictEqual(profilerFciPreviewHtml('not hex'), '');
assert.strictEqual(profilerFciPreviewHtml(''), '');
assert.ok(profilerFciPreviewItems(FCP_TRANSPARENT).includes('File size: '));
assert.strictEqual(profilerFciPreviewItems('not hex'), '');
assert.strictEqual(profilerFciPreviewItems(''), '');
delete global.t;
});
test('profilerFciInput stores the edited FCI and re-decodes the preview', () => {
global.t = s => s;
global.profilerDraft = { rules: [{ fciHex: '', fciMode: 'exact' }] };
const el = { innerHTML: '' };
global.document = { getElementById: id => (id === 'profiler-fci-preview-0' ? el : null) };
profilerFciInput(0, FCP_TRANSPARENT);
assert.strictEqual(global.profilerDraft.rules[0].fciHex, FCP_TRANSPARENT);
assert.ok(el.innerHTML.includes('File size: '));
profilerFciInput(0, 'zz');
assert.strictEqual(el.innerHTML, '');
global.profilerDraft = null;
delete global.document;
delete global.t;
});