typo3-typescript-sources 14.3.8 → 14.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (229) hide show
  1. package/.github/workflows/sync-and-publish.yml +240 -191
  2. package/.last-synced-tag +1 -1
  3. package/README.md +13 -5
  4. package/adminpanel/admin-panel.ts +22 -22
  5. package/adminpanel/modules/cache.ts +3 -3
  6. package/backend/action-dispatcher.ts +8 -3
  7. package/backend/bookmark/bookmark-manager.ts +2 -1
  8. package/backend/bookmark/bookmark-store.ts +13 -17
  9. package/backend/clipboard-panel.ts +11 -5
  10. package/backend/code-editor/element/code-mirror-element.ts +1 -1
  11. package/backend/code-editor/language/typoscript.ts +3 -3
  12. package/backend/code-editor/stream-parser/typoscript.ts +2 -2
  13. package/backend/color-picker.ts +2 -2
  14. package/backend/column-selector-button.ts +6 -6
  15. package/backend/context-help.ts +3 -3
  16. package/backend/context-menu-actions.ts +14 -12
  17. package/backend/context-menu.ts +10 -4
  18. package/backend/contextual-record-edit.ts +2 -1
  19. package/backend/date-time-picker.ts +2 -1
  20. package/backend/drag-tooltip.ts +9 -4
  21. package/backend/drag-uploader.ts +6 -5
  22. package/backend/element/contextual-record-edit-trigger.ts +7 -6
  23. package/backend/element/datetime-element.ts +2 -1
  24. package/backend/element/draggable-resizable-element.ts +18 -12
  25. package/backend/element/editable-page-title.ts +2 -1
  26. package/backend/element/icon-element.ts +2 -2
  27. package/backend/element/pseudo-button.ts +29 -5
  28. package/backend/element/qrcode-modal-button.ts +2 -2
  29. package/backend/element/sidebar-toggle-element.ts +1 -15
  30. package/backend/element/thumbnail-element.ts +2 -2
  31. package/backend/element-browser.ts +4 -3
  32. package/backend/event/consumer-scope.ts +2 -2
  33. package/backend/event/event-dispatcher.ts +4 -2
  34. package/backend/event/interaction-request-assignment.ts +1 -1
  35. package/backend/event/interaction-request-map.ts +3 -3
  36. package/backend/form-engine/container/flex-form-container-container.ts +2 -2
  37. package/backend/form-engine/container/flex-form-section-container.ts +1 -1
  38. package/backend/form-engine/container/inline-control-container.ts +14 -14
  39. package/backend/form-engine/element/abstract-sortable-select-items.ts +3 -3
  40. package/backend/form-engine/element/color-element.ts +1 -1
  41. package/backend/form-engine/element/datetime-element.ts +1 -1
  42. package/backend/form-engine/element/extra/char-counter.ts +3 -3
  43. package/backend/form-engine/element/extra/select-box-filter.ts +1 -1
  44. package/backend/form-engine/element/mfa-info-element.ts +2 -2
  45. package/backend/form-engine/element/online-media-form-element.ts +5 -1
  46. package/backend/form-engine/element/select-multiple-side-by-side-element.ts +2 -2
  47. package/backend/form-engine/element/select-tree.ts +3 -3
  48. package/backend/form-engine/element/slug-element.ts +7 -7
  49. package/backend/form-engine/element/suggest/result-container.ts +1 -1
  50. package/backend/form-engine/element/table-wizard-element.ts +4 -4
  51. package/backend/form-engine/inline-relation/ajax-dispatcher.ts +3 -3
  52. package/backend/form-engine-validation.ts +11 -5
  53. package/backend/form-engine.ts +15 -14
  54. package/backend/global-event-handler.ts +1 -1
  55. package/backend/hotkeys/hotkey-struct.ts +1 -1
  56. package/backend/hotkeys.ts +5 -4
  57. package/backend/image-manipulation.ts +21 -20
  58. package/backend/info-window.ts +4 -3
  59. package/backend/layout-module/drag-drop.ts +6 -5
  60. package/backend/layout-module/paste.ts +1 -1
  61. package/backend/live-search/element/result/item/action/action-container.ts +1 -1
  62. package/backend/live-search/element/result/item/item-container.ts +4 -4
  63. package/backend/live-search/element/result/result-container.ts +5 -0
  64. package/backend/live-search/element/result/result-pagination.ts +1 -1
  65. package/backend/live-search/live-search-configurator.ts +4 -3
  66. package/backend/live-search/live-search-shortcut.ts +2 -1
  67. package/backend/live-search/live-search.ts +6 -5
  68. package/backend/live-search/result-types/default-result-type.ts +2 -1
  69. package/backend/localization/label-provider.ts +6 -5
  70. package/backend/localization/localization-wizard.ts +4 -4
  71. package/backend/localization/steps/content-record-selection-step.ts +8 -8
  72. package/backend/localization/steps/handler-selection-step.ts +4 -4
  73. package/backend/localization/steps/mode-step.ts +4 -4
  74. package/backend/localization/steps/source-language-step.ts +4 -4
  75. package/backend/localization/steps/target-language-step.ts +4 -4
  76. package/backend/login-refresh.ts +4 -24
  77. package/backend/login.ts +5 -4
  78. package/backend/modal.ts +9 -15
  79. package/backend/module/iframe.ts +10 -0
  80. package/backend/module/router.ts +10 -0
  81. package/backend/module-menu.ts +7 -6
  82. package/backend/multi-record-selection-action.ts +1 -1
  83. package/backend/multi-record-selection-delete-action.ts +1 -1
  84. package/backend/multi-record-selection-edit-action.ts +3 -2
  85. package/backend/multi-record-selection.ts +14 -14
  86. package/backend/multi-step-wizard.ts +9 -2
  87. package/backend/new-multiple-pages.ts +2 -2
  88. package/backend/new-record-wizard.ts +17 -16
  89. package/backend/notification.ts +3 -19
  90. package/backend/page-wizard/page-wizard.ts +2 -2
  91. package/backend/page-wizard/steps/doktype-step.ts +5 -5
  92. package/backend/pagetsconfig/pagetsconfig-includes.ts +1 -1
  93. package/backend/popover.ts +5 -5
  94. package/backend/record-download-button.ts +1 -1
  95. package/backend/recordlist.ts +12 -10
  96. package/backend/security/element/csp-reports.ts +8 -8
  97. package/backend/security/element/sudo-mode.ts +6 -7
  98. package/backend/settings/type/page.ts +3 -2
  99. package/backend/setup-module.ts +2 -2
  100. package/backend/severity.ts +2 -22
  101. package/backend/sortable-table.ts +10 -4
  102. package/backend/storage/abstract-client-storage.ts +2 -2
  103. package/backend/storage/module-state-storage.ts +5 -3
  104. package/backend/storage/persistent.ts +15 -3
  105. package/backend/switch-user.ts +3 -2
  106. package/backend/tests/backend/utility/dom-helper-test.ts +2 -2
  107. package/backend/tests/element/pseudo-button-test.ts +95 -0
  108. package/backend/tests/form-engine/element/extra/select-box-filter-test.ts +3 -3
  109. package/backend/tests/form-engine-validation-test.ts +1 -1
  110. package/backend/tests/notification-test.ts +1 -1
  111. package/backend/tests/tree/tree-test.ts +41 -0
  112. package/backend/tree/file-storage-browser.ts +6 -4
  113. package/backend/tree/file-storage-tree-container.ts +12 -10
  114. package/backend/tree/page-browser.ts +3 -2
  115. package/backend/tree/page-position-select.ts +3 -2
  116. package/backend/tree/page-tree-element.ts +6 -5
  117. package/backend/tree/page-tree.ts +7 -1
  118. package/backend/tree/tree-module-state.ts +5 -5
  119. package/backend/tree/tree.ts +17 -9
  120. package/backend/user-pass-login.ts +2 -2
  121. package/backend/user-settings-manager.ts +2 -1
  122. package/backend/utility/collapse-state-persister.ts +1 -1
  123. package/backend/utility/collapse-state-search.ts +6 -6
  124. package/backend/utility/dom-helper.ts +3 -3
  125. package/backend/utility/drag-drop-utility.ts +2 -1
  126. package/backend/utility/top-level-module-import.ts +3 -1
  127. package/backend/utility.ts +6 -6
  128. package/backend/viewport/content-container.ts +2 -1
  129. package/backend/viewport/content-navigation-toggle.ts +3 -10
  130. package/backend/viewport/content-navigation.ts +5 -0
  131. package/backend/viewport/navigation-container.ts +1 -1
  132. package/backend/viewport/toolbar.ts +3 -3
  133. package/backend/viewport.ts +5 -4
  134. package/backend/window-manager.ts +7 -6
  135. package/backend/wizard/events/auto-advance-event.ts +6 -0
  136. package/backend/wizard/events/before-next-step-event.ts +6 -0
  137. package/backend/wizard/events/step-summary-event.ts +6 -0
  138. package/backend/wizard/finisher/noop-finisher.ts +3 -2
  139. package/backend/wizard/finisher/redirect-finisher.ts +4 -3
  140. package/backend/wizard/finisher/reload-finisher.ts +3 -2
  141. package/backend/wizard/move-content-element.ts +1 -1
  142. package/backend/wizard/move-page.ts +2 -1
  143. package/backend/wizard/wizard.ts +8 -10
  144. package/belog/backend-log.ts +2 -2
  145. package/beuser/permissions.ts +2 -2
  146. package/core/ajax/ajax-response.ts +1 -1
  147. package/core/ajax/input-transformer.ts +1 -1
  148. package/core/event/debounce-event.ts +4 -4
  149. package/core/event/event-interface.ts +3 -3
  150. package/core/event/regular-event.ts +7 -7
  151. package/core/event/request-animation-frame-event.ts +4 -4
  152. package/core/event/throttle-event.ts +4 -4
  153. package/core/java-script-item-processor.ts +9 -1
  154. package/core/lit-helper.ts +5 -2
  155. package/core/referrer-refresh.ts +2 -2
  156. package/core/security-utility.ts +1 -1
  157. package/core/tests/utility/top-window-test.ts +121 -0
  158. package/core/utility/top-window.ts +99 -0
  159. package/dashboard/dashboard-wizard.ts +2 -2
  160. package/dashboard/dashboard.ts +7 -6
  161. package/dashboard/wizard/steps/preset-step.ts +3 -3
  162. package/extensionmanager/dependency-check.ts +2 -1
  163. package/extensionmanager/extension-toggle-button.ts +2 -1
  164. package/extensionmanager/main.ts +7 -7
  165. package/extensionmanager/repository.ts +2 -1
  166. package/filelist/browse-files.ts +1 -1
  167. package/filelist/browse-folders.ts +2 -2
  168. package/filelist/context-menu-actions.ts +20 -19
  169. package/filelist/file-delete.ts +4 -3
  170. package/filelist/file-list-dragdrop.ts +8 -7
  171. package/filelist/file-list-rename-handler.ts +2 -1
  172. package/filelist/file-list-replace-handler.ts +2 -1
  173. package/filelist/file-list-transfer-handler.ts +7 -6
  174. package/filelist/file-list.ts +12 -11
  175. package/form/backend/form-editor/component/date-editor.ts +4 -0
  176. package/form/backend/form-editor/component/form-element-selector.ts +4 -0
  177. package/form/backend/form-editor/inspector-component.ts +6 -6
  178. package/form/backend/form-editor/mediator.ts +36 -36
  179. package/form/backend/form-editor/modals-component.ts +1 -1
  180. package/form/backend/form-editor/stage-component.ts +4 -4
  181. package/form/backend/form-editor/view-model.ts +7 -7
  182. package/form/backend/form-manager/view-model.ts +5 -5
  183. package/form/backend/form-wizard/form-wizard.ts +2 -2
  184. package/form/backend/form-wizard/steps/storage-step.ts +1 -1
  185. package/impexp/context-menu-actions.ts +5 -3
  186. package/impexp/import-export.ts +1 -1
  187. package/info/translation-status.ts +2 -2
  188. package/install/ajax/ajax-queue.ts +1 -1
  189. package/install/installer.ts +2 -1
  190. package/install/module/abstract-interactable-module.ts +4 -4
  191. package/install/module/environment/image-processing.ts +4 -4
  192. package/install/module/environment/mail-test.ts +2 -2
  193. package/install/module/maintenance/clear-tables.ts +3 -3
  194. package/install/module/maintenance/clear-typo3temp-files.ts +8 -8
  195. package/install/module/maintenance/create-admin.ts +3 -3
  196. package/install/module/maintenance/database-analyzer.ts +9 -7
  197. package/install/module/maintenance/language-packs.ts +6 -5
  198. package/install/module/maintenance/reference-index.ts +1 -1
  199. package/install/module/settings/change-install-tool-password.ts +1 -1
  200. package/install/module/settings/extension-configuration.ts +8 -9
  201. package/install/module/settings/features.ts +1 -1
  202. package/install/module/settings/local-configuration.ts +5 -5
  203. package/install/module/settings/presets.ts +2 -2
  204. package/install/module/settings/system-maintainer.ts +1 -1
  205. package/install/module/upgrade/extension-scanner.ts +5 -5
  206. package/install/module/upgrade/tca-migrations-check.ts +1 -1
  207. package/install/module/upgrade/upgrade-docs.ts +16 -16
  208. package/install/module/upgrade/upgrade-wizards.ts +7 -8
  209. package/install/renderable/flash-message.ts +2 -2
  210. package/install/renderable/info-box.ts +2 -2
  211. package/install/renderable/language-packs.ts +8 -2
  212. package/lowlevel/query-generator.ts +2 -2
  213. package/opendocs/open-document-store.ts +5 -4
  214. package/package.json +2 -2
  215. package/recycler/recycler.ts +2 -1
  216. package/redirects/event-handler.ts +8 -1
  217. package/rte-ckeditor/ckeditor5.ts +7 -3
  218. package/rte-ckeditor/tests/ckeditor5-test.ts +68 -0
  219. package/scheduler/form-engine/element/timing-options-element.ts +1 -1
  220. package/scheduler/scheduler-add-group.ts +2 -1
  221. package/scheduler/scheduler.ts +2 -2
  222. package/styleguide/checkbox-demo.ts +1 -1
  223. package/tstemplate/template-analyzer.ts +1 -1
  224. package/viewpage/main.ts +1 -1
  225. package/workspaces/backend.ts +11 -9
  226. package/workspaces/preview.ts +3 -2
  227. package/workspaces/renderable/record-table.ts +1 -1
  228. package/workspaces/renderable/send-to-stage-form.ts +1 -1
  229. package/workspaces/workspace-state.ts +5 -4
@@ -37,23 +37,23 @@
37
37
 
38
38
  constructor() {
39
39
  this.adminPanel = document.querySelector(AdminPanelSelectors.adminPanelRole) as HTMLFormElement;
40
- this.modules = (this.querySelectorAll(AdminPanelSelectors.moduleTriggerRole) as Element[]).map(
41
- (moduleTrigger: HTMLElement) => {
40
+ this.modules = this.querySelectorAll(AdminPanelSelectors.moduleTriggerRole).map(
41
+ (moduleTrigger) => {
42
42
  const moduleParent = moduleTrigger.closest(AdminPanelSelectors.moduleParentClass);
43
43
  return new AdminPanelModule(this, moduleParent, moduleTrigger);
44
44
  },
45
45
  );
46
46
  this.popups = this.querySelectorAll(AdminPanelSelectors.popupTriggerRole).map(
47
- (popupTrigger: HTMLElement) => new AdminPanelPopup(this, popupTrigger),
47
+ (popupTrigger) => new AdminPanelPopup(this, popupTrigger),
48
48
  );
49
49
  this.querySelectorAll(AdminPanelSelectors.panelTriggerRole).forEach(
50
- (panelTrigger: HTMLElement) => {
50
+ (panelTrigger) => {
51
51
  const panelParent = panelTrigger.closest(AdminPanelSelectors.panelParentClass);
52
52
  new AdminPanelPanel(panelParent, panelTrigger);
53
53
  },
54
54
  );
55
55
  this.querySelectorAll(AdminPanelSelectors.contentSettingsTriggerRole).forEach(
56
- (contentSettingTrigger: HTMLElement) => {
56
+ (contentSettingTrigger) => {
57
57
  const contentSettingElement = contentSettingTrigger
58
58
  .closest(AdminPanelSelectors.contentParentClass)
59
59
  .querySelector(AdminPanelSelectors.contentSettingsParentClass);
@@ -67,11 +67,11 @@
67
67
  }
68
68
 
69
69
  disableModules(): void {
70
- this.modules.forEach((module: AdminPanelModule) => module.disable());
70
+ this.modules.forEach((module) => module.disable());
71
71
  }
72
72
 
73
73
  disablePopups(): void {
74
- this.popups.forEach((popup: AdminPanelPopup) => popup.disable());
74
+ this.popups.forEach((popup) => popup.disable());
75
75
  }
76
76
 
77
77
  renderBackdrop(): void {
@@ -93,33 +93,33 @@
93
93
  }
94
94
  }
95
95
 
96
- private querySelectorAll(selectors: string, subject: Element = null): Node[] {
96
+ private querySelectorAll<T extends HTMLElement = HTMLElement>(selectors: string, subject: Element = null): T[] {
97
97
  if (subject === null) {
98
- return Array.from(document.querySelectorAll(selectors));
98
+ return Array.from(document.querySelectorAll<T>(selectors));
99
99
  }
100
- return Array.from(subject.querySelectorAll(selectors));
100
+ return Array.from(subject.querySelectorAll<T>(selectors));
101
101
  }
102
102
 
103
103
  private initializeEvents(): void {
104
104
  this
105
105
  .querySelectorAll(AdminPanelSelectors.contentTabRole)
106
- .forEach((tab: HTMLElement) => tab.addEventListener('click', this.switchTab.bind(this)));
106
+ .forEach((tab) => tab.addEventListener('click', this.switchTab.bind(this)));
107
107
  this
108
108
  .querySelectorAll(AdminPanelSelectors.zoomTarget)
109
- .forEach((zoomTrigger: HTMLElement) => zoomTrigger.addEventListener('click', this.openZoom.bind(this)));
109
+ .forEach((zoomTrigger) => zoomTrigger.addEventListener('click', this.openZoom.bind(this)));
110
110
  this
111
111
  .querySelectorAll(AdminPanelSelectors.zoomClose)
112
- .forEach((zoomTrigger: HTMLElement) => zoomTrigger.addEventListener('click', this.closeZoom.bind(this)));
112
+ .forEach((zoomTrigger) => zoomTrigger.addEventListener('click', this.closeZoom.bind(this)));
113
113
  this
114
114
  .querySelectorAll(AdminPanelSelectors.triggerRole)
115
- .forEach((trigger: HTMLElement) => trigger.addEventListener('click', this.toggleAdminPanelState.bind(this)));
115
+ .forEach((trigger) => trigger.addEventListener('click', this.toggleAdminPanelState.bind(this)));
116
116
  this
117
117
  .querySelectorAll(AdminPanelSelectors.saveButtonRole)
118
- .forEach((elm: HTMLElement) => elm.addEventListener('click', this.sendAdminPanelForm.bind(this)));
118
+ .forEach((elm) => elm.addEventListener('click', this.sendAdminPanelForm.bind(this)));
119
119
 
120
120
  this
121
121
  .querySelectorAll('[data-typo3-role=typo3-adminPanel-content-close]')
122
- .forEach((elm: HTMLElement) => {
122
+ .forEach((elm) => {
123
123
  elm.addEventListener('click', () => {
124
124
  this.disableModules();
125
125
  this.removeBackdrop();
@@ -127,7 +127,7 @@
127
127
  });
128
128
  this
129
129
  .querySelectorAll('.typo3-adminPanel-table th, .typo3-adminPanel-table td')
130
- .forEach((elm: HTMLElement) => {
130
+ .forEach((elm) => {
131
131
  elm.addEventListener('click', () => {
132
132
  elm.focus();
133
133
  try {
@@ -149,9 +149,9 @@
149
149
  const contentTabs = this.querySelectorAll(AdminPanelSelectors.contentTabRole, currentContent);
150
150
  const contentPanes = this.querySelectorAll(AdminPanelSelectors.contentPaneRole, currentContent);
151
151
 
152
- contentTabs.forEach((element: HTMLElement) => element.classList.remove(activeTabClass));
152
+ contentTabs.forEach((element) => element.classList.remove(activeTabClass));
153
153
  currentTab.classList.add(activeTabClass);
154
- contentPanes.forEach((element: HTMLElement) => element.classList.remove(activePaneClass));
154
+ contentPanes.forEach((element) => element.classList.remove(activePaneClass));
155
155
 
156
156
  const activePane = document.querySelector('[data-typo3-tab-id=' + currentTab.dataset.typo3TabTarget + ']');
157
157
  activePane.classList.add(activePaneClass);
@@ -196,7 +196,7 @@
196
196
  */
197
197
  private getCleanReloadUrl(): string {
198
198
  const urlParams: string[] = [];
199
- location.search.substr(1).split('&').forEach((item: string): void => {
199
+ location.search.substr(1).split('&').forEach((item): void => {
200
200
  if (item && !item.includes('ADMCMD_')) {
201
201
  urlParams.push(item);
202
202
  }
@@ -208,12 +208,12 @@
208
208
 
209
209
  private addBackdropListener(): void {
210
210
  this.querySelectorAll('.' + AdminPanelClasses.backdrop)
211
- .forEach((elm: HTMLElement) => {
211
+ .forEach((elm) => {
212
212
  elm.addEventListener('click', () => {
213
213
  this.removeBackdrop();
214
214
  this
215
215
  .querySelectorAll(AdminPanelSelectors.moduleTriggerRole)
216
- .forEach((innerElm: HTMLElement) => {
216
+ .forEach((innerElm) => {
217
217
  innerElm.closest(AdminPanelSelectors.moduleParentClass)
218
218
  .classList.remove(AdminPanelClasses.activeModule);
219
219
  });
@@ -1,11 +1,11 @@
1
1
  ((): void => {
2
2
  class AdminPanelCache {
3
- private readonly buttons: NodeList;
3
+ private readonly buttons: NodeListOf<HTMLElement>;
4
4
 
5
5
  constructor() {
6
- this.buttons = document.querySelectorAll('[data-typo3-role="clearCacheButton"]');
6
+ this.buttons = document.querySelectorAll<HTMLElement>('[data-typo3-role="clearCacheButton"]');
7
7
 
8
- this.buttons.forEach((element: HTMLElement): void => {
8
+ this.buttons.forEach((element): void => {
9
9
  element.addEventListener('click', (): void => {
10
10
  const url = element.dataset.typo3AjaxUrl;
11
11
  const request = new XMLHttpRequest();
@@ -19,6 +19,11 @@ import documentService from '@typo3/core/document-service';
19
19
  import Utility from '@typo3/backend/utility';
20
20
 
21
21
  declare type ActionDispatchArgument = unknown;
22
+ /**
23
+ * Delegates are invoked with arguments resolved from the DOM, so their concrete
24
+ * signature is only known to the registering side.
25
+ */
26
+ declare type ActionDispatchDelegate = (...args: never[]) => void;
22
27
 
23
28
  /**
24
29
  * Module: @typo3/backend/action-dispatcher
@@ -33,7 +38,7 @@ declare type ActionDispatchArgument = unknown;
33
38
  * data-dispatch-disabled>
34
39
  */
35
40
  class ActionDispatcher {
36
- private delegates: {[key: string]: (...args: ActionDispatchArgument[]) => void} = {};
41
+ private delegates: Record<string, ActionDispatchDelegate> = {};
37
42
 
38
43
  public constructor() {
39
44
  this.createDelegates();
@@ -82,7 +87,7 @@ class ActionDispatcher {
82
87
  const action = target.dataset.dispatchAction;
83
88
  let args: ActionDispatchArgument[] = ActionDispatcher.resolveArguments(target);
84
89
  if (args instanceof Array) {
85
- args = args.map((arg: string): ActionDispatchArgument => {
90
+ args = args.map((arg): ActionDispatchArgument => {
86
91
  switch (arg) {
87
92
  case '{$target}':
88
93
  return target;
@@ -94,7 +99,7 @@ class ActionDispatcher {
94
99
  });
95
100
  }
96
101
  if (this.delegates[action]) {
97
- this.delegates[action].apply(null, args || []);
102
+ this.delegates[action].apply(null, (args || []) as never[]);
98
103
  }
99
104
  }
100
105
  }
@@ -21,6 +21,7 @@ import Modal from '../modal';
21
21
  import Notification from '../notification';
22
22
  import { SeverityEnum } from '../enum/severity';
23
23
  import { PseudoButtonLitElement } from '@typo3/backend/element/pseudo-button';
24
+ import { topDocument } from '@typo3/core/utility/top-window';
24
25
  import '@typo3/backend/element/spinner-element';
25
26
  import '@typo3/backend/element/icon-element';
26
27
  import labels from '~labels/core.bookmarks';
@@ -1208,7 +1209,7 @@ export class BookmarkManagerButtonElement extends PseudoButtonLitElement {
1208
1209
 
1209
1210
  protected override buttonActivated(): void {
1210
1211
  // Create element in top frame to avoid adoptedStyleSheets cross-document issues
1211
- const targetDocument = top?.document ?? document;
1212
+ const targetDocument = topDocument;
1212
1213
  const managerElement = targetDocument.createElement('typo3-backend-bookmark-manager-content') as BookmarkManagerContentElement;
1213
1214
  if (this.editId !== undefined) {
1214
1215
  managerElement.editId = this.editId;
@@ -20,6 +20,7 @@ import Notification from '../notification';
20
20
  import { SeverityEnum } from '../enum/severity';
21
21
  import { BroadcastMessage, type BroadcastEvent } from '@typo3/backend/broadcast-message';
22
22
  import BroadcastService from '@typo3/backend/broadcast-service';
23
+ import { topWindow } from '@typo3/core/utility/top-window';
23
24
 
24
25
  export const BookmarkStoreChangedEvent = 'typo3:bookmark-store:changed';
25
26
 
@@ -159,10 +160,10 @@ class BookmarkStore {
159
160
  let bookmarks = await this.getBookmarks();
160
161
 
161
162
  if (options?.accessibleOnly) {
162
- bookmarks = bookmarks.filter((b: Bookmark) => b.accessible);
163
+ bookmarks = bookmarks.filter((b) => b.accessible);
163
164
  }
164
165
  if (options?.groupId !== undefined) {
165
- bookmarks = bookmarks.filter((b: Bookmark) => b.groupId === options.groupId);
166
+ bookmarks = bookmarks.filter((b) => b.groupId === options.groupId);
166
167
  }
167
168
  if (options?.limit !== undefined && options.limit > 0 && bookmarks.length > options.limit) {
168
169
  bookmarks = bookmarks.slice(0, options.limit);
@@ -178,8 +179,8 @@ class BookmarkStore {
178
179
  groupSortingMap.set(group.id, group.sorting);
179
180
  });
180
181
 
181
- const groupIds = [...new Set(bookmarks.map((b: Bookmark) => b.groupId))];
182
- const sortedBookmarkGroupIds = groupIds.sort((a: BookmarkGroupId, b: BookmarkGroupId) => {
182
+ const groupIds = [...new Set(bookmarks.map((b) => b.groupId))];
183
+ const sortedBookmarkGroupIds = groupIds.sort((a, b) => {
183
184
  // First sort by priority (lower values first)
184
185
  const priorityA = groupPriorityMap.get(a) ?? Number.MAX_SAFE_INTEGER;
185
186
  const priorityB = groupPriorityMap.get(b) ?? Number.MAX_SAFE_INTEGER;
@@ -195,7 +196,7 @@ class BookmarkStore {
195
196
  });
196
197
 
197
198
  for (const groupId of sortedBookmarkGroupIds) {
198
- const groupBookmarks = bookmarks.filter((b: Bookmark) => b.groupId === groupId);
199
+ const groupBookmarks = bookmarks.filter((b) => b.groupId === groupId);
199
200
  if (groupBookmarks.length > 0) {
200
201
  grouped.set(groupId, groupBookmarks);
201
202
  }
@@ -683,19 +684,14 @@ class BookmarkStore {
683
684
  * Returns singleton instance from top frame, creating it if needed.
684
685
  */
685
686
  function getOrCreateInstance(): BookmarkStore {
686
- try {
687
- if (top?.TYPO3?.BookmarkStore) {
688
- return top.TYPO3.BookmarkStore;
689
- }
690
- const instance = new BookmarkStore();
691
- if (top?.TYPO3) {
692
- top.TYPO3.BookmarkStore = instance;
693
- }
694
- return instance;
695
- } catch {
696
- // Cross-origin access denied, create local instance
697
- return new BookmarkStore();
687
+ if (topWindow.TYPO3?.BookmarkStore) {
688
+ return topWindow.TYPO3.BookmarkStore;
689
+ }
690
+ const instance = new BookmarkStore();
691
+ if (topWindow.TYPO3) {
692
+ topWindow.TYPO3.BookmarkStore = instance;
698
693
  }
694
+ return instance;
699
695
  }
700
696
 
701
697
  export default getOrCreateInstance();
@@ -21,6 +21,7 @@ import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
21
21
  import Notification from '@typo3/backend/notification';
22
22
  import '@typo3/backend/element/spinner-element';
23
23
  import '@typo3/backend/element/icon-element';
24
+ import { topWindow } from '@typo3/core/utility/top-window';
24
25
 
25
26
  enum CopyMode {
26
27
  cut = 'cut',
@@ -60,11 +61,12 @@ interface DispatchArgs {
60
61
  * Module: @typo3/backend/clipboard-panel
61
62
  *
62
63
  * @example
63
- * <typo3-backend-clipboard-panel return-url="/typo3/module" table="_FILE"></typo3-backend-clipboard-panel>
64
+ * <typo3-backend-clipboard-panel return-url="/typo3/module" module-url="/typo3/clipboard/process" table="_FILE"></typo3-backend-clipboard-panel>
64
65
  */
65
66
  @customElement('typo3-backend-clipboard-panel')
66
67
  export class ClipboardPanel extends LitElement {
67
68
  @property({ type: String, attribute: 'return-url' }) returnUrl: string = '';
69
+ @property({ type: String, attribute: 'module-url' }) moduleUrl: string = '';
68
70
  @property({ type: String }) table: string = '';
69
71
 
70
72
  private static renderLoader(): TemplateResult {
@@ -89,8 +91,12 @@ export class ClipboardPanel extends LitElement {
89
91
  `;
90
92
  }
91
93
 
94
+ private getModuleUrl(): string {
95
+ return this.moduleUrl || topWindow.TYPO3.settings.Clipboard.moduleUrl;
96
+ }
97
+
92
98
  private renderPanel(): Promise<TemplateResult> {
93
- return (new AjaxRequest(top.TYPO3.settings.Clipboard.moduleUrl))
99
+ return (new AjaxRequest(this.getModuleUrl()))
94
100
  .withQueryArguments({ action: 'getClipboardData' })
95
101
  .post({ table: this.table })
96
102
  .then(async (response: AjaxResponse): Promise<TemplateResult> => {
@@ -105,7 +111,7 @@ export class ClipboardPanel extends LitElement {
105
111
  <div class="table-fit">
106
112
  <table class="table">
107
113
  <tbody>
108
- ${clipboardData.tabs.map((tab: ClipboardTab): TemplateResult => this.renderTab(tab, clipboardData))}
114
+ ${clipboardData.tabs.map((tab): TemplateResult => this.renderTab(tab, clipboardData))}
109
115
  </tbody>
110
116
  </table>
111
117
  </div>
@@ -166,7 +172,7 @@ export class ClipboardPanel extends LitElement {
166
172
  `}
167
173
  </td>
168
174
  </tr>
169
- ${clipboardData.current === tab.identifier && tab.items ? tab.items.map((tabItem: ClipboardTabItem): TemplateResult => this.renderTabItem(tabItem, tab.identifier, clipboardData)) : nothing}
175
+ ${clipboardData.current === tab.identifier && tab.items ? tab.items.map((tabItem): TemplateResult => this.renderTabItem(tabItem, tab.identifier, clipboardData)) : nothing}
170
176
  `;
171
177
  }
172
178
 
@@ -202,7 +208,7 @@ export class ClipboardPanel extends LitElement {
202
208
  private updateClipboard(event: PointerEvent, payload: object): void {
203
209
  event.preventDefault();
204
210
  const target: HTMLElement = event.currentTarget as HTMLElement;
205
- (new AjaxRequest(top.TYPO3.settings.Clipboard.moduleUrl))
211
+ (new AjaxRequest(this.getModuleUrl()))
206
212
  .post(payload)
207
213
  .then(async (response: AjaxResponse): Promise<void> => {
208
214
  const resolvedBody = await response.resolve();
@@ -163,7 +163,7 @@ export class CodeMirrorElement extends LitElement {
163
163
  root: document.body
164
164
  };
165
165
  const observer = new IntersectionObserver((entries: IntersectionObserverEntry[]): void => {
166
- entries.forEach((entry: IntersectionObserverEntry): void => {
166
+ entries.forEach((entry): void => {
167
167
  if (entry.intersectionRatio > 0) {
168
168
  observer.unobserve(entry.target);
169
169
  if (this.firstElementChild && this.firstElementChild.nodeName.toLowerCase() === 'textarea') {
@@ -90,7 +90,7 @@ export async function complete(context: CompletionContext): Promise<CompletionRe
90
90
  const completions = getCompletions(tokenValue, keywords);
91
91
  return {
92
92
  from: completionStart,
93
- options: completions.map((result: string) => {
93
+ options: completions.map((result) => {
94
94
  return { label: result, type: 'keyword' };
95
95
  })
96
96
  };
@@ -129,7 +129,7 @@ function extractCodemirror5StyleLineTokens(lineCount: number, context: Completio
129
129
  // stream parser doesn't perform proper tokenization.
130
130
  // Insert content as null-type token into the lineToken array.
131
131
  if (lastToken < start) {
132
- context.state.sliceDoc(lastToken, start).split(context.state.lineBreak).forEach((part: string) => {
132
+ context.state.sliceDoc(lastToken, start).split(context.state.lineBreak).forEach((part) => {
133
133
  if (part) {
134
134
  lineTokens[Math.min(lineNumber - 1, lineCount - 1)].push({ type: null, string: part, start: lastToken, end: lastToken + part.length });
135
135
  lineNumber++;
@@ -162,7 +162,7 @@ function tokenIsSubStringOfKeywords(token: string, keywords: string[]): boolean
162
162
  }
163
163
 
164
164
  function getCompletions(token: string, keywords: string[]) {
165
- const found = new Set();
165
+ const found = new Set<string>();
166
166
 
167
167
  const maybeAdd = (str: string) => {
168
168
  if (str.lastIndexOf(token, 0) === 0 && !found.has(str)) {
@@ -8,8 +8,8 @@ type Keyword = {
8
8
  };
9
9
 
10
10
  type CombinatorReturnType = boolean | undefined;
11
- type CombinatorFunction = (type?: Type, value?: unknown) => CombinatorReturnType;
12
- type CombinatorLexFunction = ((type?: Type, value?: unknown) => CombinatorReturnType) & { lex: true };
11
+ type CombinatorFunction = (type?: Type, value?: Value) => CombinatorReturnType;
12
+ type CombinatorLexFunction = ((type?: Type, value?: Value) => CombinatorReturnType) & { lex: true };
13
13
  type CC = CombinatorFunction | CombinatorLexFunction;
14
14
 
15
15
  type CX = {
@@ -107,7 +107,7 @@ export class Typo3BackendColorPicker extends LitElement {
107
107
 
108
108
  // input: react on user input
109
109
  // change: react on indirect changes, e.g. a value picker
110
- ['input', 'change'].forEach((eventName: string): void => {
110
+ ['input', 'change'].forEach((eventName): void => {
111
111
  new RegularEvent(eventName, (e: Event): void => {
112
112
  const input = (e.target as HTMLInputElement);
113
113
  this.color = input.value;
@@ -151,7 +151,7 @@ class LegacyColorPicker {
151
151
  }
152
152
 
153
153
  const colorPicker = document.createElement('typo3-backend-color-picker');
154
- colorPicker.swatches = options.swatches.map((swatch: string) => ({ color: swatch, label: swatch }));
154
+ colorPicker.swatches = options.swatches.map((swatch) => ({ color: swatch, label: swatch }));
155
155
  colorPicker.opacity = options.opacity ?? false;
156
156
  element.parentNode.insertBefore(colorPicker, element);
157
157
  colorPicker.appendChild(element);
@@ -116,7 +116,7 @@ export class ColumnSelectorButton extends PseudoButtonLitElement {
116
116
  * @private
117
117
  */
118
118
  private static filterColumns(columnsFilter: HTMLInputElement, columns: NodeListOf<HTMLInputElement>): void {
119
- columns.forEach((column: HTMLInputElement) => {
119
+ columns.forEach((column) => {
120
120
  const columnContainer: HTMLDivElement = column.closest(Selectors.columnsContainerSelector);
121
121
  if (!column.disabled && columnContainer !== null) {
122
122
  const filterValue: string = columnContainer.querySelector('.form-check-label')?.textContent;
@@ -218,7 +218,7 @@ export class ColumnSelectorButton extends PseudoButtonLitElement {
218
218
  ColumnSelectorButton.toggleSelectorActions(columns, selectAll, selectNone, true);
219
219
 
220
220
  // Add event listener for each column to toggle the selector actions after change
221
- columns.forEach((column: HTMLInputElement) => {
221
+ columns.forEach((column) => {
222
222
  column.addEventListener('change', (): void => {
223
223
  ColumnSelectorButton.toggleSelectorActions(columns, selectAll, selectNone);
224
224
  });
@@ -248,7 +248,7 @@ export class ColumnSelectorButton extends PseudoButtonLitElement {
248
248
 
249
249
  // Add event listener for all columns select actions. querySelectorAll will return
250
250
  // at least two actions (selectAll and selectNone) which we checked above already
251
- columnsSelectorActions.querySelectorAll('button[data-action]').forEach((action: HTMLButtonElement) => {
251
+ columnsSelectorActions.querySelectorAll<HTMLButtonElement>('button[data-action]').forEach((action) => {
252
252
  action.addEventListener('click', (e: Event): void => {
253
253
  e.preventDefault();
254
254
 
@@ -261,21 +261,21 @@ export class ColumnSelectorButton extends PseudoButtonLitElement {
261
261
  // Perform requested action
262
262
  switch (target.dataset.action) {
263
263
  case SelectorActions.toggle:
264
- columns.forEach((column: HTMLInputElement) => {
264
+ columns.forEach((column) => {
265
265
  if (!column.disabled && !ColumnSelectorButton.isColumnHidden(column)) {
266
266
  column.checked = !column.checked;
267
267
  }
268
268
  });
269
269
  break;
270
270
  case SelectorActions.all:
271
- columns.forEach((column: HTMLInputElement) => {
271
+ columns.forEach((column) => {
272
272
  if (!column.disabled && !ColumnSelectorButton.isColumnHidden(column)) {
273
273
  column.checked = true;
274
274
  }
275
275
  });
276
276
  break;
277
277
  case SelectorActions.none:
278
- columns.forEach((column: HTMLInputElement) => {
278
+ columns.forEach((column) => {
279
279
  if (!column.disabled && !ColumnSelectorButton.isColumnHidden(column)) {
280
280
  column.checked = false;
281
281
  }
@@ -32,8 +32,8 @@ class ContextHelp {
32
32
 
33
33
  public async initialize(): Promise<void> {
34
34
  await DocumentService.ready();
35
- const elements = document.querySelectorAll(this.selector);
36
- elements.forEach((element: HTMLElement): void => {
35
+ const elements = document.querySelectorAll<HTMLElement>(this.selector);
36
+ elements.forEach((element): void => {
37
37
  element.dataset.bsHtml = 'true';
38
38
  element.dataset.bsPlacement = this.placement;
39
39
  element.dataset.bsTrigger = this.trigger;
@@ -56,7 +56,7 @@ class ContextHelp {
56
56
 
57
57
  new RegularEvent('click', (e: Event): void => {
58
58
  const me = e.target as HTMLElement;
59
- elements.forEach((element: HTMLElement): void => {
59
+ elements.forEach((element): void => {
60
60
  if (!element.isEqualNode(me)) {
61
61
  Popover.hide(element);
62
62
  }
@@ -23,6 +23,7 @@ import Viewport from './viewport';
23
23
  import '@typo3/backend/new-record-wizard';
24
24
  import Utility from '@typo3/backend/utility';
25
25
  import { topLevelModuleImport } from '@typo3/backend/utility/top-level-module-import';
26
+ import { topWindow, topDocument } from '@typo3/core/utility/top-window';
26
27
  import { html } from 'lit';
27
28
  import coreCommonLabels from '~labels/core.common';
28
29
  import cacheLabels from '~labels/core.cache';
@@ -38,7 +39,8 @@ class ContextMenuActions {
38
39
  * @returns {string}
39
40
  */
40
41
  public static getReturnUrl(): string {
41
- return encodeURIComponent(top.list_frame.document.location.pathname + top.list_frame.document.location.search);
42
+ const location = topWindow.list_frame.document.location;
43
+ return encodeURIComponent(location.pathname + location.search);
42
44
  }
43
45
 
44
46
  public static editRecord(table: string, uid: number, dataset: DOMStringMap): void {
@@ -51,10 +53,10 @@ class ContextMenuActions {
51
53
  }
52
54
 
53
55
  Viewport.ContentContainer.setUrl(
54
- top.TYPO3.settings.FormEngine.moduleUrl
56
+ topWindow.TYPO3.settings.FormEngine.moduleUrl
55
57
  + '&edit[' + table + '][' + uid + ']=edit'
56
58
  + overrideVals
57
- + '&module=' + encodeURIComponent(top.TYPO3.ModuleMenu.App.getCurrentModule())
59
+ + '&module=' + encodeURIComponent(topWindow.TYPO3.ModuleMenu.App.getCurrentModule())
58
60
  + '&returnUrl=' + ContextMenuActions.getReturnUrl(),
59
61
  );
60
62
  }
@@ -112,7 +114,7 @@ class ContextMenuActions {
112
114
  pageId: uid
113
115
  },
114
116
  });
115
- top.document.dispatchEvent(event);
117
+ topDocument.dispatchEvent(event);
116
118
  }
117
119
  }
118
120
 
@@ -152,13 +154,13 @@ class ContextMenuActions {
152
154
  }
153
155
 
154
156
  Viewport.ContentContainer.setUrl(
155
- top.TYPO3.settings.FormEngine.moduleUrl + '&edit[' + table + '][' + (table !== 'pages' ? '-' : '') + uid + ']=new&returnUrl=' + ContextMenuActions.getReturnUrl(),
157
+ topWindow.TYPO3.settings.FormEngine.moduleUrl + '&edit[' + table + '][' + (table !== 'pages' ? '-' : '') + uid + ']=new&returnUrl=' + ContextMenuActions.getReturnUrl(),
156
158
  );
157
159
  }
158
160
 
159
161
  public static openHistoryPopUp(table: string, uid: number): void {
160
162
  Viewport.ContentContainer.setUrl(
161
- top.TYPO3.settings.RecordHistory.moduleUrl + '&element=' + table + ':' + uid + '&returnUrl=' + ContextMenuActions.getReturnUrl(),
163
+ topWindow.TYPO3.settings.RecordHistory.moduleUrl + '&element=' + table + ':' + uid + '&returnUrl=' + ContextMenuActions.getReturnUrl(),
162
164
  );
163
165
  }
164
166
 
@@ -198,7 +200,7 @@ class ContextMenuActions {
198
200
  public static disableRecord(table: string, uid: number, dataset: DOMStringMap): void {
199
201
  const disableFieldName = dataset.disableField || 'hidden';
200
202
  Viewport.ContentContainer.setUrl(
201
- top.TYPO3.settings.RecordCommit.moduleUrl
203
+ topWindow.TYPO3.settings.RecordCommit.moduleUrl
202
204
  + '&data[' + table + '][' + uid + '][' + disableFieldName + ']=1'
203
205
  + '&redirect=' + ContextMenuActions.getReturnUrl(),
204
206
  );
@@ -207,7 +209,7 @@ class ContextMenuActions {
207
209
  public static enableRecord(table: string, uid: number, dataset: DOMStringMap): void {
208
210
  const disableFieldName = dataset.disableField || 'hidden';
209
211
  Viewport.ContentContainer.setUrl(
210
- top.TYPO3.settings.RecordCommit.moduleUrl
212
+ topWindow.TYPO3.settings.RecordCommit.moduleUrl
211
213
  + '&data[' + table + '][' + uid + '][' + disableFieldName + ']=0'
212
214
  + '&redirect=' + ContextMenuActions.getReturnUrl(),
213
215
  );
@@ -215,7 +217,7 @@ class ContextMenuActions {
215
217
 
216
218
  public static showInMenus(table: string, uid: number): void {
217
219
  Viewport.ContentContainer.setUrl(
218
- top.TYPO3.settings.RecordCommit.moduleUrl
220
+ topWindow.TYPO3.settings.RecordCommit.moduleUrl
219
221
  + '&data[' + table + '][' + uid + '][nav_hide]=0'
220
222
  + '&redirect=' + ContextMenuActions.getReturnUrl(),
221
223
  );
@@ -223,7 +225,7 @@ class ContextMenuActions {
223
225
 
224
226
  public static hideInMenus(table: string, uid: number): void {
225
227
  Viewport.ContentContainer.setUrl(
226
- top.TYPO3.settings.RecordCommit.moduleUrl
228
+ topWindow.TYPO3.settings.RecordCommit.moduleUrl
227
229
  + '&data[' + table + '][' + uid + '][nav_hide]=1'
228
230
  + '&redirect=' + ContextMenuActions.getReturnUrl(),
229
231
  );
@@ -350,7 +352,7 @@ class ContextMenuActions {
350
352
  + '&redirect=' + ContextMenuActions.getReturnUrl();
351
353
 
352
354
  Viewport.ContentContainer.setUrl(
353
- top.TYPO3.settings.RecordCommit.moduleUrl + url,
355
+ topWindow.TYPO3.settings.RecordCommit.moduleUrl + url,
354
356
  );
355
357
  };
356
358
  if (!dataset.title) {
@@ -384,7 +386,7 @@ class ContextMenuActions {
384
386
  }
385
387
 
386
388
  private static refreshPageTree(): void {
387
- top.document.dispatchEvent(new CustomEvent('typo3:pagetree:refresh'));
389
+ topDocument.dispatchEvent(new CustomEvent('typo3:pagetree:refresh'));
388
390
  }
389
391
  }
390
392
 
@@ -18,6 +18,7 @@ import '@typo3/backend/element/spinner-element';
18
18
  import { customElement, queryAll, state } from 'lit/decorators.js';
19
19
  import { html, LitElement, nothing, type TemplateResult } from 'lit';
20
20
  import { delay } from '@typo3/core/lit-helper';
21
+ import { topDocument } from '@typo3/core/utility/top-window';
21
22
  import { styleMap } from 'lit/directives/style-map.js';
22
23
  import { unsafeHTML } from 'lit/directives/unsafe-html.js';
23
24
  import { Task, initialState } from '@lit/task';
@@ -99,7 +100,7 @@ class ContextMenu {
99
100
  bubbles: true,
100
101
  composed: true
101
102
  });
102
- top.document.dispatchEvent(contextMenuEvent);
103
+ topDocument.dispatchEvent(contextMenuEvent);
103
104
  }
104
105
 
105
106
  private handleTriggerEvent(event: PointerEvent): void {
@@ -192,11 +193,11 @@ export class ContextMenuElement extends LitElement {
192
193
  onComplete: () => {
193
194
  this.focusFirstElement = true;
194
195
  },
195
- onError: (error: Error|AjaxResponse) => {
196
+ onError: (error: unknown) => {
196
197
  if (error instanceof AjaxResponse) {
197
198
  Notification.error('', error.response.status + ' ' + error.response.statusText, 5);
198
199
  } else {
199
- Notification.error('', error.message);
200
+ Notification.error('', (error as Error).message);
200
201
  }
201
202
  },
202
203
  });
@@ -551,7 +552,7 @@ export class ContextMenuElement extends LitElement {
551
552
 
552
553
  private getNodeByIdentifier(identifier: string): MenuItemInterface | null {
553
554
  const flattenedNodes = this.flattenMenuItems(this.nodes);
554
- return flattenedNodes.find((node: MenuItemInterface) => {
555
+ return flattenedNodes.find((node) => {
555
556
  return this.getNodeIdentifier(node) === identifier;
556
557
  }) ?? null;
557
558
  }
@@ -748,4 +749,9 @@ declare global {
748
749
  interface HTMLElementTagNameMap {
749
750
  'typo3-backend-context-menu': ContextMenuElement;
750
751
  }
752
+
753
+ interface DocumentEventMap {
754
+ [ContextMenuEvent.open]: CustomEvent<ContextMenuEventDetail>;
755
+ [ContextMenuEvent.close]: CustomEvent<ContextMenuEventDetail>;
756
+ }
751
757
  }
@@ -15,6 +15,7 @@ import FormEngine from '@typo3/backend/form-engine';
15
15
  import Modal from '@typo3/backend/modal';
16
16
  import Severity from '@typo3/backend/severity';
17
17
  import DocumentService from '@typo3/core/document-service';
18
+ import { topWindow } from '@typo3/core/utility/top-window';
18
19
  import '@typo3/backend/element/icon-element';
19
20
  import labels from '~labels/backend.alt_doc';
20
21
 
@@ -78,7 +79,7 @@ class ContextualRecordEdit {
78
79
  document.querySelectorAll('.has-change').forEach((el) => el.classList.remove('has-change'));
79
80
  // Navigate the content frame directly (same-origin access) — using
80
81
  // postMessage for this failed silently in Firefox.
81
- top?.TYPO3?.Backend?.ContentContainer?.setUrl(this.fullscreenButton.href);
82
+ topWindow.TYPO3?.Backend?.ContentContainer?.setUrl(this.fullscreenButton.href);
82
83
  // Tell the parent to close the modal
83
84
  window.parent.postMessage(
84
85
  { actionName: 'typo3:editform:navigate' },