fix(simple-editor): preserve scroll position across loadAll() re-renders
Regression of an earlier fix. Operators reported the editor jumping to the top of the page on every step save / insert / remove / promote. Root cause: .o_fp_simple_editor is the overflow:auto scroll container. loadAll() replaces state.steps with a fresh JSONRPC payload — OWL tears down the t-foreach and rebuilds every row, which snaps scrollTop back to 0. Every author action (Save Step, Add Step, Remove, Promote, Demote, Reorder, Import Template) routes through loadAll, so the symptom hit everywhere. Fix: capture scrollTop before the RPC, restore in a double-rAF after the response settles. rAF (microtask runs before paint in OWL 2; we need the rebuilt DOM to exist). One choke point fix — every caller benefits without per-handler changes. Cheap: a single DOM lookup + an integer save/restore. No XML or state-shape changes. Module: fusion_plating 19.0.20.6.0 → 19.0.20.6.1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
|
||||
{
|
||||
'name': 'Fusion Plating',
|
||||
'version': '19.0.20.6.0',
|
||||
'version': '19.0.20.6.1',
|
||||
'category': 'Manufacturing/Plating',
|
||||
'summary': 'Core plating / metal finishing ERP: facilities, processes, tanks, baths, jobs, operators.',
|
||||
'description': """
|
||||
|
||||
@@ -86,6 +86,20 @@ export class FpSimpleRecipeEditor extends Component {
|
||||
}
|
||||
|
||||
async loadAll() {
|
||||
// Preserve scroll position across the re-render. .o_fp_simple_editor
|
||||
// is the overflow:auto scroll container — when `state.steps` is
|
||||
// replaced with a fresh array, OWL tears down the t-foreach and
|
||||
// rebuilds every row, which snaps scrollTop back to 0. Operators
|
||||
// hate this: they save a step half-way down the recipe and the
|
||||
// page jumps to the top. Capture the position before the RPC,
|
||||
// restore it after the next paint.
|
||||
//
|
||||
// Regression note (2026-05-20): every save/insert/remove/promote
|
||||
// handler calls loadAll, so this single choke point fixes scroll
|
||||
// reset for the whole editor.
|
||||
const scrollRoot = document.querySelector(".o_fp_simple_editor");
|
||||
const savedScrollTop = scrollRoot ? scrollRoot.scrollTop : 0;
|
||||
|
||||
this.state.loading = true;
|
||||
const [recipeData, libraryData, templateData] = await Promise.all([
|
||||
rpc("/fp/simple_recipe/load", { recipe_id: this._recipeId }),
|
||||
@@ -97,6 +111,21 @@ export class FpSimpleRecipeEditor extends Component {
|
||||
this.state.library = libraryData.templates;
|
||||
this.state.templateOptions = templateData.templates;
|
||||
this.state.loading = false;
|
||||
|
||||
// Restore AFTER OWL repaints. Microtask runs before paint in OWL 2;
|
||||
// we need rAF (or two of them, defensively) so the rebuilt DOM
|
||||
// exists when we set scrollTop. Without this the assignment fires
|
||||
// against the pre-render DOM and gets discarded.
|
||||
if (savedScrollTop > 0) {
|
||||
requestAnimationFrame(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const el = document.querySelector(".o_fp_simple_editor");
|
||||
if (el) {
|
||||
el.scrollTop = savedScrollTop;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async onSearchLibrary(ev) {
|
||||
|
||||
Reference in New Issue
Block a user