Skip to content

Commit 67df4c0

Browse files
committed
[IMP] web_timeline - defer canvas dependency rendering until DOM is fully settled to avoid errors when collapsing groups
1 parent ba6c963 commit 67df4c0

1 file changed

Lines changed: 31 additions & 4 deletions

File tree

web_timeline/static/src/js/timeline_renderer.js

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,8 +236,14 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
236236
this.canvas = new TimelineCanvas(this);
237237
this.canvas.appendTo(this.$centerContainer);
238238
this.timeline.on("changed", () => {
239-
this.draw_canvas();
240239
this.load_initial_data();
240+
// Defer drawing until after DOM settles (e.g., after group collapse/expand)
241+
const draw = () => this.draw_canvas();
242+
if (typeof window !== "undefined" && window.requestAnimationFrame) {
243+
window.requestAnimationFrame(draw);
244+
} else {
245+
setTimeout(draw, 0);
246+
}
241247
});
242248
},
243249

@@ -269,12 +275,17 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
269275
const item = items[key];
270276
const data = datas.get(key);
271277
if (!data || !data.evt) {
272-
return;
278+
continue; // Skip items without data or event payload
279+
}
280+
const deps = data.evt[this.dependency_arrow];
281+
if (!Array.isArray(deps) || deps.length === 0) {
282+
continue;
273283
}
274-
for (const id of data.evt[this.dependency_arrow]) {
284+
for (const id of deps) {
275285
for (const k of keys) {
276286
if (k.split("_")[0].toString() === id.toString()) {
277-
this.draw_dependency(item, items[k]);
287+
const toItem = items[k];
288+
this.draw_dependency(item, toItem);
278289
}
279290
}
280291
}
@@ -292,9 +303,25 @@ odoo.define("web_timeline.TimelineRenderer", function (require) {
292303
* @private
293304
*/
294305
draw_dependency: function (from, to, options) {
306+
// Skip if any item is missing, hidden, or its DOM node is not available/attached
307+
if (!from || !to) {
308+
return;
309+
}
295310
if (!from.displayed || !to.displayed) {
296311
return;
297312
}
313+
if (!from.dom || !to.dom || !from.dom.box || !to.dom.box) {
314+
return;
315+
}
316+
// In some cases after collapsing a group, items can be logically displayed
317+
// but their DOM nodes are detached. Guard against that situation.
318+
if (
319+
typeof document !== "undefined" &&
320+
(!document.body.contains(from.dom.box) ||
321+
!document.body.contains(to.dom.box))
322+
) {
323+
return;
324+
}
298325
const defaults = _.defaults({}, options, {
299326
line_color: "black",
300327
line_width: 1,

0 commit comments

Comments
 (0)