typo3-typescript-sources 14.0.0 → 14.1.1

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 (77) hide show
  1. package/.last-synced-tag +1 -1
  2. package/README-TYPO3.md +1 -1
  3. package/README.md +1 -1
  4. package/backend/clear-cache.ts +1 -1
  5. package/backend/code-editor/stream-parser/typoscript.ts +1 -1
  6. package/backend/context-menu-actions.ts +16 -2
  7. package/backend/date-time-picker.ts +20 -0
  8. package/backend/drag-uploader.ts +10 -4
  9. package/backend/element/progress-bar-element.ts +127 -1
  10. package/backend/element/qrcode-element.ts +1 -1
  11. package/backend/element/sidebar-toggle-element.ts +110 -0
  12. package/backend/enum/viewport/scaffold-identifier.ts +24 -4
  13. package/backend/form-engine/container/files-control-container.ts +8 -8
  14. package/backend/form-engine/container/inline-control-container.ts +8 -12
  15. package/backend/form-engine/container/site-language-container.ts +8 -8
  16. package/backend/form-engine/element/category-element.ts +0 -1
  17. package/backend/form-engine/element/extra/select-box-filter.ts +4 -0
  18. package/backend/form-engine/element/select-tree-element.ts +0 -1
  19. package/backend/form-engine/element/select-tree-toolbar.ts +1 -6
  20. package/backend/form-engine-validation.ts +1 -0
  21. package/backend/live-search/element/result/result-container.ts +5 -0
  22. package/backend/live-search/element/result/result-pagination.ts +2 -1
  23. package/backend/localization/steps/content-record-selection-step.ts +2 -2
  24. package/backend/login.ts +5 -1
  25. package/backend/modal.ts +46 -11
  26. package/backend/module-menu.ts +4 -80
  27. package/backend/online-media.ts +9 -3
  28. package/backend/recordlist.ts +3 -3
  29. package/backend/security/element/csp-reports.ts +83 -4
  30. package/backend/settings/editor/editable-setting.ts +1 -1
  31. package/backend/settings/editor.ts +1 -0
  32. package/backend/toolbar/live-search.ts +11 -7
  33. package/backend/toolbar/shortcut-menu.ts +2 -2
  34. package/backend/toolbar.ts +8 -5
  35. package/backend/tree/file-storage-browser.ts +8 -13
  36. package/backend/tree/file-storage-tree-container.ts +12 -15
  37. package/backend/tree/page-browser.ts +12 -8
  38. package/backend/tree/page-tree-element.ts +89 -36
  39. package/backend/tree/tree-node.ts +1 -0
  40. package/backend/tree/tree-toolbar.ts +8 -4
  41. package/backend/tree/tree.ts +11 -4
  42. package/backend/user-settings-manager.ts +22 -1
  43. package/backend/utility/collapse-state-search.ts +5 -6
  44. package/backend/viewport/content-navigation-toggle.ts +277 -0
  45. package/backend/viewport/content-navigation.ts +470 -0
  46. package/backend/viewport/loader.ts +13 -5
  47. package/backend/viewport/navigation-container.ts +27 -20
  48. package/backend/viewport/scaffold-state.ts +268 -0
  49. package/backend/viewport/toolbar.ts +75 -0
  50. package/backend/wizard/move-page.ts +2 -2
  51. package/extensionmanager/main.ts +30 -15
  52. package/extensionmanager/repository.ts +21 -16
  53. package/extensionmanager/update.ts +13 -3
  54. package/filelist/browse-files.ts +0 -6
  55. package/filelist/file-list.ts +18 -8
  56. package/form/backend/form-editor/inspector-component.ts +6 -1
  57. package/form/backend/form-editor/stage-component.ts +6 -1
  58. package/form/backend/form-editor/tree-component.ts +3 -1
  59. package/form/backend/form-manager/main.ts +10 -11
  60. package/install/module/environment/folder-structure.ts +4 -1
  61. package/install/module/maintenance/reference-index.ts +1 -1
  62. package/install/module/password-strength.ts +2 -0
  63. package/install/module/settings/extension-configuration.ts +0 -2
  64. package/install/module/settings/local-configuration.ts +0 -4
  65. package/install/module/upgrade/upgrade-docs.ts +5 -4
  66. package/install/module/upgrade/upgrade-wizards.ts +3 -1
  67. package/install/router.ts +5 -29
  68. package/package.json +2 -2
  69. package/recycler/recycler.ts +30 -18
  70. package/redirects/element/qrcode-modal-button.ts +75 -0
  71. package/rte-ckeditor/plugin/typo3-link.ts +32 -0
  72. package/styleguide/element/theme-switcher-element.ts +2 -2
  73. package/styleguide/processing-indicator.ts +16 -7
  74. package/workspaces/backend.ts +8 -14
  75. package/workspaces/workspaces.ts +10 -4
  76. package/backend/viewport/resizable-navigation.ts +0 -176
  77. package/install/renderable/clearable.ts +0 -113
package/.last-synced-tag CHANGED
@@ -1 +1 @@
1
- v14.0.0
1
+ v14.1.1
package/README-TYPO3.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # TYPO3 CMS
2
2
 
3
3
  TYPO3 is an open source PHP based web content management system released
4
- under the GNU GPL. TYPO3 is copyright © 1999-2025 by Kasper Skårhøj.
4
+ under the GNU GPL. TYPO3 is copyright © 1999-2026 by Kasper Skårhøj.
5
5
 
6
6
  This document provides a basic introduction to TYPO3.
7
7
 
package/README.md CHANGED
@@ -16,7 +16,7 @@ npm install typo3-typescript-sources
16
16
 
17
17
  - **Original Repository:** [TYPO3/typo3](https://github.com/TYPO3/typo3)
18
18
  - **Source Path:** `Build/Sources/TypeScript/`
19
- - **Current TYPO3 Version:** `v14.0.0`
19
+ - **Current TYPO3 Version:** `v14.1.1`
20
20
 
21
21
  ## 🌿 Branches
22
22
 
@@ -42,7 +42,7 @@ class ClearCache {
42
42
  * @return Promise<AjaxResponse>
43
43
  */
44
44
  private static sendClearCacheRequest(pageId: number): Promise<AjaxResponse> {
45
- const request = new AjaxRequest(TYPO3.settings.ajaxUrls.web_list_clearpagecache).withQueryArguments({ id: pageId }).get({ cache: 'no-cache' });
45
+ const request = new AjaxRequest(TYPO3.settings.ajaxUrls.records_clearpagecache).withQueryArguments({ id: pageId }).get({ cache: 'no-cache' });
46
46
  request.then(async (response: AjaxResponse): Promise<void> => {
47
47
  const data = await response.resolve();
48
48
  if (data.success === true) {
@@ -929,7 +929,7 @@ export class TypoScriptStreamParserFactory {
929
929
  'web_func': B,
930
930
  'web_info': B,
931
931
  'web_layout': B,
932
- 'web_list': B,
932
+ 'records': B,
933
933
  'web_ts': kw('web_ts'),
934
934
  'where': kw('where'),
935
935
  'width': kw('width'),
@@ -117,7 +117,7 @@ class ContextMenuActions {
117
117
 
118
118
  public static openListModule(table: string, uid: number, dataset: DOMStringMap): void {
119
119
  const pageId = table === 'pages' ? uid : dataset.pageUid;
120
- ModuleMenu.App.showModule('web_list', 'id=' + pageId);
120
+ ModuleMenu.App.showModule('records', 'id=' + pageId);
121
121
  }
122
122
 
123
123
  public static pagesSort(table: string, uid: number, dataset: DOMStringMap): void {
@@ -127,6 +127,20 @@ class ContextMenuActions {
127
127
  }
128
128
  }
129
129
 
130
+ public static openSiteSettings(table: string, uid: number, dataset: DOMStringMap): void {
131
+ const siteSettingsUrl = dataset.siteSettingsUrl;
132
+ if (siteSettingsUrl) {
133
+ Viewport.ContentContainer.setUrl(siteSettingsUrl + '&returnUrl=' + ContextMenuActions.getReturnUrl());
134
+ }
135
+ }
136
+
137
+ public static openSiteConfiguration(table: string, uid: number, dataset: DOMStringMap): void {
138
+ const siteConfigurationUrl = dataset.siteConfigurationUrl;
139
+ if (siteConfigurationUrl) {
140
+ Viewport.ContentContainer.setUrl(siteConfigurationUrl + '&returnUrl=' + ContextMenuActions.getReturnUrl());
141
+ }
142
+ }
143
+
130
144
  public static pagesNewMultiple(table: string, uid: number, dataset: DOMStringMap): void {
131
145
  const pagesSortUrl = dataset.pagesNewMultipleUrl;
132
146
  if (pagesSortUrl) {
@@ -240,7 +254,7 @@ class ContextMenuActions {
240
254
  * Clear cache for given page uid
241
255
  */
242
256
  public static clearCache(table: string, uid: number): void {
243
- (new AjaxRequest(TYPO3.settings.ajaxUrls.web_list_clearpagecache)).withQueryArguments({ id: uid }).get({ cache: 'no-cache' }).then(
257
+ (new AjaxRequest(TYPO3.settings.ajaxUrls.records_clearpagecache)).withQueryArguments({ id: uid }).get({ cache: 'no-cache' }).then(
244
258
  async (response: AjaxResponse): Promise<void> => {
245
259
  const data = await response.resolve();
246
260
  if (data.success === true) {
@@ -12,6 +12,7 @@
12
12
  */
13
13
 
14
14
  import flatpickr from 'flatpickr';
15
+ import Persistent from '@typo3/backend/storage/persistent';
15
16
  import ShortcutButtonsPlugin from 'shortcut-buttons-flatpickr';
16
17
  import { DateTime } from 'luxon';
17
18
  import ThrottleEvent from '@typo3/core/event/throttle-event';
@@ -63,6 +64,20 @@ class DateTimePicker {
63
64
  const scrollEvent = this.getScrollEvent();
64
65
  const options = this.getDateOptions(inputElement);
65
66
  options.locale = locale;
67
+
68
+ // Custom "first day of week" user preference
69
+ const dow = Persistent.get('dateTimeFirstDayOfWeek');
70
+
71
+ if (dow !== '') {
72
+ // stored number is 1-index based, convert to 0-index.
73
+ const dowNumber = parseInt(dow, 10) - 1;
74
+
75
+ // two entries need to be adjusted here for proper utilization
76
+ // in non-english localisations.
77
+ flatpickr.l10ns[locale].firstDayOfWeek = dowNumber;
78
+ flatpickr.l10ns.default.firstDayOfWeek = dowNumber;
79
+ }
80
+
66
81
  options.onOpen = [
67
82
  (): void => {
68
83
  scrollEvent.bindTo(document.querySelector('.t3js-module-body'));
@@ -251,6 +266,11 @@ class DateTimePicker {
251
266
  options.enableTime = true;
252
267
  options.noCalendar = true;
253
268
  break;
269
+ case 'datetimesec':
270
+ options.altFormat = format[0] + ' HH:mm:ss';
271
+ options.enableSeconds = true;
272
+ options.enableTime = true;
273
+ break;
254
274
  case 'year':
255
275
  options.altFormat = 'yyyy';
256
276
  break;
@@ -16,7 +16,6 @@ import { DateTime } from 'luxon';
16
16
  import type { AjaxResponse } from '@typo3/core/ajax/ajax-response';
17
17
  import { SeverityEnum } from './enum/severity';
18
18
  import { MessageUtility } from './utility/message-utility';
19
- import NProgress from 'nprogress';
20
19
  import AjaxRequest from '@typo3/core/ajax/ajax-request';
21
20
  import { default as Modal, type ModalElement, Sizes as ModalSizes } from './modal';
22
21
  import Notification from './notification';
@@ -97,6 +96,7 @@ export default class DragUploader {
97
96
  private askForOverride: Array<FileConflict> = [];
98
97
 
99
98
  private percentagePerFile: number = 1;
99
+ private overallProgressBar: ProgressBarElement | null = null;
100
100
 
101
101
  private readonly body: HTMLElement;
102
102
  private readonly element: HTMLElement;
@@ -364,7 +364,9 @@ export default class DragUploader {
364
364
  this.fileList.closest('.filelist-main')?.querySelector('.t3-filelist-info-container')?.setAttribute('hidden', 'hidden');
365
365
  }
366
366
 
367
- NProgress.start();
367
+ this.overallProgressBar = document.createElement('typo3-backend-progress-bar');
368
+ document.body.appendChild(this.overallProgressBar);
369
+ this.overallProgressBar.start();
368
370
  this.percentagePerFile = 1 / files.length;
369
371
 
370
372
  // Check for each file if is already exist before adding it to the queue
@@ -382,7 +384,9 @@ export default class DragUploader {
382
384
  uploaded: file,
383
385
  action: this.irreObjectUid ? Action.USE_EXISTING : this.defaultAction,
384
386
  });
385
- NProgress.inc(this.percentagePerFile);
387
+ if (this.overallProgressBar) {
388
+ this.overallProgressBar.inc(this.percentagePerFile);
389
+ }
386
390
  } else {
387
391
  new FileQueueItem(this, file, Action.SKIP, this.fileList.dataset.mode === Mode.BROWSE ? Mode.BROWSE : Mode.MANAGE);
388
392
  }
@@ -392,7 +396,9 @@ export default class DragUploader {
392
396
 
393
397
  Promise.all(ajaxCalls).then((): void => {
394
398
  this.drawOverrideModal();
395
- NProgress.done();
399
+ if (this.overallProgressBar) {
400
+ this.overallProgressBar.done();
401
+ }
396
402
  });
397
403
 
398
404
  this.fileInput.value = '';
@@ -11,7 +11,7 @@
11
11
  * The TYPO3 project - inspiring people to share!
12
12
  */
13
13
 
14
- import { css, html, LitElement, nothing, type TemplateResult } from 'lit';
14
+ import { css, html, LitElement, nothing, type PropertyValues, type TemplateResult } from 'lit';
15
15
  import { customElement, property } from 'lit/decorators';
16
16
  import { classMap } from 'lit/directives/class-map';
17
17
  import { styleMap } from 'lit/directives/style-map.js';
@@ -23,6 +23,7 @@ import { SeverityEnum } from '@typo3/backend/enum/severity';
23
23
  * @internal
24
24
  *
25
25
  * @example
26
+ * Instance usage:
26
27
  * <typo3-backend-progress-bar></typo3-backend-progress-bar>
27
28
  * + `value` can be any positive number value between and 0 and `max` or `undefined`. The latter will render an indeterminate state.
28
29
  * + `max` represents the upper value range
@@ -42,6 +43,15 @@ export class ProgressBarElement extends LitElement {
42
43
  }
43
44
  }
44
45
 
46
+ @keyframes fade-out {
47
+ from {
48
+ opacity: 1;
49
+ }
50
+ to {
51
+ opacity: 0;
52
+ }
53
+ }
54
+
45
55
  :host {
46
56
  --progress-bar-height: 4px;
47
57
  --progress-bar-color-primary: var(--typo3-state-primary-border-color);
@@ -57,6 +67,14 @@ export class ProgressBarElement extends LitElement {
57
67
  border-radius: var(--progress-border-radius);
58
68
  }
59
69
 
70
+ :host([hidden]) {
71
+ display: none;
72
+ }
73
+
74
+ :host([is-hiding]) {
75
+ animation: fade-out 0.3s ease-out forwards;
76
+ }
77
+
60
78
  .progress {
61
79
  position: relative;
62
80
  overflow: hidden;
@@ -126,6 +144,99 @@ export class ProgressBarElement extends LitElement {
126
144
  @property({ type: Number, reflect: true }) max: number = 100;
127
145
  @property({ type: Number, reflect: true }) severity: SeverityEnum|undefined = undefined;
128
146
  @property({ type: String, reflect: true }) label: string|undefined;
147
+ @property({ type: Boolean, reflect: true, attribute: 'hidden' }) isHidden: boolean = false;
148
+ @property({ type: Boolean, state: true }) isHiding: boolean = false;
149
+
150
+ /**
151
+ * Used to cancel pending done/hide operations when the progress bar is reused.
152
+ * This prevents race conditions where a previous done() call could remove the
153
+ * element while a new start() has already begun.
154
+ */
155
+ private abortController: AbortController = new AbortController();
156
+
157
+ /**
158
+ * Start the progress bar. Sets value to 0 by default or undefined for indeterminate mode.
159
+ *
160
+ * @param indeterminate If true, shows indeterminate loading animation
161
+ */
162
+ public start(indeterminate: boolean = false): void {
163
+ // Cancel any pending done/hide operations
164
+ this.abortController.abort();
165
+ this.abortController = new AbortController();
166
+
167
+ this.isHiding = false;
168
+ this.isHidden = false;
169
+ this.value = indeterminate ? undefined : 0;
170
+ }
171
+
172
+ /**
173
+ * Increment the progress bar by a specific amount (or auto-increment if no amount given).
174
+ *
175
+ * @param amount The amount to increment (default: 5)
176
+ */
177
+ public inc(amount: number = 5): void {
178
+ let currentValue = this.value ?? 0;
179
+ currentValue = this.clamp(currentValue + amount, 0, this.max);
180
+ this.value = currentValue >= this.max ? this.max : currentValue;
181
+ }
182
+
183
+ /**
184
+ * Complete the progress bar and automatically hide it after the bar animation completes.
185
+ */
186
+ public async done(): Promise<void> {
187
+ // Capture signal at start to detect if start() was called during async operations
188
+ const signal = this.abortController.signal;
189
+
190
+ const currentValue = this.value ?? 0;
191
+ if (currentValue >= this.max) {
192
+ this.hide();
193
+ return;
194
+ }
195
+
196
+ if (isNaN(this.value)) {
197
+ this.value = 0;
198
+ }
199
+
200
+ await this.updateComplete;
201
+ if (signal.aborted) {
202
+ return;
203
+ }
204
+
205
+ await new Promise((resolve) => requestAnimationFrame(() => requestAnimationFrame(resolve)));
206
+ if (signal.aborted) {
207
+ return;
208
+ }
209
+
210
+ this.value = this.max;
211
+ await this.updateComplete;
212
+ if (signal.aborted) {
213
+ return;
214
+ }
215
+
216
+ const bar = this.shadowRoot.querySelector('.bar');
217
+ bar.addEventListener('transitionend', () => {
218
+ this.hide();
219
+ }, { once: true, signal });
220
+ }
221
+
222
+ /**
223
+ * Hide the progress bar with fade-out animation and remove from DOM.
224
+ */
225
+ public hide(): void {
226
+ this.isHiding = true;
227
+ this.addEventListener('animationend', () => {
228
+ this.remove();
229
+ }, { once: true, signal: this.abortController.signal });
230
+ }
231
+
232
+ public override connectedCallback(): void {
233
+ super.connectedCallback();
234
+ this.updateHostClass();
235
+ }
236
+
237
+ public override disconnectedCallback(): void {
238
+ super.disconnectedCallback();
239
+ }
129
240
 
130
241
  protected override render(): TemplateResult {
131
242
  const labelIdentifier = 'progress-label-' + (Math.random() + 1).toString(36).substring(2);
@@ -160,6 +271,21 @@ export class ProgressBarElement extends LitElement {
160
271
  `;
161
272
  }
162
273
 
274
+ protected override updated(changedProperties: PropertyValues): void {
275
+ super.updated(changedProperties);
276
+ if (changedProperties.has('isHiding')) {
277
+ this.updateHostClass();
278
+ }
279
+ }
280
+
281
+ private updateHostClass(): void {
282
+ if (this.isHiding) {
283
+ this.setAttribute('is-hiding', '');
284
+ } else {
285
+ this.removeAttribute('is-hiding');
286
+ }
287
+ }
288
+
163
289
  private clamp(value: number, min: number, max: number): number {
164
290
  return Math.min(max, Math.max(min, value));
165
291
  }
@@ -92,7 +92,7 @@ export class QrCodeElement extends LitElement {
92
92
  </select>
93
93
  </div>
94
94
  <div class="form-group">
95
- <button type="submit" class="btn btn-default">${downloadLabel}</button>
95
+ <button type="submit" class="btn btn-primary">${downloadLabel}</button>
96
96
  </div>
97
97
  </div>
98
98
  </form>`;
@@ -0,0 +1,110 @@
1
+ /*
2
+ * This file is part of the TYPO3 CMS project.
3
+ *
4
+ * It is free software; you can redistribute it and/or modify it under
5
+ * the terms of the GNU General Public License, either version 2
6
+ * of the License, or any later version.
7
+ *
8
+ * For the full copyright and license information, please read the
9
+ * LICENSE.txt file that was distributed with this source code.
10
+ *
11
+ * The TYPO3 project - inspiring people to share!
12
+ */
13
+
14
+ import { html, css, type TemplateResult } from 'lit';
15
+ import { customElement, property, state } from 'lit/decorators';
16
+ import { PseudoButtonLitElement } from './pseudo-button';
17
+ import { ScaffoldState, ScaffoldSidebarToggleEvent } from '../viewport/scaffold-state';
18
+ import '@typo3/backend/element/icon-element';
19
+
20
+ /**
21
+ * Module: @typo3/backend/element/sidebar-toggle-element
22
+ *
23
+ * Sidebar toggle button that displays different icons and labels based on sidebar state.
24
+ *
25
+ * @example
26
+ * <typo3-backend-sidebar-toggle
27
+ * label-collapse="Collapse sidebar"
28
+ * label-expand="Expand sidebar"
29
+ * ></typo3-backend-sidebar-toggle>
30
+ */
31
+ @customElement('typo3-backend-sidebar-toggle')
32
+ export class SidebarToggleElement extends PseudoButtonLitElement {
33
+ static override styles = [
34
+ ...PseudoButtonLitElement.styles,
35
+ css`
36
+ :host {
37
+ display: inline-flex;
38
+ align-items: center;
39
+ justify-content: center;
40
+ user-select: none;
41
+ }
42
+ :host([disabled]) {
43
+ pointer-events: none;
44
+ opacity: 0.5;
45
+ cursor: default;
46
+ }
47
+ `
48
+ ];
49
+
50
+ @property({ type: String, attribute: 'label-collapse' }) labelCollapse: string = 'Collapse sidebar';
51
+ @property({ type: String, attribute: 'label-expand' }) labelExpand: string = 'Expand sidebar';
52
+ @property({ type: Boolean, reflect: true }) disabled: boolean = false;
53
+
54
+ @state() private expanded: boolean = false;
55
+
56
+ public override connectedCallback(): void {
57
+ super.connectedCallback();
58
+ this.expanded = ScaffoldState.isLargeScreen() ? ScaffoldState.isSidebarExpanded() : ScaffoldState.isSidebarVisible();
59
+ this.updateLabels();
60
+ document.addEventListener(ScaffoldSidebarToggleEvent.eventName, this.handleSidebarToggle as EventListener);
61
+ }
62
+
63
+ public override disconnectedCallback(): void {
64
+ super.disconnectedCallback();
65
+ document.removeEventListener(ScaffoldSidebarToggleEvent.eventName, this.handleSidebarToggle as EventListener);
66
+ }
67
+
68
+ protected override updated(): void {
69
+ this.updateLabels();
70
+ this.updateDisabledState();
71
+ }
72
+
73
+ protected override render(): TemplateResult {
74
+ const iconIdentifier = this.expanded ? 'actions-menu-sidebar-collapsed' : 'actions-menu-sidebar-expanded';
75
+ const overlay = this.disabled ? 'overlay-readonly' : null;
76
+ return html`<typo3-backend-icon identifier="${iconIdentifier}" size="small" overlay="${overlay}"></typo3-backend-icon>`;
77
+ }
78
+
79
+ protected override buttonActivated(): void {
80
+ if (!this.disabled) {
81
+ ScaffoldState.toggleSidebar();
82
+ }
83
+ }
84
+
85
+ private readonly handleSidebarToggle = (event: ScaffoldSidebarToggleEvent): void => {
86
+ this.expanded = event.detail.expanded;
87
+ };
88
+
89
+ private updateLabels(): void {
90
+ const label = this.expanded ? this.labelCollapse : this.labelExpand;
91
+ this.title = label;
92
+ this.setAttribute('aria-label', label);
93
+ }
94
+
95
+ private updateDisabledState(): void {
96
+ if (this.disabled) {
97
+ this.setAttribute('aria-disabled', 'true');
98
+ this.tabIndex = -1;
99
+ } else {
100
+ this.removeAttribute('aria-disabled');
101
+ this.tabIndex = 0;
102
+ }
103
+ }
104
+ }
105
+
106
+ declare global {
107
+ interface HTMLElementTagNameMap {
108
+ 'typo3-backend-sidebar-toggle': SidebarToggleElement;
109
+ }
110
+ }
@@ -11,14 +11,34 @@
11
11
  * The TYPO3 project - inspiring people to share!
12
12
  */
13
13
 
14
+ import { ContentNavigationSlotEnum, type ContentNavigation } from '@typo3/backend/viewport/content-navigation';
15
+
14
16
  export enum ScaffoldIdentifierEnum {
15
17
  scaffold = '.t3js-scaffold',
16
18
  header = '.t3js-scaffold-header',
17
- moduleMenu = '.t3js-scaffold-modulemenu',
19
+ sidebar = '.t3js-scaffold-sidebar',
18
20
  content = '.t3js-scaffold-content',
19
- contentModule = '.t3js-scaffold-content-module',
20
21
  contentModuleRouter = 'typo3-backend-module-router',
21
22
  contentModuleIframe = '.t3js-scaffold-content-module-iframe',
22
- contentNavigation = '.t3js-scaffold-content-navigation',
23
- contentNavigationDataComponent = '.t3js-scaffold-content-navigation [data-component]',
23
+ }
24
+
25
+ /**
26
+ * Helper to get scaffold content area elements scoped to the backend content navigation
27
+ */
28
+ export class ScaffoldContentArea {
29
+ public static readonly selector = 'typo3-backend-content-navigation[identifier="backend"]';
30
+
31
+ public static getContentNavigation(): ContentNavigation | null {
32
+ return document.querySelector(this.selector) as ContentNavigation | null;
33
+ }
34
+
35
+ public static getNavigationContainer(): HTMLElement | null {
36
+ const container = this.getContentNavigation();
37
+ return container?.querySelector(`[slot="${ContentNavigationSlotEnum.navigation}"]`) ?? null;
38
+ }
39
+
40
+ public static getContentContainer(): HTMLElement | null {
41
+ const container = this.getContentNavigation();
42
+ return container?.querySelector(`[slot="${ContentNavigationSlotEnum.content}"]`) ?? null;
43
+ }
24
44
  }
@@ -13,7 +13,7 @@
13
13
 
14
14
  import { MessageUtility } from '../../utility/message-utility';
15
15
  import { AjaxDispatcher } from './../inline-relation/ajax-dispatcher';
16
- import NProgress from 'nprogress';
16
+ import { ProgressBarElement } from '@typo3/backend/element/progress-bar-element';
17
17
  import Sortable from 'sortablejs';
18
18
  import FormEngine from '@typo3/backend/form-engine';
19
19
  import FormEngineValidation from '@typo3/backend/form-engine-validation';
@@ -59,7 +59,7 @@ interface RequestQueue {
59
59
  }
60
60
 
61
61
  interface ProgressQueue {
62
- [key: string]: any;
62
+ [key: string]: ProgressBarElement;
63
63
  }
64
64
 
65
65
  interface Appearance {
@@ -369,7 +369,7 @@ class FilesControlContainer extends HTMLElement {
369
369
  const isLoaded = recordFieldsContainer !== null && !recordContainer.classList.contains(States.notLoaded);
370
370
 
371
371
  if (!isLoaded) {
372
- const progress = this.getProgress(objectId, recordContainer.dataset.objectIdHash);
372
+ const progress = this.getProgress(objectId);
373
373
 
374
374
  if (!isLoading) {
375
375
  const ajaxRequest = this.ajaxDispatcher.newRequest(this.ajaxDispatcher.getEndpoint('file_reference_details'));
@@ -582,15 +582,15 @@ class FilesControlContainer extends HTMLElement {
582
582
  });
583
583
  }
584
584
 
585
- private getProgress(objectId: string, objectIdHash: string): any {
586
- const headerIdentifier = '#' + objectIdHash + '_header';
587
- let progress: any;
585
+ private getProgress(objectId: string): ProgressBarElement {
586
+ let progress: ProgressBarElement;
588
587
 
589
588
  if (typeof this.progressQueue[objectId] !== 'undefined') {
590
589
  progress = this.progressQueue[objectId];
591
590
  } else {
592
- progress = NProgress;
593
- progress.configure({ parent: headerIdentifier, showSpinner: false });
591
+ progress = document.createElement('typo3-backend-progress-bar');
592
+ const panel = document.querySelector<HTMLElement>(selector`[data-object-id="${objectId}"]`);
593
+ panel.insertBefore(progress, panel.firstChild);
594
594
  this.progressQueue[objectId] = progress;
595
595
  }
596
596
 
@@ -14,7 +14,7 @@
14
14
  import { MessageUtility } from '../../utility/message-utility';
15
15
  import { AjaxDispatcher } from './../inline-relation/ajax-dispatcher';
16
16
  import DocumentService from '@typo3/core/document-service';
17
- import NProgress from 'nprogress';
17
+ import { ProgressBarElement } from '@typo3/backend/element/progress-bar-element';
18
18
  import Sortable from 'sortablejs';
19
19
  import FormEngine from '@typo3/backend/form-engine';
20
20
  import FormEngineValidation from '@typo3/backend/form-engine-validation';
@@ -64,7 +64,7 @@ interface RequestQueue {
64
64
  }
65
65
 
66
66
  interface ProgressQueue {
67
- [key: string]: any;
67
+ [key: string]: ProgressBarElement;
68
68
  }
69
69
 
70
70
  interface Appearance {
@@ -562,7 +562,7 @@ class InlineControlContainer {
562
562
  const isLoaded = recordFieldsContainer !== null && !recordContainer.classList.contains(States.notLoaded);
563
563
 
564
564
  if (!isLoaded) {
565
- const progress = this.getProgress(objectId, recordContainer.dataset.objectIdHash);
565
+ const progress = this.getProgress(objectId);
566
566
 
567
567
  if (!isLoading) {
568
568
  const ajaxRequest = this.ajaxDispatcher.newRequest(this.ajaxDispatcher.getEndpoint('record_inline_details'));
@@ -804,19 +804,15 @@ class InlineControlContainer {
804
804
  });
805
805
  }
806
806
 
807
- /**
808
- * @param {string} objectId
809
- * @param {string} objectIdHash
810
- */
811
- private getProgress(objectId: string, objectIdHash: string): any {
812
- const headerIdentifier = '#' + objectIdHash + '_header';
813
- let progress: any;
807
+ private getProgress(objectId: string): ProgressBarElement {
808
+ let progress: ProgressBarElement;
814
809
 
815
810
  if (typeof this.progressQueue[objectId] !== 'undefined') {
816
811
  progress = this.progressQueue[objectId];
817
812
  } else {
818
- progress = NProgress;
819
- progress.configure({ parent: headerIdentifier, showSpinner: false });
813
+ progress = document.createElement('typo3-backend-progress-bar');
814
+ const panel = InlineControlContainer.getInlineRecordContainer(objectId);
815
+ panel.insertBefore(progress, panel.firstChild);
820
816
  this.progressQueue[objectId] = progress;
821
817
  }
822
818
 
@@ -13,7 +13,7 @@
13
13
 
14
14
  import { MessageUtility } from '../../utility/message-utility';
15
15
  import { AjaxDispatcher } from './../inline-relation/ajax-dispatcher';
16
- import NProgress from 'nprogress';
16
+ import { ProgressBarElement } from '@typo3/backend/element/progress-bar-element';
17
17
  import FormEngine from '@typo3/backend/form-engine';
18
18
  import FormEngineValidation from '@typo3/backend/form-engine-validation';
19
19
  import { default as Modal, type ModalElement } from '@typo3/backend/modal';
@@ -51,7 +51,7 @@ interface RequestQueue {
51
51
  }
52
52
 
53
53
  interface ProgressQueue {
54
- [key: string]: any;
54
+ [key: string]: ProgressBarElement;
55
55
  }
56
56
 
57
57
  interface UniqueDefinition {
@@ -345,7 +345,7 @@ class SiteLanguageContainer extends HTMLElement {
345
345
  const isLoaded = recordFieldsContainer !== null && !recordContainer.classList.contains(States.notLoaded);
346
346
 
347
347
  if (!isLoaded) {
348
- const progress = this.getProgress(objectId, recordContainer.dataset.objectIdHash);
348
+ const progress = this.getProgress(objectId);
349
349
 
350
350
  if (!isLoading) {
351
351
  const ajaxRequest = this.ajaxDispatcher.newRequest(this.ajaxDispatcher.getEndpoint('site_configuration_inline_details'));
@@ -460,15 +460,15 @@ class SiteLanguageContainer extends HTMLElement {
460
460
  recordContainer.classList.add('form-irre-object--deleted');
461
461
  }
462
462
 
463
- private getProgress(objectId: string, objectIdHash: string): any {
464
- const headerIdentifier = '#' + objectIdHash + '_header';
465
- let progress: any;
463
+ private getProgress(objectId: string): ProgressBarElement {
464
+ let progress: ProgressBarElement;
466
465
 
467
466
  if (typeof this.progressQueue[objectId] !== 'undefined') {
468
467
  progress = this.progressQueue[objectId];
469
468
  } else {
470
- progress = NProgress;
471
- progress.configure({ parent: headerIdentifier, showSpinner: false });
469
+ progress = document.createElement('typo3-backend-progress-bar');
470
+ const panel = SiteLanguageContainer.getInlineRecordContainer(objectId);
471
+ panel.insertBefore(progress, panel.firstChild);
472
472
  this.progressQueue[objectId] = progress;
473
473
  }
474
474
 
@@ -51,7 +51,6 @@ class CategoryElement extends HTMLElement {
51
51
  }
52
52
 
53
53
  this.tree = document.createElement('typo3-backend-form-selecttree') as SelectTree;
54
- this.tree.classList.add('tree-wrapper');
55
54
  this.tree.setup = {
56
55
  id: this.treeWrapper.id,
57
56
  dataUrl: this.generateDataUrl(),
@@ -56,6 +56,10 @@ class SelectBoxFilter {
56
56
  this.filter((<HTMLInputElement>e.target).value);
57
57
  }).delegateTo(wizardsElement, Selectors.filterTextFieldSelector);
58
58
 
59
+ new RegularEvent('search', (e: Event): void => {
60
+ this.filter((<HTMLInputElement>e.target).value);
61
+ }).delegateTo(wizardsElement, Selectors.filterTextFieldSelector);
62
+
59
63
  new RegularEvent('change', (e: Event): void => {
60
64
  this.filter((<HTMLInputElement>e.target).value);
61
65
  }).delegateTo(wizardsElement, Selectors.filterSelectFieldSelector);