MagicMirror icon indicating copy to clipboard operation
MagicMirror copied to clipboard

Modules with no header are always redrawn in updateDom, even when module content is unchanged

Open benjaminflessner opened this issue 2 months ago • 4 comments

I found a bug in MagicMirror

Platform: Mac, Chrome

Node Version: 18

MagicMirror² Version: Latest khassel docker image

Description: Modules with no header seems to be always refreshing, even if content did not change.

Steps to Reproduce: Set any module to a low-update frequency, and lose the header. (Easier to see if the module calls updateDom with a visible fade)

Notice that the module refreshes every time, even if its contents do not change.

Expected Results: Expect to see the module NOT refresh unless data changes.

Actual Results: Module refreshes constantly!

Additional Notes: First traced down to https://github.com/MagicMirrorOrg/MagicMirror/blob/5ea8a3469aad922007907134833f0b3a10805fb8/js/main.js#L224 where newHeader === undefined and headerWrapper[0].innerHTML === "undefined" (the string). Looking at my page source - this is indeed correct!

<header class="module-header" style="display: none;">undefined</header>

The innerHTML is literally the string "undefined." But why?

Traced that to https://github.com/MagicMirrorOrg/MagicMirror/blob/5ea8a3469aad922007907134833f0b3a10805fb8/js/main.js#L37 which converts the undefined return of getHeader() to the string "undefined" in innerText.

.... then I got distracted by a rabbit trail trying to figure out how the heck the following line worked at all. Shouldn't it set the style.display to none if getHeader was ==="" not !==""? https://github.com/MagicMirrorOrg/MagicMirror/blob/5ea8a3469aad922007907134833f0b3a10805fb8/js/main.js#L41

I think the only reason things work is because updateModuleContent re-sets the display style to block here: https://github.com/MagicMirrorOrg/MagicMirror/blob/5ea8a3469aad922007907134833f0b3a10805fb8/js/main.js#L251

I'd be happy to submit a PR for this, but I'm a bit concerned I'm mis-understanding what's going on in line 41. The easy fix is to change moduleNeedsUpdate to set headerNeedsUpdate to false when newHeader === undefined && headerWrapper[0].innerHTML === "undefined". But it would be cleaner to not be sticking the string "undefined" into the DOM at all. Should probably just be setting the innerHTML to an empty string in this instance, and then handling that in moduleNeedsUpdate.

benjaminflessner avatar May 01 '24 22:05 benjaminflessner

undefined in this context means not set.

the module calling updateDom() says the content changed. it's the module's job to tell MagicMirror. we don't compare old vs new.

sdetweil avatar May 02 '24 00:05 sdetweil

in modules where I don't want the change flash, I return the same Dom object tree I built last(first) time. so the replace is identical.

the browser knows if the dom elements are different or not.

more and more the browsers are implementing a shadow Dom. memory access is significantly faster than screen drawing, so they draw to a shadow compare and draw diffs to the screen

sdetweil avatar May 02 '24 00:05 sdetweil

the module calling updateDom() says the content changed. it's the module's job to tell MagicMirror. we don't compare old vs new.

updateDom calls updateDomWithContent which literally calls moduleNeedsUpdate whose sole purpose is to compare the header and body of the new module content with the current content to determine if an update is needed. It just doesn't work when the header is null because undefined !== "undefined".

benjaminflessner avatar May 02 '24 14:05 benjaminflessner

cool.. I am wrong.. so, edit the code and try it out.. see what happens.. all you have to do is remove 2 quotes..

you can use the developers window (ctrl-shift-i) , sources tab , to put a stop on this line of code and checkout the behavior now i don't see any difference.. that line of code is called once at startup of module..

sdetweil avatar May 02 '24 16:05 sdetweil