artalk 2.8.4 → 2.8.6

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.
@@ -142,11 +142,14 @@ class HttpClient {
142
142
  /* Json */
143
143
  ];
144
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* () {
145
+ return this.customFetch(
146
+ `${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`,
147
+ __spreadProps(__spreadValues({}, requestParams), {
148
+ headers: __spreadValues(__spreadValues({}, requestParams.headers || {}), type && type !== "multipart/form-data" ? { "Content-Type": type } : {}),
149
+ signal: (cancelToken ? this.createAbortSignal(cancelToken) : requestParams.signal) || null,
150
+ body: typeof body === "undefined" || body === null ? null : payloadFormatter(body)
151
+ })
152
+ ).then((response) => __async(this, null, function* () {
150
153
  const r = response;
151
154
  r.data = null;
152
155
  r.error = null;
@@ -185,7 +188,9 @@ class HttpClient {
185
188
  toQueryString(rawQuery) {
186
189
  const query = rawQuery || {};
187
190
  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("&");
191
+ return keys.map(
192
+ (key) => Array.isArray(query[key]) ? this.addArrayQueryParam(query, key) : this.addQueryParam(query, key)
193
+ ).join("&");
189
194
  }
190
195
  addQueryParams(rawQuery) {
191
196
  const queryString = this.toQueryString(rawQuery);
@@ -209,6 +214,133 @@ class HttpClient {
209
214
  let Api$1 = class Api extends HttpClient {
210
215
  constructor() {
211
216
  super(...arguments);
217
+ __publicField(this, "auth", {
218
+ /**
219
+ * @description Login by email with verify code (Need send email verify code first) or password
220
+ *
221
+ * @tags Auth
222
+ * @name LoginByEmail
223
+ * @summary Login by email
224
+ * @request POST:/auth/email/login
225
+ * @response `200` `HandlerResponseUserLogin` OK
226
+ * @response `400` `(HandlerMap & {
227
+ msg?: string,
228
+
229
+ })` Bad Request
230
+ * @response `500` `(HandlerMap & {
231
+ msg?: string,
232
+
233
+ })` Internal Server Error
234
+ */
235
+ loginByEmail: (data, params = {}) => this.request(__spreadValues({
236
+ path: `/auth/email/login`,
237
+ method: "POST",
238
+ body: data,
239
+ type: "application/json",
240
+ format: "json"
241
+ }, params)),
242
+ /**
243
+ * @description Register by email and verify code (if user exists, will update user, like forget password. Need send email verify code first)
244
+ *
245
+ * @tags Auth
246
+ * @name RegisterByEmail
247
+ * @summary Register by email
248
+ * @request POST:/auth/email/register
249
+ * @response `200` `HandlerResponseUserLogin` OK
250
+ * @response `400` `(HandlerMap & {
251
+ msg?: string,
252
+
253
+ })` Bad Request
254
+ * @response `500` `(HandlerMap & {
255
+ msg?: string,
256
+
257
+ })` Internal Server Error
258
+ */
259
+ registerByEmail: (data, params = {}) => this.request(__spreadValues({
260
+ path: `/auth/email/register`,
261
+ method: "POST",
262
+ body: data,
263
+ type: "application/json",
264
+ format: "json"
265
+ }, params)),
266
+ /**
267
+ * @description Send email including verify code to user
268
+ *
269
+ * @tags Auth
270
+ * @name SendVerifyEmail
271
+ * @summary Send verify email
272
+ * @request POST:/auth/email/send
273
+ * @response `200` `(HandlerMap & {
274
+ msg?: string,
275
+
276
+ })` OK
277
+ * @response `400` `(HandlerMap & {
278
+ msg?: string,
279
+
280
+ })` Bad Request
281
+ * @response `500` `(HandlerMap & {
282
+ msg?: string,
283
+
284
+ })` Internal Server Error
285
+ */
286
+ sendVerifyEmail: (data, params = {}) => this.request(__spreadValues({
287
+ path: `/auth/email/send`,
288
+ method: "POST",
289
+ body: data,
290
+ type: "application/json",
291
+ format: "json"
292
+ }, params)),
293
+ /**
294
+ * @description Get all users with same email, if there are more than one user with same email, need merge
295
+ *
296
+ * @tags Auth
297
+ * @name CheckDataMerge
298
+ * @summary Check data merge
299
+ * @request GET:/auth/merge
300
+ * @secure
301
+ * @response `200` `HandlerResponseAuthDataMergeCheck` OK
302
+ * @response `400` `(HandlerMap & {
303
+ msg?: string,
304
+
305
+ })` Bad Request
306
+ * @response `500` `(HandlerMap & {
307
+ msg?: string,
308
+
309
+ })` Internal Server Error
310
+ */
311
+ checkDataMerge: (params = {}) => this.request(__spreadValues({
312
+ path: `/auth/merge`,
313
+ method: "GET",
314
+ secure: true,
315
+ format: "json"
316
+ }, params)),
317
+ /**
318
+ * @description This function is to solve the problem of multiple users with the same email address, should be called after user login and then check, and perform data merge.
319
+ *
320
+ * @tags Auth
321
+ * @name ApplyDataMerge
322
+ * @summary Apply data merge
323
+ * @request POST:/auth/merge
324
+ * @secure
325
+ * @response `200` `HandlerResponseAuthDataMergeApply` OK
326
+ * @response `400` `(HandlerMap & {
327
+ msg?: string,
328
+
329
+ })` Bad Request
330
+ * @response `500` `(HandlerMap & {
331
+ msg?: string,
332
+
333
+ })` Internal Server Error
334
+ */
335
+ applyDataMerge: (data, params = {}) => this.request(__spreadValues({
336
+ path: `/auth/merge`,
337
+ method: "POST",
338
+ body: data,
339
+ secure: true,
340
+ type: "application/json",
341
+ format: "json"
342
+ }, params))
343
+ });
212
344
  __publicField(this, "cache", {
213
345
  /**
214
346
  * @description Flush all cache on the server
@@ -469,6 +601,24 @@ let Api$1 = class Api extends HttpClient {
469
601
  method: "GET",
470
602
  format: "json"
471
603
  }, params)),
604
+ /**
605
+ * @description Get social login providers
606
+ *
607
+ * @tags System
608
+ * @name GetSocialLoginProviders
609
+ * @summary Get Social Login Providers
610
+ * @request GET:/conf/auth/providers
611
+ * @response `200` `HandlerResponseConfAuthProviders` OK
612
+ * @response `404` `(HandlerMap & {
613
+ msg?: string,
614
+
615
+ })` Not Found
616
+ */
617
+ getSocialLoginProviders: (params = {}) => this.request(__spreadValues({
618
+ path: `/conf/auth/providers`,
619
+ method: "GET",
620
+ format: "json"
621
+ }, params)),
472
622
  /**
473
623
  * @description Get Domain Info
474
624
  *
@@ -1328,8 +1478,6 @@ function getDefaultExportFromCjs(x) {
1328
1478
  function _createClass(Constructor, protoProps, staticProps) {
1329
1479
  if (protoProps)
1330
1480
  _defineProperties(Constructor.prototype, protoProps);
1331
- if (staticProps)
1332
- _defineProperties(Constructor, staticProps);
1333
1481
  Object.defineProperty(Constructor, "prototype", {
1334
1482
  writable: false
1335
1483
  });
@@ -1706,7 +1854,7 @@ function getDefaultExportFromCjs(x) {
1706
1854
  const Fetch$1 = (opts, input, init2) => __async(void 0, null, function* () {
1707
1855
  const apiToken = opts.getApiToken && opts.getApiToken();
1708
1856
  const headers = new Headers(__spreadValues({
1709
- "Authorization": apiToken ? `Bearer ${apiToken}` : ""
1857
+ Authorization: apiToken ? `Bearer ${apiToken}` : ""
1710
1858
  }, init2 == null ? void 0 : init2.headers));
1711
1859
  if (!headers.get("Authorization"))
1712
1860
  headers.delete("Authorization");
@@ -2228,7 +2376,7 @@ const insaneOptions = {
2228
2376
  allowedAttributes: {
2229
2377
  "*": ["title", "accesskey"],
2230
2378
  a: ["href", "name", "target", "aria-label", "rel"],
2231
- img: ["src", "alt", "title", "atk-emoticon", "aria-label"],
2379
+ img: ["src", "alt", "title", "atk-emoticon", "aria-label", "data-src", "class", "loading"],
2232
2380
  // for code highlight
2233
2381
  code: ["class"],
2234
2382
  span: ["class", "style"]
@@ -2236,7 +2384,8 @@ const insaneOptions = {
2236
2384
  filter: (node) => {
2237
2385
  const allowed = [
2238
2386
  ["code", /^hljs\W+language-(.*)$/],
2239
- ["span", /^(hljs-.*)$/]
2387
+ ["span", /^(hljs-.*)$/],
2388
+ ["img", /^lazyload$/]
2240
2389
  ];
2241
2390
  allowed.forEach(([tag, reg]) => {
2242
2391
  if (node.tag === tag && !!node.attrs.class && !reg.test(node.attrs.class)) {
@@ -2313,16 +2462,27 @@ const hanabi = /* @__PURE__ */ getDefaultExportFromCjs(hanabiExports);
2313
2462
  function renderCode(code) {
2314
2463
  return hanabi(code);
2315
2464
  }
2316
- function getRenderer() {
2465
+ function getRenderer(options) {
2317
2466
  const renderer = new marked$1.Renderer();
2318
2467
  renderer.link = markedLinkRenderer(renderer, renderer.link);
2319
2468
  renderer.code = markedCodeRenderer();
2469
+ renderer.image = markedImageRenderer(renderer, renderer.image, options);
2320
2470
  return renderer;
2321
2471
  }
2322
2472
  const markedLinkRenderer = (renderer, orgLinkRenderer) => (href, title, text) => {
2323
- const localLink = href == null ? void 0 : href.startsWith(`${window.location.protocol}//${window.location.hostname}`);
2473
+ const getLinkOrigin = (link) => {
2474
+ try {
2475
+ return new URL(link).origin;
2476
+ } catch (e) {
2477
+ return "";
2478
+ }
2479
+ };
2480
+ const isSameOriginLink = getLinkOrigin(href) === window.location.origin;
2324
2481
  const html = orgLinkRenderer.call(renderer, href, title, text);
2325
- return html.replace(/^<a /, `<a target="_blank" ${!localLink ? `rel="noreferrer noopener nofollow"` : ""} `);
2482
+ return html.replace(
2483
+ /^<a /,
2484
+ `<a target="_blank" ${!isSameOriginLink ? `rel="noreferrer noopener nofollow"` : ""} `
2485
+ );
2326
2486
  };
2327
2487
  const markedCodeRenderer = () => (block, lang) => {
2328
2488
  const realLang = !lang ? "plaintext" : lang;
@@ -2338,6 +2498,16 @@ const markedCodeRenderer = () => (block, lang) => {
2338
2498
  <code class="hljs language-${realLang}">${colorized.replace(/&amp;/g, "&")}</code>
2339
2499
  </pre>`;
2340
2500
  };
2501
+ const markedImageRenderer = (renderer, orgImageRenderer, { imgLazyLoad }) => (href, title, text) => {
2502
+ const html = orgImageRenderer.call(renderer, href, title, text);
2503
+ if (!imgLazyLoad)
2504
+ return html;
2505
+ if (imgLazyLoad === "native" || imgLazyLoad === true)
2506
+ return html.replace(/^<img /, '<img class="lazyload" loading="lazy" ');
2507
+ if (imgLazyLoad === "data-src")
2508
+ return html.replace(/^<img /, '<img class="lazyload" ').replace("src=", "data-src=");
2509
+ return html;
2510
+ };
2341
2511
  let instance;
2342
2512
  let replacers = [];
2343
2513
  const markedOptions = {
@@ -2351,16 +2521,18 @@ function getInstance() {
2351
2521
  function setReplacers(arr) {
2352
2522
  replacers = arr;
2353
2523
  }
2354
- function initMarked() {
2524
+ function initMarked(options) {
2355
2525
  try {
2356
2526
  if (!marked$1.name)
2357
2527
  return;
2358
2528
  } catch (e) {
2359
2529
  return;
2360
2530
  }
2361
- marked$1.setOptions(__spreadValues({
2362
- renderer: getRenderer()
2363
- }, markedOptions));
2531
+ marked$1.setOptions(__spreadValues(__spreadValues({
2532
+ renderer: getRenderer({
2533
+ imgLazyLoad: options.imgLazyLoad
2534
+ })
2535
+ }, markedOptions), options.markedOptions));
2364
2536
  instance = marked$1;
2365
2537
  }
2366
2538
  function marked(src) {
@@ -2377,7 +2549,13 @@ function marked(src) {
2377
2549
  return dest;
2378
2550
  }
2379
2551
  function simpleMarked(src) {
2380
- return src.replace(/```\s*([^]+?.*?[^]+?[^]+?)```/g, (_, code) => `<pre><code>${renderCode(code)}</code></pre>`).replace(/!\[(.*?)\]\((.*?)\)/g, (_, alt, imgSrc) => `<img src="${imgSrc}" alt="${alt}" />`).replace(/\[(.*?)\]\((.*?)\)/g, (_, text, link) => `<a href="${link}" target="_blank">${text}</a>`).replace(/\n/g, "<br>");
2552
+ return src.replace(
2553
+ /```\s*([^]+?.*?[^]+?[^]+?)```/g,
2554
+ (_, code) => `<pre><code>${renderCode(code)}</code></pre>`
2555
+ ).replace(/!\[(.*?)\]\((.*?)\)/g, (_, alt, imgSrc) => `<img src="${imgSrc}" alt="${alt}" />`).replace(
2556
+ /\[(.*?)\]\((.*?)\)/g,
2557
+ (_, text, link) => `<a href="${link}" target="_blank">${text}</a>`
2558
+ ).replace(/\n/g, "<br>");
2381
2559
  }
2382
2560
  function mergeDeep(...objects) {
2383
2561
  const isObject = (obj) => obj && typeof obj === "object" && obj.constructor === Object;
@@ -2490,6 +2668,8 @@ const en = {
2490
2668
  placeholder: "Leave a comment",
2491
2669
  noComment: "No Comment",
2492
2670
  send: "Send",
2671
+ signIn: "Sign in",
2672
+ signUp: "Sign up",
2493
2673
  save: "Save",
2494
2674
  nick: "Nickname",
2495
2675
  email: "Email",
@@ -2548,7 +2728,26 @@ const en = {
2548
2728
  /* Sidebar */
2549
2729
  msgCenter: "Messages",
2550
2730
  ctrlCenter: "Admin",
2731
+ /* Auth */
2732
+ noAccountPrompt: "Don't have an account?",
2733
+ haveAccountPrompt: "Already have an account?",
2734
+ forgetPassword: "Forget Password",
2735
+ resetPassword: "Reset Password",
2736
+ verificationCode: "Verification Code",
2737
+ verifySend: "Verify",
2738
+ verifyResend: "Resend",
2739
+ waitSeconds: "Wait {seconds}s",
2551
2740
  emailVerified: "Email has been verified",
2741
+ password: "Password",
2742
+ username: "Username",
2743
+ nextStep: "Next Step",
2744
+ skipNotVerify: "Skip, do not verify",
2745
+ logoutConfirm: "Are you sure to logout?",
2746
+ accountMergeNotice: "Your email has multiple accounts with different id.",
2747
+ accountMergeSelectOne: "Please select one you want to merge all the data into it.",
2748
+ accountMergeConfirm: "All data will be merged into one account, the id is {id}.",
2749
+ dismiss: "Dismiss",
2750
+ merge: "Merge",
2552
2751
  /* General */
2553
2752
  frontend: "Frontend",
2554
2753
  backend: "Backend",
@@ -2560,7 +2759,7 @@ const en = {
2560
2759
  deleteFail: "Delete Failed",
2561
2760
  reqGot: "Request got",
2562
2761
  reqAborted: "Request timed out or terminated unexpectedly",
2563
- updateMsg: "Please update Artalk {name} to get the full experience",
2762
+ updateMsg: "Please update Artalk {name} to get the best experience!",
2564
2763
  currentVersion: "Current Version",
2565
2764
  ignore: "Ignore",
2566
2765
  open: "Open",
@@ -2571,6 +2770,8 @@ const zhCN = {
2571
2770
  placeholder: "键入内容...",
2572
2771
  noComment: "「此时无声胜有声」",
2573
2772
  send: "发送",
2773
+ signIn: "登录",
2774
+ signUp: "注册",
2574
2775
  save: "保存",
2575
2776
  nick: "昵称",
2576
2777
  email: "邮箱",
@@ -2629,7 +2830,26 @@ const zhCN = {
2629
2830
  /* Sidebar */
2630
2831
  msgCenter: "通知中心",
2631
2832
  ctrlCenter: "控制中心",
2833
+ /* Auth */
2834
+ noAccountPrompt: "没有账号?",
2835
+ haveAccountPrompt: "已有账号?",
2836
+ forgetPassword: "忘记密码",
2837
+ resetPassword: "重置密码",
2838
+ verificationCode: "验证码",
2839
+ verifySend: "发送验证码",
2840
+ verifyResend: "重新发送",
2841
+ waitSeconds: "等待 {seconds}秒",
2632
2842
  emailVerified: "邮箱已验证",
2843
+ password: "密码",
2844
+ username: "用户名",
2845
+ nextStep: "下一步",
2846
+ skipNotVerify: "跳过,不验证",
2847
+ logoutConfirm: "确定要退出登录吗?",
2848
+ accountMergeNotice: "您的电子邮件下有多个不同 ID 的账户。",
2849
+ accountMergeSelectOne: "请选择将所有数据合并到其中的一个。",
2850
+ accountMergeConfirm: "所有数据将合并到 ID 为 {id} 的账户中。",
2851
+ dismiss: "忽略",
2852
+ merge: "合并",
2633
2853
  /* General */
2634
2854
  frontend: "前端",
2635
2855
  backend: "后端",
@@ -2641,7 +2861,7 @@ const zhCN = {
2641
2861
  deleteFail: "删除失败",
2642
2862
  reqGot: "请求响应",
2643
2863
  reqAborted: "请求超时或意外终止",
2644
- updateMsg: "请更新 Artalk {name} 以获得完整体验",
2864
+ updateMsg: "请更新 Artalk {name} 以获得更好的体验!",
2645
2865
  currentVersion: "当前版本",
2646
2866
  ignore: "忽略",
2647
2867
  open: "打开",
@@ -2732,27 +2952,6 @@ function timeAgo(date, $t = (n) => n) {
2732
2952
  return " - ";
2733
2953
  }
2734
2954
  }
2735
- function onImagesLoaded($container, event) {
2736
- if (!$container)
2737
- return;
2738
- const images = $container.getElementsByTagName("img");
2739
- if (!images.length)
2740
- return;
2741
- let loaded = images.length;
2742
- for (let i = 0; i < images.length; i++) {
2743
- if (images[i].complete) {
2744
- loaded--;
2745
- } else {
2746
- images[i].addEventListener("load", () => {
2747
- loaded--;
2748
- if (loaded === 0)
2749
- event();
2750
- });
2751
- }
2752
- if (loaded === 0)
2753
- event();
2754
- }
2755
- }
2756
2955
  function getGravatarURL(opts) {
2757
2956
  return `${opts.mirror.replace(/\/$/, "")}/${opts.emailMD5}?${opts.params.replace(/^\?/, "")}`;
2758
2957
  }
@@ -2795,7 +2994,10 @@ function getCorrectUserAgent() {
2795
2994
  }
2796
2995
  if (uaData.platform === "macOS") {
2797
2996
  if (majorPlatformVersion >= 11) {
2798
- return uaRaw.replace(/(Mac OS X \d+_\d+_\d+|Mac OS X)/, `Mac OS X ${uaGot.platformVersion.replace(/\./g, "_")}`);
2997
+ return uaRaw.replace(
2998
+ /(Mac OS X \d+_\d+_\d+|Mac OS X)/,
2999
+ `Mac OS X ${uaGot.platformVersion.replace(/\./g, "_")}`
3000
+ );
2799
3001
  }
2800
3002
  }
2801
3003
  return uaRaw;
@@ -2817,7 +3019,7 @@ function getURLBasedOn(baseURL, path) {
2817
3019
  return `${baseURL.replace(/\/$/, "")}/${path.replace(/^\//, "")}`;
2818
3020
  }
2819
3021
  const internal = {
2820
- "en": en,
3022
+ en,
2821
3023
  "en-US": en,
2822
3024
  "zh-CN": zhCN
2823
3025
  };
@@ -2855,7 +3057,10 @@ class EventManager {
2855
3057
  * Add an event listener for a specific event name
2856
3058
  */
2857
3059
  on(name, handler, opts = {}) {
2858
- this.events.push(__spreadValues({ name, handler }, opts));
3060
+ this.events.push(__spreadValues({
3061
+ name,
3062
+ handler
3063
+ }, opts));
2859
3064
  }
2860
3065
  /**
2861
3066
  * Remove an event listener for a specific event name and handler
@@ -2946,17 +3151,12 @@ function handelCustomConf(customConf, full = false) {
2946
3151
  return conf;
2947
3152
  }
2948
3153
  function handleConfFormServer(conf) {
2949
- const DisabledKeys = [
2950
- "el",
2951
- "pageKey",
2952
- "pageTitle",
2953
- "server",
2954
- "site",
2955
- "darkMode"
2956
- ];
3154
+ const DisabledKeys = ["el", "pageKey", "pageTitle", "server", "site"];
2957
3155
  Object.keys(conf).forEach((k) => {
2958
3156
  if (DisabledKeys.includes(k))
2959
3157
  delete conf[k];
3158
+ if (k === "darkMode" && conf[k] !== "auto")
3159
+ delete conf[k];
2960
3160
  });
2961
3161
  if (conf.emoticons && typeof conf.emoticons === "string") {
2962
3162
  conf.emoticons = conf.emoticons.trim();
@@ -3264,8 +3464,6 @@ function playFadeAnim(elem, after, type = "in") {
3264
3464
  const onAnimEnded = () => {
3265
3465
  elem.classList.remove(`atk-fade-${type}`);
3266
3466
  elem.removeEventListener("animationend", onAnimEnded);
3267
- if (after)
3268
- after();
3269
3467
  };
3270
3468
  elem.addEventListener("animationend", onAnimEnded);
3271
3469
  }
@@ -3333,7 +3531,9 @@ function imgBody(checker) {
3333
3531
  }
3334
3532
  function iframeBody(checker) {
3335
3533
  const $iframeWrap = createElement(`<div class="atk-checker-iframe-wrap"></div>`);
3336
- const $iframe = createElement(`<iframe class="atk-fade-in" referrerpolicy="strict-origin-when-cross-origin"></iframe>`);
3534
+ const $iframe = createElement(
3535
+ `<iframe class="atk-fade-in" referrerpolicy="strict-origin-when-cross-origin"></iframe>`
3536
+ );
3337
3537
  $iframe.style.display = "none";
3338
3538
  showLoading($iframeWrap, { transparentBg: true });
3339
3539
  $iframe.src = checker.getOpts().getCaptchaIframeURL();
@@ -3342,7 +3542,9 @@ function iframeBody(checker) {
3342
3542
  hideLoading($iframeWrap);
3343
3543
  };
3344
3544
  $iframeWrap.append($iframe);
3345
- const $closeBtn = createElement(`<div class="atk-close-btn"><i class="atk-icon atk-icon-close"></i></div>`);
3545
+ const $closeBtn = createElement(
3546
+ `<div class="atk-close-btn"><i class="atk-icon atk-icon-close"></i></div>`
3547
+ );
3346
3548
  $iframeWrap.append($closeBtn);
3347
3549
  checker.hideInteractInput();
3348
3550
  let stop = false;
@@ -3554,7 +3756,7 @@ class Component {
3554
3756
  return this.$el;
3555
3757
  }
3556
3758
  }
3557
- 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-bottom-left">\n <span class="atk-state-wrap"></span>\n <span class="atk-plug-btn-wrap"></span>\n </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';
3759
+ 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-bottom-left">\n <span class="atk-state-wrap"></span>\n <span class="atk-plug-btn-wrap"></span>\n </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';
3558
3760
  const Sel = {
3559
3761
  $header: ".atk-header",
3560
3762
  $nick: '.atk-header [name="nick"]',
@@ -3728,7 +3930,9 @@ class Editor extends Component {
3728
3930
  const sStart = this.ui.$textarea.selectionStart;
3729
3931
  const sEnd = this.ui.$textarea.selectionEnd;
3730
3932
  const sT = this.ui.$textarea.scrollTop;
3731
- this.setContent(this.ui.$textarea.value.substring(0, sStart) + val + this.ui.$textarea.value.substring(sEnd, this.ui.$textarea.value.length));
3933
+ this.setContent(
3934
+ this.ui.$textarea.value.substring(0, sStart) + val + this.ui.$textarea.value.substring(sEnd, this.ui.$textarea.value.length)
3935
+ );
3732
3936
  this.ui.$textarea.focus();
3733
3937
  this.ui.$textarea.selectionStart = sStart + val.length;
3734
3938
  this.ui.$textarea.selectionEnd = sStart + val.length;
@@ -3772,7 +3976,7 @@ class Editor extends Component {
3772
3976
  }
3773
3977
  }
3774
3978
  }
3775
- const SidebarHTML = '<div class="atk-sidebar-layer">\n <div class="atk-sidebar-inner">\n <div class="atk-sidebar-header">\n <div class="atk-sidebar-close"><i class="atk-icon atk-icon-close-slim"></i></div>\n </div>\n <div class="atk-sidebar-iframe-wrap"></div>\n </div>\n</div>\n';
3979
+ const SidebarHTML = '<div class="atk-sidebar-layer">\n <div class="atk-sidebar-inner">\n <div class="atk-sidebar-header">\n <div class="atk-sidebar-close">\n <i class="atk-icon atk-icon-close-slim"></i>\n </div>\n </div>\n <div class="atk-sidebar-iframe-wrap"></div>\n </div>\n</div>\n';
3776
3980
  class SidebarLayer extends Component {
3777
3981
  constructor(ctx) {
3778
3982
  super(ctx);
@@ -3810,8 +4014,11 @@ class SidebarLayer extends Component {
3810
4014
  } else {
3811
4015
  const $iframe = this.$iframe;
3812
4016
  const iFrameSrc = $iframe.src;
3813
- if (this.conf.darkMode !== iFrameSrc.includes("darkMode=1")) {
3814
- this.iframeLoad($iframe, this.conf.darkMode ? iFrameSrc.concat("&darkMode=1") : iFrameSrc.replace("&darkMode=1", ""));
4017
+ if (this.getDarkMode() !== iFrameSrc.includes("&darkMode=1")) {
4018
+ this.iframeLoad(
4019
+ $iframe,
4020
+ this.getDarkMode() ? iFrameSrc.concat("&darkMode=1") : iFrameSrc.replace("&darkMode=1", "")
4021
+ );
3815
4022
  }
3816
4023
  }
3817
4024
  this.authCheck({
@@ -3865,7 +4072,9 @@ class SidebarLayer extends Component {
3865
4072
  });
3866
4073
  }
3867
4074
  createIframe(view) {
3868
- const $iframe = createElement('<iframe referrerpolicy="strict-origin-when-cross-origin"></iframe>');
4075
+ const $iframe = createElement(
4076
+ '<iframe referrerpolicy="strict-origin-when-cross-origin"></iframe>'
4077
+ );
3869
4078
  const baseURL = getURLBasedOnApi({
3870
4079
  base: this.ctx.conf.server,
3871
4080
  path: "/sidebar/"
@@ -3878,12 +4087,15 @@ class SidebarLayer extends Component {
3878
4087
  };
3879
4088
  if (view)
3880
4089
  query.view = view;
3881
- if (this.conf.darkMode)
4090
+ if (this.getDarkMode())
3882
4091
  query.darkMode = "1";
3883
4092
  const urlParams = new URLSearchParams(query);
3884
4093
  this.iframeLoad($iframe, `${baseURL}?${urlParams.toString()}`);
3885
4094
  return $iframe;
3886
4095
  }
4096
+ getDarkMode() {
4097
+ return this.conf.darkMode === "auto" ? window.matchMedia("(prefers-color-scheme: dark)").matches : this.conf.darkMode;
4098
+ }
3887
4099
  iframeLoad($iframe, src) {
3888
4100
  $iframe.src = src;
3889
4101
  showLoading(this.$iframeWrap);
@@ -3892,7 +4104,7 @@ class SidebarLayer extends Component {
3892
4104
  };
3893
4105
  }
3894
4106
  }
3895
- const ListHTML = '<div class="atk-list">\n <div class="atk-list-header">\n <div class="atk-comment-count">\n <div class="atk-text"></div>\n </div>\n <div class="atk-right-action">\n <span data-action="admin-close-comment" class="atk-hide" atk-only-admin-show></span>\n <span data-action="open-sidebar" class="atk-hide atk-on">\n <span class="atk-unread-badge" style="display: none;"></span>\n <div class="atk-text"></div>\n </span>\n </div>\n </div>\n <div class="atk-list-body">\n <div class="atk-list-comments-wrap"></div>\n </div>\n <div class="atk-list-footer">\n <div class="atk-copyright"></div>\n </div>\n</div>\n';
4107
+ const ListHTML = '<div class="atk-list">\n <div class="atk-list-header">\n <div class="atk-comment-count">\n <div class="atk-text"></div>\n </div>\n <div class="atk-right-action">\n <span data-action="admin-close-comment" class="atk-hide" atk-only-admin-show></span>\n <span data-action="open-sidebar" class="atk-hide atk-on">\n <span class="atk-unread-badge" style="display: none"></span>\n <div class="atk-text"></div>\n </span>\n </div>\n </div>\n <div class="atk-list-body">\n <div class="atk-list-comments-wrap"></div>\n </div>\n <div class="atk-list-footer">\n <div class="atk-copyright"></div>\n </div>\n</div>\n';
3896
4108
  function makeNestCommentNodeList(srcData, sortBy = "DATE_DESC", nestMax = 2) {
3897
4109
  const nodeList = [];
3898
4110
  const roots = srcData.filter((o) => o.rid === 0);
@@ -3954,8 +4166,9 @@ const createNestStrategy = (opts) => ({
3954
4166
  rootC.getRender().playFadeAnim();
3955
4167
  const loadChildren = (parentC, parentNode) => {
3956
4168
  parentNode.children.forEach((node) => {
4169
+ const replyD = comments.find((c) => c.id === node.comment.rid);
3957
4170
  const childD = node.comment;
3958
- const childC = opts.createCommentNode(childD, parentC.getData());
4171
+ const childC = opts.createCommentNode(childD, replyD);
3959
4172
  parentC.putChild(childC);
3960
4173
  loadChildren(childC, node);
3961
4174
  });
@@ -4217,45 +4430,51 @@ function Detect(userAgent) {
4217
4430
  return dest;
4218
4431
  }
4219
4432
  function check(conf, rules) {
4220
- rules.forEach(({
4221
- el,
4222
- max: maxHeight,
4223
- imgContains
4224
- }) => {
4225
- const _apply = () => {
4226
- if (!el)
4227
- return;
4228
- if (!conf.scrollable)
4229
- applyHeightLimit({ el, maxHeight, postBtnClick: conf.postExpandBtnClick });
4230
- else
4231
- applyScrollableHeightLimit({ el, maxHeight });
4232
- };
4433
+ rules.forEach(({ el, max, imgCheck }) => {
4434
+ if (!el)
4435
+ return;
4436
+ if (imgCheck)
4437
+ el.style.maxHeight = `${max + 1}px`;
4438
+ let lock = false;
4233
4439
  const _check = () => {
4234
- if (el && getHeight(el) > maxHeight)
4235
- _apply();
4440
+ if (lock)
4441
+ return;
4442
+ if (getHeight(el) <= max)
4443
+ return;
4444
+ const afterExpandBtnClick = () => {
4445
+ var _a;
4446
+ lock = true;
4447
+ (_a = conf.afterExpandBtnClick) == null ? void 0 : _a.call(conf);
4448
+ };
4449
+ !conf.scrollable ? applyHeightLimit({ el, max, afterExpandBtnClick }) : applyScrollableHeightLimit({ el, max });
4236
4450
  };
4237
4451
  _check();
4238
- if (imgContains && el)
4239
- onImagesLoaded(el, () => _check());
4452
+ if (imgCheck) {
4453
+ el.querySelectorAll(".atk-content img").forEach((img) => {
4454
+ img.onload = () => _check();
4455
+ });
4456
+ }
4240
4457
  });
4241
4458
  }
4242
4459
  const HEIGHT_LIMIT_CSS = "atk-height-limit";
4243
4460
  function applyHeightLimit(obj) {
4244
4461
  if (!obj.el)
4245
4462
  return;
4246
- if (!obj.maxHeight)
4463
+ if (!obj.max)
4247
4464
  return;
4248
4465
  if (obj.el.classList.contains(HEIGHT_LIMIT_CSS))
4249
4466
  return;
4250
4467
  obj.el.classList.add(HEIGHT_LIMIT_CSS);
4251
- obj.el.style.height = `${obj.maxHeight}px`;
4468
+ obj.el.style.height = `${obj.max}px`;
4252
4469
  obj.el.style.overflow = "hidden";
4253
- const $expandBtn = createElement(`<div class="atk-height-limit-btn">${t("readMore")}</span>`);
4470
+ const $expandBtn = createElement(
4471
+ `<div class="atk-height-limit-btn">${t("readMore")}</span>`
4472
+ );
4254
4473
  $expandBtn.onclick = (e) => {
4255
4474
  e.stopPropagation();
4256
4475
  disposeHeightLimit(obj.el);
4257
- if (obj.postBtnClick)
4258
- obj.postBtnClick(e);
4476
+ if (obj.afterExpandBtnClick)
4477
+ obj.afterExpandBtnClick(e);
4259
4478
  };
4260
4479
  obj.el.append($expandBtn);
4261
4480
  }
@@ -4270,16 +4489,17 @@ function disposeHeightLimit($el) {
4270
4489
  e.remove();
4271
4490
  });
4272
4491
  $el.style.height = "";
4492
+ $el.style.maxHeight = "";
4273
4493
  $el.style.overflow = "";
4274
4494
  }
4275
4495
  const HEIGHT_LIMIT_SCROLL_CSS = "atk-height-limit-scroll";
4276
- function applyScrollableHeightLimit(obj) {
4277
- if (!obj.el)
4496
+ function applyScrollableHeightLimit(opt) {
4497
+ if (!opt.el)
4278
4498
  return;
4279
- if (obj.el.classList.contains(HEIGHT_LIMIT_SCROLL_CSS))
4499
+ if (opt.el.classList.contains(HEIGHT_LIMIT_SCROLL_CSS))
4280
4500
  return;
4281
- obj.el.classList.add(HEIGHT_LIMIT_SCROLL_CSS);
4282
- obj.el.style.height = `${obj.maxHeight}px`;
4501
+ opt.el.classList.add(HEIGHT_LIMIT_SCROLL_CSS);
4502
+ opt.el.style.height = `${opt.max}px`;
4283
4503
  }
4284
4504
  const CommentHTML = '<div class="atk-comment-wrap">\n <div class="atk-comment">\n <div class="atk-avatar"></div>\n <div class="atk-main">\n <div class="atk-header">\n <span class="atk-item atk-nick"></span>\n <span class="atk-badge-wrap"></span>\n <span class="atk-item atk-date"></span>\n </div>\n <div class="atk-body">\n <div class="atk-content"></div>\n </div>\n <div class="atk-footer">\n <div class="atk-actions"></div>\n </div>\n </div>\n </div>\n</div>\n';
4285
4505
  function renderAvatar(r) {
@@ -4288,7 +4508,9 @@ function renderAvatar(r) {
4288
4508
  const avatarURLBuilder = r.opts.avatarURLBuilder;
4289
4509
  $avatarImg.src = avatarURLBuilder ? avatarURLBuilder(r.data) : r.comment.getGravatarURL();
4290
4510
  if (r.data.link) {
4291
- const $avatarA = createElement('<a target="_blank" rel="noreferrer noopener nofollow"></a>');
4511
+ const $avatarA = createElement(
4512
+ '<a target="_blank" rel="noreferrer noopener nofollow"></a>'
4513
+ );
4292
4514
  $avatarA.href = isValidURL(r.data.link) ? r.data.link : `https://${r.data.link}`;
4293
4515
  $avatarA.append($avatarImg);
4294
4516
  $avatar.append($avatarA);
@@ -4309,7 +4531,9 @@ function renderHeader(r) {
4309
4531
  function renderNick(r) {
4310
4532
  r.$headerNick = r.$el.querySelector(".atk-nick");
4311
4533
  if (r.data.link) {
4312
- const $nickA = createElement('<a target="_blank" rel="noreferrer noopener nofollow"></a>');
4534
+ const $nickA = createElement(
4535
+ '<a target="_blank" rel="noreferrer noopener nofollow"></a>'
4536
+ );
4313
4537
  $nickA.innerText = r.data.nick;
4314
4538
  $nickA.href = isValidURL(r.data.link) ? r.data.link : `https://${r.data.link}`;
4315
4539
  r.$headerNick.append($nickA);
@@ -4328,7 +4552,9 @@ function renderVerifyBadge(ctx) {
4328
4552
  $badge.style.backgroundColor = badgeColor || "";
4329
4553
  ctx.$headerBadgeWrap.append($badge);
4330
4554
  } else if (ctx.data.is_verified) {
4331
- const $verifiedBadge = createElement(`<span class="atk-verified-icon" title="${t("emailVerified")}"></span>`);
4555
+ const $verifiedBadge = createElement(
4556
+ `<span class="atk-verified-icon" title="${t("emailVerified")}"></span>`
4557
+ );
4332
4558
  ctx.$headerBadgeWrap.append($verifiedBadge);
4333
4559
  }
4334
4560
  if (ctx.data.is_pinned) {
@@ -4402,7 +4628,9 @@ function renderReplyAt(r) {
4402
4628
  return;
4403
4629
  if (!r.opts.replyTo)
4404
4630
  return;
4405
- r.$replyAt = createElement(`<span class="atk-item atk-reply-at"><span class="atk-arrow"></span><span class="atk-nick"></span></span>`);
4631
+ r.$replyAt = createElement(
4632
+ `<span class="atk-item atk-reply-at"><span class="atk-arrow"></span><span class="atk-nick"></span></span>`
4633
+ );
4406
4634
  r.$replyAt.querySelector(".atk-nick").innerText = `${r.opts.replyTo.nick}`;
4407
4635
  r.$replyAt.onclick = () => {
4408
4636
  r.comment.getActions().goToReplyComment();
@@ -4593,7 +4821,9 @@ function renderVote(r) {
4593
4821
  r.comment.getActions().vote("up");
4594
4822
  });
4595
4823
  if (r.opts.voteDown) {
4596
- r.voteBtnDown = new ActionBtn(() => `${t("voteDown")} (${r.data.vote_down || 0})`).appendTo(r.$actions);
4824
+ r.voteBtnDown = new ActionBtn(() => `${t("voteDown")} (${r.data.vote_down || 0})`).appendTo(
4825
+ r.$actions
4826
+ );
4597
4827
  r.voteBtnDown.setClick(() => {
4598
4828
  r.comment.getActions().vote("down");
4599
4829
  });
@@ -4731,20 +4961,23 @@ class Render {
4731
4961
  return;
4732
4962
  const contentMaxH = conf.content;
4733
4963
  const childrenMaxH = conf.children;
4734
- check({
4735
- postExpandBtnClick: () => {
4736
- const children = this.comment.getChildren();
4737
- if (children.length === 1)
4738
- disposeHeightLimit(children[0].getRender().$content);
4964
+ check(
4965
+ {
4966
+ afterExpandBtnClick: () => {
4967
+ const children = this.comment.getChildren();
4968
+ if (children.length === 1)
4969
+ disposeHeightLimit(children[0].getRender().$content);
4970
+ },
4971
+ scrollable: conf.scrollable
4739
4972
  },
4740
- scrollable: conf.scrollable
4741
- }, [
4742
- // 评论内容限高
4743
- { el: this.$content, max: contentMaxH, imgContains: true },
4744
- { el: this.$replyTo, max: contentMaxH, imgContains: true },
4745
- // 子评论区域限高(仅嵌套模式)
4746
- { el: this.$childrenWrap, max: childrenMaxH, imgContains: false }
4747
- ]);
4973
+ [
4974
+ // 评论内容限高
4975
+ { el: this.$content, max: contentMaxH, imgCheck: true },
4976
+ { el: this.$replyTo, max: contentMaxH, imgCheck: true },
4977
+ // 子评论区域限高(仅嵌套模式)
4978
+ { el: this.$childrenWrap, max: childrenMaxH, imgCheck: false }
4979
+ ]
4980
+ );
4748
4981
  }
4749
4982
  /** 子评论区域移除限高 */
4750
4983
  heightLimitRemoveForChildren() {
@@ -4831,7 +5064,7 @@ class CommentActions {
4831
5064
  (_b = this.comment.getRender().voteBtnDown) == null ? void 0 : _b.updateText();
4832
5065
  }).catch((err) => {
4833
5066
  actionBtn == null ? void 0 : actionBtn.setError(t("voteFail"));
4834
- console.log(err);
5067
+ console.error(err);
4835
5068
  });
4836
5069
  }
4837
5070
  /** 管理员 - 评论状态修改 */
@@ -5463,7 +5696,9 @@ class List extends Component {
5463
5696
  }
5464
5697
  });
5465
5698
  this.ctx.on("comment-inserted", (comment) => {
5466
- this.getListLayout().insert(comment);
5699
+ var _a;
5700
+ const replyComment = comment.rid ? (_a = this.commentNodes.find((c) => c.getID() === comment.rid)) == null ? void 0 : _a.getData() : void 0;
5701
+ this.getListLayout().insert(comment, replyComment);
5467
5702
  });
5468
5703
  this.ctx.on("comment-deleted", (comment) => {
5469
5704
  const node = this.commentNodes.find((c) => c.getID() === comment.id);
@@ -5494,7 +5729,10 @@ function getScrollbarHelper() {
5494
5729
  },
5495
5730
  lock() {
5496
5731
  document.body.style.overflow = "hidden";
5497
- const barPaddingRight = parseInt(window.getComputedStyle(document.body, null).getPropertyValue("padding-right"), 10);
5732
+ const barPaddingRight = parseInt(
5733
+ window.getComputedStyle(document.body, null).getPropertyValue("padding-right"),
5734
+ 10
5735
+ );
5498
5736
  document.body.style.paddingRight = `${getScrollBarWidth() + barPaddingRight || 0}px`;
5499
5737
  }
5500
5738
  };
@@ -5705,13 +5943,7 @@ const services = {
5705
5943
  }
5706
5944
  };
5707
5945
  const PvCountWidget = (ctx) => {
5708
- ctx.watchConf([
5709
- "site",
5710
- "pageKey",
5711
- "pageTitle",
5712
- "countEl",
5713
- "pvEl"
5714
- ], (conf) => {
5946
+ ctx.watchConf(["site", "pageKey", "pageTitle", "countEl", "pvEl"], (conf) => {
5715
5947
  initCountWidget({
5716
5948
  getApi: () => ctx.getApi(),
5717
5949
  siteName: conf.site,
@@ -5778,15 +6010,20 @@ ${opts.errMsg}`;
5778
6010
  errEl.appendChild($retryBtn);
5779
6011
  }
5780
6012
  if (opts.onOpenSidebar) {
5781
- const $openSidebar = createElement(`<span atk-only-admin-show> | <span style="cursor:pointer;">${t("openName", { name: t("ctrlCenter") })}</span></span>`);
6013
+ const $openSidebar = createElement(
6014
+ `<span atk-only-admin-show> | <span style="cursor:pointer;">${t("openName", { name: t("ctrlCenter") })}</span></span>`
6015
+ );
5782
6016
  errEl.appendChild($openSidebar);
5783
6017
  $openSidebar.onclick = () => opts.onOpenSidebar && opts.onOpenSidebar();
5784
6018
  }
5785
6019
  setError(opts.$err, errEl);
5786
6020
  }
5787
6021
  const Markdown = (ctx) => {
5788
- initMarked();
5789
- ctx.on("updated", (conf) => {
6022
+ ctx.watchConf(["markedReplacers", "imgLazyLoad", "markedOptions"], (conf) => {
6023
+ initMarked({
6024
+ markedOptions: ctx.getConf().markedOptions,
6025
+ imgLazyLoad: ctx.getConf().imgLazyLoad
6026
+ });
5790
6027
  if (conf.markedReplacers)
5791
6028
  setReplacers(conf.markedReplacers);
5792
6029
  });
@@ -6121,7 +6358,9 @@ class Closable extends EditorPlug {
6121
6358
  }
6122
6359
  close() {
6123
6360
  if (!this.kit.useUI().$textareaWrap.querySelector(".atk-comment-closed"))
6124
- this.kit.useUI().$textareaWrap.prepend(createElement(`<div class="atk-comment-closed">${t("onlyAdminCanReply")}</div>`));
6361
+ this.kit.useUI().$textareaWrap.prepend(
6362
+ createElement(`<div class="atk-comment-closed">${t("onlyAdminCanReply")}</div>`)
6363
+ );
6125
6364
  if (!this.kit.useUser().getData().isAdmin) {
6126
6365
  this.kit.useUI().$textarea.style.display = "none";
6127
6366
  this.kit.useEvents().trigger("panel-close");
@@ -6145,8 +6384,14 @@ class HeaderEvent extends EditorPlug {
6145
6384
  };
6146
6385
  this.kit.useMounted(() => {
6147
6386
  Object.entries(this.$inputs).forEach(([key, $input]) => {
6148
- $input.addEventListener("input", inputEventFns[key] = trigger("header-input", $input, key));
6149
- $input.addEventListener("change", changeEventFns[key] = trigger("header-change", $input, key));
6387
+ $input.addEventListener(
6388
+ "input",
6389
+ inputEventFns[key] = trigger("header-input", $input, key)
6390
+ );
6391
+ $input.addEventListener(
6392
+ "change",
6393
+ changeEventFns[key] = trigger("header-change", $input, key)
6394
+ );
6150
6395
  });
6151
6396
  });
6152
6397
  this.kit.useUnmounted(() => {
@@ -6196,9 +6441,12 @@ class HeaderUser extends EditorPlug {
6196
6441
  const api = this.kit.useApi();
6197
6442
  const CANCEL_TOKEN = "getUserCancelToken";
6198
6443
  this.query.abortFn = () => api.abortRequest(CANCEL_TOKEN);
6199
- api.user.getUser(__spreadValues({}, api.getUserFields()), {
6200
- cancelToken: CANCEL_TOKEN
6201
- }).then((res) => this.onUserInfoFetched(res.data)).catch((err) => {
6444
+ api.user.getUser(
6445
+ __spreadValues({}, api.getUserFields()),
6446
+ {
6447
+ cancelToken: CANCEL_TOKEN
6448
+ }
6449
+ ).then((res) => this.onUserInfoFetched(res.data)).catch((err) => {
6202
6450
  }).finally(() => {
6203
6451
  this.query.abortFn = null;
6204
6452
  });
@@ -6259,7 +6507,9 @@ class Emoticons extends EditorPlug {
6259
6507
  __publicField(this, "isImgLoaded", false);
6260
6508
  this.kit.useMounted(() => {
6261
6509
  this.usePanel(`<div class="atk-editor-plug-emoticons"></div>`);
6262
- this.useBtn(`<i aria-label="${t("emoticon")}"><svg fill="currentColor" aria-hidden="true" height="14" viewBox="0 0 14 14" width="14"><path d="m4.26829 5.29294c0-.94317.45893-1.7074 1.02439-1.7074.56547 0 1.02439.76423 1.02439 1.7074s-.45892 1.7074-1.02439 1.7074c-.56546 0-1.02439-.76423-1.02439-1.7074zm4.43903 1.7074c.56546 0 1.02439-.76423 1.02439-1.7074s-.45893-1.7074-1.02439-1.7074c-.56547 0-1.02439.76423-1.02439 1.7074s.45892 1.7074 1.02439 1.7074zm-1.70732 2.73184c-1.51883 0-2.06312-1.52095-2.08361-1.58173l-1.29551.43231c.03414.10244.868 2.51604 3.3798 2.51604 2.51181 0 3.34502-2.41291 3.37982-2.51604l-1.29484-.43573c-.02254.06488-.56683 1.58583-2.08498 1.58583zm7-2.73252c0 3.86004-3.1401 7.00034-7 7.00034s-7-3.1396-7-6.99966c0-3.86009 3.1401-7.00034 7-7.00034s7 3.14025 7 7.00034zm-1.3659 0c0-3.10679-2.5275-5.63442-5.6341-5.63442-3.10663 0-5.63415 2.52832-5.63415 5.6351 0 3.10676 2.52752 5.63446 5.63415 5.63446 3.1066 0 5.6341-2.5277 5.6341-5.63446z"/></svg></i>`);
6510
+ this.useBtn(
6511
+ `<i aria-label="${t("emoticon")}"><svg fill="currentColor" aria-hidden="true" height="14" viewBox="0 0 14 14" width="14"><path d="m4.26829 5.29294c0-.94317.45893-1.7074 1.02439-1.7074.56547 0 1.02439.76423 1.02439 1.7074s-.45892 1.7074-1.02439 1.7074c-.56546 0-1.02439-.76423-1.02439-1.7074zm4.43903 1.7074c.56546 0 1.02439-.76423 1.02439-1.7074s-.45893-1.7074-1.02439-1.7074c-.56547 0-1.02439.76423-1.02439 1.7074s.45892 1.7074 1.02439 1.7074zm-1.70732 2.73184c-1.51883 0-2.06312-1.52095-2.08361-1.58173l-1.29551.43231c.03414.10244.868 2.51604 3.3798 2.51604 2.51181 0 3.34502-2.41291 3.37982-2.51604l-1.29484-.43573c-.02254.06488-.56683 1.58583-2.08498 1.58583zm7-2.73252c0 3.86004-3.1401 7.00034-7 7.00034s-7-3.1396-7-6.99966c0-3.86009 3.1401-7.00034 7-7.00034s7 3.14025 7 7.00034zm-1.3659 0c0-3.10679-2.5275-5.63442-5.6341-5.63442-3.10663 0-5.63415 2.52832-5.63415 5.6351 0 3.10676 2.52752 5.63446 5.63415 5.63446 3.1066 0 5.6341-2.5277 5.6341-5.63446z"/></svg></i>`
6512
+ );
6263
6513
  });
6264
6514
  this.kit.useUnmounted(() => {
6265
6515
  });
@@ -6319,19 +6569,21 @@ class Emoticons extends EditorPlug {
6319
6569
  data.push(grp);
6320
6570
  };
6321
6571
  const remoteLoad = (d) => __async(this, null, function* () {
6322
- yield Promise.all(d.map((grp, index) => __async(this, null, function* () {
6323
- if (typeof grp === "object" && !Array.isArray(grp)) {
6324
- pushGrp(grp);
6325
- } else if (Array.isArray(grp)) {
6326
- yield remoteLoad(grp);
6327
- } else if (typeof grp === "string") {
6328
- const grpData = yield this.remoteLoad(grp);
6329
- if (Array.isArray(grpData))
6330
- yield remoteLoad(grpData);
6331
- else if (typeof grpData === "object")
6332
- pushGrp(grpData);
6333
- }
6334
- })));
6572
+ yield Promise.all(
6573
+ d.map((grp, index) => __async(this, null, function* () {
6574
+ if (typeof grp === "object" && !Array.isArray(grp)) {
6575
+ pushGrp(grp);
6576
+ } else if (Array.isArray(grp)) {
6577
+ yield remoteLoad(grp);
6578
+ } else if (typeof grp === "string") {
6579
+ const grpData = yield this.remoteLoad(grp);
6580
+ if (Array.isArray(grpData))
6581
+ yield remoteLoad(grpData);
6582
+ else if (typeof grpData === "object")
6583
+ pushGrp(grpData);
6584
+ }
6585
+ }))
6586
+ );
6335
6587
  });
6336
6588
  yield remoteLoad(data);
6337
6589
  data.forEach((item) => {
@@ -6346,7 +6598,9 @@ class Emoticons extends EditorPlug {
6346
6598
  });
6347
6599
  }
6348
6600
  });
6349
- data = data.filter((item) => typeof item === "object" && !Array.isArray(item) && !!item && !!item.name);
6601
+ data = data.filter(
6602
+ (item) => typeof item === "object" && !Array.isArray(item) && !!item && !!item.name
6603
+ );
6350
6604
  this.solveNullKey(data);
6351
6605
  this.solveSameKey(data);
6352
6606
  return data;
@@ -6414,7 +6668,10 @@ class Emoticons extends EditorPlug {
6414
6668
  if (find && find.length > 1)
6415
6669
  item.icon = find[1];
6416
6670
  }
6417
- nGrp.items.push({ key: item.text || `${grpName} ${index + 1}`, val: item.icon });
6671
+ nGrp.items.push({
6672
+ key: item.text || `${grpName} ${index + 1}`,
6673
+ val: item.icon
6674
+ });
6418
6675
  });
6419
6676
  dest.push(nGrp);
6420
6677
  });
@@ -6510,7 +6767,9 @@ class Upload extends EditorPlug {
6510
6767
  this.$imgUploadInput.type = "file";
6511
6768
  this.$imgUploadInput.style.display = "none";
6512
6769
  this.$imgUploadInput.accept = AllowImgExts.map((o) => `.${o}`).join(",");
6513
- const $btn = this.useBtn(`<i aria-label="${t("uploadImage")}"><svg fill="currentColor" aria-hidden="true" height="14" viewBox="0 0 14 14" width="14"><path d="m0 1.94444c0-1.074107.870333-1.94444 1.94444-1.94444h10.11116c1.0741 0 1.9444.870333 1.9444 1.94444v10.11116c0 1.0741-.8703 1.9444-1.9444 1.9444h-10.11116c-1.074107 0-1.94444-.8703-1.94444-1.9444zm1.94444-.38888c-.21466 0-.38888.17422-.38888.38888v7.06689l2.33333-2.33333 2.33333 2.33333 3.88888-3.88889 2.3333 2.33334v-5.51134c0-.21466-.1742-.38888-.3888-.38888zm10.49996 8.09977-2.3333-2.33333-3.88888 3.8889-2.33333-2.33334-2.33333 2.33334v.8447c0 .2146.17422.3888.38888.3888h10.11116c.2146 0 .3888-.1742.3888-.3888zm-7.1944-6.54422c-.75133 0-1.36111.60978-1.36111 1.36111 0 .75134.60978 1.36111 1.36111 1.36111s1.36111-.60977 1.36111-1.36111c0-.75133-.60978-1.36111-1.36111-1.36111z"/></svg></i>`);
6770
+ const $btn = this.useBtn(
6771
+ `<i aria-label="${t("uploadImage")}"><svg fill="currentColor" aria-hidden="true" height="14" viewBox="0 0 14 14" width="14"><path d="m0 1.94444c0-1.074107.870333-1.94444 1.94444-1.94444h10.11116c1.0741 0 1.9444.870333 1.9444 1.94444v10.11116c0 1.0741-.8703 1.9444-1.9444 1.9444h-10.11116c-1.074107 0-1.94444-.8703-1.94444-1.9444zm1.94444-.38888c-.21466 0-.38888.17422-.38888.38888v7.06689l2.33333-2.33333 2.33333 2.33333 3.88888-3.88889 2.3333 2.33334v-5.51134c0-.21466-.1742-.38888-.3888-.38888zm10.49996 8.09977-2.3333-2.33333-3.88888 3.8889-2.33333-2.33334-2.33333 2.33334v.8447c0 .2146.17422.3888.38888.3888h10.11116c.2146 0 .3888-.1742.3888-.3888zm-7.1944-6.54422c-.75133 0-1.36111.60978-1.36111 1.36111 0 .75134.60978 1.36111 1.36111 1.36111s1.36111-.60977 1.36111-1.36111c0-.75133-.60978-1.36111-1.36111-1.36111z"/></svg></i>`
6772
+ );
6514
6773
  $btn.after(this.$imgUploadInput);
6515
6774
  $btn.onclick = () => {
6516
6775
  const $input = this.$imgUploadInput;
@@ -6571,7 +6830,7 @@ class Upload extends EditorPlug {
6571
6830
  uploadImg(file) {
6572
6831
  return __async(this, null, function* () {
6573
6832
  const fileExt = /[^.]+$/.exec(file.name);
6574
- if (!fileExt || !AllowImgExts.includes(fileExt[0]))
6833
+ if (!fileExt || !AllowImgExts.includes(String(fileExt[0]).toLowerCase()))
6575
6834
  return;
6576
6835
  if (!this.kit.useUser().checkHasBasicUserInfo()) {
6577
6836
  this.kit.useEditor().showNotify(t("uploadLoginMsg"), "w");
@@ -6601,7 +6860,9 @@ class Upload extends EditorPlug {
6601
6860
  base: this.kit.useConf().server,
6602
6861
  path: imgURL
6603
6862
  });
6604
- this.kit.useEditor().setContent(this.kit.useUI().$textarea.value.replace(uploadPlaceholderTxt, `${insertPrefix}![](${imgURL})`));
6863
+ this.kit.useEditor().setContent(
6864
+ this.kit.useUI().$textarea.value.replace(uploadPlaceholderTxt, `${insertPrefix}![](${imgURL})`)
6865
+ );
6605
6866
  } else {
6606
6867
  this.kit.useEditor().setContent(this.kit.useUI().$textarea.value.replace(uploadPlaceholderTxt, ""));
6607
6868
  }
@@ -6614,7 +6875,9 @@ class Preview extends EditorPlug {
6614
6875
  __publicField(this, "isPlugPanelShow", false);
6615
6876
  this.kit.useMounted(() => {
6616
6877
  this.usePanel(`<div class="atk-editor-plug-preview"></div>`);
6617
- this.useBtn(`<i aria-label="${t("preview")}"><svg fill="currentColor" aria-hidden="true" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"></path></svg></i>`);
6878
+ this.useBtn(
6879
+ `<i aria-label="${t("preview")}"><svg fill="currentColor" aria-hidden="true" viewBox="0 0 16 16" width="16" height="16"><path fill-rule="evenodd" d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"></path></svg></i>`
6880
+ );
6618
6881
  });
6619
6882
  this.kit.useUnmounted(() => {
6620
6883
  });
@@ -6720,23 +6983,20 @@ class PlugManager {
6720
6983
  __publicField(this, "events", new EventManager());
6721
6984
  this.editor = editor;
6722
6985
  let confLoaded = false;
6723
- this.editor.ctx.watchConf([
6724
- "imgUpload",
6725
- "emoticons",
6726
- "preview",
6727
- "editorTravel",
6728
- "locale"
6729
- ], (conf) => {
6730
- confLoaded && this.getEvents().trigger("unmounted");
6731
- this.clear();
6732
- getEnabledPlugs(conf).forEach((Plug) => {
6733
- const kit = new PlugKit(this);
6734
- this.plugs.push(new Plug(kit));
6735
- });
6736
- this.getEvents().trigger("mounted");
6737
- confLoaded = true;
6738
- this.loadPluginUI();
6739
- });
6986
+ this.editor.ctx.watchConf(
6987
+ ["imgUpload", "emoticons", "preview", "editorTravel", "locale"],
6988
+ (conf) => {
6989
+ confLoaded && this.getEvents().trigger("unmounted");
6990
+ this.clear();
6991
+ getEnabledPlugs(conf).forEach((Plug) => {
6992
+ const kit = new PlugKit(this);
6993
+ this.plugs.push(new Plug(kit));
6994
+ });
6995
+ this.getEvents().trigger("mounted");
6996
+ confLoaded = true;
6997
+ this.loadPluginUI();
6998
+ }
6999
+ );
6740
7000
  this.events.on("panel-close", () => this.closePlugPanel());
6741
7001
  }
6742
7002
  getPlugs() {
@@ -6875,7 +7135,9 @@ const Unread = (ctx) => {
6875
7135
  const notifyKey = getQueryParam("atk_notify_key");
6876
7136
  if (notifyKey) {
6877
7137
  ctx.getApi().notifies.markNotifyRead(commentID, notifyKey).then(() => {
6878
- ctx.getData().updateNotifies(ctx.getData().getNotifies().filter((o) => o.comment_id !== commentID));
7138
+ ctx.getData().updateNotifies(
7139
+ ctx.getData().getNotifies().filter((o) => o.comment_id !== commentID)
7140
+ );
6879
7141
  });
6880
7142
  }
6881
7143
  });
@@ -6887,7 +7149,11 @@ const Count = (ctx) => {
6887
7149
  const $count = list.$el.querySelector(".atk-comment-count .atk-text");
6888
7150
  if (!$count)
6889
7151
  return;
6890
- const text = htmlEncode(t("counter", { count: `${Number((_b = (_a = ctx.getData().getListLastFetch()) == null ? void 0 : _a.data) == null ? void 0 : _b.count) || 0}` }));
7152
+ const text = htmlEncode(
7153
+ t("counter", {
7154
+ count: `${Number((_b = (_a = ctx.getData().getListLastFetch()) == null ? void 0 : _a.data) == null ? void 0 : _b.count) || 0}`
7155
+ })
7156
+ );
6891
7157
  $count.innerHTML = text.replace(/(\d+)/, '<span class="atk-comment-count-num">$1</span>');
6892
7158
  };
6893
7159
  ctx.on("list-loaded", () => {
@@ -6996,7 +7262,7 @@ const GotoFocus = (ctx) => {
6996
7262
  comment.focus();
6997
7263
  }));
6998
7264
  };
6999
- const version = "2.8.4";
7265
+ const version = "2.8.6";
7000
7266
  const Copyright = (ctx) => {
7001
7267
  ctx.on("mounted", () => {
7002
7268
  const list = ctx.get("list");
@@ -7031,26 +7297,38 @@ const Dropdown = (ctx) => {
7031
7297
  renderDropdown({
7032
7298
  $dropdownWrap: $dropdownOn,
7033
7299
  dropdownList: [
7034
- [t("sortLatest"), () => {
7035
- reloadUseParamsEditor((p) => {
7036
- p.sort_by = "date_desc";
7037
- });
7038
- }],
7039
- [t("sortBest"), () => {
7040
- reloadUseParamsEditor((p) => {
7041
- p.sort_by = "vote";
7042
- });
7043
- }],
7044
- [t("sortOldest"), () => {
7045
- reloadUseParamsEditor((p) => {
7046
- p.sort_by = "date_asc";
7047
- });
7048
- }],
7049
- [t("sortAuthor"), () => {
7050
- reloadUseParamsEditor((p) => {
7051
- p.view_only_admin = true;
7052
- });
7053
- }]
7300
+ [
7301
+ t("sortLatest"),
7302
+ () => {
7303
+ reloadUseParamsEditor((p) => {
7304
+ p.sort_by = "date_desc";
7305
+ });
7306
+ }
7307
+ ],
7308
+ [
7309
+ t("sortBest"),
7310
+ () => {
7311
+ reloadUseParamsEditor((p) => {
7312
+ p.sort_by = "vote";
7313
+ });
7314
+ }
7315
+ ],
7316
+ [
7317
+ t("sortOldest"),
7318
+ () => {
7319
+ reloadUseParamsEditor((p) => {
7320
+ p.sort_by = "date_asc";
7321
+ });
7322
+ }
7323
+ ],
7324
+ [
7325
+ t("sortAuthor"),
7326
+ () => {
7327
+ reloadUseParamsEditor((p) => {
7328
+ p.view_only_admin = true;
7329
+ });
7330
+ }
7331
+ ]
7054
7332
  ]
7055
7333
  });
7056
7334
  };
@@ -7199,18 +7477,21 @@ const ReachBottom = (ctx) => {
7199
7477
  let observer = null;
7200
7478
  const setupObserver = ($target) => {
7201
7479
  const scrollEvtAt = ctx.conf.scrollRelativeTo && ctx.conf.scrollRelativeTo() || null;
7202
- observer = new IntersectionObserver(([entries]) => {
7203
- if (entries.isIntersecting) {
7204
- clearObserver();
7205
- ctx.trigger("list-reach-bottom");
7480
+ observer = new IntersectionObserver(
7481
+ ([entries]) => {
7482
+ if (entries.isIntersecting) {
7483
+ clearObserver();
7484
+ ctx.trigger("list-reach-bottom");
7485
+ }
7486
+ },
7487
+ {
7488
+ threshold: 0.9,
7489
+ // when the target is 90% visible
7490
+ // @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/root
7491
+ // If the root is null, then the bounds of the actual document viewport are used.
7492
+ root: scrollEvtAt
7206
7493
  }
7207
- }, {
7208
- threshold: 0.9,
7209
- // when the target is 90% visible
7210
- // @see https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/root
7211
- // If the root is null, then the bounds of the actual document viewport are used.
7212
- root: scrollEvtAt
7213
- });
7494
+ );
7214
7495
  observer.observe($target);
7215
7496
  };
7216
7497
  const clearObserver = () => {
@@ -7294,22 +7575,26 @@ function versionCheck(list, feVer, beVer) {
7294
7575
  if (sameVer)
7295
7576
  return;
7296
7577
  const errEl = createElement(
7297
- `<div>${t("updateMsg", { name: comp < 0 ? t("frontend") : t("backend") })}<br/><br/><span style="color: var(--at-color-meta);">${t("currentVersion")}: ${t("frontend")} ${feVer} / ${t("backend")} ${beVer}</span><br/><br/></div>`
7578
+ `<div class="atk-version-check-notice">${t("updateMsg", {
7579
+ name: comp < 0 ? t("frontend") : t("backend")
7580
+ })} <span class="atk-info">${t("currentVersion")}: ${t("frontend")} ${feVer} / ${t("backend")} ${beVer}</span></div>`
7298
7581
  );
7299
- const ignoreBtn = createElement(`<span style="cursor:pointer">${t("ignore")}</span>`);
7582
+ const ignoreBtn = createElement(`<span class="atk-ignore-btn">${t("ignore")}</span>`);
7300
7583
  ignoreBtn.onclick = () => {
7301
- setError(list.$el.parentElement, null);
7584
+ errEl.remove();
7302
7585
  IgnoreVersionCheck = true;
7303
- list.ctx.fetch({ offset: 0 });
7304
7586
  };
7305
7587
  errEl.append(ignoreBtn);
7306
- setError(list.$el.parentElement, errEl, '<span class="atk-warn-title">Artalk Warn</span>');
7588
+ list.$el.parentElement.prepend(errEl);
7307
7589
  }
7308
7590
  const AdminOnlyElem = (ctx) => {
7309
7591
  const scanApply = () => {
7310
- applyAdminOnlyEls(ctx.get("user").getData().isAdmin, getAdminOnlyEls({
7311
- $root: ctx.$root
7312
- }));
7592
+ applyAdminOnlyEls(
7593
+ ctx.get("user").getData().isAdmin,
7594
+ getAdminOnlyEls({
7595
+ $root: ctx.$root
7596
+ })
7597
+ );
7313
7598
  };
7314
7599
  ctx.on("list-loaded", () => {
7315
7600
  scanApply();
@@ -7406,7 +7691,9 @@ function load(ctx) {
7406
7691
  };
7407
7692
  if (ctx.conf.useBackendConf) {
7408
7693
  if (!data.frontend_conf)
7409
- throw new Error("The remote backend does not respond to the frontend conf, but `useBackendConf` conf is enabled");
7694
+ throw new Error(
7695
+ "The remote backend does not respond to the frontend conf, but `useBackendConf` conf is enabled"
7696
+ );
7410
7697
  conf = __spreadValues(__spreadValues({}, conf), handleConfFormServer(data.frontend_conf));
7411
7698
  }
7412
7699
  ctx.conf.remoteConfModifier && ctx.conf.remoteConfModifier(conf);
@@ -7431,17 +7718,19 @@ function loadNetworkPlugins(scripts, apiBase) {
7431
7718
  scripts.forEach((url) => {
7432
7719
  if (!/^(http|https):\/\//.test(url))
7433
7720
  url = `${apiBase.replace(/\/$/, "")}/${url.replace(/^\//, "")}`;
7434
- tasks.push(new Promise((resolve, reject) => {
7435
- if (document.querySelector(`script[src="${url}"]`)) {
7436
- resolve();
7437
- return;
7438
- }
7439
- const script = document.createElement("script");
7440
- script.src = url;
7441
- document.head.appendChild(script);
7442
- script.onload = () => resolve();
7443
- script.onerror = (err) => reject(err);
7444
- }));
7721
+ tasks.push(
7722
+ new Promise((resolve, reject) => {
7723
+ if (document.querySelector(`script[src="${url}"]`)) {
7724
+ resolve();
7725
+ return;
7726
+ }
7727
+ const script = document.createElement("script");
7728
+ script.src = url;
7729
+ document.head.appendChild(script);
7730
+ script.onload = () => resolve();
7731
+ script.onerror = (err) => reject(err);
7732
+ })
7733
+ );
7445
7734
  });
7446
7735
  yield Promise.all(tasks);
7447
7736
  return Object.values(window.ArtalkPlugins || {});
@@ -7451,7 +7740,10 @@ function onLoadErr(ctx, err) {
7451
7740
  var _a;
7452
7741
  let sidebarOpenView = "";
7453
7742
  if ((_a = err.data) == null ? void 0 : _a.err_no_site) {
7454
- const viewLoadParam = { create_name: ctx.conf.site, create_urls: `${window.location.protocol}//${window.location.host}` };
7743
+ const viewLoadParam = {
7744
+ create_name: ctx.conf.site,
7745
+ create_urls: `${window.location.protocol}//${window.location.host}`
7746
+ };
7455
7747
  sidebarOpenView = `sites|${JSON.stringify(viewLoadParam)}`;
7456
7748
  }
7457
7749
  showErrorDialog({