There is 1 update, 1 comment.
 
 
XWiki Platform / cid:jira-generated-image-avatar-bc421614-6414-42f7-8d14-d3be06389f53 XWIKI-23180 Open

The color pickers from Theme customization are not always loading

 
View issue   ·   Add comment
 

1 update

 
cid:jira-generated-image-avatar-80c91d50-650e-4dda-9023-64c212fec70b Changes by Vincent Massol on 14/Aug/26 09:47
 
Assignee: Vincent Massol
 
 

1 comment

 
cid:jira-generated-image-avatar-80c91d50-650e-4dda-9023-64c212fec70b Vincent Massol on 14/Aug/26 09:48
 

Root cause

colorPicker.js never listens for xwiki:dom:loaded — it only checks a flag once, and if that flag is not set yet the pickers are never initialized.

In xwiki-platform-flamingo-skin-resources/src/main/resources/flamingo/colorPicker.js (lines 94-95):

$(document).on('xwiki:dom:updated', init);
return XWiki.domIsLoaded && init();

Every other initialization in the code base uses the safe two-branch idiom, for example in uicomponents/lock/lock.js:

(XWiki.domIsLoaded && init()) || document.observe('xwiki:dom:loaded', init);

The color picker is missing the || document.observe('xwiki:dom:loaded', init) half. So when the RequireJS callback resolves before xwiki:dom:loaded has fired, init() is never called and nothing will ever call it again. The inputs still render (they are server-side HTML produced by #colorPicker_input in flamingo/macros.vm) but stay plain text fields with an empty grey swatch — exactly what the attached screenshot shows. It also explains why there is usually no error in the JavaScript console.

Why the race flips from one page load to the next

  • colorPicker.js is pulled in by #colorPicker_import in flamingo/macros.vm via $xwiki.jsfx.use('colorPicker.js', true), so it is emitted as a deferred script tag inside the #javaScriptExtensionHooks block of flamingo/javascript.vm.
  • Deferred scripts execute in document order as soon as they are available, but DOMContentLoaded only fires once the last one has run. At least compatibility.js and markerScript.js come after the extension hooks block, plus the theme page's own JSX (FlamingoThemesCode.ThemeSheet, FlamingoThemesCode.LessCodePluginJs).
  • XWiki.domIsLoaded is only set at the very end of that chain: dom:loaded -> XWiki.initialize() -> xwiki.js. And initialize() postpones itself once more if markerScript.js has not run yet.
  • Meanwhile require(['jquery', 'colpick'], ...) has already started loading asynchronously. When jQuery is already resolved and colpick is served from the browser HTTP cache, that callback can easily land inside the window during which the remaining deferred scripts are still being downloaded. At that moment XWiki.domIsLoaded is still false, so the pickers are silently skipped.

That is why the bug depends on the browser cache, on the number and weight of the scripts on the page and on the browser's script scheduler (reproduced easily on Chrome/Edge, rarely on Firefox), why repeated refreshes keep reproducing it (a warm cache keeps winning the race), and why it eventually "fixes itself".

Secondary defect in the same file

colorPicker.js uses jQuery to listen for xwiki:dom:updated, but it does not require xwiki-events-bridge. That module is only declared as a RequireJS path in flamingo/javascript.vm, it is not loaded by default, and it is what forwards Prototype-fired xwiki:* events to jQuery listeners. Compare with localePicker.js, which does require it. So even the xwiki:dom:updated fallback only works when some other module happens to have loaded the bridge.

About the two console errors in the screenshot

Both look like red herrings for this particular bug:

  • Uncaught ReferenceError: Effect is not defined (ModalBox:519) — a dom:loaded handler using script.aculo.us' Effect without require(['scriptaculous/effects']). Prototype fires custom events through dispatchEvent, so the browser isolates the exception and the remaining dom:loaded handlers (including XWiki.initialize) still run. ModalBox does not exist anywhere in xwiki-platform, so it comes from an extension installed on that instance. It is a genuine bug, but a different one.
  • The 404 on .../skin/skins/flamingo/resources/js/scriptaculous/scriptaculous.js — that is the legacy path; script.aculo.us is a WebJar RequireJS package now. A slow or failing request in the deferred script chain is however a good aggravator: it widens the DOMContentLoaded window and makes the race described above much more likely.

Fix

Register the xwiki:dom:loaded listener unconditionally (safe: if the DOM is already loaded the event will not fire again, so there is no double initialization), and require the events bridge:

require(['jquery', 'colpick', 'xwiki-events-bridge'], function($) {
  ...
  $(document).on('xwiki:dom:loaded xwiki:dom:updated', init);
  return XWiki.domIsLoaded && init();
});

localePicker.js has the identical missing-xwiki:dom:loaded defect and is fixed in the same pass.