artalk 2.7.3 → 2.8.0

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.
@@ -17,6 +17,18 @@ var __spreadValues = (a, b) => {
17
17
  return a;
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
20
32
  var __publicField = (obj, key, value) => {
21
33
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
22
34
  return value;
@@ -42,174 +54,1217 @@ var __async = (__this, __arguments, generator) => {
42
54
  });
43
55
  };
44
56
  import { marked as marked$1 } from "marked";
45
- function createElement(htmlStr = "") {
46
- const div = document.createElement("div");
47
- div.innerHTML = htmlStr.trim();
48
- return div.firstElementChild || div;
49
- }
50
- function getHeight(el) {
51
- return parseFloat(getComputedStyle(el, null).height.replace("px", ""));
52
- }
53
- function htmlEncode(str) {
54
- const temp = document.createElement("div");
55
- temp.innerText = str;
56
- const output = temp.innerHTML;
57
- return output;
58
- }
59
- function getQueryParam(name) {
60
- const match = RegExp(`[?&]${name}=([^&]*)`).exec(window.location.search);
61
- return match && decodeURIComponent(match[1].replace(/\+/g, " "));
62
- }
63
- function getOffset(el, relativeTo) {
64
- const getOffsetRecursive = (element) => {
65
- const rect = element.getBoundingClientRect();
66
- const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
67
- const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
68
- return {
69
- top: rect.top + scrollTop,
70
- left: rect.left + scrollLeft
71
- };
72
- };
73
- const elOffset = getOffsetRecursive(el);
74
- if (!relativeTo)
75
- return elOffset;
76
- const relativeToOffset = getOffsetRecursive(relativeTo);
77
- return {
78
- top: elOffset.top - relativeToOffset.top,
79
- left: elOffset.left - relativeToOffset.left
80
- };
81
- }
82
- function padWithZeros(vNumber, width) {
83
- let numAsString = vNumber.toString();
84
- while (numAsString.length < width) {
85
- numAsString = `0${numAsString}`;
86
- }
87
- return numAsString;
88
- }
89
- function dateFormat(date) {
90
- const vDay = padWithZeros(date.getDate(), 2);
91
- const vMonth = padWithZeros(date.getMonth() + 1, 2);
92
- const vYear = padWithZeros(date.getFullYear(), 2);
93
- return `${vYear}-${vMonth}-${vDay}`;
94
- }
95
- function timeAgo(date, $t = (n) => n) {
96
- try {
97
- const oldTime = date.getTime();
98
- const currTime = (/* @__PURE__ */ new Date()).getTime();
99
- const diffValue = currTime - oldTime;
100
- const days = Math.floor(diffValue / (24 * 3600 * 1e3));
101
- if (days === 0) {
102
- const leave1 = diffValue % (24 * 3600 * 1e3);
103
- const hours = Math.floor(leave1 / (3600 * 1e3));
104
- if (hours === 0) {
105
- const leave2 = leave1 % (3600 * 1e3);
106
- const minutes = Math.floor(leave2 / (60 * 1e3));
107
- if (minutes === 0) {
108
- const leave3 = leave2 % (60 * 1e3);
109
- const seconds = Math.round(leave3 / 1e3);
110
- if (seconds < 10)
111
- return $t("now");
112
- return `${seconds} ${$t("seconds")}`;
57
+ class HttpClient {
58
+ constructor(apiConfig = {}) {
59
+ __publicField(this, "baseUrl", "/api/v2");
60
+ __publicField(this, "securityData", null);
61
+ __publicField(this, "securityWorker");
62
+ __publicField(this, "abortControllers", /* @__PURE__ */ new Map());
63
+ __publicField(this, "customFetch", (...fetchParams) => fetch(...fetchParams));
64
+ __publicField(this, "baseApiParams", {
65
+ credentials: "same-origin",
66
+ headers: {},
67
+ redirect: "follow",
68
+ referrerPolicy: "no-referrer"
69
+ });
70
+ __publicField(this, "setSecurityData", (data) => {
71
+ this.securityData = data;
72
+ });
73
+ __publicField(this, "contentFormatters", {
74
+ [
75
+ "application/json"
76
+ /* Json */
77
+ ]: (input) => input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input,
78
+ [
79
+ "text/plain"
80
+ /* Text */
81
+ ]: (input) => input !== null && typeof input !== "string" ? JSON.stringify(input) : input,
82
+ [
83
+ "multipart/form-data"
84
+ /* FormData */
85
+ ]: (input) => Object.keys(input || {}).reduce((formData, key) => {
86
+ const property = input[key];
87
+ formData.append(
88
+ key,
89
+ property instanceof Blob ? property : typeof property === "object" && property !== null ? JSON.stringify(property) : `${property}`
90
+ );
91
+ return formData;
92
+ }, new FormData()),
93
+ [
94
+ "application/x-www-form-urlencoded"
95
+ /* UrlEncoded */
96
+ ]: (input) => this.toQueryString(input)
97
+ });
98
+ __publicField(this, "createAbortSignal", (cancelToken) => {
99
+ if (this.abortControllers.has(cancelToken)) {
100
+ const abortController2 = this.abortControllers.get(cancelToken);
101
+ if (abortController2) {
102
+ return abortController2.signal;
113
103
  }
114
- return `${minutes} ${$t("minutes")}`;
104
+ return void 0;
115
105
  }
116
- return `${hours} ${$t("hours")}`;
117
- }
118
- if (days < 0)
119
- return $t("now");
120
- if (days < 8) {
121
- return `${days} ${$t("days")}`;
122
- }
123
- return dateFormat(date);
124
- } catch (error) {
125
- console.error(error);
126
- return " - ";
106
+ const abortController = new AbortController();
107
+ this.abortControllers.set(cancelToken, abortController);
108
+ return abortController.signal;
109
+ });
110
+ __publicField(this, "abortRequest", (cancelToken) => {
111
+ const abortController = this.abortControllers.get(cancelToken);
112
+ if (abortController) {
113
+ abortController.abort();
114
+ this.abortControllers.delete(cancelToken);
115
+ }
116
+ });
117
+ __publicField(this, "request", (_a) => __async(this, null, function* () {
118
+ var _b = _a, {
119
+ body,
120
+ secure,
121
+ path,
122
+ type,
123
+ query,
124
+ format,
125
+ baseUrl,
126
+ cancelToken
127
+ } = _b, params = __objRest(_b, [
128
+ "body",
129
+ "secure",
130
+ "path",
131
+ "type",
132
+ "query",
133
+ "format",
134
+ "baseUrl",
135
+ "cancelToken"
136
+ ]);
137
+ const secureParams = (typeof secure === "boolean" ? secure : this.baseApiParams.secure) && this.securityWorker && (yield this.securityWorker(this.securityData)) || {};
138
+ const requestParams = this.mergeRequestParams(params, secureParams);
139
+ const queryString = query && this.toQueryString(query);
140
+ const payloadFormatter = this.contentFormatters[
141
+ type || "application/json"
142
+ /* Json */
143
+ ];
144
+ const responseFormat = format || requestParams.format;
145
+ return this.customFetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, __spreadProps(__spreadValues({}, requestParams), {
146
+ headers: __spreadValues(__spreadValues({}, requestParams.headers || {}), type && type !== "multipart/form-data" ? { "Content-Type": type } : {}),
147
+ signal: (cancelToken ? this.createAbortSignal(cancelToken) : requestParams.signal) || null,
148
+ body: typeof body === "undefined" || body === null ? null : payloadFormatter(body)
149
+ })).then((response) => __async(this, null, function* () {
150
+ const r = response;
151
+ r.data = null;
152
+ r.error = null;
153
+ const data = !responseFormat ? r : yield response[responseFormat]().then((data2) => {
154
+ if (r.ok) {
155
+ r.data = data2;
156
+ } else {
157
+ r.error = data2;
158
+ }
159
+ return r;
160
+ }).catch((e) => {
161
+ r.error = e;
162
+ return r;
163
+ });
164
+ if (cancelToken) {
165
+ this.abortControllers.delete(cancelToken);
166
+ }
167
+ if (!response.ok)
168
+ throw data;
169
+ return data;
170
+ }));
171
+ }));
172
+ Object.assign(this, apiConfig);
127
173
  }
128
- }
129
- function onImagesLoaded($container, event) {
130
- if (!$container)
131
- return;
132
- const images = $container.getElementsByTagName("img");
133
- if (!images.length)
134
- return;
135
- let loaded = images.length;
136
- for (let i = 0; i < images.length; i++) {
137
- if (images[i].complete) {
138
- loaded--;
139
- } else {
140
- images[i].addEventListener("load", () => {
141
- loaded--;
142
- if (loaded === 0)
143
- event();
144
- });
145
- }
146
- if (loaded === 0)
147
- event();
174
+ encodeQueryParam(key, value) {
175
+ const encodedKey = encodeURIComponent(key);
176
+ return `${encodedKey}=${encodeURIComponent(typeof value === "number" ? value : `${value}`)}`;
148
177
  }
149
- }
150
- function getGravatarURL(opts) {
151
- return `${opts.mirror.replace(/\/$/, "")}/${opts.emailMD5}?${opts.params.replace(/^\?/, "")}`;
152
- }
153
- function versionCompare(a, b) {
154
- const pa = a.split(".");
155
- const pb = b.split(".");
156
- for (let i = 0; i < 3; i++) {
157
- const na = Number(pa[i]);
158
- const nb = Number(pb[i]);
159
- if (na > nb)
160
- return 1;
161
- if (nb > na)
162
- return -1;
163
- if (!Number.isNaN(na) && Number.isNaN(nb))
164
- return 1;
165
- if (Number.isNaN(na) && !Number.isNaN(nb))
166
- return -1;
178
+ addQueryParam(query, key) {
179
+ return this.encodeQueryParam(key, query[key]);
167
180
  }
168
- return 0;
169
- }
170
- function getCorrectUserAgent() {
171
- return __async(this, null, function* () {
172
- const uaRaw = navigator.userAgent;
173
- if (!navigator.userAgentData || !navigator.userAgentData.getHighEntropyValues) {
174
- return uaRaw;
175
- }
176
- const uaData = navigator.userAgentData;
177
- let uaGot = null;
178
- try {
179
- uaGot = yield uaData.getHighEntropyValues(["platformVersion"]);
180
- } catch (err) {
181
- console.error(err);
182
- return uaRaw;
183
- }
184
- const majorPlatformVersion = Number(uaGot.platformVersion.split(".")[0]);
185
- if (uaData.platform === "Windows") {
186
- if (majorPlatformVersion >= 13) {
187
- return uaRaw.replace(/Windows NT 10.0/, "Windows NT 11.0");
188
- }
189
- }
190
- if (uaData.platform === "macOS") {
191
- if (majorPlatformVersion >= 11) {
192
- return uaRaw.replace(/(Mac OS X \d+_\d+_\d+|Mac OS X)/, `Mac OS X ${uaGot.platformVersion.replace(/\./g, "_")}`);
193
- }
194
- }
195
- return uaRaw;
196
- });
197
- }
198
- function isValidURL(urlRaw) {
199
- let url;
200
- try {
201
- url = new URL(urlRaw);
202
- } catch (_) {
203
- return false;
181
+ addArrayQueryParam(query, key) {
182
+ const value = query[key];
183
+ return value.map((v) => this.encodeQueryParam(key, v)).join("&");
184
+ }
185
+ toQueryString(rawQuery) {
186
+ const query = rawQuery || {};
187
+ const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]);
188
+ return keys.map((key) => Array.isArray(query[key]) ? this.addArrayQueryParam(query, key) : this.addQueryParam(query, key)).join("&");
189
+ }
190
+ addQueryParams(rawQuery) {
191
+ const queryString = this.toQueryString(rawQuery);
192
+ return queryString ? `?${queryString}` : "";
193
+ }
194
+ mergeRequestParams(params1, params2) {
195
+ return __spreadProps(__spreadValues(__spreadValues(__spreadValues({}, this.baseApiParams), params1), params2 || {}), {
196
+ headers: __spreadValues(__spreadValues(__spreadValues({}, this.baseApiParams.headers || {}), params1.headers || {}), params2 && params2.headers || {})
197
+ });
204
198
  }
205
- return url.protocol === "http:" || url.protocol === "https:";
206
- }
207
- function getURLBasedOnApi(opts) {
208
- return getURLBasedOn(opts.base, opts.path);
209
- }
210
- function getURLBasedOn(baseURL, path) {
211
- return `${baseURL.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
212
199
  }
200
+ /**
201
+ * @title Artalk API
202
+ * @version 2.0
203
+ * @license MIT (https://github.com/ArtalkJS/Artalk/blob/master/LICENSE)
204
+ * @baseUrl /api/v2
205
+ * @contact API Support <artalkjs@gmail.com> (https://artalk.js.org)
206
+ *
207
+ * Artalk is a modern comment system based on Golang.
208
+ */
209
+ let Api$1 = class Api extends HttpClient {
210
+ constructor() {
211
+ super(...arguments);
212
+ __publicField(this, "cache", {
213
+ /**
214
+ * @description Flush all cache on the server
215
+ *
216
+ * @tags Cache
217
+ * @name FlushCache
218
+ * @summary Flush Cache
219
+ * @request POST:/cache/flush
220
+ * @secure
221
+ * @response `200` `(HandlerMap & {
222
+ msg?: string,
223
+
224
+ })` OK
225
+ * @response `400` `(HandlerMap & {
226
+ msg?: string,
227
+
228
+ })` Bad Request
229
+ * @response `403` `(HandlerMap & {
230
+ msg?: string,
231
+
232
+ })` Forbidden
233
+ */
234
+ flushCache: (params = {}) => this.request(__spreadValues({
235
+ path: `/cache/flush`,
236
+ method: "POST",
237
+ secure: true,
238
+ format: "json"
239
+ }, params)),
240
+ /**
241
+ * @description Cache warming helps you to pre-load the cache to improve the performance of the first request
242
+ *
243
+ * @tags Cache
244
+ * @name WarmUpCache
245
+ * @summary Warm-Up Cache
246
+ * @request POST:/cache/warm_up
247
+ * @secure
248
+ * @response `200` `(HandlerMap & {
249
+ msg?: string,
250
+
251
+ })` OK
252
+ * @response `400` `(HandlerMap & {
253
+ msg?: string,
254
+
255
+ })` Bad Request
256
+ * @response `403` `(HandlerMap & {
257
+ msg?: string,
258
+
259
+ })` Forbidden
260
+ */
261
+ warmUpCache: (params = {}) => this.request(__spreadValues({
262
+ path: `/cache/warm_up`,
263
+ method: "POST",
264
+ secure: true,
265
+ format: "json"
266
+ }, params))
267
+ });
268
+ __publicField(this, "captcha", {
269
+ /**
270
+ * @description Get a base64 encoded captcha image or a HTML page to verify for user
271
+ *
272
+ * @tags Captcha
273
+ * @name GetCaptcha
274
+ * @summary Get Captcha
275
+ * @request GET:/captcha
276
+ * @response `200` `HandlerResponseCaptchaGet` OK
277
+ * @response `500` `(HandlerMap & {
278
+ msg?: string,
279
+
280
+ })` Internal Server Error
281
+ */
282
+ getCaptcha: (params = {}) => this.request(__spreadValues({
283
+ path: `/captcha`,
284
+ method: "GET",
285
+ format: "json"
286
+ }, params)),
287
+ /**
288
+ * @description Get the status of the user's captcha verification
289
+ *
290
+ * @tags Captcha
291
+ * @name GetCaptchaStatus
292
+ * @summary Get Captcha Status
293
+ * @request GET:/captcha/status
294
+ * @response `200` `HandlerResponseCaptchaStatus` OK
295
+ */
296
+ getCaptchaStatus: (params = {}) => this.request(__spreadValues({
297
+ path: `/captcha/status`,
298
+ method: "GET",
299
+ format: "json"
300
+ }, params)),
301
+ /**
302
+ * @description Verify user enters correct captcha code
303
+ *
304
+ * @tags Captcha
305
+ * @name VerifyCaptcha
306
+ * @summary Verify Captcha
307
+ * @request POST:/captcha/verify
308
+ * @response `200` `HandlerMap` OK
309
+ * @response `403` `(HandlerMap & {
310
+ img_data?: string,
311
+
312
+ })` Forbidden
313
+ */
314
+ verifyCaptcha: (data, params = {}) => this.request(__spreadValues({
315
+ path: `/captcha/verify`,
316
+ method: "POST",
317
+ body: data,
318
+ type: "application/json",
319
+ format: "json"
320
+ }, params))
321
+ });
322
+ __publicField(this, "comments", {
323
+ /**
324
+ * @description Get a list of comments by some conditions
325
+ *
326
+ * @tags Comment
327
+ * @name GetComments
328
+ * @summary Get Comment List
329
+ * @request GET:/comments
330
+ * @secure
331
+ * @response `200` `HandlerResponseCommentList` OK
332
+ * @response `500` `(HandlerMap & {
333
+ msg?: string,
334
+
335
+ })` Internal Server Error
336
+ */
337
+ getComments: (query, params = {}) => this.request(__spreadValues({
338
+ path: `/comments`,
339
+ method: "GET",
340
+ query,
341
+ secure: true,
342
+ type: "application/json",
343
+ format: "json"
344
+ }, params)),
345
+ /**
346
+ * @description Create a new comment
347
+ *
348
+ * @tags Comment
349
+ * @name CreateComment
350
+ * @summary Create Comment
351
+ * @request POST:/comments
352
+ * @secure
353
+ * @response `200` `HandlerResponseCommentCreate` OK
354
+ * @response `400` `(HandlerMap & {
355
+ msg?: string,
356
+
357
+ })` Bad Request
358
+ * @response `500` `(HandlerMap & {
359
+ msg?: string,
360
+
361
+ })` Internal Server Error
362
+ */
363
+ createComment: (comment, params = {}) => this.request(__spreadValues({
364
+ path: `/comments`,
365
+ method: "POST",
366
+ body: comment,
367
+ secure: true,
368
+ type: "application/json",
369
+ format: "json"
370
+ }, params)),
371
+ /**
372
+ * @description Update a specific comment
373
+ *
374
+ * @tags Comment
375
+ * @name UpdateComment
376
+ * @summary Update Comment
377
+ * @request PUT:/comments/{id}
378
+ * @secure
379
+ * @response `200` `HandlerResponseCommentUpdate` OK
380
+ * @response `400` `(HandlerMap & {
381
+ msg?: string,
382
+
383
+ })` Bad Request
384
+ * @response `403` `(HandlerMap & {
385
+ msg?: string,
386
+
387
+ })` Forbidden
388
+ * @response `404` `(HandlerMap & {
389
+ msg?: string,
390
+
391
+ })` Not Found
392
+ * @response `500` `(HandlerMap & {
393
+ msg?: string,
394
+
395
+ })` Internal Server Error
396
+ */
397
+ updateComment: (id, comment, params = {}) => this.request(__spreadValues({
398
+ path: `/comments/${id}`,
399
+ method: "PUT",
400
+ body: comment,
401
+ secure: true,
402
+ type: "application/json",
403
+ format: "json"
404
+ }, params)),
405
+ /**
406
+ * @description Delete a specific comment
407
+ *
408
+ * @tags Comment
409
+ * @name DeleteComment
410
+ * @summary Delete Comment
411
+ * @request DELETE:/comments/{id}
412
+ * @secure
413
+ * @response `200` `HandlerMap` OK
414
+ * @response `403` `(HandlerMap & {
415
+ msg?: string,
416
+
417
+ })` Forbidden
418
+ * @response `404` `(HandlerMap & {
419
+ msg?: string,
420
+
421
+ })` Not Found
422
+ * @response `500` `(HandlerMap & {
423
+ msg?: string,
424
+
425
+ })` Internal Server Error
426
+ */
427
+ deleteComment: (id, params = {}) => this.request(__spreadValues({
428
+ path: `/comments/${id}`,
429
+ method: "DELETE",
430
+ secure: true,
431
+ format: "json"
432
+ }, params))
433
+ });
434
+ __publicField(this, "conf", {
435
+ /**
436
+ * @description Get System Configs for UI
437
+ *
438
+ * @tags System
439
+ * @name Conf
440
+ * @summary Get System Configs
441
+ * @request GET:/conf
442
+ * @response `200` `CommonConfData` OK
443
+ */
444
+ conf: (params = {}) => this.request(__spreadValues({
445
+ path: `/conf`,
446
+ method: "GET",
447
+ format: "json"
448
+ }, params))
449
+ });
450
+ __publicField(this, "notifies", {
451
+ /**
452
+ * @description Get a list of notifies for user
453
+ *
454
+ * @tags Notify
455
+ * @name GetNotifies
456
+ * @summary Get Notifies
457
+ * @request GET:/notifies
458
+ * @response `200` `HandlerResponseNotifyList` OK
459
+ * @response `400` `(HandlerMap & {
460
+ msg?: string,
461
+
462
+ })` Bad Request
463
+ * @response `500` `(HandlerMap & {
464
+ msg?: string,
465
+
466
+ })` Internal Server Error
467
+ */
468
+ getNotifies: (query, params = {}) => this.request(__spreadValues({
469
+ path: `/notifies`,
470
+ method: "GET",
471
+ query,
472
+ type: "application/json",
473
+ format: "json"
474
+ }, params)),
475
+ /**
476
+ * @description Mark all notifies as read for user
477
+ *
478
+ * @tags Notify
479
+ * @name MarkAllNotifyRead
480
+ * @summary Mark All Notifies as Read
481
+ * @request POST:/notifies/read
482
+ * @response `200` `HandlerMap` OK
483
+ * @response `400` `(HandlerMap & {
484
+ msg?: string,
485
+
486
+ })` Bad Request
487
+ * @response `500` `(HandlerMap & {
488
+ msg?: string,
489
+
490
+ })` Internal Server Error
491
+ */
492
+ markAllNotifyRead: (options, params = {}) => this.request(__spreadValues({
493
+ path: `/notifies/read`,
494
+ method: "POST",
495
+ body: options,
496
+ type: "application/json",
497
+ format: "json"
498
+ }, params)),
499
+ /**
500
+ * @description Mark specific notification as read for user
501
+ *
502
+ * @tags Notify
503
+ * @name MarkNotifyRead
504
+ * @summary Mark Notify as Read
505
+ * @request POST:/notifies/{comment_id}/{notify_key}
506
+ * @response `200` `HandlerMap` OK
507
+ * @response `400` `(HandlerMap & {
508
+ msg?: string,
509
+
510
+ })` Bad Request
511
+ * @response `404` `(HandlerMap & {
512
+ msg?: string,
513
+
514
+ })` Not Found
515
+ * @response `500` `(HandlerMap & {
516
+ msg?: string,
517
+
518
+ })` Internal Server Error
519
+ */
520
+ markNotifyRead: (commentId, notifyKey, params = {}) => this.request(__spreadValues({
521
+ path: `/notifies/${commentId}/${notifyKey}`,
522
+ method: "POST",
523
+ format: "json"
524
+ }, params))
525
+ });
526
+ __publicField(this, "pages", {
527
+ /**
528
+ * @description Get a list of pages by some conditions
529
+ *
530
+ * @tags Page
531
+ * @name GetPages
532
+ * @summary Get Page List
533
+ * @request GET:/pages
534
+ * @secure
535
+ * @response `200` `HandlerResponsePageList` OK
536
+ * @response `403` `(HandlerMap & {
537
+ msg?: string,
538
+
539
+ })` Forbidden
540
+ */
541
+ getPages: (query, params = {}) => this.request(__spreadValues({
542
+ path: `/pages`,
543
+ method: "GET",
544
+ query,
545
+ secure: true,
546
+ type: "application/json",
547
+ format: "json"
548
+ }, params)),
549
+ /**
550
+ * @description Fetch the data of all pages
551
+ *
552
+ * @tags Page
553
+ * @name FetchAllPages
554
+ * @summary Fetch All Pages Data
555
+ * @request POST:/pages/fetch
556
+ * @secure
557
+ * @response `200` `HandlerMap` OK
558
+ * @response `400` `(HandlerMap & {
559
+ msg?: string,
560
+
561
+ })` Bad Request
562
+ * @response `500` `(HandlerMap & {
563
+ msg?: string,
564
+
565
+ })` Internal Server Error
566
+ */
567
+ fetchAllPages: (options, params = {}) => this.request(__spreadValues({
568
+ path: `/pages/fetch`,
569
+ method: "POST",
570
+ body: options,
571
+ secure: true,
572
+ type: "application/json",
573
+ format: "json"
574
+ }, params)),
575
+ /**
576
+ * @description Get the status of the task of fetching all pages
577
+ *
578
+ * @tags Page
579
+ * @name GetPageFetchStatus
580
+ * @summary Get Pages Fetch Status
581
+ * @request GET:/pages/fetch/status
582
+ * @secure
583
+ * @response `200` `HandlerResponsePageFetchStatus` OK
584
+ */
585
+ getPageFetchStatus: (params = {}) => this.request(__spreadValues({
586
+ path: `/pages/fetch/status`,
587
+ method: "GET",
588
+ secure: true,
589
+ format: "json"
590
+ }, params)),
591
+ /**
592
+ * @description Increase and get the number of page views
593
+ *
594
+ * @tags Page
595
+ * @name LogPv
596
+ * @summary Increase Page Views (PV)
597
+ * @request POST:/pages/pv
598
+ * @response `200` `HandlerResponsePagePV` OK
599
+ */
600
+ logPv: (page, params = {}) => this.request(__spreadValues({
601
+ path: `/pages/pv`,
602
+ method: "POST",
603
+ body: page,
604
+ type: "application/json",
605
+ format: "json"
606
+ }, params)),
607
+ /**
608
+ * @description Update a specific page
609
+ *
610
+ * @tags Page
611
+ * @name UpdatePage
612
+ * @summary Update Page
613
+ * @request PUT:/pages/{id}
614
+ * @secure
615
+ * @response `200` `HandlerResponsePageUpdate` OK
616
+ * @response `400` `(HandlerMap & {
617
+ msg?: string,
618
+
619
+ })` Bad Request
620
+ * @response `403` `(HandlerMap & {
621
+ msg?: string,
622
+
623
+ })` Forbidden
624
+ * @response `404` `(HandlerMap & {
625
+ msg?: string,
626
+
627
+ })` Not Found
628
+ * @response `500` `(HandlerMap & {
629
+ msg?: string,
630
+
631
+ })` Internal Server Error
632
+ */
633
+ updatePage: (id, page, params = {}) => this.request(__spreadValues({
634
+ path: `/pages/${id}`,
635
+ method: "PUT",
636
+ body: page,
637
+ secure: true,
638
+ type: "application/json",
639
+ format: "json"
640
+ }, params)),
641
+ /**
642
+ * @description Delete a specific page
643
+ *
644
+ * @tags Page
645
+ * @name DeletePage
646
+ * @summary Delete Page
647
+ * @request DELETE:/pages/{id}
648
+ * @secure
649
+ * @response `200` `HandlerMap` OK
650
+ * @response `403` `(HandlerMap & {
651
+ msg?: string,
652
+
653
+ })` Forbidden
654
+ * @response `404` `(HandlerMap & {
655
+ msg?: string,
656
+
657
+ })` Not Found
658
+ * @response `500` `(HandlerMap & {
659
+ msg?: string,
660
+
661
+ })` Internal Server Error
662
+ */
663
+ deletePage: (id, params = {}) => this.request(__spreadValues({
664
+ path: `/pages/${id}`,
665
+ method: "DELETE",
666
+ secure: true,
667
+ format: "json"
668
+ }, params)),
669
+ /**
670
+ * @description Fetch the data of a specific page
671
+ *
672
+ * @tags Page
673
+ * @name FetchPage
674
+ * @summary Fetch Page Data
675
+ * @request POST:/pages/{id}/fetch
676
+ * @secure
677
+ * @response `200` `HandlerResponsePageFetch` OK
678
+ * @response `404` `(HandlerMap & {
679
+ msg?: string,
680
+
681
+ })` Not Found
682
+ * @response `500` `(HandlerMap & {
683
+ msg?: string,
684
+
685
+ })` Internal Server Error
686
+ */
687
+ fetchPage: (id, params = {}) => this.request(__spreadValues({
688
+ path: `/pages/${id}/fetch`,
689
+ method: "POST",
690
+ secure: true,
691
+ type: "application/json",
692
+ format: "json"
693
+ }, params))
694
+ });
695
+ __publicField(this, "sendEmail", {
696
+ /**
697
+ * @description Send an email to test the email sender
698
+ *
699
+ * @tags System
700
+ * @name SendEmail
701
+ * @summary Send Email
702
+ * @request POST:/send_email
703
+ * @secure
704
+ * @response `200` `HandlerMap` OK
705
+ * @response `403` `(HandlerMap & {
706
+ msg?: string,
707
+
708
+ })` Forbidden
709
+ * @response `500` `HandlerMap` Internal Server Error
710
+ */
711
+ sendEmail: (email, params = {}) => this.request(__spreadValues({
712
+ path: `/send_email`,
713
+ method: "POST",
714
+ body: email,
715
+ secure: true,
716
+ type: "application/json",
717
+ format: "json"
718
+ }, params))
719
+ });
720
+ __publicField(this, "settings", {
721
+ /**
722
+ * @description Get settings from app config file
723
+ *
724
+ * @tags System
725
+ * @name GetSettings
726
+ * @summary Get Settings
727
+ * @request GET:/settings
728
+ * @secure
729
+ * @response `200` `HandlerResponseSettingGet` OK
730
+ * @response `403` `(HandlerMap & {
731
+ msg?: string,
732
+
733
+ })` Forbidden
734
+ * @response `500` `(HandlerMap & {
735
+ msg?: string,
736
+
737
+ })` Internal Server Error
738
+ */
739
+ getSettings: (params = {}) => this.request(__spreadValues({
740
+ path: `/settings`,
741
+ method: "GET",
742
+ secure: true,
743
+ format: "json"
744
+ }, params)),
745
+ /**
746
+ * @description Apply settings and restart the server
747
+ *
748
+ * @tags System
749
+ * @name ApplySettings
750
+ * @summary Save and apply Settings
751
+ * @request PUT:/settings
752
+ * @secure
753
+ * @response `200` `HandlerMap` OK
754
+ * @response `403` `(HandlerMap & {
755
+ msg?: string,
756
+
757
+ })` Forbidden
758
+ * @response `500` `(HandlerMap & {
759
+ msg?: string,
760
+
761
+ })` Internal Server Error
762
+ */
763
+ applySettings: (settings, params = {}) => this.request(__spreadValues({
764
+ path: `/settings`,
765
+ method: "PUT",
766
+ body: settings,
767
+ secure: true,
768
+ type: "application/json",
769
+ format: "json"
770
+ }, params)),
771
+ /**
772
+ * @description Get config templates in different languages for rendering the settings page in the frontend
773
+ *
774
+ * @tags System
775
+ * @name GetSettingsTemplate
776
+ * @summary Get Settings Template
777
+ * @request GET:/settings/template/{locale}
778
+ * @secure
779
+ * @response `200` `HandlerResponseSettingTemplate` OK
780
+ */
781
+ getSettingsTemplate: (locale, params = {}) => this.request(__spreadValues({
782
+ path: `/settings/template/${locale}`,
783
+ method: "GET",
784
+ secure: true,
785
+ format: "json"
786
+ }, params))
787
+ });
788
+ __publicField(this, "sites", {
789
+ /**
790
+ * @description Get a list of sites by some conditions
791
+ *
792
+ * @tags Site
793
+ * @name GetSites
794
+ * @summary Get Site List
795
+ * @request GET:/sites
796
+ * @secure
797
+ * @response `200` `HandlerResponseSiteList` OK
798
+ */
799
+ getSites: (params = {}) => this.request(__spreadValues({
800
+ path: `/sites`,
801
+ method: "GET",
802
+ secure: true,
803
+ format: "json"
804
+ }, params)),
805
+ /**
806
+ * @description Create a new site
807
+ *
808
+ * @tags Site
809
+ * @name CreateSite
810
+ * @summary Create Site
811
+ * @request POST:/sites
812
+ * @secure
813
+ * @response `200` `HandlerResponseSiteCreate` OK
814
+ * @response `400` `(HandlerMap & {
815
+ msg?: string,
816
+
817
+ })` Bad Request
818
+ * @response `403` `(HandlerMap & {
819
+ msg?: string,
820
+
821
+ })` Forbidden
822
+ * @response `500` `(HandlerMap & {
823
+ msg?: string,
824
+
825
+ })` Internal Server Error
826
+ */
827
+ createSite: (site, params = {}) => this.request(__spreadValues({
828
+ path: `/sites`,
829
+ method: "POST",
830
+ body: site,
831
+ secure: true,
832
+ type: "application/json",
833
+ format: "json"
834
+ }, params)),
835
+ /**
836
+ * @description Update a specific site
837
+ *
838
+ * @tags Site
839
+ * @name UpdateSite
840
+ * @summary Update Site
841
+ * @request PUT:/sites/{id}
842
+ * @secure
843
+ * @response `200` `HandlerResponseSiteUpdate` OK
844
+ */
845
+ updateSite: (id, site, params = {}) => this.request(__spreadValues({
846
+ path: `/sites/${id}`,
847
+ method: "PUT",
848
+ body: site,
849
+ secure: true,
850
+ type: "application/json",
851
+ format: "json"
852
+ }, params)),
853
+ /**
854
+ * @description Delete a specific site
855
+ *
856
+ * @tags Site
857
+ * @name DeleteSite
858
+ * @summary Site Delete
859
+ * @request DELETE:/sites/{id}
860
+ * @secure
861
+ * @response `200` `HandlerMap` OK
862
+ * @response `403` `(HandlerMap & {
863
+ msg?: string,
864
+
865
+ })` Forbidden
866
+ * @response `404` `(HandlerMap & {
867
+ msg?: string,
868
+
869
+ })` Not Found
870
+ * @response `500` `(HandlerMap & {
871
+ msg?: string,
872
+
873
+ })` Internal Server Error
874
+ */
875
+ deleteSite: (id, params = {}) => this.request(__spreadValues({
876
+ path: `/sites/${id}`,
877
+ method: "DELETE",
878
+ secure: true,
879
+ format: "json"
880
+ }, params))
881
+ });
882
+ __publicField(this, "stats", {
883
+ /**
884
+ * @description Get the statistics of various data analysis
885
+ *
886
+ * @tags Statistic
887
+ * @name GetStats
888
+ * @summary Statistic
889
+ * @request GET:/stats/{type}
890
+ * @response `200` `CommonJSONResult` OK
891
+ * @response `400` `(HandlerMap & {
892
+ msg?: string,
893
+
894
+ })` Bad Request
895
+ * @response `403` `(HandlerMap & {
896
+ msg?: string,
897
+
898
+ })` Forbidden
899
+ * @response `404` `(HandlerMap & {
900
+ msg?: string,
901
+
902
+ })` Not Found
903
+ * @response `500` `(HandlerMap & {
904
+ msg?: string,
905
+
906
+ })` Internal Server Error
907
+ */
908
+ getStats: (type, query, params = {}) => this.request(__spreadValues({
909
+ path: `/stats/${type}`,
910
+ method: "GET",
911
+ query,
912
+ type: "application/json",
913
+ format: "json"
914
+ }, params))
915
+ });
916
+ __publicField(this, "transfer", {
917
+ /**
918
+ * @description Export data from Artalk
919
+ *
920
+ * @tags Transfer
921
+ * @name ExportArtrans
922
+ * @summary Export Artrans
923
+ * @request GET:/transfer/export
924
+ * @secure
925
+ * @response `200` `HandlerResponseTransferExport` OK
926
+ * @response `500` `(HandlerMap & {
927
+ msg?: string,
928
+
929
+ })` Internal Server Error
930
+ */
931
+ exportArtrans: (params = {}) => this.request(__spreadValues({
932
+ path: `/transfer/export`,
933
+ method: "GET",
934
+ secure: true,
935
+ format: "json"
936
+ }, params)),
937
+ /**
938
+ * @description Import data to Artalk
939
+ *
940
+ * @tags Transfer
941
+ * @name ImportArtrans
942
+ * @summary Import Artrans
943
+ * @request POST:/transfer/import
944
+ * @secure
945
+ * @response `200` `string` OK
946
+ */
947
+ importArtrans: (data, params = {}) => this.request(__spreadValues({
948
+ path: `/transfer/import`,
949
+ method: "POST",
950
+ body: data,
951
+ secure: true,
952
+ type: "application/json"
953
+ }, params)),
954
+ /**
955
+ * @description Upload a file to prepare to import
956
+ *
957
+ * @tags Transfer
958
+ * @name UploadArtrans
959
+ * @summary Upload Artrans
960
+ * @request POST:/transfer/upload
961
+ * @secure
962
+ * @response `200` `(HandlerResponseTransferUpload & {
963
+ filename?: string,
964
+
965
+ })` OK
966
+ * @response `500` `(HandlerMap & {
967
+ msg?: string,
968
+
969
+ })` Internal Server Error
970
+ */
971
+ uploadArtrans: (data, params = {}) => this.request(__spreadValues({
972
+ path: `/transfer/upload`,
973
+ method: "POST",
974
+ body: data,
975
+ secure: true,
976
+ type: "multipart/form-data",
977
+ format: "json"
978
+ }, params))
979
+ });
980
+ __publicField(this, "upload", {
981
+ /**
982
+ * @description Upload file from this endpoint
983
+ *
984
+ * @tags Upload
985
+ * @name Upload
986
+ * @summary Upload
987
+ * @request POST:/upload
988
+ * @secure
989
+ * @response `200` `HandlerResponseUpload` OK
990
+ * @response `400` `(HandlerMap & {
991
+ msg?: string,
992
+
993
+ })` Bad Request
994
+ * @response `403` `(HandlerMap & {
995
+ msg?: string,
996
+
997
+ })` Forbidden
998
+ * @response `500` `(HandlerMap & {
999
+ msg?: string,
1000
+
1001
+ })` Internal Server Error
1002
+ */
1003
+ upload: (data, params = {}) => this.request(__spreadValues({
1004
+ path: `/upload`,
1005
+ method: "POST",
1006
+ body: data,
1007
+ secure: true,
1008
+ type: "multipart/form-data",
1009
+ format: "json"
1010
+ }, params))
1011
+ });
1012
+ __publicField(this, "user", {
1013
+ /**
1014
+ * @description Get user info to prepare for login or check current user status
1015
+ *
1016
+ * @tags Account
1017
+ * @name GetUser
1018
+ * @summary Get User Info
1019
+ * @request GET:/user
1020
+ * @secure
1021
+ * @response `200` `HandlerResponseUserInfo` OK
1022
+ * @response `400` `(HandlerMap & {
1023
+ msg?: string,
1024
+
1025
+ })` Bad Request
1026
+ */
1027
+ getUser: (query, params = {}) => this.request(__spreadValues({
1028
+ path: `/user`,
1029
+ method: "GET",
1030
+ query,
1031
+ secure: true,
1032
+ format: "json"
1033
+ }, params)),
1034
+ /**
1035
+ * @description Login user by name or email
1036
+ *
1037
+ * @tags Account
1038
+ * @name Login
1039
+ * @summary Get Access Token
1040
+ * @request POST:/user/access_token
1041
+ * @response `200` `HandlerResponseUserLogin` OK
1042
+ * @response `400` `(HandlerMap & {
1043
+ " data"?: {
1044
+ need_name_select?: (string)[],
1045
+
1046
+ },
1047
+ msg?: string,
1048
+
1049
+ })` Multiple users with the same email address are matched
1050
+ * @response `403` `(HandlerMap & {
1051
+ msg?: string,
1052
+
1053
+ })` Forbidden
1054
+ * @response `500` `(HandlerMap & {
1055
+ msg?: string,
1056
+
1057
+ })` Internal Server Error
1058
+ */
1059
+ login: (user, params = {}) => this.request(__spreadValues({
1060
+ path: `/user/access_token`,
1061
+ method: "POST",
1062
+ body: user,
1063
+ type: "application/json",
1064
+ format: "json"
1065
+ }, params)),
1066
+ /**
1067
+ * @description Get user login status by header Authorization
1068
+ *
1069
+ * @tags Account
1070
+ * @name GetUserStatus
1071
+ * @summary Get Login Status
1072
+ * @request GET:/user/status
1073
+ * @secure
1074
+ * @response `200` `HandlerResponseUserStatus` OK
1075
+ */
1076
+ getUserStatus: (query, params = {}) => this.request(__spreadValues({
1077
+ path: `/user/status`,
1078
+ method: "GET",
1079
+ query,
1080
+ secure: true,
1081
+ format: "json"
1082
+ }, params))
1083
+ });
1084
+ __publicField(this, "users", {
1085
+ /**
1086
+ * @description Create a new user
1087
+ *
1088
+ * @tags User
1089
+ * @name CreateUser
1090
+ * @summary Create User
1091
+ * @request POST:/users
1092
+ * @secure
1093
+ * @response `200` `HandlerResponseUserCreate` OK
1094
+ * @response `400` `(HandlerMap & {
1095
+ msg?: string,
1096
+
1097
+ })` Bad Request
1098
+ * @response `403` `(HandlerMap & {
1099
+ msg?: string,
1100
+
1101
+ })` Forbidden
1102
+ * @response `500` `(HandlerMap & {
1103
+ msg?: string,
1104
+
1105
+ })` Internal Server Error
1106
+ */
1107
+ createUser: (user, params = {}) => this.request(__spreadValues({
1108
+ path: `/users`,
1109
+ method: "POST",
1110
+ body: user,
1111
+ secure: true,
1112
+ type: "application/json",
1113
+ format: "json"
1114
+ }, params)),
1115
+ /**
1116
+ * @description Update a specific user
1117
+ *
1118
+ * @tags User
1119
+ * @name UpdateUser
1120
+ * @summary Update User
1121
+ * @request PUT:/users/{id}
1122
+ * @secure
1123
+ * @response `200` `HandlerResponseUserUpdate` OK
1124
+ * @response `400` `(HandlerMap & {
1125
+ msg?: string,
1126
+
1127
+ })` Bad Request
1128
+ * @response `403` `(HandlerMap & {
1129
+ msg?: string,
1130
+
1131
+ })` Forbidden
1132
+ * @response `404` `(HandlerMap & {
1133
+ msg?: string,
1134
+
1135
+ })` Not Found
1136
+ * @response `500` `(HandlerMap & {
1137
+ msg?: string,
1138
+
1139
+ })` Internal Server Error
1140
+ */
1141
+ updateUser: (id, user, params = {}) => this.request(__spreadValues({
1142
+ path: `/users/${id}`,
1143
+ method: "PUT",
1144
+ body: user,
1145
+ secure: true,
1146
+ type: "application/json",
1147
+ format: "json"
1148
+ }, params)),
1149
+ /**
1150
+ * @description Delete a specific user
1151
+ *
1152
+ * @tags User
1153
+ * @name DeleteUser
1154
+ * @summary Delete User
1155
+ * @request DELETE:/users/{id}
1156
+ * @secure
1157
+ * @response `200` `HandlerMap` OK
1158
+ * @response `403` `(HandlerMap & {
1159
+ msg?: string,
1160
+
1161
+ })` Forbidden
1162
+ * @response `404` `(HandlerMap & {
1163
+ msg?: string,
1164
+
1165
+ })` Not Found
1166
+ * @response `500` `(HandlerMap & {
1167
+ msg?: string,
1168
+
1169
+ })` Internal Server Error
1170
+ */
1171
+ deleteUser: (id, params = {}) => this.request(__spreadValues({
1172
+ path: `/users/${id}`,
1173
+ method: "DELETE",
1174
+ secure: true,
1175
+ format: "json"
1176
+ }, params)),
1177
+ /**
1178
+ * @description Get a list of users by some conditions
1179
+ *
1180
+ * @tags User
1181
+ * @name GetUsers
1182
+ * @summary Get User List
1183
+ * @request GET:/users/{type}
1184
+ * @secure
1185
+ * @response `200` `HandlerResponseAdminUserList` OK
1186
+ * @response `403` `(HandlerMap & {
1187
+ msg?: string,
1188
+
1189
+ })` Forbidden
1190
+ */
1191
+ getUsers: (type, query, params = {}) => this.request(__spreadValues({
1192
+ path: `/users/${type}`,
1193
+ method: "GET",
1194
+ query,
1195
+ secure: true,
1196
+ type: "application/json",
1197
+ format: "json"
1198
+ }, params))
1199
+ });
1200
+ __publicField(this, "version", {
1201
+ /**
1202
+ * @description Get the version of Artalk
1203
+ *
1204
+ * @tags System
1205
+ * @name GetVersion
1206
+ * @summary Get Version Info
1207
+ * @request GET:/version
1208
+ * @response `200` `CommonApiVersionData` OK
1209
+ */
1210
+ getVersion: (params = {}) => this.request(__spreadValues({
1211
+ path: `/version`,
1212
+ method: "GET",
1213
+ format: "json"
1214
+ }, params))
1215
+ });
1216
+ __publicField(this, "votes", {
1217
+ /**
1218
+ * @description Sync the number of votes in the `comments` or `pages` data tables to keep them the same as the `votes` table
1219
+ *
1220
+ * @tags Vote
1221
+ * @name SyncVotes
1222
+ * @summary Sync Vote Data
1223
+ * @request POST:/votes/sync
1224
+ * @secure
1225
+ * @response `200` `HandlerMap` OK
1226
+ * @response `403` `(HandlerMap & {
1227
+ msg?: string,
1228
+
1229
+ })` Forbidden
1230
+ */
1231
+ syncVotes: (params = {}) => this.request(__spreadValues({
1232
+ path: `/votes/sync`,
1233
+ method: "POST",
1234
+ secure: true,
1235
+ format: "json"
1236
+ }, params)),
1237
+ /**
1238
+ * @description Vote for a specific comment or page
1239
+ *
1240
+ * @tags Vote
1241
+ * @name Vote
1242
+ * @summary Vote
1243
+ * @request POST:/votes/{type}/{target_id}
1244
+ * @response `200` `HandlerResponseVote` OK
1245
+ * @response `403` `(HandlerMap & {
1246
+ msg?: string,
1247
+
1248
+ })` Forbidden
1249
+ * @response `404` `(HandlerMap & {
1250
+ msg?: string,
1251
+
1252
+ })` Not Found
1253
+ * @response `500` `(HandlerMap & {
1254
+ msg?: string,
1255
+
1256
+ })` Internal Server Error
1257
+ */
1258
+ vote: (type, targetId, vote, params = {}) => this.request(__spreadValues({
1259
+ path: `/votes/${type}/${targetId}`,
1260
+ method: "POST",
1261
+ body: vote,
1262
+ type: "application/json",
1263
+ format: "json"
1264
+ }, params))
1265
+ });
1266
+ }
1267
+ };
213
1268
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
214
1269
  function getDefaultExportFromCjs(x) {
215
1270
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -610,746 +1665,91 @@ function getDefaultExportFromCjs(x) {
610
1665
  });
611
1666
  })(typeof self !== "undefined" ? self : commonjsGlobal);
612
1667
  });
613
- const en = {
614
- /* Editor */
615
- placeholder: "Leave a comment",
616
- noComment: "No Comment",
617
- send: "Send",
618
- save: "Save",
619
- nick: "Nickname",
620
- email: "Email",
621
- link: "Website",
622
- emoticon: "Emoji",
623
- preview: "Preview",
624
- image: "Image",
625
- uploadFail: "Upload Failed",
626
- commentFail: "Failed to comment",
627
- restoredMsg: "Content has been restored",
628
- onlyAdminCanReply: "Only admin can reply",
629
- uploadLoginMsg: "Please fill in your name and email to upload",
630
- /* List */
631
- counter: "{count} Comments",
632
- sortLatest: "Latest",
633
- sortOldest: "Oldest",
634
- sortBest: "Best",
635
- sortAuthor: "Author",
636
- openComment: "Open Comment",
637
- closeComment: "Close Comment",
638
- listLoadFailMsg: "Failed to load comments",
639
- listRetry: "Click to retry",
640
- loadMore: "Load More",
641
- /* Comment */
642
- admin: "Admin",
643
- reply: "Reply",
644
- voteUp: "Up",
645
- voteDown: "Down",
646
- voteFail: "Vote Failed",
647
- readMore: "Read More",
648
- actionConfirm: "Confirm",
649
- collapse: "Collapse",
650
- collapsed: "Collapsed",
651
- collapsedMsg: "This comment has been collapsed",
652
- expand: "Expand",
653
- approved: "Approved",
654
- pending: "Pending",
655
- pendingMsg: "Pending, visible only to commenter.",
656
- edit: "Edit",
657
- editCancel: "Cancel Edit",
658
- delete: "Delete",
659
- deleteConfirm: "Confirm",
660
- pin: "Pin",
661
- unpin: "Unpin",
662
- /* Time */
663
- seconds: "seconds ago",
664
- minutes: "minutes ago",
665
- hours: "hours ago",
666
- days: "days ago",
667
- now: "just now",
668
- /* Checker */
669
- adminCheck: "Enter admin password:",
670
- captchaCheck: "Enter the CAPTCHA to continue:",
671
- confirm: "Confirm",
672
- cancel: "Cancel",
673
- /* Sidebar */
674
- msgCenter: "Messages",
675
- ctrlCenter: "Admin",
676
- /* General */
677
- frontend: "Frontend",
678
- backend: "Backend",
679
- loading: "Loading",
680
- loadFail: "Load Failed",
681
- editing: "Editing",
682
- editFail: "Edit Failed",
683
- deleting: "Deleting",
684
- deleteFail: "Delete Failed",
685
- reqGot: "Request got",
686
- reqAborted: "Request timed out or terminated unexpectedly",
687
- updateMsg: "Please update Artalk {name} to get the full experience",
688
- currentVersion: "Current Version",
689
- ignore: "Ignore",
690
- open: "Open"
691
- };
692
- const zhCN = {
693
- /* Editor */
694
- placeholder: "键入内容...",
695
- noComment: "「此时无声胜有声」",
696
- send: "发送评论",
697
- save: "保存评论",
698
- nick: "昵称",
699
- email: "邮箱",
700
- link: "网址",
701
- emoticon: "表情",
702
- preview: "预览",
703
- image: "图片",
704
- uploadFail: "上传失败",
705
- commentFail: "评论失败",
706
- restoredMsg: "内容已自动恢复",
707
- onlyAdminCanReply: "仅管理员可评论",
708
- uploadLoginMsg: "填入你的名字邮箱才能上传哦",
709
- /* List */
710
- counter: "{count} 条评论",
711
- sortLatest: "最新",
712
- sortOldest: "最早",
713
- sortBest: "最热",
714
- sortAuthor: "作者",
715
- openComment: "打开评论",
716
- closeComment: "关闭评论",
717
- listLoadFailMsg: "无法获取评论列表数据",
718
- listRetry: "点击重新获取",
719
- loadMore: "加载更多",
720
- /* Comment */
721
- admin: "管理员",
722
- reply: "回复",
723
- voteUp: "赞同",
724
- voteDown: "反对",
725
- voteFail: "投票失败",
726
- readMore: "阅读更多",
727
- actionConfirm: "确认操作",
728
- collapse: "折叠",
729
- collapsed: "已折叠",
730
- collapsedMsg: "该评论已被系统或管理员折叠",
731
- expand: "展开",
732
- approved: "已审",
733
- pending: "待审",
734
- pendingMsg: "审核中,仅本人可见。",
735
- edit: "编辑",
736
- editCancel: "取消编辑",
737
- delete: "删除",
738
- deleteConfirm: "确认删除",
739
- pin: "置顶",
740
- unpin: "取消置顶",
741
- /* Time */
742
- seconds: "秒前",
743
- minutes: "分钟前",
744
- hours: "小时前",
745
- days: "天前",
746
- now: "刚刚",
747
- /* Checker */
748
- adminCheck: "键入密码来验证管理员身份:",
749
- captchaCheck: "键入验证码继续:",
750
- confirm: "确认",
751
- cancel: "取消",
752
- /* Sidebar */
753
- msgCenter: "通知中心",
754
- ctrlCenter: "控制中心",
755
- /* General */
756
- frontend: "前端",
757
- backend: "后端",
758
- loading: "加载中",
759
- loadFail: "加载失败",
760
- editing: "修改中",
761
- editFail: "修改失败",
762
- deleting: "删除中",
763
- deleteFail: "删除失败",
764
- reqGot: "请求响应",
765
- reqAborted: "请求超时或意外终止",
766
- updateMsg: "请更新 Artalk {name} 以获得完整体验",
767
- currentVersion: "当前版本",
768
- ignore: "忽略",
769
- open: "打开"
770
- };
771
- const GLOBAL_LOCALES_KEY = "ArtalkI18n";
772
- const internal = {
773
- "en": en,
774
- "en-US": en,
775
- "zh-CN": zhCN
776
- };
777
- function findLocaleSet(lang) {
778
- lang = lang.replace(
779
- /^([a-zA-Z]+)(-[a-zA-Z]+)?$/,
780
- (_, p1, p2) => p1.toLowerCase() + (p2 || "").toUpperCase()
781
- );
782
- if (internal[lang]) {
783
- return internal[lang];
784
- }
785
- if (window[GLOBAL_LOCALES_KEY] && window[GLOBAL_LOCALES_KEY][lang]) {
786
- return window[GLOBAL_LOCALES_KEY][lang];
787
- }
788
- return internal.en;
789
- }
790
- let LocaleConf = "en";
791
- let LocaleDict = findLocaleSet(LocaleConf);
792
- function setLocale(locale) {
793
- if (locale === LocaleConf)
794
- return;
795
- LocaleConf = locale;
796
- LocaleDict = typeof locale === "string" ? findLocaleSet(locale) : locale;
797
- }
798
- function t(key, args = {}) {
799
- let str = (LocaleDict == null ? void 0 : LocaleDict[key]) || key;
800
- str = str.replace(/\{\s*(\w+?)\s*\}/g, (_, token) => args[token] || "");
801
- return str;
802
- }
803
- function Fetch$1(opts, input, init2, timeout) {
804
- return __async(this, null, function* () {
805
- var _a, _b;
806
- if (opts.apiToken) {
807
- const headers = new Headers(init2.headers);
808
- headers.set("Authorization", `Bearer ${opts.apiToken}`);
809
- init2.headers = headers;
1668
+ const Fetch$1 = (opts, input, init2) => __async(void 0, null, function* () {
1669
+ const apiToken = opts.getApiToken && opts.getApiToken();
1670
+ const headers = new Headers(__spreadValues({
1671
+ "Authorization": apiToken ? `Bearer ${apiToken}` : ""
1672
+ }, init2 == null ? void 0 : init2.headers));
1673
+ if (!headers.get("Authorization"))
1674
+ headers.delete("Authorization");
1675
+ const resp = yield fetch(input, __spreadProps(__spreadValues({}, init2), {
1676
+ headers
1677
+ }));
1678
+ if (!resp.ok) {
1679
+ const json = (yield resp.json().catch(() => {
1680
+ })) || {};
1681
+ if (json.need_captcha) {
1682
+ opts.onNeedCheckCaptcha && (yield opts.onNeedCheckCaptcha({
1683
+ data: { imgData: json.img_data, iframe: json.iframe }
1684
+ }));
1685
+ return Fetch$1(opts, input, init2);
810
1686
  }
811
- const resp = yield timeoutFetch(input, timeout || opts.timeout || 15e3, init2);
812
- const respHttpCode = resp.status;
813
- const noAccessCodes = [401, 400];
814
- const isNoAccess = noAccessCodes.includes(respHttpCode);
815
- if (!resp.ok && !isNoAccess)
816
- throw new Error(`${t("reqGot")} ${respHttpCode}`);
817
- let json = yield resp.json();
818
- const recall = (resolve, reject) => {
819
- Fetch$1(opts, input, init2).then((d) => {
820
- resolve(d);
821
- }).catch((e) => {
822
- reject(e);
823
- });
824
- };
825
- if ((_a = json.data) == null ? void 0 : _a.need_captcha) {
826
- json = yield new Promise((resolve, reject) => {
827
- opts.onNeedCheckCaptcha && opts.onNeedCheckCaptcha({
828
- data: { imgData: json.data.img_data, iframe: json.data.iframe },
829
- recall: () => {
830
- recall(resolve, reject);
831
- },
832
- reject: () => {
833
- reject(json);
834
- }
835
- });
836
- });
837
- } else if (((_b = json.data) == null ? void 0 : _b.need_login) || isNoAccess) {
838
- json = yield new Promise((resolve, reject) => {
839
- opts.onNeedCheckAdmin && opts.onNeedCheckAdmin({
840
- recall: () => {
841
- recall(resolve, reject);
842
- },
843
- reject: () => {
844
- reject(json);
845
- }
846
- });
847
- });
1687
+ if (json.need_login) {
1688
+ opts.onNeedCheckAdmin && (yield opts.onNeedCheckAdmin({}));
1689
+ return Fetch$1(opts, input, init2);
848
1690
  }
849
- if (!json.success)
850
- throw json;
851
- return json;
852
- });
853
- }
854
- function POST(opts, url, data) {
855
- return __async(this, null, function* () {
856
- const init2 = {
857
- method: "POST"
858
- };
859
- data = __spreadValues({ site_name: opts.siteName || "" }, data || {});
860
- init2.body = ToFormData(data);
861
- const json = yield Fetch$1(opts, url, init2);
862
- return json.data || {};
863
- });
864
- }
865
- function ToFormData(object) {
866
- const formData = new FormData();
867
- Object.keys(object).forEach((key) => formData.append(key, String(object[key])));
868
- return formData;
869
- }
870
- function timeoutFetch(url, ms, opts) {
871
- var _a;
872
- const controller = new AbortController();
873
- (_a = opts.signal) == null ? void 0 : _a.addEventListener("abort", () => controller.abort());
874
- let promise = fetch(url, __spreadProps(__spreadValues({}, opts), { signal: controller.signal }));
875
- if (ms > 0) {
876
- const timer = setTimeout(() => controller.abort(), ms);
877
- promise.finally(() => {
878
- clearTimeout(timer);
879
- });
1691
+ throw createError(resp.status, json);
880
1692
  }
881
- promise = promise.catch((err) => {
882
- throw (err || {}).name === "AbortError" ? new Error(t("reqAborted")) : err;
883
- });
884
- return promise;
885
- }
886
- class ApiBase {
887
- constructor(options) {
888
- this.options = options;
889
- }
890
- POST(path, data) {
891
- return __async(this, null, function* () {
892
- return POST(this.options, this.options.baseURL + path, data);
893
- });
1693
+ return resp;
1694
+ });
1695
+ class FetchException extends Error {
1696
+ constructor() {
1697
+ super(...arguments);
1698
+ __publicField(this, "code", 0);
1699
+ __publicField(this, "message", "fetch error");
1700
+ __publicField(this, "data");
894
1701
  }
895
- Fetch(path, init2, timeout) {
896
- return __async(this, null, function* () {
897
- return Fetch$1(this.options, this.options.baseURL + path, init2, timeout);
1702
+ }
1703
+ function createError(code, data) {
1704
+ const err = new FetchException();
1705
+ err.message = data.msg || data.message || "fetch error";
1706
+ err.code = code;
1707
+ err.data = data;
1708
+ console.error(err);
1709
+ return err;
1710
+ }
1711
+ class Api2 extends Api$1 {
1712
+ constructor(opts) {
1713
+ super({
1714
+ baseUrl: opts.baseURL,
1715
+ customFetch: (input, init2) => Fetch$1(opts, input, init2)
898
1716
  });
1717
+ __publicField(this, "_opts");
1718
+ this._opts = opts;
899
1719
  }
900
1720
  /**
901
- * Carry user info to request params
1721
+ * Get user info as params for request
902
1722
  *
903
- * @param params Request params
904
1723
  * @returns Request params with user info
905
1724
  */
906
- withUserInfo(params) {
907
- const user = this.options.userInfo;
908
- if (user == null ? void 0 : user.name)
909
- params.name = user.name;
910
- if (user == null ? void 0 : user.email)
911
- params.email = user.email;
912
- return params;
913
- }
914
- }
915
- class CommentApi extends ApiBase {
916
- /** 评论 · 获取 */
917
- get(offset, pageSize, flatMode, paramsEditor) {
918
- const params = {
919
- page_key: this.options.pageKey,
920
- site_name: this.options.siteName,
921
- limit: pageSize,
922
- offset
923
- };
924
- if (flatMode)
925
- params.flat_mode = flatMode;
926
- this.withUserInfo(params);
927
- if (paramsEditor)
928
- paramsEditor(params);
929
- return this.POST("/get", params);
930
- }
931
- /** 评论 · 创建 */
932
- add(comment) {
933
- return __async(this, null, function* () {
934
- const params = {
935
- name: comment.nick,
936
- email: comment.email,
937
- link: comment.link,
938
- content: comment.content,
939
- rid: comment.rid,
940
- page_key: comment.page_key,
941
- ua: yield getCorrectUserAgent()
942
- // 需要后端支持,获取修正后的 UA
943
- };
944
- if (comment.page_title)
945
- params.page_title = comment.page_title;
946
- if (comment.site_name)
947
- params.site_name = comment.site_name;
948
- const data = yield this.POST("/add", params);
949
- return data.comment;
950
- });
951
- }
952
- /** 评论 · 修改 */
953
- commentEdit(data) {
954
- return __async(this, null, function* () {
955
- const params = __spreadValues({}, data);
956
- const d = yield this.POST("/admin/comment-edit", params);
957
- return d.comment;
958
- });
959
- }
960
- /** 评论 · 删除 */
961
- commentDel(commentID, siteName) {
962
- const params = {
963
- id: String(commentID),
964
- site_name: siteName || ""
965
- };
966
- return this.POST("/admin/comment-del", params);
967
- }
968
- /** 投票 */
969
- vote(targetID, type) {
970
- return __async(this, null, function* () {
971
- const params = {
972
- target_id: targetID,
973
- type
974
- };
975
- this.withUserInfo(params);
976
- const data = yield this.POST("/vote", params);
977
- return data;
978
- });
1725
+ getUserFields() {
1726
+ const user = this._opts.userInfo;
1727
+ if (!(user == null ? void 0 : user.name) || !(user == null ? void 0 : user.email))
1728
+ return void 0;
1729
+ return { name: user.name, email: user.email };
979
1730
  }
980
1731
  }
981
- class PageApi extends ApiBase {
982
- /** 页面 · 获取 */
983
- pageGet(siteName, offset, limit) {
984
- return __async(this, null, function* () {
985
- const params = {
986
- site_name: siteName || "",
987
- offset: offset || 0,
988
- limit: limit || 15
989
- };
990
- const d = yield this.POST("/admin/page-get", params);
991
- return d;
992
- });
993
- }
994
- /** 页面 · 修改 */
995
- pageEdit(data) {
996
- return __async(this, null, function* () {
997
- const params = {
998
- id: data.id,
999
- key: data.key,
1000
- title: data.title,
1001
- admin_only: data.admin_only,
1002
- site_name: data.site_name || this.options.siteName
1003
- };
1004
- const d = yield this.POST("/admin/page-edit", params);
1005
- return d.page;
1006
- });
1007
- }
1008
- /** 页面 · 删除 */
1009
- pageDel(pageKey, siteName) {
1010
- const params = {
1011
- key: String(pageKey),
1012
- site_name: siteName || ""
1013
- };
1014
- return this.POST("/admin/page-del", params);
1015
- }
1016
- /** 页面 · 数据更新 */
1017
- pageFetch(id, siteName, getStatus) {
1018
- return __async(this, null, function* () {
1019
- const params = {};
1020
- if (id)
1021
- params.id = id;
1022
- if (siteName)
1023
- params.site_name = siteName;
1024
- if (getStatus)
1025
- params.get_status = getStatus;
1026
- const d = yield this.POST("/admin/page-fetch", params);
1027
- return d;
1028
- });
1029
- }
1030
- /** PV */
1031
- pv() {
1032
- return __async(this, null, function* () {
1033
- const params = {
1034
- page_key: this.options.pageKey || "",
1035
- page_title: this.options.pageTitle || ""
1036
- };
1037
- const p = yield this.POST("/pv", params);
1038
- return p.pv;
1039
- });
1040
- }
1041
- /** 统计 */
1042
- stat(type, pageKeys, limit) {
1043
- return __async(this, null, function* () {
1044
- const params = {
1045
- type
1046
- };
1047
- if (pageKeys)
1048
- params.page_keys = Array.isArray(pageKeys) ? pageKeys.join(",") : pageKeys;
1049
- if (limit)
1050
- params.limit = limit;
1051
- const data = yield this.POST(`/stat`, params);
1052
- return data;
1053
- });
1054
- }
1732
+ var escapes = {
1733
+ "&": "&amp;",
1734
+ "<": "&lt;",
1735
+ ">": "&gt;",
1736
+ '"': "&quot;",
1737
+ "'": "&#39;"
1738
+ };
1739
+ var unescapes = {
1740
+ "&amp;": "&",
1741
+ "&lt;": "<",
1742
+ "&gt;": ">",
1743
+ "&quot;": '"',
1744
+ "&#39;": "'"
1745
+ };
1746
+ var rescaped = /(&amp;|&lt;|&gt;|&quot;|&#39;)/g;
1747
+ var runescaped = /[&<>"']/g;
1748
+ function escapeHtmlChar(match) {
1749
+ return escapes[match];
1055
1750
  }
1056
- class SiteApi extends ApiBase {
1057
- /** 站点 · 获取 */
1058
- siteGet() {
1059
- return __async(this, null, function* () {
1060
- const params = {};
1061
- const d = yield this.POST("/admin/site-get", params);
1062
- return d.sites;
1063
- });
1064
- }
1065
- /** 站点 · 创建 */
1066
- siteAdd(name, urls) {
1067
- return __async(this, null, function* () {
1068
- const params = {
1069
- name,
1070
- urls,
1071
- site_name: ""
1072
- // 全局保留字段,当前站点名
1073
- };
1074
- const d = yield this.POST("/admin/site-add", params);
1075
- return d.site;
1076
- });
1077
- }
1078
- /** 站点 · 修改 */
1079
- siteEdit(data) {
1080
- return __async(this, null, function* () {
1081
- const params = {
1082
- id: data.id,
1083
- name: data.name || "",
1084
- urls: data.urls || ""
1085
- };
1086
- const d = yield this.POST("/admin/site-edit", params);
1087
- return d.site;
1088
- });
1089
- }
1090
- /** 站点 · 删除 */
1091
- siteDel(id, delContent = false) {
1092
- const params = { id, del_content: delContent };
1093
- return this.POST("/admin/site-del", params);
1094
- }
1095
- /** 导出 */
1096
- export() {
1097
- return __async(this, null, function* () {
1098
- var _a;
1099
- const d = yield this.Fetch(`/admin/export`, { method: "POST" }, 0);
1100
- return ((_a = d.data) == null ? void 0 : _a.data) || "";
1101
- });
1102
- }
1103
- }
1104
- class UserApi extends ApiBase {
1105
- /** 用户 · 登录 */
1106
- login(name, email, password) {
1107
- return __async(this, null, function* () {
1108
- const params = {
1109
- name,
1110
- email,
1111
- password
1112
- };
1113
- const data = yield this.POST("/login", params);
1114
- return data;
1115
- });
1116
- }
1117
- /** 用户 · 获取 */
1118
- userGet(name, email) {
1119
- const ctrl = new AbortController();
1120
- const params = {
1121
- name,
1122
- email
1123
- };
1124
- const req = this.Fetch(`/user-get`, {
1125
- method: "POST",
1126
- body: ToFormData(params),
1127
- signal: ctrl.signal
1128
- }).then((json) => ({
1129
- user: json.data.user,
1130
- is_login: json.data.is_login,
1131
- unread: json.data.unread || [],
1132
- unread_count: json.data.unread_count || 0
1133
- }));
1134
- return {
1135
- req,
1136
- abort: () => {
1137
- ctrl.abort();
1138
- }
1139
- };
1140
- }
1141
- /** 用户 · 登录状态 */
1142
- loginStatus() {
1143
- return __async(this, null, function* () {
1144
- const data = yield this.POST("/login-status", this.withUserInfo({}));
1145
- return data || { is_login: false, is_admin: false };
1146
- });
1147
- }
1148
- /** 用户 · 注销 */
1149
- logout() {
1150
- return __async(this, null, function* () {
1151
- return this.POST("/logout");
1152
- });
1153
- }
1154
- /** 已读标记 */
1155
- markRead(commentID, notifyKey, readAll = false) {
1156
- const params = {
1157
- comment_id: commentID,
1158
- notify_key: notifyKey
1159
- };
1160
- if (readAll) {
1161
- delete params.comment_id;
1162
- delete params.notify_key;
1163
- params.read_all = true;
1164
- this.withUserInfo(params);
1165
- }
1166
- return this.POST(`/mark-read`, params);
1167
- }
1168
- /** 用户 · 列表 */
1169
- userList(offset, limit, type) {
1170
- return __async(this, null, function* () {
1171
- const params = {
1172
- offset: offset || 0,
1173
- limit: limit || 15
1174
- };
1175
- if (type)
1176
- params.type = type;
1177
- const d = yield this.POST("/admin/user-get", params);
1178
- return d;
1179
- });
1180
- }
1181
- /** 用户 · 新增 */
1182
- userAdd(user, password) {
1183
- return __async(this, null, function* () {
1184
- const params = {
1185
- name: user.name || "",
1186
- email: user.email || "",
1187
- password: password || "",
1188
- link: user.link || "",
1189
- is_admin: user.is_admin || false,
1190
- site_names: user.site_names_raw || "",
1191
- receive_email: user.receive_email || true,
1192
- badge_name: user.badge_name || "",
1193
- badge_color: user.badge_color || ""
1194
- };
1195
- const d = yield this.POST("/admin/user-add", params);
1196
- return d.user;
1197
- });
1198
- }
1199
- /** 用户 · 修改 */
1200
- userEdit(user, password) {
1201
- return __async(this, null, function* () {
1202
- const params = {
1203
- id: user.id,
1204
- name: user.name || "",
1205
- email: user.email || "",
1206
- password: password || "",
1207
- link: user.link || "",
1208
- is_admin: user.is_admin || false,
1209
- site_names: user.site_names_raw || "",
1210
- receive_email: user.receive_email || true,
1211
- badge_name: user.badge_name || "",
1212
- badge_color: user.badge_color || ""
1213
- };
1214
- const d = yield this.POST("/admin/user-edit", params);
1215
- return d.user;
1216
- });
1217
- }
1218
- /** 用户 · 删除 */
1219
- userDel(userID) {
1220
- return this.POST("/admin/user-del", {
1221
- id: String(userID)
1222
- });
1223
- }
1224
- }
1225
- class SystemApi extends ApiBase {
1226
- /** 获取配置 */
1227
- conf() {
1228
- return __async(this, null, function* () {
1229
- const data = yield this.POST(`/conf`);
1230
- return {
1231
- frontend_conf: data.frontend_conf,
1232
- version: data.version
1233
- };
1234
- });
1235
- }
1236
- /** 获取配置数据 */
1237
- getSettings() {
1238
- return __async(this, null, function* () {
1239
- const data = yield this.POST("/admin/setting-get");
1240
- return data;
1241
- });
1242
- }
1243
- /** 保存配置数据 */
1244
- saveSettings(yamlStr) {
1245
- return __async(this, null, function* () {
1246
- const data = yield this.POST("/admin/setting-save", {
1247
- data: yamlStr
1248
- });
1249
- return data;
1250
- });
1251
- }
1252
- /** 获取 API 版本信息 */
1253
- version() {
1254
- return __async(this, null, function* () {
1255
- const resp = yield fetch(`${this.options.baseURL}/version`, { method: "POST" });
1256
- const data = yield resp.json();
1257
- return data;
1258
- });
1259
- }
1260
- }
1261
- class CaptchaApi extends ApiBase {
1262
- /** 验证码 · 获取 */
1263
- captchaGet() {
1264
- return __async(this, null, function* () {
1265
- const data = yield this.POST("/captcha/refresh");
1266
- return data.img_data || "";
1267
- });
1268
- }
1269
- /** 验证码 · 检验 */
1270
- captchaCheck(value) {
1271
- return __async(this, null, function* () {
1272
- const data = yield this.POST("/captcha/check", { value });
1273
- return data.img_data || "";
1274
- });
1275
- }
1276
- /** 验证码 · 状态 */
1277
- captchaStatus() {
1278
- return __async(this, null, function* () {
1279
- const data = yield this.POST("/captcha/status");
1280
- return data || { is_pass: false };
1281
- });
1282
- }
1283
- }
1284
- class AdminApi extends ApiBase {
1285
- /** 缓存清除 */
1286
- cacheFlushAll() {
1287
- const params = { flush_all: true };
1288
- return this.POST("/admin/cache-flush", params);
1289
- }
1290
- /** 缓存预热 */
1291
- cacheWarmUp() {
1292
- const params = {};
1293
- return this.POST("/admin/cache-warm", params);
1294
- }
1295
- }
1296
- class UploadApi extends ApiBase {
1297
- /** 图片上传 */
1298
- imgUpload(file) {
1299
- return __async(this, null, function* () {
1300
- const params = {
1301
- page_key: this.options.pageKey
1302
- };
1303
- this.withUserInfo(params);
1304
- const form = ToFormData(params);
1305
- form.set("file", file);
1306
- const init2 = {
1307
- method: "POST",
1308
- body: form
1309
- };
1310
- const json = yield this.Fetch("/img-upload", init2);
1311
- return json.data || {};
1312
- });
1313
- }
1314
- }
1315
- const ApiComponents = {
1316
- comment: CommentApi,
1317
- page: PageApi,
1318
- site: SiteApi,
1319
- user: UserApi,
1320
- system: SystemApi,
1321
- captcha: CaptchaApi,
1322
- admin: AdminApi,
1323
- upload: UploadApi
1324
- };
1325
- class Api {
1326
- constructor(opts) {
1327
- Object.entries(ApiComponents).forEach(([key, ApiComponent]) => {
1328
- this[key] = new ApiComponent(opts);
1329
- });
1330
- }
1331
- }
1332
- var escapes = {
1333
- "&": "&amp;",
1334
- "<": "&lt;",
1335
- ">": "&gt;",
1336
- '"': "&quot;",
1337
- "'": "&#39;"
1338
- };
1339
- var unescapes = {
1340
- "&amp;": "&",
1341
- "&lt;": "<",
1342
- "&gt;": ">",
1343
- "&quot;": '"',
1344
- "&#39;": "'"
1345
- };
1346
- var rescaped = /(&amp;|&lt;|&gt;|&quot;|&#39;)/g;
1347
- var runescaped = /[&<>"']/g;
1348
- function escapeHtmlChar(match) {
1349
- return escapes[match];
1350
- }
1351
- function unescapeHtmlChar(match) {
1352
- return unescapes[match];
1751
+ function unescapeHtmlChar(match) {
1752
+ return unescapes[match];
1353
1753
  }
1354
1754
  function escapeHtml(text) {
1355
1755
  return text == null ? "" : String(text).replace(runescaped, escapeHtmlChar);
@@ -1894,14 +2294,9 @@ const markedCodeRenderer = () => (block, lang) => {
1894
2294
  let instance;
1895
2295
  let replacers = [];
1896
2296
  const markedOptions = {
1897
- pedantic: false,
1898
2297
  gfm: true,
1899
2298
  breaks: true,
1900
- smartLists: true,
1901
- smartypants: true,
1902
- xhtml: false,
1903
- sanitize: false,
1904
- silent: true
2299
+ async: false
1905
2300
  };
1906
2301
  function getInstance() {
1907
2302
  return instance;
@@ -1963,7 +2358,7 @@ class DataManager {
1963
2358
  __publicField(this, "listLastFetch");
1964
2359
  __publicField(this, "comments", []);
1965
2360
  // Note: 无层级结构 + 无须排列
1966
- __publicField(this, "unreads", []);
2361
+ __publicField(this, "notifies", []);
1967
2362
  __publicField(this, "page");
1968
2363
  this.events = events;
1969
2364
  }
@@ -2022,26 +2417,386 @@ class DataManager {
2022
2417
  this.events.trigger("comment-deleted", comment);
2023
2418
  this.events.trigger("list-loaded", this.comments);
2024
2419
  }
2025
- // -------------------------------------------------------------------
2026
- // Unreads
2027
- // -------------------------------------------------------------------
2028
- getUnreads() {
2029
- return this.unreads;
2420
+ // -------------------------------------------------------------------
2421
+ // Notifies
2422
+ // -------------------------------------------------------------------
2423
+ getNotifies() {
2424
+ return this.notifies;
2425
+ }
2426
+ updateNotifies(notifies) {
2427
+ this.notifies = notifies;
2428
+ this.events.trigger("notifies-updated", this.notifies);
2429
+ }
2430
+ // -------------------------------------------------------------------
2431
+ // Page
2432
+ // -------------------------------------------------------------------
2433
+ getPage() {
2434
+ return this.page;
2435
+ }
2436
+ updatePage(pageData) {
2437
+ this.page = pageData;
2438
+ this.events.trigger("page-loaded", pageData);
2439
+ }
2440
+ }
2441
+ const en = {
2442
+ /* Editor */
2443
+ placeholder: "Leave a comment",
2444
+ noComment: "No Comment",
2445
+ send: "Send",
2446
+ save: "Save",
2447
+ nick: "Nickname",
2448
+ email: "Email",
2449
+ link: "Website",
2450
+ emoticon: "Emoji",
2451
+ preview: "Preview",
2452
+ image: "Image",
2453
+ uploadFail: "Upload Failed",
2454
+ commentFail: "Failed to comment",
2455
+ restoredMsg: "Content has been restored",
2456
+ onlyAdminCanReply: "Only admin can reply",
2457
+ uploadLoginMsg: "Please fill in your name and email to upload",
2458
+ /* List */
2459
+ counter: "{count} Comments",
2460
+ sortLatest: "Latest",
2461
+ sortOldest: "Oldest",
2462
+ sortBest: "Best",
2463
+ sortAuthor: "Author",
2464
+ openComment: "Open Comment",
2465
+ closeComment: "Close Comment",
2466
+ listLoadFailMsg: "Failed to load comments",
2467
+ listRetry: "Retry",
2468
+ loadMore: "Load More",
2469
+ /* Comment */
2470
+ admin: "Admin",
2471
+ reply: "Reply",
2472
+ voteUp: "Up",
2473
+ voteDown: "Down",
2474
+ voteFail: "Vote Failed",
2475
+ readMore: "Read More",
2476
+ actionConfirm: "Confirm",
2477
+ collapse: "Collapse",
2478
+ collapsed: "Collapsed",
2479
+ collapsedMsg: "This comment has been collapsed",
2480
+ expand: "Expand",
2481
+ approved: "Approved",
2482
+ pending: "Pending",
2483
+ pendingMsg: "Pending, visible only to commenter.",
2484
+ edit: "Edit",
2485
+ editCancel: "Cancel Edit",
2486
+ delete: "Delete",
2487
+ deleteConfirm: "Confirm",
2488
+ pin: "Pin",
2489
+ unpin: "Unpin",
2490
+ /* Time */
2491
+ seconds: "seconds ago",
2492
+ minutes: "minutes ago",
2493
+ hours: "hours ago",
2494
+ days: "days ago",
2495
+ now: "just now",
2496
+ /* Checker */
2497
+ adminCheck: "Enter admin password:",
2498
+ captchaCheck: "Enter the CAPTCHA to continue:",
2499
+ confirm: "Confirm",
2500
+ cancel: "Cancel",
2501
+ /* Sidebar */
2502
+ msgCenter: "Messages",
2503
+ ctrlCenter: "Admin",
2504
+ /* General */
2505
+ frontend: "Frontend",
2506
+ backend: "Backend",
2507
+ loading: "Loading",
2508
+ loadFail: "Load Failed",
2509
+ editing: "Editing",
2510
+ editFail: "Edit Failed",
2511
+ deleting: "Deleting",
2512
+ deleteFail: "Delete Failed",
2513
+ reqGot: "Request got",
2514
+ reqAborted: "Request timed out or terminated unexpectedly",
2515
+ updateMsg: "Please update Artalk {name} to get the full experience",
2516
+ currentVersion: "Current Version",
2517
+ ignore: "Ignore",
2518
+ open: "Open",
2519
+ openName: "Open {name}"
2520
+ };
2521
+ const zhCN = {
2522
+ /* Editor */
2523
+ placeholder: "键入内容...",
2524
+ noComment: "「此时无声胜有声」",
2525
+ send: "发送评论",
2526
+ save: "保存评论",
2527
+ nick: "昵称",
2528
+ email: "邮箱",
2529
+ link: "网址",
2530
+ emoticon: "表情",
2531
+ preview: "预览",
2532
+ image: "图片",
2533
+ uploadFail: "上传失败",
2534
+ commentFail: "评论失败",
2535
+ restoredMsg: "内容已自动恢复",
2536
+ onlyAdminCanReply: "仅管理员可评论",
2537
+ uploadLoginMsg: "填入你的名字邮箱才能上传哦",
2538
+ /* List */
2539
+ counter: "{count} 条评论",
2540
+ sortLatest: "最新",
2541
+ sortOldest: "最早",
2542
+ sortBest: "最热",
2543
+ sortAuthor: "作者",
2544
+ openComment: "打开评论",
2545
+ closeComment: "关闭评论",
2546
+ listLoadFailMsg: "无法获取评论列表数据",
2547
+ listRetry: "点击重新获取",
2548
+ loadMore: "加载更多",
2549
+ /* Comment */
2550
+ admin: "管理员",
2551
+ reply: "回复",
2552
+ voteUp: "赞同",
2553
+ voteDown: "反对",
2554
+ voteFail: "投票失败",
2555
+ readMore: "阅读更多",
2556
+ actionConfirm: "确认操作",
2557
+ collapse: "折叠",
2558
+ collapsed: "已折叠",
2559
+ collapsedMsg: "该评论已被系统或管理员折叠",
2560
+ expand: "展开",
2561
+ approved: "已审",
2562
+ pending: "待审",
2563
+ pendingMsg: "审核中,仅本人可见。",
2564
+ edit: "编辑",
2565
+ editCancel: "取消编辑",
2566
+ delete: "删除",
2567
+ deleteConfirm: "确认删除",
2568
+ pin: "置顶",
2569
+ unpin: "取消置顶",
2570
+ /* Time */
2571
+ seconds: "秒前",
2572
+ minutes: "分钟前",
2573
+ hours: "小时前",
2574
+ days: "天前",
2575
+ now: "刚刚",
2576
+ /* Checker */
2577
+ adminCheck: "键入密码来验证管理员身份:",
2578
+ captchaCheck: "键入验证码继续:",
2579
+ confirm: "确认",
2580
+ cancel: "取消",
2581
+ /* Sidebar */
2582
+ msgCenter: "通知中心",
2583
+ ctrlCenter: "控制中心",
2584
+ /* General */
2585
+ frontend: "前端",
2586
+ backend: "后端",
2587
+ loading: "加载中",
2588
+ loadFail: "加载失败",
2589
+ editing: "修改中",
2590
+ editFail: "修改失败",
2591
+ deleting: "删除中",
2592
+ deleteFail: "删除失败",
2593
+ reqGot: "请求响应",
2594
+ reqAborted: "请求超时或意外终止",
2595
+ updateMsg: "请更新 Artalk {name} 以获得完整体验",
2596
+ currentVersion: "当前版本",
2597
+ ignore: "忽略",
2598
+ open: "打开",
2599
+ openName: "打开{name}"
2600
+ };
2601
+ const GLOBAL_LOCALES_KEY = "ArtalkI18n";
2602
+ function createElement(htmlStr = "") {
2603
+ const div = document.createElement("div");
2604
+ div.innerHTML = htmlStr.trim();
2605
+ return div.firstElementChild || div;
2606
+ }
2607
+ function getHeight(el) {
2608
+ return parseFloat(getComputedStyle(el, null).height.replace("px", ""));
2609
+ }
2610
+ function htmlEncode(str) {
2611
+ const temp = document.createElement("div");
2612
+ temp.innerText = str;
2613
+ const output = temp.innerHTML;
2614
+ return output;
2615
+ }
2616
+ function getQueryParam(name) {
2617
+ const match = RegExp(`[?&]${name}=([^&]*)`).exec(window.location.search);
2618
+ return match && decodeURIComponent(match[1].replace(/\+/g, " "));
2619
+ }
2620
+ function getOffset(el, relativeTo) {
2621
+ const getOffsetRecursive = (element) => {
2622
+ const rect = element.getBoundingClientRect();
2623
+ const scrollLeft = window.pageXOffset || document.documentElement.scrollLeft;
2624
+ const scrollTop = window.pageYOffset || document.documentElement.scrollTop;
2625
+ return {
2626
+ top: rect.top + scrollTop,
2627
+ left: rect.left + scrollLeft
2628
+ };
2629
+ };
2630
+ const elOffset = getOffsetRecursive(el);
2631
+ if (!relativeTo)
2632
+ return elOffset;
2633
+ const relativeToOffset = getOffsetRecursive(relativeTo);
2634
+ return {
2635
+ top: elOffset.top - relativeToOffset.top,
2636
+ left: elOffset.left - relativeToOffset.left
2637
+ };
2638
+ }
2639
+ function padWithZeros(vNumber, width) {
2640
+ let numAsString = vNumber.toString();
2641
+ while (numAsString.length < width) {
2642
+ numAsString = `0${numAsString}`;
2643
+ }
2644
+ return numAsString;
2645
+ }
2646
+ function dateFormat(date) {
2647
+ const vDay = padWithZeros(date.getDate(), 2);
2648
+ const vMonth = padWithZeros(date.getMonth() + 1, 2);
2649
+ const vYear = padWithZeros(date.getFullYear(), 2);
2650
+ return `${vYear}-${vMonth}-${vDay}`;
2651
+ }
2652
+ function timeAgo(date, $t = (n) => n) {
2653
+ try {
2654
+ const oldTime = date.getTime();
2655
+ const currTime = (/* @__PURE__ */ new Date()).getTime();
2656
+ const diffValue = currTime - oldTime;
2657
+ const days = Math.floor(diffValue / (24 * 3600 * 1e3));
2658
+ if (days === 0) {
2659
+ const leave1 = diffValue % (24 * 3600 * 1e3);
2660
+ const hours = Math.floor(leave1 / (3600 * 1e3));
2661
+ if (hours === 0) {
2662
+ const leave2 = leave1 % (3600 * 1e3);
2663
+ const minutes = Math.floor(leave2 / (60 * 1e3));
2664
+ if (minutes === 0) {
2665
+ const leave3 = leave2 % (60 * 1e3);
2666
+ const seconds = Math.round(leave3 / 1e3);
2667
+ if (seconds < 10)
2668
+ return $t("now");
2669
+ return `${seconds} ${$t("seconds")}`;
2670
+ }
2671
+ return `${minutes} ${$t("minutes")}`;
2672
+ }
2673
+ return `${hours} ${$t("hours")}`;
2674
+ }
2675
+ if (days < 0)
2676
+ return $t("now");
2677
+ if (days < 8) {
2678
+ return `${days} ${$t("days")}`;
2679
+ }
2680
+ return dateFormat(date);
2681
+ } catch (error) {
2682
+ console.error(error);
2683
+ return " - ";
2684
+ }
2685
+ }
2686
+ function onImagesLoaded($container, event) {
2687
+ if (!$container)
2688
+ return;
2689
+ const images = $container.getElementsByTagName("img");
2690
+ if (!images.length)
2691
+ return;
2692
+ let loaded = images.length;
2693
+ for (let i = 0; i < images.length; i++) {
2694
+ if (images[i].complete) {
2695
+ loaded--;
2696
+ } else {
2697
+ images[i].addEventListener("load", () => {
2698
+ loaded--;
2699
+ if (loaded === 0)
2700
+ event();
2701
+ });
2702
+ }
2703
+ if (loaded === 0)
2704
+ event();
2705
+ }
2706
+ }
2707
+ function getGravatarURL(opts) {
2708
+ return `${opts.mirror.replace(/\/$/, "")}/${opts.emailMD5}?${opts.params.replace(/^\?/, "")}`;
2709
+ }
2710
+ function versionCompare(a, b) {
2711
+ const pa = a.split(".");
2712
+ const pb = b.split(".");
2713
+ for (let i = 0; i < 3; i++) {
2714
+ const na = Number(pa[i]);
2715
+ const nb = Number(pb[i]);
2716
+ if (na > nb)
2717
+ return 1;
2718
+ if (nb > na)
2719
+ return -1;
2720
+ if (!Number.isNaN(na) && Number.isNaN(nb))
2721
+ return 1;
2722
+ if (Number.isNaN(na) && !Number.isNaN(nb))
2723
+ return -1;
2030
2724
  }
2031
- updateUnreads(unread) {
2032
- this.unreads = unread;
2033
- this.events.trigger("unreads-updated", this.unreads);
2725
+ return 0;
2726
+ }
2727
+ function getCorrectUserAgent() {
2728
+ return __async(this, null, function* () {
2729
+ const uaRaw = navigator.userAgent;
2730
+ if (!navigator.userAgentData || !navigator.userAgentData.getHighEntropyValues) {
2731
+ return uaRaw;
2732
+ }
2733
+ const uaData = navigator.userAgentData;
2734
+ let uaGot = null;
2735
+ try {
2736
+ uaGot = yield uaData.getHighEntropyValues(["platformVersion"]);
2737
+ } catch (err) {
2738
+ console.error(err);
2739
+ return uaRaw;
2740
+ }
2741
+ const majorPlatformVersion = Number(uaGot.platformVersion.split(".")[0]);
2742
+ if (uaData.platform === "Windows") {
2743
+ if (majorPlatformVersion >= 13) {
2744
+ return uaRaw.replace(/Windows NT 10.0/, "Windows NT 11.0");
2745
+ }
2746
+ }
2747
+ if (uaData.platform === "macOS") {
2748
+ if (majorPlatformVersion >= 11) {
2749
+ return uaRaw.replace(/(Mac OS X \d+_\d+_\d+|Mac OS X)/, `Mac OS X ${uaGot.platformVersion.replace(/\./g, "_")}`);
2750
+ }
2751
+ }
2752
+ return uaRaw;
2753
+ });
2754
+ }
2755
+ function isValidURL(urlRaw) {
2756
+ let url;
2757
+ try {
2758
+ url = new URL(urlRaw);
2759
+ } catch (_) {
2760
+ return false;
2034
2761
  }
2035
- // -------------------------------------------------------------------
2036
- // Page
2037
- // -------------------------------------------------------------------
2038
- getPage() {
2039
- return this.page;
2762
+ return url.protocol === "http:" || url.protocol === "https:";
2763
+ }
2764
+ function getURLBasedOnApi(opts) {
2765
+ return getURLBasedOn(opts.base, opts.path);
2766
+ }
2767
+ function getURLBasedOn(baseURL, path) {
2768
+ return `${baseURL.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
2769
+ }
2770
+ const internal = {
2771
+ "en": en,
2772
+ "en-US": en,
2773
+ "zh-CN": zhCN
2774
+ };
2775
+ function findLocaleSet(lang) {
2776
+ lang = lang.replace(
2777
+ /^([a-zA-Z]+)(-[a-zA-Z]+)?$/,
2778
+ (_, p1, p2) => p1.toLowerCase() + (p2 || "").toUpperCase()
2779
+ );
2780
+ if (internal[lang]) {
2781
+ return internal[lang];
2040
2782
  }
2041
- updatePage(pageData) {
2042
- this.page = pageData;
2043
- this.events.trigger("page-loaded", pageData);
2783
+ if (window[GLOBAL_LOCALES_KEY] && window[GLOBAL_LOCALES_KEY][lang]) {
2784
+ return window[GLOBAL_LOCALES_KEY][lang];
2044
2785
  }
2786
+ return internal.en;
2787
+ }
2788
+ let LocaleConf = "en";
2789
+ let LocaleDict = findLocaleSet(LocaleConf);
2790
+ function setLocale(locale) {
2791
+ if (locale === LocaleConf)
2792
+ return;
2793
+ LocaleConf = locale;
2794
+ LocaleDict = typeof locale === "string" ? findLocaleSet(locale) : locale;
2795
+ }
2796
+ function t(key, args = {}) {
2797
+ let str = (LocaleDict == null ? void 0 : LocaleDict[key]) || key;
2798
+ str = str.replace(/\{\s*(\w+?)\s*\}/g, (_, token) => args[token] || "");
2799
+ return htmlEncode(str);
2045
2800
  }
2046
2801
  class EventManager {
2047
2802
  constructor() {
@@ -2112,7 +2867,7 @@ const defaults = {
2112
2867
  reqTimeout: 15e3,
2113
2868
  versionCheck: true,
2114
2869
  useBackendConf: true,
2115
- locale: "zh-CN"
2870
+ locale: "en"
2116
2871
  };
2117
2872
  function handelCustomConf(customConf, full = false) {
2118
2873
  const conf = full ? mergeDeep(defaults, customConf) : customConf;
@@ -2166,40 +2921,53 @@ function handleConfFormServer(conf) {
2166
2921
  }
2167
2922
  function convertApiOptions(conf, ctx) {
2168
2923
  return {
2169
- baseURL: `${conf.server}/api`,
2924
+ baseURL: `${conf.server}/api/v2`,
2170
2925
  siteName: conf.site || "",
2171
2926
  pageKey: conf.pageKey || "",
2172
2927
  pageTitle: conf.pageTitle || "",
2173
2928
  timeout: conf.reqTimeout,
2174
- apiToken: ctx == null ? void 0 : ctx.get("user").getData().token,
2929
+ getApiToken: () => ctx == null ? void 0 : ctx.get("user").getData().token,
2175
2930
  userInfo: (ctx == null ? void 0 : ctx.get("user").checkHasBasicUserInfo()) ? {
2176
2931
  name: ctx == null ? void 0 : ctx.get("user").getData().nick,
2177
2932
  email: ctx == null ? void 0 : ctx.get("user").getData().email
2178
2933
  } : void 0,
2179
- onNeedCheckAdmin(payload) {
2180
- ctx == null ? void 0 : ctx.checkAdmin({
2181
- onSuccess: () => {
2182
- payload.recall();
2183
- },
2184
- onCancel: () => {
2185
- payload.reject();
2186
- }
2187
- });
2934
+ onNeedCheckAdmin: (payload) => {
2935
+ if (!ctx)
2936
+ throw new Error("`ctx` is required when `onNeedCheckAdmin` is called.");
2937
+ return ctx.checkAdmin({});
2188
2938
  },
2189
- onNeedCheckCaptcha(payload) {
2190
- ctx == null ? void 0 : ctx.checkCaptcha({
2939
+ onNeedCheckCaptcha: (payload) => {
2940
+ if (!ctx)
2941
+ throw new Error("`ctx` is required when `onNeedCheckCaptcha` is called.");
2942
+ return ctx.checkCaptcha({
2191
2943
  imgData: payload.data.imgData,
2192
- iframe: payload.data.iframe,
2193
- onSuccess: () => {
2194
- payload.recall();
2195
- },
2196
- onCancel: () => {
2197
- payload.reject();
2198
- }
2944
+ iframe: payload.data.iframe
2199
2945
  });
2200
2946
  }
2201
2947
  };
2202
2948
  }
2949
+ function watchConf(ctx, keys, effect) {
2950
+ const deepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
2951
+ const val = () => {
2952
+ const conf = ctx.getConf();
2953
+ const res = {};
2954
+ keys.forEach((key) => {
2955
+ res[key] = conf[key];
2956
+ });
2957
+ return res;
2958
+ };
2959
+ let lastVal = null;
2960
+ const handler = () => {
2961
+ const newVal = val();
2962
+ const isDiff = lastVal == null || !deepEqual(lastVal, newVal);
2963
+ if (isDiff) {
2964
+ lastVal = newVal;
2965
+ effect(newVal);
2966
+ }
2967
+ };
2968
+ ctx.on("mounted", handler);
2969
+ ctx.on("updated", handler);
2970
+ }
2203
2971
  class Context {
2204
2972
  constructor(conf) {
2205
2973
  /* 运行参数 */
@@ -2208,11 +2976,17 @@ class Context {
2208
2976
  __publicField(this, "$root");
2209
2977
  /* Event Manager */
2210
2978
  __publicField(this, "events", new EventManager());
2979
+ __publicField(this, "mounted", false);
2980
+ __publicField(this, "getCommentList", this.getCommentNodes);
2981
+ __publicField(this, "getCommentDataList", this.getComments);
2211
2982
  this.conf = conf;
2212
2983
  this.$root = conf.el;
2213
2984
  this.$root.classList.add("artalk");
2214
2985
  this.$root.innerHTML = "";
2215
2986
  this.data = new DataManager(this.events);
2987
+ this.on("mounted", () => {
2988
+ this.mounted = true;
2989
+ });
2216
2990
  }
2217
2991
  inject(depName, obj) {
2218
2992
  this[depName] = obj;
@@ -2221,7 +2995,7 @@ class Context {
2221
2995
  return this[depName];
2222
2996
  }
2223
2997
  getApi() {
2224
- return new Api(convertApiOptions(this.conf, this));
2998
+ return new Api2(convertApiOptions(this.conf, this));
2225
2999
  }
2226
3000
  getData() {
2227
3001
  return this.data;
@@ -2238,10 +3012,17 @@ class Context {
2238
3012
  reload() {
2239
3013
  this.data.fetchComments({ offset: 0 });
2240
3014
  }
3015
+ /* List */
2241
3016
  listGotoFirst() {
2242
3017
  this.events.trigger("list-goto-first");
2243
3018
  }
2244
- /* 编辑器 */
3019
+ getCommentNodes() {
3020
+ return this.list.getCommentNodes();
3021
+ }
3022
+ getComments() {
3023
+ return this.data.getComments();
3024
+ }
3025
+ /* Editor */
2245
3026
  editorShowLoading() {
2246
3027
  this.editor.showLoading();
2247
3028
  }
@@ -2254,19 +3035,19 @@ class Context {
2254
3035
  editorResetState() {
2255
3036
  this.editor.resetState();
2256
3037
  }
2257
- /* 侧边栏 */
3038
+ /* Sidebar */
2258
3039
  showSidebar(payload) {
2259
3040
  this.sidebarLayer.show(payload);
2260
3041
  }
2261
3042
  hideSidebar() {
2262
3043
  this.sidebarLayer.hide();
2263
3044
  }
2264
- /* 权限检测 */
3045
+ /* Checker */
2265
3046
  checkAdmin(payload) {
2266
- this.checkerLauncher.checkAdmin(payload);
3047
+ return this.checkerLauncher.checkAdmin(payload);
2267
3048
  }
2268
3049
  checkCaptcha(payload) {
2269
- this.checkerLauncher.checkCaptcha(payload);
3050
+ return this.checkerLauncher.checkCaptcha(payload);
2270
3051
  }
2271
3052
  /* Events */
2272
3053
  on(name, handler) {
@@ -2283,12 +3064,11 @@ class Context {
2283
3064
  return t(key, args);
2284
3065
  }
2285
3066
  setDarkMode(darkMode) {
2286
- this.conf.darkMode = darkMode;
2287
- this.events.trigger("dark-mode-changed", darkMode);
3067
+ this.updateConf({ darkMode });
2288
3068
  }
2289
3069
  updateConf(nConf) {
2290
3070
  this.conf = mergeDeep(this.conf, handelCustomConf(nConf, false));
2291
- this.events.trigger("conf-loaded", this.conf);
3071
+ this.mounted && this.events.trigger("updated", this.conf);
2292
3072
  }
2293
3073
  getConf() {
2294
3074
  return this.conf;
@@ -2299,6 +3079,9 @@ class Context {
2299
3079
  getMarked() {
2300
3080
  return getInstance();
2301
3081
  }
3082
+ watchConf(keys, effect) {
3083
+ watchConf(this, keys, effect);
3084
+ }
2302
3085
  }
2303
3086
  class Dialog {
2304
3087
  constructor(contentEl) {
@@ -2491,8 +3274,8 @@ function imgBody(checker) {
2491
3274
  );
2492
3275
  elem.querySelector(".atk-captcha-img").onclick = () => {
2493
3276
  const imgEl = elem.querySelector(".atk-captcha-img");
2494
- checker.getApi().captcha.captchaGet().then((imgData) => {
2495
- imgEl.setAttribute("src", imgData);
3277
+ checker.getApi().captcha.getCaptcha().then((res) => {
3278
+ imgEl.setAttribute("src", res.data.img_data);
2496
3279
  }).catch((err) => {
2497
3280
  console.error("Failed to get captcha image ", err);
2498
3281
  });
@@ -2504,7 +3287,7 @@ function iframeBody(checker) {
2504
3287
  const $iframe = createElement(`<iframe class="atk-fade-in" referrerpolicy="strict-origin-when-cross-origin"></iframe>`);
2505
3288
  $iframe.style.display = "none";
2506
3289
  showLoading($iframeWrap, { transparentBg: true });
2507
- $iframe.src = `${checker.getOpts().getIframeURLBase() || ""}/api/captcha/get?t=${+/* @__PURE__ */ new Date()}`;
3290
+ $iframe.src = checker.getOpts().getCaptchaIframeURL();
2508
3291
  $iframe.onload = () => {
2509
3292
  $iframe.style.display = "";
2510
3293
  hideLoading($iframeWrap);
@@ -2526,8 +3309,8 @@ function iframeBody(checker) {
2526
3309
  return;
2527
3310
  let isPass = false;
2528
3311
  try {
2529
- const resp = yield checker.getApi().captcha.captchaStatus();
2530
- isPass = resp.is_pass;
3312
+ const resp = yield checker.getApi().captcha.getCaptchaStatus();
3313
+ isPass = resp.data.is_pass;
2531
3314
  } catch (e) {
2532
3315
  isPass = false;
2533
3316
  }
@@ -2546,7 +3329,9 @@ function iframeBody(checker) {
2546
3329
  }
2547
3330
  const CaptchaChecker = {
2548
3331
  request(checker, inputVal) {
2549
- return checker.getApi().captcha.captchaCheck(inputVal);
3332
+ return checker.getApi().captcha.verifyCaptcha({
3333
+ value: inputVal
3334
+ });
2550
3335
  },
2551
3336
  body(checker) {
2552
3337
  if (checker.get("iframe"))
@@ -2564,45 +3349,61 @@ const CaptchaChecker = {
2564
3349
  const AdminChecker = {
2565
3350
  inputType: "password",
2566
3351
  request(checker, inputVal) {
2567
- const data = {
2568
- name: checker.getUser().getData().nick,
2569
- email: checker.getUser().getData().email,
2570
- password: inputVal
2571
- };
2572
- return (() => __async(this, null, function* () {
2573
- const resp = yield checker.getApi().user.login(data.name, data.email, data.password);
2574
- return resp.token;
2575
- }))();
3352
+ return __async(this, null, function* () {
3353
+ return (yield checker.getApi().user.login({
3354
+ name: checker.getUser().getData().nick,
3355
+ email: checker.getUser().getData().email,
3356
+ password: inputVal
3357
+ })).data;
3358
+ });
2576
3359
  },
2577
3360
  body(checker) {
2578
3361
  return createElement(`<span>${t("adminCheck")}</span>`);
2579
3362
  },
2580
- onSuccess(checker, userToken, inputVal, formEl) {
3363
+ onSuccess(checker, res, inputVal, formEl) {
2581
3364
  checker.getUser().update({
2582
3365
  isAdmin: true,
2583
- token: userToken
3366
+ token: res.token
2584
3367
  });
2585
3368
  checker.getOpts().onReload();
2586
3369
  },
2587
3370
  onError(checker, err, inputVal, formEl) {
2588
3371
  }
2589
3372
  };
3373
+ function wrapPromise(fn) {
3374
+ return (payload) => new Promise((resolve, reject) => {
3375
+ const cancelFn = payload.onCancel;
3376
+ payload.onCancel = () => {
3377
+ cancelFn && cancelFn();
3378
+ reject(new Error("user canceled the checker"));
3379
+ };
3380
+ const successFn = payload.onSuccess;
3381
+ payload.onSuccess = () => {
3382
+ successFn && successFn();
3383
+ resolve();
3384
+ };
3385
+ fn(payload);
3386
+ });
3387
+ }
2590
3388
  class CheckerLauncher {
2591
3389
  constructor(opts) {
3390
+ __publicField(this, "checkCaptcha", wrapPromise((p) => {
3391
+ this.fire(CaptchaChecker, p, (ctx) => {
3392
+ ctx.set("img_data", p.imgData);
3393
+ ctx.set("iframe", p.iframe);
3394
+ });
3395
+ }));
3396
+ __publicField(this, "checkAdmin", wrapPromise((p) => {
3397
+ this.fire(AdminChecker, p);
3398
+ }));
2592
3399
  this.opts = opts;
2593
3400
  }
2594
- checkCaptcha(payload) {
2595
- this.fire(CaptchaChecker, payload, (ctx) => {
2596
- ctx.set("img_data", payload.imgData);
2597
- ctx.set("iframe", payload.iframe);
2598
- });
2599
- }
2600
- checkAdmin(payload) {
2601
- this.fire(AdminChecker, payload);
2602
- }
2603
3401
  fire(checker, payload, postFire) {
2604
3402
  const layer = this.opts.getCtx().get("layerManager").create(`checker-${(/* @__PURE__ */ new Date()).getTime()}`);
2605
3403
  layer.show();
3404
+ const close = () => {
3405
+ layer.destroy();
3406
+ };
2606
3407
  const checkerStore = {};
2607
3408
  let hideInteractInput = false;
2608
3409
  const checkerCtx = {
@@ -2617,14 +3418,14 @@ class CheckerLauncher {
2617
3418
  hideInteractInput = true;
2618
3419
  },
2619
3420
  triggerSuccess: () => {
2620
- this.close(checker, layer);
3421
+ close();
2621
3422
  if (checker.onSuccess)
2622
3423
  checker.onSuccess(checkerCtx, "", "", formEl);
2623
3424
  if (payload.onSuccess)
2624
- payload.onSuccess("", dialog.$el);
3425
+ payload.onSuccess();
2625
3426
  },
2626
3427
  cancel: () => {
2627
- this.close(checker, layer);
3428
+ close();
2628
3429
  if (payload.onCancel)
2629
3430
  payload.onCancel();
2630
3431
  }
@@ -2660,11 +3461,11 @@ class CheckerLauncher {
2660
3461
  };
2661
3462
  btnEl.innerText = `${t("loading")}...`;
2662
3463
  checker.request(checkerCtx, inputVal).then((data) => {
2663
- this.close(checker, layer);
3464
+ close();
2664
3465
  if (checker.onSuccess)
2665
3466
  checker.onSuccess(checkerCtx, data, inputVal, formEl);
2666
3467
  if (payload.onSuccess)
2667
- payload.onSuccess(inputVal, dialog.$el);
3468
+ payload.onSuccess();
2668
3469
  }).catch((err) => {
2669
3470
  btnTextSet(String(err.msg || String(err)));
2670
3471
  if (checker.onError)
@@ -2678,7 +3479,7 @@ class CheckerLauncher {
2678
3479
  return false;
2679
3480
  });
2680
3481
  dialog.setNo(() => {
2681
- this.close(checker, layer);
3482
+ close();
2682
3483
  if (payload.onCancel)
2683
3484
  payload.onCancel();
2684
3485
  return false;
@@ -2691,17 +3492,14 @@ class CheckerLauncher {
2691
3492
  if (payload.onMount)
2692
3493
  payload.onMount(dialog.$el);
2693
3494
  }
2694
- // 关闭 checker 对话框
2695
- close(checker, layer) {
2696
- layer.destroy();
2697
- }
2698
3495
  }
2699
3496
  class Component {
2700
3497
  constructor(ctx) {
2701
3498
  __publicField(this, "$el");
2702
- __publicField(this, "conf");
2703
3499
  this.ctx = ctx;
2704
- this.conf = ctx.conf;
3500
+ }
3501
+ get conf() {
3502
+ return this.ctx.conf;
2705
3503
  }
2706
3504
  }
2707
3505
  const EditorHTML = '<div class="atk-main-editor">\n <div class="atk-header">\n <input name="nick" class="atk-nick" type="text" required="required">\n <input name="email" class="atk-email" type="email" required="required">\n <input name="link" class="atk-link" type="url">\n </div>\n <div class="atk-textarea-wrap">\n <textarea class="atk-textarea"></textarea>\n </div>\n <div class="atk-plug-panel-wrap" style="display: none;"></div>\n <div class="atk-bottom">\n <div class="atk-item atk-plug-btn-wrap"></div>\n <div class="atk-item">\n <button type="button" class="atk-send-btn"></button>\n </div>\n </div>\n <div class="atk-notify-wrap"></div>\n</div>\n';
@@ -2924,7 +3722,10 @@ class SidebarLayer extends Component {
2924
3722
  __publicField(this, "$closeBtn");
2925
3723
  __publicField(this, "$iframeWrap");
2926
3724
  __publicField(this, "$iframe");
2927
- __publicField(this, "firstShow", true);
3725
+ /** Refresh iFrame on show */
3726
+ __publicField(this, "refreshOnShow", true);
3727
+ /** Animation timer */
3728
+ __publicField(this, "animTimer");
2928
3729
  this.$el = createElement(SidebarHTML);
2929
3730
  this.$header = this.$el.querySelector(".atk-sidebar-header");
2930
3731
  this.$closeBtn = this.$header.querySelector(".atk-sidebar-close");
@@ -2933,7 +3734,7 @@ class SidebarLayer extends Component {
2933
3734
  this.hide();
2934
3735
  };
2935
3736
  this.ctx.on("user-changed", () => {
2936
- this.firstShow = true;
3737
+ this.refreshOnShow = true;
2937
3738
  });
2938
3739
  }
2939
3740
  /** 显示 */
@@ -2942,45 +3743,43 @@ class SidebarLayer extends Component {
2942
3743
  this.$el.style.transform = "";
2943
3744
  this.initLayer();
2944
3745
  this.layer.show();
2945
- this.authCheck({
2946
- onSuccess: () => this.show(conf)
2947
- // retry show after auth check
2948
- });
2949
- if (this.firstShow) {
3746
+ if (this.refreshOnShow) {
3747
+ this.refreshOnShow = false;
2950
3748
  this.$iframeWrap.innerHTML = "";
2951
3749
  this.$iframe = this.createIframe(conf.view);
2952
3750
  this.$iframeWrap.append(this.$iframe);
2953
- this.firstShow = false;
2954
3751
  } else {
2955
3752
  const $iframe = this.$iframe;
2956
- const isIframeSrcDarkMode = $iframe.src.includes("darkMode=1");
2957
- if (this.conf.darkMode && !isIframeSrcDarkMode)
2958
- this.iframeLoad($iframe, `${this.$iframe.src}&darkMode=1`);
2959
- if (!this.conf.darkMode && isIframeSrcDarkMode)
2960
- this.iframeLoad($iframe, this.$iframe.src.replace("&darkMode=1", ""));
3753
+ const iFrameSrc = $iframe.src;
3754
+ if (this.conf.darkMode !== iFrameSrc.includes("darkMode=1")) {
3755
+ this.iframeLoad($iframe, this.conf.darkMode ? iFrameSrc.concat("&darkMode=1") : iFrameSrc.replace("&darkMode=1", ""));
3756
+ }
2961
3757
  }
2962
- setTimeout(() => {
3758
+ this.authCheck({
3759
+ onSuccess: () => this.show(conf)
3760
+ // retry show after auth check
3761
+ });
3762
+ this.animTimer = setTimeout(() => {
3763
+ this.animTimer = void 0;
2963
3764
  this.$el.style.transform = "translate(0, 0)";
3765
+ setTimeout(() => {
3766
+ this.ctx.getData().updateNotifies([]);
3767
+ }, 0);
3768
+ this.ctx.trigger("sidebar-show");
2964
3769
  }, 100);
2965
- setTimeout(() => {
2966
- this.ctx.getData().updateUnreads([]);
2967
- }, 0);
2968
- this.ctx.trigger("sidebar-show");
2969
3770
  });
2970
3771
  }
2971
3772
  /** 隐藏 */
2972
3773
  hide() {
2973
3774
  var _a;
2974
- this.$el.style.transform = "";
2975
3775
  (_a = this.layer) == null ? void 0 : _a.hide();
2976
- this.ctx.trigger("sidebar-hide");
2977
3776
  }
2978
3777
  // --------------------------------------------------
2979
3778
  authCheck(opts) {
2980
3779
  return __async(this, null, function* () {
2981
- const resp = yield this.ctx.getApi().user.loginStatus();
2982
- if (resp.is_admin && !resp.is_login) {
2983
- this.firstShow = true;
3780
+ const data = (yield this.ctx.getApi().user.getUserStatus(__spreadValues({}, this.ctx.getApi().getUserFields()))).data;
3781
+ if (data.is_admin && !data.is_login) {
3782
+ this.refreshOnShow = true;
2984
3783
  this.ctx.checkAdmin({
2985
3784
  onSuccess: () => {
2986
3785
  setTimeout(() => {
@@ -2991,6 +3790,7 @@ class SidebarLayer extends Component {
2991
3790
  this.hide();
2992
3791
  }
2993
3792
  });
3793
+ this.hide();
2994
3794
  }
2995
3795
  });
2996
3796
  }
@@ -3000,6 +3800,9 @@ class SidebarLayer extends Component {
3000
3800
  this.layer = this.ctx.get("layerManager").create("sidebar", this.$el);
3001
3801
  this.layer.setOnAfterHide(() => {
3002
3802
  this.ctx.editorResetState();
3803
+ this.animTimer && clearTimeout(this.animTimer);
3804
+ this.$el.style.transform = "";
3805
+ this.ctx.trigger("sidebar-hide");
3003
3806
  });
3004
3807
  }
3005
3808
  createIframe(view) {
@@ -3018,8 +3821,6 @@ class SidebarLayer extends Component {
3018
3821
  query.view = view;
3019
3822
  if (this.conf.darkMode)
3020
3823
  query.darkMode = "1";
3021
- if (typeof this.conf.locale === "string")
3022
- query.locale = this.conf.locale;
3023
3824
  const urlParams = new URLSearchParams(query);
3024
3825
  this.iframeLoad($iframe, `${baseURL}?${urlParams.toString()}`);
3025
3826
  return $iframe;
@@ -3562,7 +4363,7 @@ function renderReplyTo(r) {
3562
4363
  };
3563
4364
  let replyContent = marked(r.cConf.replyTo.content);
3564
4365
  if (r.cConf.replyTo.is_collapsed)
3565
- replyContent = `[${htmlEncode(r.ctx.$t("collapsed"))}]`;
4366
+ replyContent = `[${r.ctx.$t("collapsed")}]`;
3566
4367
  r.$replyTo.querySelector(".atk-content").innerHTML = replyContent;
3567
4368
  r.$body.prepend(r.$replyTo);
3568
4369
  }
@@ -3963,10 +4764,10 @@ class CommentActions {
3963
4764
  /** 投票操作 */
3964
4765
  vote(type) {
3965
4766
  const actionBtn = type === "up" ? this.comment.getRender().voteBtnUp : this.comment.getRender().voteBtnDown;
3966
- this.ctx.getApi().comment.vote(this.data.id, `comment_${type}`).then((v) => {
4767
+ this.ctx.getApi().votes.vote(`comment_${type}`, this.data.id, __spreadValues({}, this.ctx.getApi().getUserFields())).then((res) => {
3967
4768
  var _a, _b;
3968
- this.data.vote_up = v.up;
3969
- this.data.vote_down = v.down;
4769
+ this.data.vote_up = res.data.up;
4770
+ this.data.vote_down = res.data.down;
3970
4771
  (_a = this.comment.getRender().voteBtnUp) == null ? void 0 : _a.updateText();
3971
4772
  (_b = this.comment.getRender().voteBtnDown) == null ? void 0 : _b.updateText();
3972
4773
  }).catch((err) => {
@@ -3987,9 +4788,9 @@ class CommentActions {
3987
4788
  } else if (type === "pinned") {
3988
4789
  modify.is_pinned = !modify.is_pinned;
3989
4790
  }
3990
- this.ctx.getApi().comment.commentEdit(modify).then((data) => {
4791
+ this.ctx.getApi().comments.updateComment(this.data.id, __spreadValues({}, modify)).then((res) => {
3991
4792
  btnElem.setLoading(false);
3992
- this.comment.setData(data);
4793
+ this.comment.setData(res.data);
3993
4794
  }).catch((err) => {
3994
4795
  console.error(err);
3995
4796
  btnElem.setError(this.ctx.$t("editFail"));
@@ -4000,7 +4801,7 @@ class CommentActions {
4000
4801
  if (btnElem.isLoading)
4001
4802
  return;
4002
4803
  btnElem.setLoading(true, `${this.ctx.$t("deleting")}...`);
4003
- this.ctx.getApi().comment.commentDel(this.data.id, this.data.site_name).then(() => {
4804
+ this.ctx.getApi().comments.deleteComment(this.data.id).then(() => {
4004
4805
  btnElem.setLoading(false);
4005
4806
  if (this.cConf.onDelete)
4006
4807
  this.cConf.onDelete(this.comment);
@@ -4018,7 +4819,7 @@ class CommentActions {
4018
4819
  window.dispatchEvent(new Event("hashchange"));
4019
4820
  }
4020
4821
  }
4021
- class Comment extends Component {
4822
+ class CommentNode extends Component {
4022
4823
  // 最大嵌套层数
4023
4824
  constructor(ctx, data, conf) {
4024
4825
  super(ctx);
@@ -4159,7 +4960,7 @@ class Comment extends Component {
4159
4960
  }
4160
4961
  function createComment(ctx, comment, ctxComments) {
4161
4962
  var _a;
4162
- const instance2 = new Comment(ctx, comment, {
4963
+ const instance2 = new CommentNode(ctx, comment, {
4163
4964
  isFlatMode: (_a = ctx.getData().getListLastFetch()) == null ? void 0 : _a.params.flatMode,
4164
4965
  afterRender: () => {
4165
4966
  ctx.trigger("comment-rendered", instance2);
@@ -4307,9 +5108,13 @@ class Pagination {
4307
5108
  this.$el = createElement(
4308
5109
  `<div class="atk-pagination-wrap">
4309
5110
  <div class="atk-pagination">
4310
- <div class="atk-btn atk-btn-prev">Prev</div>
5111
+ <div class="atk-btn atk-btn-prev" aria-label="Previous page">
5112
+ <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="14px" width="14px" xmlns="http://www.w3.org/2000/svg"><path d="M217.9 256L345 129c9.4-9.4 9.4-24.6 0-33.9-9.4-9.4-24.6-9.3-34 0L167 239c-9.1 9.1-9.3 23.7-.7 33.1L310.9 417c4.7 4.7 10.9 7 17 7s12.3-2.3 17-7c9.4-9.4 9.4-24.6 0-33.9L217.9 256z"></path></svg>
5113
+ </div>
4311
5114
  <input type="text" class="atk-input" aria-label="Enter the number of page" />
4312
- <div class="atk-btn atk-btn-next">Next</div>
5115
+ <div class="atk-btn atk-btn-next" aria-label="Next page">
5116
+ <svg stroke="currentColor" fill="currentColor" stroke-width="0" viewBox="0 0 512 512" height="14px" width="14px" xmlns="http://www.w3.org/2000/svg"><path d="M294.1 256L167 129c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.3 34 0L345 239c9.1 9.1 9.3 23.7.7 33.1L201.1 417c-4.7 4.7-10.9 7-17 7s-12.3-2.3-17-7c-9.4-9.4-9.4-24.6 0-33.9l127-127.1z"></path></svg>
5117
+ </div>
4313
5118
  </div>
4314
5119
  </div>`
4315
5120
  );
@@ -4482,12 +5287,12 @@ function getPageDataByLastData(ctx) {
4482
5287
  return r;
4483
5288
  r.offset = last.params.offset;
4484
5289
  if (last.data)
4485
- r.total = last.params.flatMode ? last.data.total : last.data.total_roots;
5290
+ r.total = last.params.flatMode ? last.data.count : last.data.roots_count;
4486
5291
  return r;
4487
5292
  }
4488
5293
  const initListPaginatorFunc = (ctx) => {
4489
5294
  let paginator = null;
4490
- ctx.on("conf-loaded", (conf) => {
5295
+ ctx.watchConf(["pagination", "locale"], (conf) => {
4491
5296
  const list = ctx.get("list");
4492
5297
  if (paginator)
4493
5298
  paginator.dispose();
@@ -4511,7 +5316,7 @@ const initListPaginatorFunc = (ctx) => {
4511
5316
  ctx.getData().clearComments();
4512
5317
  }
4513
5318
  });
4514
- ctx.on("list-error", () => {
5319
+ ctx.on("list-failed", () => {
4515
5320
  var _a;
4516
5321
  (_a = paginator == null ? void 0 : paginator.showErr) == null ? void 0 : _a.call(paginator, t("loadFail"));
4517
5322
  });
@@ -4600,11 +5405,48 @@ function getScrollbarHelper() {
4600
5405
  }
4601
5406
  };
4602
5407
  }
5408
+ class Layer {
5409
+ constructor($el, opts) {
5410
+ __publicField(this, "allowMaskClose", true);
5411
+ __publicField(this, "onAfterHide");
5412
+ this.$el = $el;
5413
+ this.opts = opts;
5414
+ }
5415
+ setOnAfterHide(func) {
5416
+ this.onAfterHide = func;
5417
+ }
5418
+ setAllowMaskClose(allow) {
5419
+ this.allowMaskClose = allow;
5420
+ }
5421
+ getAllowMaskClose() {
5422
+ return this.allowMaskClose;
5423
+ }
5424
+ getEl() {
5425
+ return this.$el;
5426
+ }
5427
+ show() {
5428
+ this.opts.onShow();
5429
+ this.$el.style.display = "";
5430
+ }
5431
+ hide() {
5432
+ return __async(this, null, function* () {
5433
+ this.opts.onHide();
5434
+ this.$el.style.display = "none";
5435
+ this.onAfterHide && this.onAfterHide();
5436
+ });
5437
+ }
5438
+ destroy() {
5439
+ return __async(this, null, function* () {
5440
+ this.opts.onHide();
5441
+ this.$el.remove();
5442
+ this.onAfterHide && this.onAfterHide();
5443
+ });
5444
+ }
5445
+ }
4603
5446
  class LayerWrap {
4604
5447
  constructor() {
4605
5448
  __publicField(this, "$wrap");
4606
5449
  __publicField(this, "$mask");
4607
- __publicField(this, "allowMaskClose", true);
4608
5450
  __publicField(this, "items", []);
4609
5451
  this.$wrap = createElement(
4610
5452
  `<div class="atk-layer-wrap" style="display: none;"><div class="atk-layer-mask"></div></div>`
@@ -4612,14 +5454,24 @@ class LayerWrap {
4612
5454
  this.$mask = this.$wrap.querySelector(".atk-layer-mask");
4613
5455
  }
4614
5456
  createItem(name, el) {
4615
- if (!el) {
4616
- el = document.createElement("div");
4617
- el.classList.add("atk-layer-item");
4618
- el.setAttribute("data-layer-name", name);
4619
- el.style.display = "none";
4620
- }
5457
+ el = el || this.createItemElement(name);
5458
+ el.setAttribute("data-layer-name", name);
5459
+ this.$wrap.appendChild(el);
5460
+ const layer = new Layer(el, {
5461
+ onHide: () => this.hideWrap(el),
5462
+ onShow: () => this.showWrap()
5463
+ });
5464
+ this.getMask().addEventListener("click", () => {
5465
+ layer.getAllowMaskClose() && layer.hide();
5466
+ });
5467
+ this.items.push(layer);
5468
+ return layer;
5469
+ }
5470
+ createItemElement(name) {
5471
+ const el = document.createElement("div");
5472
+ el.classList.add("atk-layer-item");
5473
+ el.style.display = "none";
4621
5474
  this.$wrap.appendChild(el);
4622
- this.items.push(el);
4623
5475
  return el;
4624
5476
  }
4625
5477
  getWrap() {
@@ -4628,78 +5480,36 @@ class LayerWrap {
4628
5480
  getMask() {
4629
5481
  return this.$mask;
4630
5482
  }
4631
- setMaskClose(enabled) {
4632
- this.allowMaskClose = enabled;
4633
- }
4634
- show() {
5483
+ showWrap() {
4635
5484
  this.$wrap.style.display = "block";
4636
5485
  this.$mask.style.display = "block";
4637
5486
  this.$mask.classList.add("atk-fade-in");
4638
- this.$mask.onclick = () => {
4639
- if (this.allowMaskClose)
4640
- this.hide();
4641
- };
4642
5487
  getScrollbarHelper().lock();
4643
5488
  }
4644
- hide(callback) {
4645
- if (this.items.filter((e) => e.isConnected && e.style.display !== "none").length > 1) {
4646
- callback && callback();
5489
+ hideWrap($el) {
5490
+ if (this.items.map((l) => l.getEl()).filter((e) => e !== $el && e.isConnected && e.style.display !== "none").length > 0) {
4647
5491
  return;
4648
5492
  }
4649
- const onAfterHide = () => {
5493
+ const onHide = () => {
4650
5494
  this.$wrap.style.display = "none";
4651
5495
  this.$wrap.classList.remove("atk-fade-out");
4652
- callback && callback();
4653
5496
  getScrollbarHelper().unlock();
4654
5497
  this.$wrap.onanimationend = null;
4655
5498
  };
4656
5499
  this.$wrap.classList.add("atk-fade-out");
4657
5500
  if (window.getComputedStyle(this.$wrap)["animation-name"] !== "none") {
4658
- this.$wrap.onanimationend = () => onAfterHide();
5501
+ this.$wrap.onanimationend = () => onHide();
4659
5502
  } else {
4660
- onAfterHide();
5503
+ onHide();
4661
5504
  }
4662
5505
  }
4663
5506
  }
4664
- class Layer {
4665
- constructor(wrap, name, el) {
4666
- __publicField(this, "$el");
4667
- __publicField(this, "wrap");
4668
- __publicField(this, "onAfterHide");
4669
- this.wrap = wrap;
4670
- this.$el = this.wrap.createItem(name, el);
4671
- }
4672
- setOnAfterHide(func) {
4673
- this.onAfterHide = func;
4674
- }
4675
- getEl() {
4676
- return this.$el;
4677
- }
4678
- show() {
4679
- this.$el.style.display = "";
4680
- this.wrap.show();
4681
- }
4682
- hide() {
4683
- this.wrap.hide(() => {
4684
- this.$el.style.display = "none";
4685
- this.onAfterHide && this.onAfterHide();
4686
- });
4687
- }
4688
- destroy() {
4689
- this.wrap.hide(() => {
4690
- this.$el.remove();
4691
- this.onAfterHide && this.onAfterHide();
4692
- });
4693
- }
4694
- }
4695
5507
  class LayerManager {
4696
5508
  constructor(ctx) {
4697
5509
  __publicField(this, "wrap");
4698
- __publicField(this, "ctx");
4699
- this.ctx = ctx;
4700
5510
  this.wrap = new LayerWrap();
4701
5511
  document.body.appendChild(this.wrap.getWrap());
4702
- ctx.on("destroy", () => {
5512
+ ctx.on("unmounted", () => {
4703
5513
  this.wrap.getWrap().remove();
4704
5514
  });
4705
5515
  getScrollbarHelper().init();
@@ -4708,8 +5518,7 @@ class LayerManager {
4708
5518
  return this.wrap.getWrap();
4709
5519
  }
4710
5520
  create(name, el) {
4711
- const layer = new Layer(this.wrap, name, el);
4712
- return layer;
5521
+ return this.wrap.createItem(name, el);
4713
5522
  }
4714
5523
  }
4715
5524
  const LOCAL_USER_KEY = "ArtalkUser";
@@ -4729,7 +5538,7 @@ class User {
4729
5538
  getData() {
4730
5539
  return this.data;
4731
5540
  }
4732
- /** 保存用户到 localStorage 中 */
5541
+ /** Update user data and save to localStorage */
4733
5542
  update(obj = {}) {
4734
5543
  Object.entries(obj).forEach(([key, value]) => {
4735
5544
  this.data[key] = value;
@@ -4748,7 +5557,7 @@ class User {
4748
5557
  isAdmin: false
4749
5558
  });
4750
5559
  }
4751
- /** 是否已填写基本用户信息 */
5560
+ /** Check if user has filled basic data */
4752
5561
  checkHasBasicUserInfo() {
4753
5562
  return !!this.data.nick && !!this.data.email;
4754
5563
  }
@@ -4757,8 +5566,8 @@ const services = {
4757
5566
  // I18n
4758
5567
  i18n(ctx) {
4759
5568
  setLocale(ctx.conf.locale);
4760
- ctx.on("conf-loaded", () => {
4761
- setLocale(ctx.conf.locale);
5569
+ ctx.watchConf(["locale"], (conf) => {
5570
+ setLocale(conf.locale);
4762
5571
  });
4763
5572
  },
4764
5573
  // User Store
@@ -4779,8 +5588,9 @@ const services = {
4779
5588
  const checkerLauncher = new CheckerLauncher({
4780
5589
  getCtx: () => ctx,
4781
5590
  getApi: () => ctx.getApi(),
4782
- getIframeURLBase: () => ctx.conf.server,
4783
- onReload: () => ctx.reload()
5591
+ onReload: () => ctx.reload(),
5592
+ // make sure suffix with a slash, because it will be used as a base url when call `fetch`
5593
+ getCaptchaIframeURL: () => `${ctx.conf.server}/api/v2/captcha/?t=${+/* @__PURE__ */ new Date()}`
4784
5594
  });
4785
5595
  return checkerLauncher;
4786
5596
  },
@@ -4811,39 +5621,41 @@ const services = {
4811
5621
  }
4812
5622
  };
4813
5623
  function showErrorDialog(opts) {
4814
- const errEl = createElement(`<span>${opts.errMsg},${t("listLoadFailMsg")}<br/></span>`);
5624
+ const errEl = createElement(`<span><span class="error-message"></span><br/><br/></span>`);
5625
+ errEl.querySelector(".error-message").innerText = `${t("listLoadFailMsg")}
5626
+ ${opts.errMsg}`;
4815
5627
  if (opts.retryFn) {
4816
5628
  const $retryBtn = createElement(`<span style="cursor:pointer;">${t("listRetry")}</span>`);
4817
5629
  $retryBtn.onclick = () => opts.retryFn && opts.retryFn();
4818
5630
  errEl.appendChild($retryBtn);
4819
5631
  }
4820
5632
  if (opts.onOpenSidebar) {
4821
- const $openSidebar = createElement(`<span atk-only-admin-show> | <span style="cursor:pointer;">${t("open") + t("ctrlCenter")}</span></span>`);
5633
+ const $openSidebar = createElement(`<span atk-only-admin-show> | <span style="cursor:pointer;">${t("openName", { name: t("ctrlCenter") })}</span></span>`);
4822
5634
  errEl.appendChild($openSidebar);
4823
5635
  $openSidebar.onclick = () => opts.onOpenSidebar && opts.onOpenSidebar();
4824
5636
  }
4825
5637
  setError(opts.$err, errEl);
4826
5638
  }
4827
5639
  const ConfRemoter = (ctx) => {
4828
- ctx.on("inited", () => {
4829
- if (ctx.conf.immediateFetch === false)
4830
- return;
4831
- ctx.trigger("conf-fetch");
5640
+ ctx.on("created", () => {
5641
+ if (ctx.conf.immediateFetch !== false)
5642
+ ctx.trigger("conf-fetch");
4832
5643
  });
4833
5644
  ctx.on("conf-fetch", () => {
4834
5645
  loadConf(ctx);
4835
5646
  });
4836
5647
  };
4837
5648
  function loadConf(ctx) {
4838
- ctx.getApi().system.conf().then((data) => {
5649
+ ctx.getApi().conf.conf().then((res) => {
5650
+ var _a;
4839
5651
  let conf = {
4840
- apiVersion: data.version.version
5652
+ apiVersion: (_a = res.data.version) == null ? void 0 : _a.version
4841
5653
  // version info
4842
5654
  };
4843
5655
  if (ctx.conf.useBackendConf) {
4844
- if (!data.frontend_conf)
5656
+ if (!res.data.frontend_conf)
4845
5657
  throw new Error("The remote backend does not respond to the frontend conf, but `useBackendConf` conf is enabled");
4846
- conf = __spreadValues(__spreadValues({}, conf), handleConfFormServer(data.frontend_conf));
5658
+ conf = __spreadValues(__spreadValues({}, conf), handleConfFormServer(res.data.frontend_conf));
4847
5659
  }
4848
5660
  ctx.conf.remoteConfModifier && ctx.conf.remoteConfModifier(conf);
4849
5661
  ctx.updateConf(conf);
@@ -4865,7 +5677,10 @@ function loadConf(ctx) {
4865
5677
  }) : void 0
4866
5678
  // only show open sidebar button when user is admin
4867
5679
  });
5680
+ console.error(err);
4868
5681
  throw err;
5682
+ }).then(() => {
5683
+ ctx.trigger("mounted");
4869
5684
  }).then(() => {
4870
5685
  if (ctx.conf.remoteConfModifier)
4871
5686
  return;
@@ -4875,7 +5690,7 @@ function loadConf(ctx) {
4875
5690
  }
4876
5691
  const Markdown = (ctx) => {
4877
5692
  initMarked();
4878
- ctx.on("conf-loaded", (conf) => {
5693
+ ctx.on("updated", (conf) => {
4879
5694
  if (conf.markedReplacers)
4880
5695
  setReplacers(conf.markedReplacers);
4881
5696
  });
@@ -4963,23 +5778,27 @@ class SubmitAddPreset {
4963
5778
  }
4964
5779
  reqAdd() {
4965
5780
  return __async(this, null, function* () {
4966
- const nComment = yield this.kit.useApi().comment.add(__spreadValues({}, this.getSubmitAddParams()));
5781
+ const nComment = (yield this.kit.useApi().comments.createComment(__spreadValues({}, yield this.getSubmitAddParams()))).data;
4967
5782
  return nComment;
4968
5783
  });
4969
5784
  }
4970
5785
  getSubmitAddParams() {
4971
- const { nick, email, link } = this.kit.useUser().getData();
4972
- const conf = this.kit.useConf();
4973
- return {
4974
- content: this.kit.useEditor().getContentFinal(),
4975
- nick,
4976
- email,
4977
- link,
4978
- rid: 0,
4979
- page_key: conf.pageKey,
4980
- page_title: conf.pageTitle,
4981
- site_name: conf.site
4982
- };
5786
+ return __async(this, null, function* () {
5787
+ const { nick, email, link } = this.kit.useUser().getData();
5788
+ const conf = this.kit.useConf();
5789
+ return {
5790
+ content: this.kit.useEditor().getContentFinal(),
5791
+ name: nick,
5792
+ email,
5793
+ link,
5794
+ rid: 0,
5795
+ page_key: conf.pageKey,
5796
+ page_title: conf.pageTitle,
5797
+ site_name: conf.site,
5798
+ ua: yield getCorrectUserAgent()
5799
+ // Get the corrected UA
5800
+ };
5801
+ });
4983
5802
  }
4984
5803
  postSubmitAdd(commentNew) {
4985
5804
  this.kit.useGlobalCtx().getData().insertComment(commentNew);
@@ -5024,7 +5843,7 @@ class Submit extends EditorPlug {
5024
5843
  this.defaultPreset.postSubmitAdd(nComment);
5025
5844
  } catch (err) {
5026
5845
  console.error(err);
5027
- this.kit.useEditor().showNotify(`${t("commentFail")},${err.msg || String(err)}`, "e");
5846
+ this.kit.useEditor().showNotify(`${t("commentFail")}: ${err.msg || String(err)}`, "e");
5028
5847
  return;
5029
5848
  } finally {
5030
5849
  this.kit.useEditor().hideLoading();
@@ -5055,12 +5874,12 @@ class StateReply extends EditorPlug {
5055
5874
  req: () => __async(this, null, function* () {
5056
5875
  if (!this.comment)
5057
5876
  throw new Error("reply comment cannot be empty");
5058
- const nComment = yield this.kit.useApi().comment.add(__spreadProps(__spreadValues({}, defaultPreset.getSubmitAddParams()), {
5877
+ const nComment = (yield this.kit.useApi().comments.createComment(__spreadProps(__spreadValues({}, yield defaultPreset.getSubmitAddParams()), {
5059
5878
  rid: this.comment.id,
5060
5879
  page_key: this.comment.page_key,
5061
5880
  page_title: void 0,
5062
5881
  site_name: this.comment.site_name
5063
- }));
5882
+ }))).data;
5064
5883
  return nComment;
5065
5884
  }),
5066
5885
  post: (nComment) => {
@@ -5127,8 +5946,9 @@ class StateEdit extends EditorPlug {
5127
5946
  email: this.kit.useUI().$email.value,
5128
5947
  link: this.kit.useUI().$link.value
5129
5948
  };
5130
- const nComment = yield this.kit.useApi().comment.commentEdit(__spreadValues(__spreadValues({}, this.comment), saveData));
5131
- return nComment;
5949
+ const comment = this.comment;
5950
+ const nComment = yield this.kit.useApi().comments.updateComment(comment.id, __spreadValues(__spreadValues({}, comment), saveData));
5951
+ return nComment.data;
5132
5952
  }),
5133
5953
  post: (nComment) => {
5134
5954
  this.kit.useGlobalCtx().getData().updateComment(nComment);
@@ -5276,12 +6096,12 @@ class HeaderUser extends EditorPlug {
5276
6096
  this.query.abortFn();
5277
6097
  this.query.timer = window.setTimeout(() => {
5278
6098
  this.query.timer = null;
5279
- const { req, abort } = this.kit.useApi().user.userGet(
5280
- this.kit.useUser().getData().nick,
5281
- this.kit.useUser().getData().email
5282
- );
5283
- this.query.abortFn = abort;
5284
- req.then((data) => this.onUserInfoFetched(data)).catch((err) => {
6099
+ const api = this.kit.useApi();
6100
+ const CANCEL_TOKEN = "getUserCancelToken";
6101
+ this.query.abortFn = () => api.abortRequest(CANCEL_TOKEN);
6102
+ api.user.getUser(__spreadValues({}, api.getUserFields()), {
6103
+ cancelToken: CANCEL_TOKEN
6104
+ }).then((res) => this.onUserInfoFetched(res.data)).catch((err) => {
5285
6105
  }).finally(() => {
5286
6106
  this.query.abortFn = null;
5287
6107
  });
@@ -5296,7 +6116,7 @@ class HeaderUser extends EditorPlug {
5296
6116
  var _a;
5297
6117
  if (!data.is_login)
5298
6118
  this.kit.useUser().logout();
5299
- this.kit.useGlobalCtx().getData().updateUnreads(data.unread);
6119
+ this.kit.useGlobalCtx().getData().updateNotifies(data.notifies);
5300
6120
  if (this.kit.useUser().checkHasBasicUserInfo() && !data.is_login && ((_a = data.user) == null ? void 0 : _a.is_admin)) {
5301
6121
  this.kit.useGlobalCtx().checkAdmin({
5302
6122
  onSuccess: () => {
@@ -5390,7 +6210,7 @@ class Emoticons extends EditorPlug {
5390
6210
  data = [data];
5391
6211
  }
5392
6212
  if (!Array.isArray(data)) {
5393
- setError(this.$panel, "表情包数据必须为 Array/Object/String 类型");
6213
+ setError(this.$panel, `[${t("emoticon")}] Data must be of Array/Object/String type`);
5394
6214
  hideLoading(this.$panel);
5395
6215
  return [];
5396
6216
  }
@@ -5447,7 +6267,7 @@ class Emoticons extends EditorPlug {
5447
6267
  } catch (err) {
5448
6268
  hideLoading(this.$panel);
5449
6269
  console.error("[Emoticons] Load Failed:", err);
5450
- setError(this.$panel, `${t("emoticon")}${t("loadFail")} ${String(err)}`);
6270
+ setError(this.$panel, `[${t("emoticon")}] ${t("loadFail")}: ${String(err)}`);
5451
6271
  return [];
5452
6272
  }
5453
6273
  });
@@ -5669,16 +6489,16 @@ class Upload extends EditorPlug {
5669
6489
  try {
5670
6490
  const customUploaderFn = this.kit.useConf().imgUploader;
5671
6491
  if (!customUploaderFn) {
5672
- resp = yield this.kit.useApi().upload.imgUpload(file);
6492
+ resp = (yield this.kit.useApi().upload.upload({ file })).data;
5673
6493
  } else {
5674
- resp = { img_url: yield customUploaderFn(file) };
6494
+ resp = { public_url: yield customUploaderFn(file) };
5675
6495
  }
5676
6496
  } catch (err) {
5677
6497
  console.error(err);
5678
- this.kit.useEditor().showNotify(`${t("uploadFail")},${err.msg}`, "e");
6498
+ this.kit.useEditor().showNotify(`${t("uploadFail")}: ${err.msg}`, "e");
5679
6499
  }
5680
- if (!!resp && resp.img_url) {
5681
- let imgURL = resp.img_url;
6500
+ if (!!resp && resp.public_url) {
6501
+ let imgURL = resp.public_url;
5682
6502
  if (!isValidURL(imgURL))
5683
6503
  imgURL = getURLBasedOnApi({
5684
6504
  base: this.kit.useConf().server,
@@ -5719,7 +6539,7 @@ class Preview extends EditorPlug {
5719
6539
  this.$panel.innerHTML = this.kit.useEditor().getContentMarked();
5720
6540
  }
5721
6541
  }
5722
- const ENABLED_PLUGS = [
6542
+ const EDITOR_PLUGS = [
5723
6543
  // Core
5724
6544
  LocalStorage,
5725
6545
  HeaderEvent,
@@ -5737,13 +6557,13 @@ const ENABLED_PLUGS = [
5737
6557
  Upload,
5738
6558
  Preview
5739
6559
  ];
5740
- function getDisabledPlugByConf(conf) {
5741
- return [
5742
- { k: Upload, v: conf.imgUpload },
5743
- { k: Emoticons, v: conf.emoticons },
5744
- { k: Preview, v: conf.preview },
5745
- { k: Mover, v: conf.editorTravel }
5746
- ].filter((n) => !n.v).flatMap((n) => n.k);
6560
+ function getEnabledPlugs(conf) {
6561
+ const confRefs = /* @__PURE__ */ new Map();
6562
+ confRefs.set(Upload, conf.imgUpload);
6563
+ confRefs.set(Emoticons, conf.emoticons);
6564
+ confRefs.set(Preview, conf.preview);
6565
+ confRefs.set(Mover, conf.editorTravel);
6566
+ return EDITOR_PLUGS.filter((p) => !confRefs.has(p) || !!confRefs.get(p));
5747
6567
  }
5748
6568
  class PlugKit {
5749
6569
  constructor(plugs) {
@@ -5806,11 +6626,16 @@ class PlugManager {
5806
6626
  __publicField(this, "events", new EventManager());
5807
6627
  this.editor = editor;
5808
6628
  let confLoaded = false;
5809
- this.editor.ctx.on("conf-loaded", () => {
6629
+ this.editor.ctx.watchConf([
6630
+ "imgUpload",
6631
+ "emoticons",
6632
+ "preview",
6633
+ "editorTravel",
6634
+ "locale"
6635
+ ], (conf) => {
5810
6636
  confLoaded && this.getEvents().trigger("unmounted");
5811
6637
  this.clear();
5812
- const DISABLED = getDisabledPlugByConf(this.editor.ctx.conf);
5813
- ENABLED_PLUGS.filter((p) => !DISABLED.includes(p)).forEach((Plug) => {
6638
+ getEnabledPlugs(conf).forEach((Plug) => {
5814
6639
  const kit = new PlugKit(this);
5815
6640
  this.plugs.push(new Plug(kit));
5816
6641
  });
@@ -5836,6 +6661,9 @@ class PlugManager {
5836
6661
  this.editor.getUI().$plugPanelWrap.innerHTML = "";
5837
6662
  this.editor.getUI().$plugPanelWrap.style.display = "none";
5838
6663
  this.editor.getUI().$plugBtnWrap.innerHTML = "";
6664
+ this.editor.getUI().$el.addEventListener("click", (e) => {
6665
+ e.stopPropagation();
6666
+ });
5839
6667
  this.plugs.forEach((plug) => this.loadPluginItem(plug));
5840
6668
  }
5841
6669
  /** Load the plug btn and plug panel on editor ui */
@@ -5900,7 +6728,7 @@ class PlugManager {
5900
6728
  }
5901
6729
  const WithEditor = (ctx) => {
5902
6730
  let $closeCommentBtn;
5903
- ctx.on("inited", () => {
6731
+ ctx.on("mounted", () => {
5904
6732
  const list = ctx.get("list");
5905
6733
  $closeCommentBtn = list.$el.querySelector('[data-action="admin-close-comment"]');
5906
6734
  $closeCommentBtn.addEventListener("click", () => {
@@ -5928,8 +6756,8 @@ const WithEditor = (ctx) => {
5928
6756
  };
5929
6757
  function adminPageEditSave(ctx, page) {
5930
6758
  ctx.editorShowLoading();
5931
- ctx.getApi().page.pageEdit(page).then((respPage) => {
5932
- ctx.getData().updatePage(respPage);
6759
+ ctx.getApi().pages.updatePage(page.id, page).then(({ data }) => {
6760
+ ctx.getData().updatePage(data);
5933
6761
  }).catch((err) => {
5934
6762
  ctx.editorShowNotify(`${t("editFail")}: ${err.msg || String(err)}`, "e");
5935
6763
  }).finally(() => {
@@ -5939,13 +6767,13 @@ function adminPageEditSave(ctx, page) {
5939
6767
  const Unread = (ctx) => {
5940
6768
  ctx.on("comment-rendered", (comment) => {
5941
6769
  if (ctx.conf.listUnreadHighlight === true) {
5942
- const unreads = ctx.getData().getUnreads();
5943
- const notify = unreads.find((o) => o.comment_id === comment.getID());
6770
+ const notifies = ctx.getData().getNotifies();
6771
+ const notify = notifies.find((o) => o.comment_id === comment.getID());
5944
6772
  if (notify) {
5945
6773
  comment.getRender().setUnread(true);
5946
6774
  comment.getRender().setOpenAction(() => {
5947
6775
  window.open(notify.read_link);
5948
- ctx.getData().updateUnreads(unreads.filter((o) => o.comment_id !== comment.getID()));
6776
+ ctx.getData().updateNotifies(notifies.filter((o) => o.comment_id !== comment.getID()));
5949
6777
  });
5950
6778
  } else {
5951
6779
  comment.getRender().setUnread(false);
@@ -5955,8 +6783,8 @@ const Unread = (ctx) => {
5955
6783
  ctx.on("list-goto", (commentID) => {
5956
6784
  const notifyKey = getQueryParam("atk_notify_key");
5957
6785
  if (notifyKey) {
5958
- ctx.getApi().user.markRead(commentID, notifyKey).then(() => {
5959
- ctx.getData().updateUnreads(ctx.getData().getUnreads().filter((o) => o.comment_id !== commentID));
6786
+ ctx.getApi().notifies.markNotifyRead(commentID, notifyKey).then(() => {
6787
+ ctx.getData().updateNotifies(ctx.getData().getNotifies().filter((o) => o.comment_id !== commentID));
5960
6788
  });
5961
6789
  }
5962
6790
  });
@@ -5968,7 +6796,7 @@ const Count = (ctx) => {
5968
6796
  const $count = list.$el.querySelector(".atk-comment-count .atk-text");
5969
6797
  if (!$count)
5970
6798
  return;
5971
- const text = htmlEncode(t("counter", { count: `${Number((_b = (_a = ctx.getData().getListLastFetch()) == null ? void 0 : _a.data) == null ? void 0 : _b.total) || 0}` }));
6799
+ const text = htmlEncode(t("counter", { count: `${Number((_b = (_a = ctx.getData().getListLastFetch()) == null ? void 0 : _a.data) == null ? void 0 : _b.count) || 0}` }));
5972
6800
  $count.innerHTML = text.replace(/(\d+)/, '<span class="atk-comment-count-num">$1</span>');
5973
6801
  };
5974
6802
  ctx.on("list-loaded", () => {
@@ -5977,12 +6805,12 @@ const Count = (ctx) => {
5977
6805
  ctx.on("comment-inserted", () => {
5978
6806
  const last = ctx.getData().getListLastFetch();
5979
6807
  if (last == null ? void 0 : last.data)
5980
- last.data.total += 1;
6808
+ last.data.count += 1;
5981
6809
  });
5982
6810
  ctx.on("comment-deleted", () => {
5983
6811
  const last = ctx.getData().getListLastFetch();
5984
6812
  if (last == null ? void 0 : last.data)
5985
- last.data.total -= 1;
6813
+ last.data.count -= 1;
5986
6814
  });
5987
6815
  };
5988
6816
  const SidebarBtn = (ctx) => {
@@ -6000,7 +6828,7 @@ const SidebarBtn = (ctx) => {
6000
6828
  $openSidebarBtn.classList.add("atk-hide");
6001
6829
  }
6002
6830
  };
6003
- ctx.on("conf-loaded", () => {
6831
+ ctx.watchConf(["locale"], (conf) => {
6004
6832
  const list = ctx.get("list");
6005
6833
  $openSidebarBtn = list.$el.querySelector('[data-action="open-sidebar"]');
6006
6834
  if (!$openSidebarBtn)
@@ -6026,12 +6854,12 @@ const UnreadBadge = (ctx) => {
6026
6854
  $unreadBadge.style.display = "none";
6027
6855
  }
6028
6856
  };
6029
- ctx.on("conf-loaded", () => {
6857
+ ctx.on("mounted", () => {
6030
6858
  const list = ctx.get("list");
6031
6859
  $unreadBadge = list.$el.querySelector(".atk-unread-badge");
6032
6860
  });
6033
- ctx.on("unreads-updated", (unreads) => {
6034
- showUnreadBadge(unreads.length || 0);
6861
+ ctx.on("notifies-updated", (notifies) => {
6862
+ showUnreadBadge(notifies.length || 0);
6035
6863
  });
6036
6864
  };
6037
6865
  const Goto = (ctx) => {
@@ -6047,11 +6875,11 @@ const Goto = (ctx) => {
6047
6875
  delayGoto = false;
6048
6876
  check2();
6049
6877
  };
6050
- ctx.on("inited", () => {
6878
+ ctx.on("mounted", () => {
6051
6879
  window.addEventListener("hashchange", hashChangeHandler);
6052
6880
  ctx.on("list-loaded", check2);
6053
6881
  });
6054
- ctx.on("destroy", () => {
6882
+ ctx.on("unmounted", () => {
6055
6883
  window.removeEventListener("hashchange", hashChangeHandler);
6056
6884
  ctx.off("list-loaded", check2);
6057
6885
  });
@@ -6089,9 +6917,9 @@ function extractCommentID() {
6089
6917
  }
6090
6918
  return commentId || null;
6091
6919
  }
6092
- const version = "2.7.3";
6920
+ const version = "2.8.0";
6093
6921
  const Copyright = (ctx) => {
6094
- ctx.on("conf-loaded", () => {
6922
+ ctx.on("mounted", () => {
6095
6923
  const list = ctx.get("list");
6096
6924
  const $copyright = list.$el.querySelector(".atk-copyright");
6097
6925
  if (!$copyright)
@@ -6100,7 +6928,14 @@ const Copyright = (ctx) => {
6100
6928
  });
6101
6929
  };
6102
6930
  const NoComment = (ctx) => {
6931
+ let isFetching = false;
6932
+ ctx.on("list-fetch", (params) => {
6933
+ isFetching = true;
6934
+ });
6103
6935
  ctx.on("list-loaded", (comments) => {
6936
+ if (!isFetching)
6937
+ return;
6938
+ isFetching = false;
6104
6939
  const list = ctx.get("list");
6105
6940
  const isNoComment = comments.length <= 0;
6106
6941
  let $noComment = list.getCommentsWrapEl().querySelector(".atk-list-no-comment");
@@ -6147,12 +6982,12 @@ const Dropdown = (ctx) => {
6147
6982
  ]
6148
6983
  });
6149
6984
  };
6150
- ctx.on("conf-loaded", () => {
6985
+ ctx.watchConf(["listSort", "locale"], (conf) => {
6151
6986
  const list = ctx.get("list");
6152
6987
  const $count = list.$el.querySelector(".atk-comment-count");
6153
6988
  if (!$count)
6154
6989
  return;
6155
- if (ctx.conf.listSort) {
6990
+ if (conf.listSort) {
6156
6991
  initDropdown($count);
6157
6992
  } else {
6158
6993
  removeDropdown({
@@ -6205,7 +7040,7 @@ function removeDropdown(conf) {
6205
7040
  }
6206
7041
  const TimeTicking = (ctx) => {
6207
7042
  let timer = null;
6208
- ctx.on("inited", () => {
7043
+ ctx.on("mounted", () => {
6209
7044
  timer = window.setInterval(() => {
6210
7045
  const list = ctx.get("list");
6211
7046
  list.$el.querySelectorAll("[data-atk-comment-date]").forEach((el) => {
@@ -6214,7 +7049,7 @@ const TimeTicking = (ctx) => {
6214
7049
  });
6215
7050
  }, 30 * 1e3);
6216
7051
  });
6217
- ctx.on("destroy", () => {
7052
+ ctx.on("unmounted", () => {
6218
7053
  timer && window.clearInterval(timer);
6219
7054
  });
6220
7055
  };
@@ -6223,7 +7058,7 @@ const ErrorDialog = (ctx) => {
6223
7058
  const list = ctx.get("list");
6224
7059
  setError(list.$el, null);
6225
7060
  });
6226
- ctx.on("list-error", (err) => {
7061
+ ctx.on("list-failed", (err) => {
6227
7062
  showErrorDialog({
6228
7063
  $err: ctx.get("list").$el,
6229
7064
  errMsg: err.msg,
@@ -6259,11 +7094,19 @@ const Fetch = (ctx) => {
6259
7094
  ctx.getData().setListLastFetch({
6260
7095
  params
6261
7096
  });
6262
- ctx.getApi().comment.get(params.offset, params.limit, params.flatMode, params.paramsModifier).then((data) => {
7097
+ const reqParams = {
7098
+ limit: params.limit,
7099
+ offset: params.offset,
7100
+ flat_mode: params.flatMode,
7101
+ page_key: ctx.getConf().pageKey,
7102
+ site_name: ctx.getConf().site
7103
+ };
7104
+ if (params.paramsModifier)
7105
+ params.paramsModifier(reqParams);
7106
+ ctx.getApi().comments.getComments(__spreadValues(__spreadValues({}, reqParams), ctx.getApi().getUserFields())).then(({ data }) => {
6263
7107
  ctx.getData().setListLastFetch({ params, data });
6264
7108
  ctx.getData().loadComments(data.comments);
6265
7109
  ctx.getData().updatePage(data.page);
6266
- ctx.getData().updateUnreads(data.unread || []);
6267
7110
  params.onSuccess && params.onSuccess(data);
6268
7111
  ctx.trigger("list-fetched", { params, data });
6269
7112
  }).catch((e) => {
@@ -6272,7 +7115,7 @@ const Fetch = (ctx) => {
6272
7115
  data: e.data
6273
7116
  };
6274
7117
  params.onError && params.onError(error);
6275
- ctx.trigger("list-error", error);
7118
+ ctx.trigger("list-failed", error);
6276
7119
  ctx.trigger("list-fetched", { params, error });
6277
7120
  throw e;
6278
7121
  }).finally(() => {
@@ -6281,15 +7124,19 @@ const Fetch = (ctx) => {
6281
7124
  });
6282
7125
  };
6283
7126
  const ReachBottom = (ctx) => {
6284
- const scrollEvtAt = document;
6285
7127
  let observer = null;
6286
7128
  const setupObserver = ($target) => {
7129
+ const scrollEvtAt = ctx.conf.scrollRelativeTo && ctx.conf.scrollRelativeTo() || null;
6287
7130
  observer = new IntersectionObserver(([entries]) => {
6288
7131
  if (entries.isIntersecting) {
6289
7132
  clearObserver();
6290
7133
  ctx.trigger("list-reach-bottom");
6291
7134
  }
6292
7135
  }, {
7136
+ threshold: 0.9,
7137
+ // when the target is 90% visible
7138
+ // @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/root
7139
+ // If the root is null, then the bounds of the actual document viewport are used.
6293
7140
  root: scrollEvtAt
6294
7141
  });
6295
7142
  observer.observe($target);
@@ -6301,7 +7148,8 @@ const ReachBottom = (ctx) => {
6301
7148
  ctx.on("list-loaded", () => {
6302
7149
  clearObserver();
6303
7150
  const list = ctx.get("list");
6304
- const $target = list.getCommentsWrapEl().querySelector(".atk-comment-wrap:nth-last-child(3)");
7151
+ const children = list.getCommentsWrapEl().childNodes;
7152
+ const $target = children.length > 2 ? children[children.length - 2] : null;
6305
7153
  if (!$target)
6306
7154
  return;
6307
7155
  if (!("IntersectionObserver" in window)) {
@@ -6310,7 +7158,7 @@ const ReachBottom = (ctx) => {
6310
7158
  }
6311
7159
  setupObserver($target);
6312
7160
  });
6313
- ctx.on("destroy", () => {
7161
+ ctx.on("unmounted", () => {
6314
7162
  clearObserver();
6315
7163
  });
6316
7164
  };
@@ -6323,10 +7171,10 @@ const GotoFirst = (ctx) => {
6323
7171
  left: 0
6324
7172
  });
6325
7173
  };
6326
- ctx.on("inited", () => {
7174
+ ctx.on("mounted", () => {
6327
7175
  ctx.on("list-goto-first", handler);
6328
7176
  });
6329
- ctx.on("destroy", () => {
7177
+ ctx.on("unmounted", () => {
6330
7178
  ctx.off("list-goto-first", handler);
6331
7179
  });
6332
7180
  };
@@ -6347,14 +7195,32 @@ const ListPlugins = [
6347
7195
  ReachBottom,
6348
7196
  GotoFirst
6349
7197
  ];
7198
+ const Notifies = (ctx) => {
7199
+ ctx.on("list-fetch", (params) => {
7200
+ if (params.offset !== 0)
7201
+ return;
7202
+ const user = ctx.getApi().getUserFields();
7203
+ if (!user)
7204
+ return;
7205
+ ctx.getApi().notifies.getNotifies(user).then((res) => {
7206
+ ctx.getData().updateNotifies(res.data.notifies);
7207
+ });
7208
+ });
7209
+ };
6350
7210
  const PvCountWidget = (ctx) => {
6351
- ctx.on("conf-loaded", () => {
7211
+ ctx.watchConf([
7212
+ "site",
7213
+ "pageKey",
7214
+ "countEl",
7215
+ "pvEl"
7216
+ ], (conf) => {
6352
7217
  initCountWidget({
6353
7218
  getApi: () => ctx.getApi(),
6354
- pageKey: ctx.conf.pageKey,
6355
- countEl: ctx.conf.countEl,
6356
- pvEl: ctx.conf.pvEl,
6357
- pvAdd: true
7219
+ siteName: conf.site,
7220
+ pageKey: conf.pageKey,
7221
+ countEl: conf.countEl,
7222
+ pvEl: conf.pvEl,
7223
+ pvAdd: typeof ctx.conf.pvAdd === "boolean" ? ctx.conf.pvAdd : true
6358
7224
  });
6359
7225
  });
6360
7226
  };
@@ -6364,7 +7230,11 @@ function initCountWidget(opt) {
6364
7230
  refreshStatCount(opt, { query: "page_comment", numEl: opt.countEl });
6365
7231
  }
6366
7232
  const initialData = opt.pvAdd ? {
6367
- [opt.pageKey]: yield opt.getApi().page.pv()
7233
+ [opt.pageKey]: (yield opt.getApi().pages.logPv({
7234
+ page_key: opt.pageKey,
7235
+ page_title: opt.pageKey,
7236
+ site_name: opt.siteName
7237
+ })).data.pv
6368
7238
  // pv+1 and get pv count
6369
7239
  } : void 0;
6370
7240
  if (opt.pvEl && document.querySelector(opt.pvEl)) {
@@ -6382,7 +7252,10 @@ function refreshStatCount(opt, args) {
6382
7252
  let queryPageKeys = Array.from(document.querySelectorAll(args.numEl)).map((e) => e.getAttribute("data-page-key") || opt.pageKey).filter((k) => typeof data[k] !== "number");
6383
7253
  queryPageKeys = [...new Set(queryPageKeys)];
6384
7254
  if (queryPageKeys.length > 0) {
6385
- const res = yield opt.getApi().page.stat(args.query, queryPageKeys);
7255
+ const res = (yield opt.getApi().stats.getStats(args.query, {
7256
+ page_keys: queryPageKeys.join(","),
7257
+ site_name: opt.siteName
7258
+ })).data.data;
6386
7259
  data = __spreadValues(__spreadValues({}, data), res);
6387
7260
  }
6388
7261
  applyCountData(args.numEl, data, data[opt.pageKey]);
@@ -6397,10 +7270,10 @@ function applyCountData(selector, data, defaultCount) {
6397
7270
  }
6398
7271
  let IgnoreVersionCheck = false;
6399
7272
  const VersionCheck = (ctx) => {
6400
- ctx.on("conf-loaded", () => {
7273
+ ctx.watchConf(["apiVersion", "versionCheck"], (conf) => {
6401
7274
  const list = ctx.get("list");
6402
- if (ctx.conf.apiVersion && ctx.conf.versionCheck && !IgnoreVersionCheck)
6403
- versionCheck(list, version, ctx.conf.apiVersion);
7275
+ if (conf.apiVersion && conf.versionCheck && !IgnoreVersionCheck)
7276
+ versionCheck(list, version, conf.apiVersion);
6404
7277
  });
6405
7278
  };
6406
7279
  function versionCheck(list, feVer, beVer) {
@@ -6480,10 +7353,9 @@ const DarkMode = (ctx) => {
6480
7353
  updateClassnames($els, darkMode);
6481
7354
  }
6482
7355
  };
6483
- ctx.on("inited", () => sync(ctx.conf.darkMode));
6484
- ctx.on("conf-loaded", (conf) => sync(conf.darkMode));
6485
- ctx.on("dark-mode-changed", (darkMode) => sync(darkMode));
6486
- ctx.on("destroy", () => {
7356
+ ctx.watchConf(["darkMode"], (conf) => sync(conf.darkMode));
7357
+ ctx.on("created", () => sync(ctx.conf.darkMode));
7358
+ ctx.on("unmounted", () => {
6487
7359
  darkModeAutoHandler && (darkModeMedia == null ? void 0 : darkModeMedia.removeEventListener("change", darkModeAutoHandler));
6488
7360
  darkModeAutoHandler = void 0;
6489
7361
  });
@@ -6494,6 +7366,7 @@ const DefaultPlugins = [
6494
7366
  EditorKit,
6495
7367
  AdminOnlyElem,
6496
7368
  ...ListPlugins,
7369
+ Notifies,
6497
7370
  PvCountWidget,
6498
7371
  VersionCheck,
6499
7372
  DarkMode
@@ -6515,7 +7388,7 @@ class Artalk {
6515
7388
  if (typeof plugin === "function")
6516
7389
  plugin(this.ctx);
6517
7390
  });
6518
- this.ctx.trigger("inited");
7391
+ this.ctx.trigger("created");
6519
7392
  }
6520
7393
  /** Get the config of Artalk */
6521
7394
  getConf() {
@@ -6536,7 +7409,7 @@ class Artalk {
6536
7409
  }
6537
7410
  /** Destroy instance of Artalk */
6538
7411
  destroy() {
6539
- this.ctx.trigger("destroy");
7412
+ this.ctx.trigger("unmounted");
6540
7413
  this.ctx.$root.remove();
6541
7414
  }
6542
7415
  /** Add an event listener */
@@ -6572,7 +7445,8 @@ class Artalk {
6572
7445
  static loadCountWidget(c) {
6573
7446
  const conf = handelCustomConf(c, true);
6574
7447
  initCountWidget({
6575
- getApi: () => new Api(convertApiOptions(conf)),
7448
+ getApi: () => new Api2(convertApiOptions(conf)),
7449
+ siteName: conf.site,
6576
7450
  pageKey: conf.pageKey,
6577
7451
  countEl: conf.countEl,
6578
7452
  pvEl: conf.pvEl,