artalk 2.8.2 → 2.8.4

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.
package/dist/Artalk.mjs CHANGED
@@ -481,6 +481,21 @@ let Api$1 = class Api extends HttpClient {
481
481
  path: `/conf`,
482
482
  method: "GET",
483
483
  format: "json"
484
+ }, params)),
485
+ /**
486
+ * @description Get Domain Info
487
+ *
488
+ * @tags System
489
+ * @name GetDomain
490
+ * @summary Get Domain Info
491
+ * @request GET:/conf/domain
492
+ * @response `200` `HandlerResponseConfDomain` OK
493
+ */
494
+ getDomain: (query, params = {}) => this.request(__spreadValues({
495
+ path: `/conf/domain`,
496
+ method: "GET",
497
+ query,
498
+ format: "json"
484
499
  }, params))
485
500
  });
486
501
  __publicField(this, "notifies", {
@@ -1049,7 +1064,7 @@ let Api$1 = class Api extends HttpClient {
1049
1064
  /**
1050
1065
  * @description Get user info to prepare for login or check current user status
1051
1066
  *
1052
- * @tags Account
1067
+ * @tags Auth
1053
1068
  * @name GetUser
1054
1069
  * @summary Get User Info
1055
1070
  * @request GET:/user
@@ -1070,23 +1085,23 @@ let Api$1 = class Api extends HttpClient {
1070
1085
  /**
1071
1086
  * @description Login user by name or email
1072
1087
  *
1073
- * @tags Account
1088
+ * @tags Auth
1074
1089
  * @name Login
1075
1090
  * @summary Get Access Token
1076
1091
  * @request POST:/user/access_token
1077
1092
  * @response `200` `HandlerResponseUserLogin` OK
1078
1093
  * @response `400` `(HandlerMap & {
1079
- " data"?: {
1094
+ data?: {
1080
1095
  need_name_select?: (string)[],
1081
1096
 
1082
1097
  },
1083
1098
  msg?: string,
1084
1099
 
1085
1100
  })` Multiple users with the same email address are matched
1086
- * @response `403` `(HandlerMap & {
1101
+ * @response `401` `(HandlerMap & {
1087
1102
  msg?: string,
1088
1103
 
1089
- })` Forbidden
1104
+ })` Unauthorized
1090
1105
  * @response `500` `(HandlerMap & {
1091
1106
  msg?: string,
1092
1107
 
@@ -1102,7 +1117,7 @@ let Api$1 = class Api extends HttpClient {
1102
1117
  /**
1103
1118
  * @description Get user login status by header Authorization
1104
1119
  *
1105
- * @tags Account
1120
+ * @tags Auth
1106
1121
  * @name GetUserStatus
1107
1122
  * @summary Get Login Status
1108
1123
  * @request GET:/user/status
@@ -1714,16 +1729,16 @@ const Fetch$1 = (opts, input, init2) => __async(void 0, null, function* () {
1714
1729
  if (!resp.ok) {
1715
1730
  const json = (yield resp.json().catch(() => {
1716
1731
  })) || {};
1717
- if (json.need_captcha) {
1718
- opts.onNeedCheckCaptcha && (yield opts.onNeedCheckCaptcha({
1719
- data: { imgData: json.img_data, iframe: json.iframe }
1720
- }));
1732
+ let retry = false;
1733
+ opts.handlers && (yield opts.handlers.get().reduce((promise, item) => __async(void 0, null, function* () {
1734
+ yield promise;
1735
+ if (json[item.action] === true) {
1736
+ yield item.handler(json);
1737
+ retry = true;
1738
+ }
1739
+ }), Promise.resolve()));
1740
+ if (retry)
1721
1741
  return Fetch$1(opts, input, init2);
1722
- }
1723
- if (json.need_login) {
1724
- opts.onNeedCheckAdmin && (yield opts.onNeedCheckAdmin({}));
1725
- return Fetch$1(opts, input, init2);
1726
- }
1727
1742
  throw createError(resp.status, json);
1728
1743
  }
1729
1744
  return resp;
@@ -1744,6 +1759,15 @@ function createError(code, data) {
1744
1759
  console.error(err);
1745
1760
  return err;
1746
1761
  }
1762
+ function createApiHandlers() {
1763
+ const handlers = [];
1764
+ return {
1765
+ add: (action, handler) => {
1766
+ handlers.push({ action, handler });
1767
+ },
1768
+ get: () => handlers
1769
+ };
1770
+ }
1747
1771
  class Api2 extends Api$1 {
1748
1772
  constructor(opts) {
1749
1773
  super({
@@ -2574,14 +2598,14 @@ const fences = /^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\
2574
2598
  const hr = /^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/;
2575
2599
  const heading = /^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/;
2576
2600
  const bullet = /(?:[*+-]|\d{1,9}[.)])/;
2577
- const lheading = edit(/^(?!bull )((?:.|\n(?!\s*?\n|bull ))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g, bullet).getRegex();
2601
+ const lheading = edit(/^(?!bull |blockCode|fences|blockquote|heading|html)((?:.|\n(?!\s*?\n|bull |blockCode|fences|blockquote|heading|html))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g, bullet).replace(/blockCode/g, / {4}/).replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/).replace(/blockquote/g, / {0,3}>/).replace(/heading/g, / {0,3}#{1,6}/).replace(/html/g, / {0,3}<[^\n>]+>\n/).getRegex();
2578
2602
  const _paragraph = /^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/;
2579
2603
  const blockText = /^[^\n]+/;
2580
2604
  const _blockLabel = /(?!\s*\])(?:\\.|[^\[\]\\])+/;
2581
2605
  const def = edit(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label", _blockLabel).replace("title", /(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex();
2582
2606
  const list = edit(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g, bullet).getRegex();
2583
- const _tag = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
2584
- const _comment = /<!--(?!-?>)[\s\S]*?(?:-->|$)/;
2607
+ const _tag = "address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul";
2608
+ const _comment = /<!--(?:-?>|[\s\S]*?(?:-->|$))/;
2585
2609
  const html = edit("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))", "i").replace("comment", _comment).replace("tag", _tag).replace("attribute", / +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex();
2586
2610
  const paragraph = edit(_paragraph).replace("hr", hr).replace("heading", " {0,3}#{1,6}(?:\\s|$)").replace("|lheading", "").replace("|table", "").replace("blockquote", " {0,3}>").replace("fences", " {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list", " {0,3}(?:[*+-]|1[.)]) ").replace("html", "</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag", _tag).getRegex();
2587
2611
  const blockquote = edit(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph", paragraph).getRegex();
@@ -2618,7 +2642,7 @@ const escape = /^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/;
2618
2642
  const inlineCode = /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/;
2619
2643
  const br = /^( {2,}|\\)\n(?!\s*$)/;
2620
2644
  const inlineText = /^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/;
2621
- const _punctuation = "\\p{P}$+<=>`^|~";
2645
+ const _punctuation = "\\p{P}\\p{S}";
2622
2646
  const punctuation = edit(/^((?![*_])[\spunctuation])/, "u").replace(/punctuation/g, _punctuation).getRegex();
2623
2647
  const blockSkip = /\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g;
2624
2648
  const emStrongLDelim = edit(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/, "u").replace(/punct/g, _punctuation).getRegex();
@@ -4545,6 +4569,7 @@ const en = {
4545
4569
  /* Sidebar */
4546
4570
  msgCenter: "Messages",
4547
4571
  ctrlCenter: "Admin",
4572
+ emailVerified: "Email has been verified",
4548
4573
  /* General */
4549
4574
  frontend: "Frontend",
4550
4575
  backend: "Backend",
@@ -4625,6 +4650,7 @@ const zhCN = {
4625
4650
  /* Sidebar */
4626
4651
  msgCenter: "通知中心",
4627
4652
  ctrlCenter: "控制中心",
4653
+ emailVerified: "邮箱已验证",
4628
4654
  /* General */
4629
4655
  frontend: "前端",
4630
4656
  backend: "后端",
@@ -4975,21 +5001,15 @@ function convertApiOptions(conf, ctx) {
4975
5001
  name: ctx == null ? void 0 : ctx.get("user").getData().nick,
4976
5002
  email: ctx == null ? void 0 : ctx.get("user").getData().email
4977
5003
  } : void 0,
4978
- onNeedCheckAdmin: (payload) => {
4979
- if (!ctx)
4980
- throw new Error("`ctx` is required when `onNeedCheckAdmin` is called.");
4981
- return ctx.checkAdmin({});
4982
- },
4983
- onNeedCheckCaptcha: (payload) => {
4984
- if (!ctx)
4985
- throw new Error("`ctx` is required when `onNeedCheckCaptcha` is called.");
4986
- return ctx.checkCaptcha({
4987
- imgData: payload.data.imgData,
4988
- iframe: payload.data.iframe
4989
- });
4990
- }
5004
+ handlers: ctx == null ? void 0 : ctx.getApiHandlers()
4991
5005
  };
4992
5006
  }
5007
+ function createNewApiHandlers(ctx) {
5008
+ const h = createApiHandlers();
5009
+ h.add("need_captcha", (res) => ctx.checkCaptcha(res));
5010
+ h.add("need_login", () => ctx.checkAdmin({}));
5011
+ return h;
5012
+ }
4993
5013
  function watchConf(ctx, keys, effect) {
4994
5014
  const deepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b);
4995
5015
  const val = () => {
@@ -5021,6 +5041,7 @@ class Context {
5021
5041
  /* Event Manager */
5022
5042
  __publicField(this, "events", new EventManager());
5023
5043
  __publicField(this, "mounted", false);
5044
+ __publicField(this, "apiHandlers", null);
5024
5045
  __publicField(this, "getCommentList", this.getCommentNodes);
5025
5046
  __publicField(this, "getCommentDataList", this.getComments);
5026
5047
  this.conf = conf;
@@ -5041,6 +5062,11 @@ class Context {
5041
5062
  getApi() {
5042
5063
  return new Api2(convertApiOptions(this.conf, this));
5043
5064
  }
5065
+ getApiHandlers() {
5066
+ if (!this.apiHandlers)
5067
+ this.apiHandlers = createNewApiHandlers(this);
5068
+ return this.apiHandlers;
5069
+ }
5044
5070
  getData() {
5045
5071
  return this.data;
5046
5072
  }
@@ -5433,7 +5459,7 @@ class CheckerLauncher {
5433
5459
  constructor(opts) {
5434
5460
  __publicField(this, "checkCaptcha", wrapPromise((p) => {
5435
5461
  this.fire(CaptchaChecker, p, (ctx) => {
5436
- ctx.set("img_data", p.imgData);
5462
+ ctx.set("img_data", p.img_data);
5437
5463
  ctx.set("iframe", p.iframe);
5438
5464
  });
5439
5465
  }));
@@ -5511,7 +5537,7 @@ class CheckerLauncher {
5511
5537
  if (payload.onSuccess)
5512
5538
  payload.onSuccess();
5513
5539
  }).catch((err) => {
5514
- btnTextSet(String(err.msg || String(err)));
5540
+ btnTextSet(String(err.message || String(err)));
5515
5541
  if (checker.onError)
5516
5542
  checker.onError(checkerCtx, err, inputVal, formEl);
5517
5543
  const tf = setTimeout(() => btnTextRestore(), 3e3);
@@ -5759,10 +5785,15 @@ class Editor extends Component {
5759
5785
  hideLoading(this.ui.$el);
5760
5786
  }
5761
5787
  submit() {
5762
- this.ctx.trigger("editor-submit");
5788
+ const next = () => this.ctx.trigger("editor-submit");
5789
+ if (this.ctx.conf.beforeSubmit) {
5790
+ this.ctx.conf.beforeSubmit(this, next);
5791
+ } else {
5792
+ next();
5793
+ }
5763
5794
  }
5764
5795
  }
5765
- 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"></i></div>\n </div>\n <div class="atk-sidebar-iframe-wrap"></div>\n </div>\n</div>\n';
5796
+ 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';
5766
5797
  class SidebarLayer extends Component {
5767
5798
  constructor(ctx) {
5768
5799
  super(ctx);
@@ -6317,6 +6348,9 @@ function renderVerifyBadge(ctx) {
6317
6348
  $badge.innerText = badgeText.replace("管理员", t("admin"));
6318
6349
  $badge.style.backgroundColor = badgeColor || "";
6319
6350
  ctx.$headerBadgeWrap.append($badge);
6351
+ } else if (ctx.data.is_verified) {
6352
+ const $verifiedBadge = createElement(`<span class="atk-verified-icon" title="${t("emailVerified")}"></span>`);
6353
+ ctx.$headerBadgeWrap.append($verifiedBadge);
6320
6354
  }
6321
6355
  if (ctx.data.is_pinned) {
6322
6356
  const $pinnedBadge = createElement(`<span class="atk-pinned-badge">${t("pin")}</span>`);
@@ -7571,18 +7605,8 @@ class LayerWrap {
7571
7605
  if (this.items.map((l) => l.getEl()).filter((e) => e !== $el && e.isConnected && e.style.display !== "none").length > 0) {
7572
7606
  return;
7573
7607
  }
7574
- const onHide = () => {
7575
- this.$wrap.style.display = "none";
7576
- this.$wrap.classList.remove("atk-fade-out");
7577
- getScrollbarHelper().unlock();
7578
- this.$wrap.onanimationend = null;
7579
- };
7580
- this.$wrap.classList.add("atk-fade-out");
7581
- if (window.getComputedStyle(this.$wrap)["animation-name"] !== "none") {
7582
- this.$wrap.onanimationend = () => onHide();
7583
- } else {
7584
- onHide();
7585
- }
7608
+ this.$wrap.style.display = "none";
7609
+ getScrollbarHelper().unlock();
7586
7610
  }
7587
7611
  }
7588
7612
  class LayerManager {
@@ -7701,6 +7725,70 @@ const services = {
7701
7725
  return void 0;
7702
7726
  }
7703
7727
  };
7728
+ const PvCountWidget = (ctx) => {
7729
+ ctx.watchConf([
7730
+ "site",
7731
+ "pageKey",
7732
+ "pageTitle",
7733
+ "countEl",
7734
+ "pvEl"
7735
+ ], (conf) => {
7736
+ initCountWidget({
7737
+ getApi: () => ctx.getApi(),
7738
+ siteName: conf.site,
7739
+ pageKey: conf.pageKey,
7740
+ pageTitle: conf.pageTitle,
7741
+ countEl: conf.countEl,
7742
+ pvEl: conf.pvEl,
7743
+ pvAdd: typeof ctx.conf.pvAdd === "boolean" ? ctx.conf.pvAdd : true
7744
+ });
7745
+ });
7746
+ };
7747
+ function initCountWidget(opt) {
7748
+ return __async(this, null, function* () {
7749
+ if (opt.countEl && document.querySelector(opt.countEl)) {
7750
+ refreshStatCount(opt, { query: "page_comment", numEl: opt.countEl });
7751
+ }
7752
+ const initialData = opt.pvAdd && opt.pageKey ? {
7753
+ [opt.pageKey]: (yield opt.getApi().pages.logPv({
7754
+ page_key: opt.pageKey,
7755
+ page_title: opt.pageTitle,
7756
+ site_name: opt.siteName
7757
+ })).data.pv
7758
+ // pv+1 and get pv count
7759
+ } : void 0;
7760
+ if (opt.pvEl && document.querySelector(opt.pvEl)) {
7761
+ refreshStatCount(opt, {
7762
+ query: "page_pv",
7763
+ numEl: opt.pvEl,
7764
+ data: initialData
7765
+ });
7766
+ }
7767
+ });
7768
+ }
7769
+ function refreshStatCount(opt, args) {
7770
+ return __async(this, null, function* () {
7771
+ let data = args.data || {};
7772
+ let queryPageKeys = Array.from(document.querySelectorAll(args.numEl)).map((e) => e.getAttribute("data-page-key") || opt.pageKey).filter((k) => k && typeof data[k] !== "number");
7773
+ queryPageKeys = [...new Set(queryPageKeys)];
7774
+ if (queryPageKeys.length > 0) {
7775
+ const res = (yield opt.getApi().stats.getStats(args.query, {
7776
+ page_keys: queryPageKeys.join(","),
7777
+ site_name: opt.siteName
7778
+ })).data.data;
7779
+ data = __spreadValues(__spreadValues({}, data), res);
7780
+ }
7781
+ const defaultCount = opt.pageKey ? data[opt.pageKey] : 0;
7782
+ applyCountData(args.numEl, data, defaultCount);
7783
+ });
7784
+ }
7785
+ function applyCountData(selector, data, defaultCount) {
7786
+ document.querySelectorAll(selector).forEach((el) => {
7787
+ const pageKey = el.getAttribute("data-page-key");
7788
+ const count = Number(pageKey ? data[pageKey] : defaultCount);
7789
+ el.innerHTML = `${count}`;
7790
+ });
7791
+ }
7704
7792
  function showErrorDialog(opts) {
7705
7793
  const errEl = createElement(`<span><span class="error-message"></span><br/><br/></span>`);
7706
7794
  errEl.querySelector(".error-message").innerText = `${t("listLoadFailMsg")}
@@ -7717,58 +7805,6 @@ ${opts.errMsg}`;
7717
7805
  }
7718
7806
  setError(opts.$err, errEl);
7719
7807
  }
7720
- const ConfRemoter = (ctx) => {
7721
- ctx.on("created", () => {
7722
- if (ctx.conf.immediateFetch !== false)
7723
- ctx.trigger("conf-fetch");
7724
- });
7725
- ctx.on("conf-fetch", () => {
7726
- loadConf(ctx);
7727
- });
7728
- };
7729
- function loadConf(ctx) {
7730
- ctx.getApi().conf.conf().then((res) => {
7731
- var _a;
7732
- let conf = {
7733
- apiVersion: (_a = res.data.version) == null ? void 0 : _a.version
7734
- // version info
7735
- };
7736
- if (ctx.conf.useBackendConf) {
7737
- if (!res.data.frontend_conf)
7738
- throw new Error("The remote backend does not respond to the frontend conf, but `useBackendConf` conf is enabled");
7739
- conf = __spreadValues(__spreadValues({}, conf), handleConfFormServer(res.data.frontend_conf));
7740
- }
7741
- ctx.conf.remoteConfModifier && ctx.conf.remoteConfModifier(conf);
7742
- ctx.updateConf(conf);
7743
- }).catch((err) => {
7744
- var _a;
7745
- ctx.updateConf({});
7746
- let sidebarOpenView = "";
7747
- if ((_a = err.data) == null ? void 0 : _a.err_no_site) {
7748
- const viewLoadParam = { create_name: ctx.conf.site, create_urls: `${window.location.protocol}//${window.location.host}` };
7749
- sidebarOpenView = `sites|${JSON.stringify(viewLoadParam)}`;
7750
- }
7751
- showErrorDialog({
7752
- $err: ctx.get("list").$el,
7753
- errMsg: err.msg || String(err),
7754
- errData: err.data,
7755
- retryFn: () => loadConf(ctx),
7756
- onOpenSidebar: ctx.get("user").getData().isAdmin ? () => ctx.showSidebar({
7757
- view: sidebarOpenView
7758
- }) : void 0
7759
- // only show open sidebar button when user is admin
7760
- });
7761
- console.error(err);
7762
- throw err;
7763
- }).then(() => {
7764
- ctx.trigger("mounted");
7765
- }).then(() => {
7766
- if (ctx.conf.remoteConfModifier)
7767
- return;
7768
- ctx.fetch({ offset: 0 });
7769
- }).catch(() => {
7770
- });
7771
- }
7772
7808
  const Markdown = (ctx) => {
7773
7809
  initMarked();
7774
7810
  ctx.on("updated", (conf) => {
@@ -7924,7 +7960,7 @@ class Submit extends EditorPlug {
7924
7960
  this.defaultPreset.postSubmitAdd(nComment);
7925
7961
  } catch (err) {
7926
7962
  console.error(err);
7927
- this.kit.useEditor().showNotify(`${t("commentFail")}: ${err.msg || String(err)}`, "e");
7963
+ this.kit.useEditor().showNotify(`${t("commentFail")}: ${err.message || String(err)}`, "e");
7928
7964
  return;
7929
7965
  } finally {
7930
7966
  this.kit.useEditor().hideLoading();
@@ -7977,7 +8013,7 @@ class StateReply extends EditorPlug {
7977
8013
  const ui = this.kit.useUI();
7978
8014
  if (!ui.$sendReplyBtn) {
7979
8015
  const $btn = createElement(
7980
- `<span class="atk-state-btn"><span class="atk-text-wrap">${t("reply")} <span class="atk-text"></span></span><span class="atk-cancel">×</span></span>`
8016
+ `<span class="atk-state-btn"><span class="atk-text-wrap">${t("reply")} <span class="atk-text"></span></span><span class="atk-cancel atk-icon-close atk-icon"></span></span>`
7981
8017
  );
7982
8018
  $btn.querySelector(".atk-text").innerText = `@${commentData.nick}`;
7983
8019
  $btn.addEventListener("click", () => {
@@ -8042,7 +8078,7 @@ class StateEdit extends EditorPlug {
8042
8078
  const ui = this.kit.useUI();
8043
8079
  if (!ui.$editCancelBtn) {
8044
8080
  const $btn = createElement(
8045
- `<span class="atk-state-btn"><span class="atk-text-wrap">${t("editCancel")}</span><span class="atk-cancel">×</span></span>`
8081
+ `<span class="atk-state-btn"><span class="atk-text-wrap">${t("editCancel")}</span><span class="atk-cancel atk-icon-close atk-icon"></span></span>`
8046
8082
  );
8047
8083
  $btn.onclick = () => {
8048
8084
  this.kit.useEditor().resetState();
@@ -8577,7 +8613,7 @@ class Upload extends EditorPlug {
8577
8613
  }
8578
8614
  } catch (err) {
8579
8615
  console.error(err);
8580
- this.kit.useEditor().showNotify(`${t("uploadFail")}: ${err.msg}`, "e");
8616
+ this.kit.useEditor().showNotify(`${t("uploadFail")}: ${err.message}`, "e");
8581
8617
  }
8582
8618
  if (!!resp && resp.public_url) {
8583
8619
  let imgURL = resp.public_url;
@@ -8740,9 +8776,6 @@ class PlugManager {
8740
8776
  this.editor.getUI().$plugPanelWrap.innerHTML = "";
8741
8777
  this.editor.getUI().$plugPanelWrap.style.display = "none";
8742
8778
  this.editor.getUI().$plugBtnWrap.innerHTML = "";
8743
- this.editor.getUI().$el.addEventListener("click", (e) => {
8744
- e.stopPropagation();
8745
- });
8746
8779
  this.plugs.forEach((plug) => this.loadPluginItem(plug));
8747
8780
  }
8748
8781
  /** Load the plug btn and plug panel on editor ui */
@@ -8838,7 +8871,7 @@ function adminPageEditSave(ctx, page) {
8838
8871
  ctx.getApi().pages.updatePage(page.id, page).then(({ data }) => {
8839
8872
  ctx.getData().updatePage(data);
8840
8873
  }).catch((err) => {
8841
- ctx.editorShowNotify(`${t("editFail")}: ${err.msg || String(err)}`, "e");
8874
+ ctx.editorShowNotify(`${t("editFail")}: ${err.message || String(err)}`, "e");
8842
8875
  }).finally(() => {
8843
8876
  ctx.editorHideLoading();
8844
8877
  });
@@ -8984,7 +9017,7 @@ const GotoFocus = (ctx) => {
8984
9017
  comment.focus();
8985
9018
  }));
8986
9019
  };
8987
- const version = "2.8.2";
9020
+ const version = "2.8.4";
8988
9021
  const Copyright = (ctx) => {
8989
9022
  ctx.on("mounted", () => {
8990
9023
  const list2 = ctx.get("list");
@@ -9268,70 +9301,6 @@ const Notifies = (ctx) => {
9268
9301
  });
9269
9302
  });
9270
9303
  };
9271
- const PvCountWidget = (ctx) => {
9272
- ctx.watchConf([
9273
- "site",
9274
- "pageKey",
9275
- "pageTitle",
9276
- "countEl",
9277
- "pvEl"
9278
- ], (conf) => {
9279
- initCountWidget({
9280
- getApi: () => ctx.getApi(),
9281
- siteName: conf.site,
9282
- pageKey: conf.pageKey,
9283
- pageTitle: conf.pageTitle,
9284
- countEl: conf.countEl,
9285
- pvEl: conf.pvEl,
9286
- pvAdd: typeof ctx.conf.pvAdd === "boolean" ? ctx.conf.pvAdd : true
9287
- });
9288
- });
9289
- };
9290
- function initCountWidget(opt) {
9291
- return __async(this, null, function* () {
9292
- if (opt.countEl && document.querySelector(opt.countEl)) {
9293
- refreshStatCount(opt, { query: "page_comment", numEl: opt.countEl });
9294
- }
9295
- const initialData = opt.pvAdd && opt.pageKey ? {
9296
- [opt.pageKey]: (yield opt.getApi().pages.logPv({
9297
- page_key: opt.pageKey,
9298
- page_title: opt.pageTitle,
9299
- site_name: opt.siteName
9300
- })).data.pv
9301
- // pv+1 and get pv count
9302
- } : void 0;
9303
- if (opt.pvEl && document.querySelector(opt.pvEl)) {
9304
- refreshStatCount(opt, {
9305
- query: "page_pv",
9306
- numEl: opt.pvEl,
9307
- data: initialData
9308
- });
9309
- }
9310
- });
9311
- }
9312
- function refreshStatCount(opt, args) {
9313
- return __async(this, null, function* () {
9314
- let data = args.data || {};
9315
- let queryPageKeys = Array.from(document.querySelectorAll(args.numEl)).map((e) => e.getAttribute("data-page-key") || opt.pageKey).filter((k) => k && typeof data[k] !== "number");
9316
- queryPageKeys = [...new Set(queryPageKeys)];
9317
- if (queryPageKeys.length > 0) {
9318
- const res = (yield opt.getApi().stats.getStats(args.query, {
9319
- page_keys: queryPageKeys.join(","),
9320
- site_name: opt.siteName
9321
- })).data.data;
9322
- data = __spreadValues(__spreadValues({}, data), res);
9323
- }
9324
- const defaultCount = opt.pageKey ? data[opt.pageKey] : 0;
9325
- applyCountData(args.numEl, data, defaultCount);
9326
- });
9327
- }
9328
- function applyCountData(selector, data, defaultCount) {
9329
- document.querySelectorAll(selector).forEach((el) => {
9330
- const pageKey = el.getAttribute("data-page-key");
9331
- const count = Number(pageKey ? data[pageKey] : defaultCount);
9332
- el.innerHTML = `${count}`;
9333
- });
9334
- }
9335
9304
  let IgnoreVersionCheck = false;
9336
9305
  const VersionCheck = (ctx) => {
9337
9306
  ctx.watchConf(["apiVersion", "versionCheck"], (conf) => {
@@ -9425,7 +9394,6 @@ const DarkMode = (ctx) => {
9425
9394
  });
9426
9395
  };
9427
9396
  const DefaultPlugins = [
9428
- ConfRemoter,
9429
9397
  Markdown,
9430
9398
  EditorKit,
9431
9399
  AdminOnlyElem,
@@ -9436,23 +9404,100 @@ const DefaultPlugins = [
9436
9404
  DarkMode
9437
9405
  ];
9438
9406
  const GlobalPlugins = [...DefaultPlugins];
9407
+ function load(ctx) {
9408
+ return __async(this, null, function* () {
9409
+ var _a;
9410
+ const loadedPlugins = [];
9411
+ const loadPlugins = (plugins) => {
9412
+ plugins.forEach((plugin) => {
9413
+ if (typeof plugin === "function" && !loadedPlugins.includes(plugin)) {
9414
+ plugin(ctx);
9415
+ loadedPlugins.push(plugin);
9416
+ }
9417
+ });
9418
+ };
9419
+ loadPlugins(GlobalPlugins);
9420
+ const { data } = yield ctx.getApi().conf.conf().catch((err) => {
9421
+ onLoadErr(ctx, err);
9422
+ throw err;
9423
+ });
9424
+ let conf = {
9425
+ apiVersion: (_a = data.version) == null ? void 0 : _a.version
9426
+ // version info
9427
+ };
9428
+ if (ctx.conf.useBackendConf) {
9429
+ if (!data.frontend_conf)
9430
+ throw new Error("The remote backend does not respond to the frontend conf, but `useBackendConf` conf is enabled");
9431
+ conf = __spreadValues(__spreadValues({}, conf), handleConfFormServer(data.frontend_conf));
9432
+ }
9433
+ ctx.conf.remoteConfModifier && ctx.conf.remoteConfModifier(conf);
9434
+ conf.pluginURLs && (yield loadNetworkPlugins(conf.pluginURLs, ctx.conf.server).then((plugins) => {
9435
+ loadPlugins(plugins);
9436
+ }).catch((err) => {
9437
+ console.error("Failed to load plugin", err);
9438
+ }));
9439
+ ctx.trigger("created");
9440
+ ctx.updateConf(conf);
9441
+ ctx.trigger("mounted");
9442
+ if (!ctx.conf.remoteConfModifier) {
9443
+ ctx.fetch({ offset: 0 });
9444
+ }
9445
+ });
9446
+ }
9447
+ function loadNetworkPlugins(scripts, apiBase) {
9448
+ return __async(this, null, function* () {
9449
+ if (!scripts || !Array.isArray(scripts))
9450
+ return [];
9451
+ const tasks = [];
9452
+ scripts.forEach((url) => {
9453
+ if (!/^(http|https):\/\//.test(url))
9454
+ url = `${apiBase.replace(/\/$/, "")}/${url.replace(/^\//, "")}`;
9455
+ tasks.push(new Promise((resolve, reject) => {
9456
+ if (document.querySelector(`script[src="${url}"]`)) {
9457
+ resolve();
9458
+ return;
9459
+ }
9460
+ const script = document.createElement("script");
9461
+ script.src = url;
9462
+ document.head.appendChild(script);
9463
+ script.onload = () => resolve();
9464
+ script.onerror = (err) => reject(err);
9465
+ }));
9466
+ });
9467
+ yield Promise.all(tasks);
9468
+ return Object.values(window.ArtalkPlugins || {});
9469
+ });
9470
+ }
9471
+ function onLoadErr(ctx, err) {
9472
+ var _a;
9473
+ let sidebarOpenView = "";
9474
+ if ((_a = err.data) == null ? void 0 : _a.err_no_site) {
9475
+ const viewLoadParam = { create_name: ctx.conf.site, create_urls: `${window.location.protocol}//${window.location.host}` };
9476
+ sidebarOpenView = `sites|${JSON.stringify(viewLoadParam)}`;
9477
+ }
9478
+ showErrorDialog({
9479
+ $err: ctx.get("list").$el,
9480
+ errMsg: err.msg || String(err),
9481
+ errData: err.data,
9482
+ retryFn: () => load(ctx),
9483
+ onOpenSidebar: ctx.get("user").getData().isAdmin ? () => ctx.showSidebar({
9484
+ view: sidebarOpenView
9485
+ }) : void 0
9486
+ // only show open sidebar button when user is admin
9487
+ });
9488
+ }
9439
9489
  class Artalk {
9440
9490
  constructor(conf) {
9441
9491
  __publicField(this, "ctx");
9442
- /** Plugins */
9443
- __publicField(this, "plugins", [...GlobalPlugins]);
9444
9492
  const handledConf = handelCustomConf(conf, true);
9445
9493
  this.ctx = new Context(handledConf);
9446
9494
  Object.entries(services).forEach(([name, initService]) => {
9447
9495
  const obj = initService(this.ctx);
9448
- if (obj)
9449
- this.ctx.inject(name, obj);
9496
+ obj && this.ctx.inject(name, obj);
9450
9497
  });
9451
- this.plugins.forEach((plugin) => {
9452
- if (typeof plugin === "function")
9453
- plugin(this.ctx);
9454
- });
9455
- this.ctx.trigger("created");
9498
+ {
9499
+ load(this.ctx);
9500
+ }
9456
9501
  }
9457
9502
  /** Get the config of Artalk */
9458
9503
  getConf() {
@@ -9474,7 +9519,9 @@ class Artalk {
9474
9519
  /** Destroy instance of Artalk */
9475
9520
  destroy() {
9476
9521
  this.ctx.trigger("unmounted");
9477
- this.ctx.$root.remove();
9522
+ while (this.ctx.$root.firstChild) {
9523
+ this.ctx.$root.removeChild(this.ctx.$root.firstChild);
9524
+ }
9478
9525
  }
9479
9526
  /** Add an event listener */
9480
9527
  on(name, handler) {