Project

General

Profile

Actions

Bug #103971

closed

Ajax-dispatcher.ts fails to load all stylesheets when they are loaded through an inline-relation in backend

Added by rogier Helmer 6 months ago. Updated 5 months ago.

Status:
Closed
Priority:
Should have
Assignee:
-
Category:
Backend JavaScript
Start date:
2024-06-04
Due date:
% Done:

100%

Estimated time:
TYPO3 Version:
12
PHP Version:
8.1
Tags:
ajax-disapatcher inline-relation form-engine stylesheets
Complexity:
no-brainer
Is Regression:
Yes
Sprint Focus:

Description

We have a configuration in the backend. Where we have an accordion that can have multiple accordion items. Each accordion item can have multiple buttons. When you add a button to an accordion item, you can also select an icon for in that button. The icon can be selected using an custom styled input select.

When you open the accordion item, it will try to load all js and css required by the module. These are loaded dynamically through an ajax request. `ajax-dispather.ts` is used here to inject the relevant stylesheets. In my example it uses the following stylesheets.

  [
      "/_assets/937be57c7660e085d41e9dabf38b8aa1/Css/editor.css?1710839460",
      "/_assets/f5f6d48c4a9e67b540bea426607200c5/CSS/iconField.css" 
  ],

The issue is that only the first stylesheet is injected into the dom. So we're missing out on iconField.css.
I've debugged the issue, and found a bug in ajax-dispatcher.ts. And specifically in the function `processResponse`.

Here it's going wrong:

    if (json.stylesheetFiles) {
      for (const [index, stylesheetFile] of json.stylesheetFiles.entries()) {
        if (!stylesheetFile) {
          break;
        }
        const element = document.createElement('link');
        element.rel = 'stylesheet';
        element.type = 'text/css';
        element.href = stylesheetFile;
        document.querySelector('head').appendChild(element);
        json.stylesheetFiles.splice(index, 1);
      }
    }

the line: json.stylesheetFiles.splice(index, 1); splices out an item from the array. But it modifies the array which is being looped through. This causes sideeffects. Which causes it to only inject the first item from the looped array.

The following code should fix it:

    if (json.stylesheetFiles && json.stylesheetFiles.length) {
      const copyStylesheetFiles = [...json.stylesheetFiles];

      for (const stylesheetFile of copyStylesheetFiles.values()) {
        if (!stylesheetFile) {
          break;
        }
        const element = document.createElement('link');
        element.rel = 'stylesheet';
        element.type = 'text/css';
        element.href = stylesheetFile;
        document.querySelector('head').appendChild(element);
        json.stylesheetFiles.splice(json.stylesheetFiles.indexOf(stylesheetFile), 1);
      }
    }

I've created some unit tests, to replicate the issue.
https://playcode.io/1894374


Related issues 1 (0 open1 closed)

Related to TYPO3 Core - Task #103375: Implement `@typescript-eslint/no-array-delete` ruleClosed2024-03-12

Actions
Actions

Also available in: Atom PDF