Skip to content

Commit aae64af

Browse files
committed
Merge branch '6.1' into 6.2
2 parents 7873fd2 + 39513c6 commit aae64af

33 files changed

+288
-198
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,6 @@ nbactions.xml
6060

6161
# Node.js
6262
node_modules/
63+
64+
# Composer
65+
/vendor/

com.woltlab.wcf/package.xml

Lines changed: 3 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
<packagedescription>Free CMS and web-framework, designed for awesome websites and communities.</packagedescription>
66
<packagedescription language="de">Freies CMS und Web-Framework, das eindrucksvolle Websites und Communities ermöglicht.</packagedescription>
77
<isapplication>1</isapplication>
8-
<version>6.1.3</version>
9-
<date>2025-01-06</date>
8+
<version>6.1.4 dev 1</version>
9+
<date>2025-02-11</date>
1010
</packageinformation>
1111

1212
<authorinformation>
@@ -50,70 +50,10 @@
5050
<instruction type="script">acp/install_com.woltlab.wcf_step2.php</instruction>
5151
</instructions>
5252

53-
<instructions type="update" fromversion="6.0.*">
54-
<!--
55-
tar cvf com.woltlab.wcf/files_pre_check.tar -C wcfsetup/install/files/ \
56-
acp/update_com.woltlab.wcf_6.1_checkSystemRequirements.php \
57-
acp/update_com.woltlab.wcf_6.1_messageEmbeddedObject.php \
58-
acp/update_com.woltlab.wcf_6.1_sharedTemplate.php \
59-
acp/database/update_com.woltlab.wcf_6.1.php
60-
-->
61-
<instruction type="file">files_pre_check.tar</instruction>
62-
63-
<!-- Checks that need to happen before the upgrade starts. -->
64-
<instruction type="script" run="standalone">acp/update_com.woltlab.wcf_6.1_checkSystemRequirements.php</instruction>
65-
66-
<!-- Required for the shared templates. -->
67-
<instruction type="script">acp/update_com.woltlab.wcf_6.1_sharedTemplate.php</instruction>
68-
69-
<!-- Clean up any duplicate entries in the message embedded objects table. -->
70-
<instruction type="script" run="standalone">acp/update_com.woltlab.wcf_6.1_messageEmbeddedObject.php</instruction>
71-
72-
<!-- Migrate the database as early as possible. -->
73-
<instruction type="database">acp/database/update_com.woltlab.wcf_6.1.php</instruction>
74-
75-
<!-- Deploy the new application code. -->
76-
<instruction type="file"/>
77-
<instruction type="acpTemplate"/>
78-
<instruction type="template"/>
79-
80-
<instruction type="script" run="standalone">acp/update_com.woltlab.wcf_6.1_spider_step1.php</instruction>
81-
<instruction type="database" run="standalone">acp/database/update_com.woltlab.wcf_6.1_spider_step2.php</instruction>
82-
83-
<instruction type="language"/>
84-
<instruction type="objectTypeDefinition"/>
85-
<instruction type="objectType"/>
86-
<instruction type="page"/>
87-
<instruction type="userGroupOption"/>
88-
<instruction type="userProfileMenu"/>
89-
<instruction type="bbcode"/>
90-
<instruction type="acpTemplateDelete"/>
91-
<instruction type="fileDelete"/>
92-
<instruction type="userMenu"/>
93-
<instruction type="option"/>
94-
<instruction type="templateDelete"/>
95-
<instruction type="cronjob"/>
96-
<instruction type="userOption"/>
97-
<instruction type="userNotificationEvent"/>
98-
99-
<instruction type="script" run="standalone">acp/update_com.woltlab.wcf_6.1_serviceWorker.php</instruction>
100-
</instructions>
101-
102-
<instructions type="update" fromversion="6.1.2">
53+
<instructions type="update" fromversion="6.1.3">
10354
<instruction type="acpTemplate">acptemplates_update.tar</instruction>
10455
<instruction type="file">files_update.tar</instruction>
10556
<instruction type="template">templates_update.tar</instruction>
10657
<instruction type="language"/>
10758
</instructions>
108-
<instructions type="update" fromversion="6.1.3 dev 1">
109-
<instruction type="acpTemplate">acptemplates_update.tar</instruction>
110-
<instruction type="file">files_update.tar</instruction>
111-
<instruction type="template">templates_update.tar</instruction>
112-
</instructions>
113-
<instructions type="update" fromversion="6.1.3 dev 2">
114-
<instruction type="file">files_update.tar</instruction>
115-
</instructions>
116-
<instructions type="update" fromversion="6.1.3 dev 3">
117-
<instruction type="file">files_update.tar</instruction>
118-
</instructions>
11959
</package>

ts/WoltLabSuite/Core/Component/Comment/List.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,9 @@ class CommentList {
388388
DomUtil.insertHtml(response.value.template, commentResponseList, "append");
389389
DomChangeListener.trigger();
390390

391-
const scrollTarget = commentResponseList.firstElementChild as HTMLElement;
391+
const scrollTarget = this.#container.querySelector(
392+
`.commentResponseList__item[data-response-id="${responseId}"]`,
393+
) as HTMLElement;
392394

393395
window.setTimeout(() => {
394396
UiScroll.element(scrollTarget);

ts/WoltLabSuite/Core/Component/File/Upload.ts

Lines changed: 44 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ async function resizeImage(element: WoltlabCoreFileUploadElement, file: File): P
174174

175175
let fileType: string = resizeConfiguration.fileType;
176176
if (fileType === "image/jpeg" || fileType === "image/webp") {
177-
fileType = "image/webp";
177+
fileType = "image/jpeg";
178178
} else {
179179
fileType = file.type;
180180
}
@@ -192,15 +192,15 @@ async function resizeImage(element: WoltlabCoreFileUploadElement, file: File): P
192192
return resizedFile;
193193
}
194194

195-
function validateFileLimit(element: WoltlabCoreFileUploadElement): boolean {
195+
function validateFileLimit(element: WoltlabCoreFileUploadElement, count: number): boolean {
196196
const maximumCount = element.maximumCount;
197197
if (maximumCount === -1) {
198198
return true;
199199
}
200200

201201
const files = Array.from(element.parentElement!.querySelectorAll("woltlab-core-file"));
202202
const numberOfUploadedFiles = files.filter((file) => !file.isFailedUpload()).length;
203-
if (numberOfUploadedFiles + 1 <= maximumCount) {
203+
if (numberOfUploadedFiles + count <= maximumCount) {
204204
return true;
205205
}
206206

@@ -210,6 +210,12 @@ function validateFileLimit(element: WoltlabCoreFileUploadElement): boolean {
210210
}
211211

212212
function validateFileSize(element: WoltlabCoreFileUploadElement, file: File): boolean {
213+
if (file.size === 0) {
214+
innerError(element, getPhrase("wcf.upload.error.emptyFile", { filename: file.name }));
215+
216+
return false;
217+
}
218+
213219
let isImage = false;
214220
switch (file.type) {
215221
case "image/gif":
@@ -256,47 +262,54 @@ function validateFileExtension(element: WoltlabCoreFileUploadElement, file: File
256262

257263
export function setup(): void {
258264
wheneverFirstSeen("woltlab-core-file-upload", (element: WoltlabCoreFileUploadElement) => {
259-
element.addEventListener("upload", (event: CustomEvent<File>) => {
260-
const file = event.detail;
265+
element.addEventListener("upload:files", (event: CustomEvent<{ files: File[] }>) => {
266+
const { files } = event.detail;
261267

262268
clearPreviousErrors(element);
263269

264-
if (!validateFileLimit(element)) {
265-
return;
266-
} else if (!validateFileExtension(element, file)) {
267-
return;
268-
} else if (!validateFileSize(element, file)) {
270+
if (!validateFileLimit(element, files.length)) {
269271
return;
270272
}
271273

274+
for (const file of files) {
275+
if (!validateFileExtension(element, file)) {
276+
return;
277+
} else if (!validateFileSize(element, file)) {
278+
return;
279+
}
280+
}
281+
282+
let processImage: (file: File) => Promise<File>;
272283
if (element.dataset.cropperConfiguration) {
273284
const cropperConfiguration = JSON.parse(element.dataset.cropperConfiguration) as CropperConfiguration;
274285

275-
void cropImage(element, file, cropperConfiguration)
276-
.then((resizedFile) => {
277-
void upload(element, resizedFile);
278-
})
279-
.catch((e) => {
286+
processImage = async (file) => {
287+
try {
288+
return await cropImage(element, file, cropperConfiguration);
289+
} catch (e) {
280290
element.dispatchEvent(new CustomEvent("cancel"));
281291

282-
if (e === undefined) {
283-
// User closed the dialog.
284-
return;
285-
}
286-
287-
if (e instanceof Error) {
288-
innerError(element, e.message);
289-
}
290-
});
292+
throw e;
293+
}
294+
};
291295
} else {
292-
void resizeImage(element, file)
293-
.then((resizedFile) => {
294-
void upload(element, resizedFile);
295-
})
296-
.catch(() => {
297-
innerError(element, getPhrase("wcf.upload.error.damagedImageFile", { filename: file.name }));
298-
});
296+
processImage = async (file) => resizeImage(element, file);
299297
}
298+
299+
// Resize all files in parallel but keep the original order. This ensures
300+
// that files are uploaded in the same order that they were provided by
301+
// the browser.
302+
void Promise.allSettled(files.map((file) => processImage(file))).then((results) => {
303+
for (let i = 0, length = results.length; i < length; i++) {
304+
const result = results[i];
305+
306+
if (result.status === "fulfilled") {
307+
void upload(element, result.value);
308+
} else if (result.reason !== undefined) {
309+
innerError(element, getPhrase("wcf.upload.error.damagedImageFile", { filename: files[i].name }));
310+
}
311+
}
312+
});
300313
});
301314

302315
element.addEventListener("ckeditorDrop", (event: CustomEvent<CkeditorDropEvent>) => {

ts/WoltLabSuite/Core/Notification/Handler.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import * as Ajax from "../Ajax";
1212
import { AjaxCallbackSetup } from "../Ajax/Data";
1313
import * as Core from "../Core";
1414
import * as EventHandler from "../Event/Handler";
15-
import { serviceWorkerSupported } from "./ServiceWorker";
15+
import { serviceWorkerSupported, updateNotificationLastReadTime } from "./ServiceWorker";
1616
import { updateCounter } from "WoltLabSuite/Core/Ui/User/Menu/Manager";
1717

1818
interface NotificationHandlerOptions {
@@ -206,6 +206,9 @@ class NotificationHandler {
206206

207207
this.lastRequestTimestamp = data.returnValues.lastRequestTimestamp;
208208

209+
// Update the last read time for the service worker
210+
updateNotificationLastReadTime(this.lastRequestTimestamp);
211+
209212
EventHandler.fire("com.woltlab.wcf.notification", "afterPoll", pollData);
210213

211214
this.showNotification(pollData);
@@ -264,6 +267,10 @@ class NotificationHandler {
264267
silent: !window.ENABLE_DEBUG_MODE,
265268
};
266269
}
270+
271+
updateLastRequestTimestamp(timestamp: number): void {
272+
this.lastRequestTimestamp = Math.max(timestamp, this.lastRequestTimestamp);
273+
}
267274
}
268275

269276
let notificationHandler: NotificationHandler;
@@ -281,6 +288,10 @@ export function enableNotifications(): void {
281288
notificationHandler!.enableNotifications();
282289
}
283290

291+
export function updateLastRequestTimestamp(timestamp: number): void {
292+
notificationHandler?.updateLastRequestTimestamp(timestamp);
293+
}
294+
284295
export function poll(): void {
285296
notificationHandler?.dispatchRequest();
286297
}

ts/WoltLabSuite/Core/Notification/ServiceWorker.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
*/
88

99
import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
10+
import { updateLastRequestTimestamp } from "WoltLabSuite/Core/Notification/Handler";
1011

1112
let _serviceWorker: ServiceWorker | null = null;
1213

@@ -24,6 +25,15 @@ class ServiceWorker {
2425
scope: "/",
2526
});
2627
this.#serviceWorkerRegistration = window.navigator.serviceWorker.ready;
28+
29+
window.navigator.serviceWorker.addEventListener("message", (event) => {
30+
// Validate that this is a message from our service worker
31+
if (!(event.source instanceof window.ServiceWorker) || event.source.scriptURL !== this.#serviceWorkerJsUrl) {
32+
return;
33+
}
34+
35+
updateLastRequestTimestamp(event.data.time);
36+
});
2737
}
2838

2939
async register(): Promise<void> {

ts/WoltLabSuite/WebComponent/woltlab-core-file-upload.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
}
2222

2323
for (const file of files) {
24+
/** @deprecated 6.1 No longer supported */
2425
const event = new CustomEvent<File>("shouldUpload", {
2526
cancelable: true,
2627
detail: file,
@@ -31,12 +32,20 @@
3132
continue;
3233
}
3334

35+
/** @deprecated 6.1 Use `upload:files` instead */
3436
const uploadEvent = new CustomEvent<File>("upload", {
3537
detail: file,
3638
});
3739
this.dispatchEvent(uploadEvent);
3840
}
3941

42+
const event = new CustomEvent<{ files: File[] }>("upload:files", {
43+
detail: {
44+
files: Array.from(files),
45+
},
46+
});
47+
this.dispatchEvent(event);
48+
4049
// Reset the selected file.
4150
this.#element.value = "";
4251
});

wcfsetup/install/files/js/WCF.Combined.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WCF.Combined.tiny.min.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WoltLabSuite.Core.min.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)